diff --git a/src/source_language_protocol.cpp b/src/source_language_protocol.cpp index 28c316f..d54cc74 100644 --- a/src/source_language_protocol.cpp +++ b/src/source_language_protocol.cpp @@ -49,6 +49,12 @@ LanguageProtocol::Diagnostic::Diagnostic(const boost::property_tree::ptree &pt) LanguageProtocol::TextEdit::TextEdit(const boost::property_tree::ptree &pt, std::string new_text_) : range(pt.get_child("range")), new_text(new_text_.empty() ? pt.get("newText") : std::move(new_text_)) {} +LanguageProtocol::TextDocumentEdit::TextDocumentEdit(const boost::property_tree::ptree &pt) : file(filesystem::get_path_from_uri(pt.get("textDocument.uri", "")).string()) { + auto edits_it = pt.get_child("edits", boost::property_tree::ptree()); + for(auto it = edits_it.begin(); it != edits_it.end(); ++it) + edits.emplace_back(it->second); +} + LanguageProtocol::Client::Client(boost::filesystem::path root_path_, std::string language_id_) : root_path(std::move(root_path_)), language_id(std::move(language_id_)) { process = std::make_unique( filesystem::escape_argument(language_id + "-language-server"), root_path.string(), @@ -774,16 +780,9 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() { } else if(auto changes_pt = result.get_child_optional("documentChanges")) { for(auto change_it = changes_pt->begin(); change_it != changes_pt->end(); ++change_it) { - if(auto document = change_it->second.get_child_optional("textDocument")) { - auto file = filesystem::get_path_from_uri(document->get("uri", "")); - if(filesystem::file_in_path(file, project_path)) { - std::vector edits; - auto edits_pt = change_it->second.get_child("edits", boost::property_tree::ptree()); - for(auto edit_it = edits_pt.begin(); edit_it != edits_pt.end(); ++edit_it) - edits.emplace_back(edit_it->second); - changes.emplace_back(Changes{file.string(), std::move(edits)}); - } - } + LanguageProtocol::TextDocumentEdit text_document_edit(change_it->second); + if(filesystem::file_in_path(text_document_edit.file, project_path)) + changes.emplace_back(Changes{std::move(text_document_edit.file), std::move(text_document_edit.edits)}); } } } @@ -1030,21 +1029,36 @@ void Source::LanguageProtocolView::update_diagnostics_async(std::vectorsecond.get("kind") == "quickfix") { + auto kind = it->second.get("kind", ""); + if(kind == "quickfix" || kind.empty()) { // Workaround for typescript-language-server (kind.empty()) auto title = it->second.get("title"); std::vector quickfix_diagnostics; if(auto diagnostics_pt = it->second.get_child_optional("diagnostics")) { for(auto it = diagnostics_pt->begin(); it != diagnostics_pt->end(); ++it) quickfix_diagnostics.emplace_back(it->second); } - auto changes = it->second.get_child("edit.changes"); - for(auto file_it = changes.begin(); file_it != changes.end(); ++file_it) { - for(auto edit_it = file_it->second.begin(); edit_it != file_it->second.end(); ++edit_it) { - LanguageProtocol::TextEdit edit(edit_it->second); - if(!quickfix_diagnostics.empty()) { - for(auto &diagnostic : diagnostics) { - for(auto &quickfix_diagnostic : quickfix_diagnostics) { - if(diagnostic.message == quickfix_diagnostic.message && diagnostic.range == quickfix_diagnostic.range) { + if(auto changes = it->second.get_child_optional("edit.changes")) { + for(auto file_it = changes->begin(); file_it != changes->end(); ++file_it) { + for(auto edit_it = file_it->second.begin(); edit_it != file_it->second.end(); ++edit_it) { + LanguageProtocol::TextEdit edit(edit_it->second); + if(!quickfix_diagnostics.empty()) { + for(auto &diagnostic : diagnostics) { + for(auto &quickfix_diagnostic : quickfix_diagnostics) { + if(diagnostic.message == quickfix_diagnostic.message && diagnostic.range == quickfix_diagnostic.range) { + auto pair = diagnostic.quickfixes.emplace(title, std::set{}); + pair.first->second.emplace( + edit.new_text, + filesystem::get_path_from_uri(file_it->first).string(), + std::make_pair(Offset(edit.range.start.line, edit.range.start.character), + Offset(edit.range.end.line, edit.range.end.character))); + break; + } + } + } + } + else { // Workaround for language server that does not report quickfix diagnostics + for(auto &diagnostic : diagnostics) { + if(edit.range.start.line == diagnostic.range.start.line) { auto pair = diagnostic.quickfixes.emplace(title, std::set{}); pair.first->second.emplace( edit.new_text, @@ -1056,16 +1070,47 @@ void Source::LanguageProtocolView::update_diagnostics_async(std::vector{}); - pair.first->second.emplace( - edit.new_text, - filesystem::get_path_from_uri(file_it->first).string(), - std::make_pair(Offset(edit.range.start.line, edit.range.start.character), - Offset(edit.range.end.line, edit.range.end.character))); - break; + } + } + else { + auto changes_pt = it->second.get_child_optional("edit.documentChanges"); + if(!changes_pt) { // Workaround for typescript-language-server + if(auto arguments_pt = it->second.get_child_optional("arguments")) { + if(!arguments_pt->empty()) + changes_pt = arguments_pt->begin()->second.get_child_optional("documentChanges"); + } + } + if(changes_pt) { + for(auto change_it = changes_pt->begin(); change_it != changes_pt->end(); ++change_it) { + LanguageProtocol::TextDocumentEdit text_document_edit(change_it->second); + for(auto &edit : text_document_edit.edits) { + if(!quickfix_diagnostics.empty()) { + for(auto &diagnostic : diagnostics) { + for(auto &quickfix_diagnostic : quickfix_diagnostics) { + if(diagnostic.message == quickfix_diagnostic.message && diagnostic.range == quickfix_diagnostic.range) { + auto pair = diagnostic.quickfixes.emplace(title, std::set{}); + pair.first->second.emplace( + edit.new_text, + text_document_edit.file, + std::make_pair(Offset(edit.range.start.line, edit.range.start.character), + Offset(edit.range.end.line, edit.range.end.character))); + break; + } + } + } + } + else { // Workaround for language server that does not report quickfix diagnostics + for(auto &diagnostic : diagnostics) { + if(edit.range.start.line == diagnostic.range.start.line) { + auto pair = diagnostic.quickfixes.emplace(title, std::set{}); + pair.first->second.emplace( + edit.new_text, + text_document_edit.file, + std::make_pair(Offset(edit.range.start.line, edit.range.start.character), + Offset(edit.range.end.line, edit.range.end.character))); + break; + } + } } } } diff --git a/src/source_language_protocol.hpp b/src/source_language_protocol.hpp index cfd5b28..0175017 100644 --- a/src/source_language_protocol.hpp +++ b/src/source_language_protocol.hpp @@ -83,6 +83,14 @@ namespace LanguageProtocol { std::string new_text; }; + class TextDocumentEdit { + public: + TextDocumentEdit(const boost::property_tree::ptree &pt); + + std::string file; + std::vector edits; + }; + class Capabilities { public: enum class TextDocumentSync { none = 0,