From 616f091962f8478a0a22142ef4694611157771e6 Mon Sep 17 00:00:00 2001 From: eidheim Date: Tue, 18 Jun 2019 11:26:19 +0200 Subject: [PATCH] Language protocol: added support for flow's typeCoverage instead of using the flow binary to find coverage warnings --- src/source_language_protocol.cc | 123 ++++++++++++-------------------- src/source_language_protocol.h | 10 ++- 2 files changed, 50 insertions(+), 83 deletions(-) diff --git a/src/source_language_protocol.cc b/src/source_language_protocol.cc index a62dfb6..2740fd2 100644 --- a/src/source_language_protocol.cc +++ b/src/source_language_protocol.cc @@ -133,6 +133,7 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize(Source::Lang capabilities.document_formatting = capabilities_pt->second.get("documentFormattingProvider", false); capabilities.document_range_formatting = capabilities_pt->second.get("documentRangeFormattingProvider", false); capabilities.rename = capabilities_pt->second.get("renameProvider", false); + capabilities.type_coverage = capabilities_pt->second.get("typeCoverageProvider", false); } write_notification("initialized", ""); @@ -353,21 +354,6 @@ Source::LanguageProtocolView::LanguageProtocolView(const boost::filesystem::path get_source_buffer()->set_language(language); get_source_buffer()->set_highlight_syntax(true); - if(language_id == "javascript") { - boost::filesystem::path project_path; - auto build = Project::Build::create(file_path); - if(auto npm_build = dynamic_cast(build.get())) { - boost::system::error_code ec; - if(!npm_build->project_path.empty() && boost::filesystem::exists(npm_build->project_path / ".flowconfig", ec)) { - auto executable = npm_build->project_path / "node_modules" / ".bin" / "flow"; // It is recommended to use Flow binary installed in project, despite the security risk of doing so... - if(boost::filesystem::exists(executable, ec)) - flow_coverage_executable = executable; - else - flow_coverage_executable = filesystem::find_executable("flow"); - } - } - } - initialize(true); get_buffer()->signal_insert().connect([this](const Gtk::TextBuffer::iterator &start, const Glib::ustring &text_, int bytes) { @@ -412,9 +398,6 @@ void Source::LanguageProtocolView::initialize(bool setup) { update_status_state(this); initialize_thread = std::thread([this, setup] { - if(!flow_coverage_executable.empty()) - update_flow_coverage(); - auto capabilities = client->initialize(this); dispatcher.post([this, capabilities, setup] { @@ -435,6 +418,8 @@ void Source::LanguageProtocolView::initialize(bool setup) { if(update_status_state) update_status_state(this); } + + update_type_coverage(); }); }); } @@ -445,9 +430,6 @@ void Source::LanguageProtocolView::close() { if(initialize_thread.joinable()) initialize_thread.join(); - if(flow_coverage_thread.joinable()) - flow_coverage_thread.join(); - autocomplete.state = Autocomplete::State::IDLE; if(autocomplete.thread.joinable()) autocomplete.thread.join(); @@ -473,19 +455,7 @@ bool Source::LanguageProtocolView::save() { if(!Source::View::save()) return false; - if(!flow_coverage_executable.empty()) { - if(flow_coverage_thread.joinable()) - flow_coverage_thread.join(); - flow_coverage_cleared_diagnostic_tooltips = false; - for(auto &mark : flow_coverage_marks) { - get_buffer()->delete_mark(mark.first); - get_buffer()->delete_mark(mark.second); - } - flow_coverage_marks.clear(); - flow_coverage_thread = std::thread([this] { - update_flow_coverage(); - }); - } + update_type_coverage(); return true; } @@ -942,11 +912,11 @@ void Source::LanguageProtocolView::update_diagnostics(std::vectorremove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end()); get_buffer()->remove_tag_by_name("def:error_underline", get_buffer()->begin(), get_buffer()->end()); - flow_coverage_cleared_diagnostic_tooltips = true; - num_warnings = 0; + if(!capabilities.type_coverage) + num_warnings = 0; num_errors = 0; num_fix_its = 0; for(auto &diagnostic : diagnostics) { @@ -993,12 +963,12 @@ void Source::LanguageProtocolView::update_diagnostics(std::vectorget_iter(), mark.second->get_iter(), false, [](const Glib::RefPtr &buffer) { buffer->insert_at_cursor(flow_coverage_message); }); - status_diagnostics = std::make_tuple(num_warnings + num_flow_coverage_warnings, num_errors, num_fix_its); + status_diagnostics = std::make_tuple(num_warnings, num_errors, num_fix_its); if(update_status_diagnostics) update_status_diagnostics(this); }); @@ -1510,45 +1480,44 @@ bool Source::LanguageProtocolView::has_named_parameters() { return false; } -void Source::LanguageProtocolView::update_flow_coverage() { - std::stringstream stdin_stream, stderr_stream; - auto stdout_stream = std::make_shared(); - auto exit_status = Terminal::get().process(stdin_stream, *stdout_stream, flow_coverage_executable.string() + " coverage --json " + filesystem::escape_argument(file_path.string()), "", &stderr_stream); - - dispatcher.post([this, exit_status, stdout_stream] { - if(!flow_coverage_cleared_diagnostic_tooltips) { - diagnostic_offsets.clear(); - diagnostic_tooltips.clear(); - flow_coverage_cleared_diagnostic_tooltips = true; - } - get_buffer()->remove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end()); - - num_flow_coverage_warnings = 0; +void Source::LanguageProtocolView::update_type_coverage() { + if(capabilities.type_coverage) { + client->write_request(this, "textDocument/typeCoverage", R"("textDocument": {"uri":")" + uri + "\"}", [this](const boost::property_tree::ptree &result, bool error) { + if(!error) { + std::vector ranges; + auto uncoveredRanges = result.get_child("uncoveredRanges", boost::property_tree::ptree()); + for(auto it = uncoveredRanges.begin(); it != uncoveredRanges.end(); ++it) { + try { + ranges.emplace_back(it->second.get_child("range")); + } + catch(...) { + } + } - if(exit_status == 0) { - boost::property_tree::ptree pt; - try { - boost::property_tree::read_json(*stdout_stream, pt); - auto uncovered_locs_pt = pt.get_child("expressions.uncovered_locs"); - for(auto it = uncovered_locs_pt.begin(); it != uncovered_locs_pt.end(); ++it) { - auto start_pt = it->second.get_child("start"); - auto start = get_iter_at_line_offset(start_pt.get("line") - 1, start_pt.get("column") - 1); - auto end_pt = it->second.get_child("end"); - auto end = get_iter_at_line_offset(end_pt.get("line") - 1, end_pt.get("column")); - - add_diagnostic_tooltip(start, end, false, [](const Glib::RefPtr &buffer) { - buffer->insert_at_cursor(flow_coverage_message); - }); - ++num_flow_coverage_warnings; + dispatcher.post([this, ranges = std::move(ranges)] { + num_warnings = 0; + for(auto &mark : type_coverage_marks) { + get_buffer()->delete_mark(mark.first); + get_buffer()->delete_mark(mark.second); + } + type_coverage_marks.clear(); + get_buffer()->remove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end()); + for(auto &range : ranges) { + auto start = get_iter_at_line_offset(range.start.line, range.start.character); + auto end = get_iter_at_line_offset(range.end.line, range.end.character); + add_diagnostic_tooltip(start, end, false, [](const Glib::RefPtr &buffer) { + buffer->insert_at_cursor(flow_coverage_message); + }); + type_coverage_marks.emplace_back(get_buffer()->create_mark(start), get_buffer()->create_mark(end)); + + ++num_warnings; + } - flow_coverage_marks.emplace_back(get_buffer()->create_mark(start), get_buffer()->create_mark(end)); - } - } - catch(...) { + status_diagnostics = std::make_tuple(num_warnings, num_errors, num_fix_its); + if(update_status_diagnostics) + update_status_diagnostics(this); + }); } - } - status_diagnostics = std::make_tuple(num_warnings + num_flow_coverage_warnings, num_errors, num_fix_its); - if(update_status_diagnostics) - update_status_diagnostics(this); - }); + }); + } } diff --git a/src/source_language_protocol.h b/src/source_language_protocol.h index d1932ff..80a7357 100644 --- a/src/source_language_protocol.h +++ b/src/source_language_protocol.h @@ -95,6 +95,7 @@ namespace LanguageProtocol { bool document_formatting; bool document_range_formatting; bool rename; + bool type_coverage; }; class Client { @@ -190,11 +191,8 @@ namespace Source { bool has_named_parameters(); - boost::filesystem::path flow_coverage_executable; - std::thread flow_coverage_thread; - bool flow_coverage_cleared_diagnostic_tooltips = false; - std::vector, Glib::RefPtr>> flow_coverage_marks; - size_t num_warnings = 0, num_errors = 0, num_fix_its = 0, num_flow_coverage_warnings = 0; - void update_flow_coverage(); + std::vector, Glib::RefPtr>> type_coverage_marks; + size_t num_warnings = 0, num_errors = 0, num_fix_its = 0; + void update_type_coverage(); }; } // namespace Source