Browse Source

Language client: added support for textDocument/diagnostic

master
eidheim 4 days ago
parent
commit
0e79894422
  1. 108
      src/source_language_protocol.cpp
  2. 4
      src/source_language_protocol.hpp

108
src/source_language_protocol.cpp

@ -277,7 +277,8 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize() {
"formatting": { "dynamicRegistration": false },
"rangeFormatting": { "dynamicRegistration": false },
"rename": { "dynamicRegistration": false },
"publishDiagnostics": { "relatedInformation":true }
"publishDiagnostics": { "relatedInformation": true },
"diagnostic": { "dynamicRegistration": false, "relatedDocumentSupport": true }
}
},
"initializationOptions": {
@ -340,6 +341,8 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize() {
capabilities.workspace_folders = change_notifications->boolean_or(true); // Can be string as well
}
}
// Workaround since rust-analyzer erroneously uses both publish and pull diagnostic
capabilities.pull_diagnostic = language_id == "rust" ? false : boolean_or_object("diagnosticProvider");
}
// See https://clangd.llvm.org/extensions.html#utf-8-offsets for documentation on offsetEncoding
@ -743,7 +746,10 @@ void Source::LanguageProtocolView::initialize() {
update_status_state(this);
}
update_type_coverage();
if(capabilities.type_coverage)
update_type_coverage();
if(capabilities.pull_diagnostic)
pull_diagnostic();
initialized = true;
};
@ -765,6 +771,7 @@ Source::LanguageProtocolView::~LanguageProtocolView() {
autocomplete_delayed_show_arguments_connection.disconnect();
resolve_completion_item_connection.disconnect();
update_type_coverage_connection.disconnect();
pull_diagnostic_connection.disconnect();
if(initialize_thread.joinable())
initialize_thread.join();
@ -878,7 +885,8 @@ bool Source::LanguageProtocolView::save() {
write_notification("textDocument/didSave");
update_type_coverage();
if(capabilities.type_coverage)
update_type_coverage();
return true;
}
@ -1545,6 +1553,12 @@ void Source::LanguageProtocolView::setup_signals() {
write_did_change_notification({{"contentChanges", "[{" + to_string({"text", '"' + JSON::escape_string(get_buffer()->get_text().raw()) + '"'}) + "}]"}});
});
}
if(capabilities.pull_diagnostic) {
get_buffer()->signal_changed().connect([this]() {
pull_diagnostic();
});
}
}
void Source::LanguageProtocolView::setup_autocomplete() {
@ -2526,44 +2540,64 @@ boost::optional<char> Source::LanguageProtocolView::get_named_parameter_symbol()
}
void Source::LanguageProtocolView::update_type_coverage() {
if(capabilities.type_coverage) {
write_request("textDocument/typeCoverage", {}, [this](JSON &&result, bool error) {
if(error) {
if(update_type_coverage_retries > 0) { // Retry typeCoverage request, since these requests can fail while waiting for language server to start
dispatcher.post([this] {
update_type_coverage_connection.disconnect();
update_type_coverage_connection = Glib::signal_timeout().connect(
[this]() {
--update_type_coverage_retries;
update_type_coverage();
return false;
},
1000);
});
}
return;
write_request("textDocument/typeCoverage", {}, [this](JSON &&result, bool error) {
if(error) {
if(update_type_coverage_retries > 0) { // Retry typeCoverage request, since these requests can fail while waiting for language server to start
dispatcher.post([this] {
update_type_coverage_connection.disconnect();
update_type_coverage_connection = Glib::signal_timeout().connect(
[this]() {
--update_type_coverage_retries;
update_type_coverage();
return false;
},
1000);
});
}
update_type_coverage_retries = 0;
return;
}
update_type_coverage_retries = 0;
std::vector<LanguageProtocol::Range> ranges;
for(auto &uncovered_range : result.array_or_empty("uncoveredRanges")) {
try {
ranges.emplace_back(uncovered_range.object("range"));
}
catch(...) {
}
std::vector<LanguageProtocol::Range> ranges;
for(auto &uncovered_range : result.array_or_empty("uncoveredRanges")) {
try {
ranges.emplace_back(uncovered_range.object("range"));
}
catch(...) {
}
}
dispatcher.post([this, ranges = std::move(ranges)] {
type_coverage_marks.clear();
for(auto &range : ranges) {
auto start = get_iter_at_line_pos(range.start.line, range.start.character);
auto end = get_iter_at_line_pos(range.end.line, range.end.character);
type_coverage_marks.emplace_back(start, end);
}
dispatcher.post([this, ranges = std::move(ranges)] {
type_coverage_marks.clear();
for(auto &range : ranges) {
auto start = get_iter_at_line_pos(range.start.line, range.start.character);
auto end = get_iter_at_line_pos(range.end.line, range.end.character);
type_coverage_marks.emplace_back(start, end);
}
update_diagnostics(last_diagnostics);
});
update_diagnostics(last_diagnostics);
});
}
});
}
void Source::LanguageProtocolView::pull_diagnostic() {
pull_diagnostic_connection.disconnect();
pull_diagnostic_connection = Glib::signal_timeout().connect(
[this]() {
write_request("textDocument/diagnostic", {}, [this](JSON &&result, bool error) {
if(!error) {
std::vector<std::shared_ptr<LanguageProtocol::Diagnostic>> diagnostics;
for(auto &child : result.array_or_empty("items")) {
try {
diagnostics.emplace_back(std::make_shared<LanguageProtocol::Diagnostic>(std::move(child)));
}
catch(...) {
}
}
update_diagnostics_async(std::move(diagnostics));
}
});
return false;
},
1000);
}

4
src/source_language_protocol.hpp

@ -140,6 +140,7 @@ namespace LanguageProtocol {
bool code_action_resolve = false;
bool execute_command = false;
bool type_coverage = false;
bool pull_diagnostic = false;
bool use_line_index = false;
};
@ -307,5 +308,8 @@ namespace Source {
size_t num_warnings = 0, num_errors = 0, num_fix_its = 0;
void update_type_coverage();
std::atomic<int> update_type_coverage_retries = {60};
sigc::connection pull_diagnostic_connection;
void pull_diagnostic();
};
} // namespace Source

Loading…
Cancel
Save