From 35f094d2c8ca1b18628af618eaae83e5f5d9ba1b Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 11 May 2018 10:25:46 +0200 Subject: [PATCH] Language protocol: added Flow coverage support --- src/source.cc | 7 +++ src/source_clang.cc | 8 +-- src/source_language_protocol.cc | 86 ++++++++++++++++++++++++++++----- src/source_language_protocol.h | 8 +++ 4 files changed, 91 insertions(+), 18 deletions(-) diff --git a/src/source.cc b/src/source.cc index 07c867e..b196a93 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1173,6 +1173,13 @@ void Source::View::add_diagnostic_tooltip(const Gtk::TextIter &start, const Gtk: diagnostic_tooltips.emplace_back(create_tooltip_buffer, this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); get_buffer()->apply_tag_by_name(severity_tag_name+"_underline", start, end); + + auto iter=get_buffer()->get_insert()->get_iter(); + if(iter.ends_line()) { + auto next_iter=iter; + if(next_iter.forward_char()) + get_buffer()->remove_tag_by_name(severity_tag_name+"_underline", iter, next_iter); + } } void Source::View::clear_diagnostic_tooltips() { diff --git a/src/source_clang.cc b/src/source_clang.cc index 33e7504..afd6076 100644 --- a/src/source_clang.cc +++ b/src/source_clang.cc @@ -338,14 +338,8 @@ void Source::ClangViewParse::update_diagnostics() { if(!fix_its_string.empty()) diagnostic.spelling+="\n\n"+fix_its_string; - add_diagnostic_tooltip(start, end, diagnostic.spelling, error); - auto iter=get_buffer()->get_insert()->get_iter(); - if(iter.ends_line()) { - auto next_iter=iter; - if(next_iter.forward_char()) - get_buffer()->remove_tag_by_name(severity_tag_name+"_underline", iter, next_iter); - } + add_diagnostic_tooltip(start, end, diagnostic.spelling, error); } } status_diagnostics=std::make_tuple(num_warnings, num_errors, num_fix_its); diff --git a/src/source_language_protocol.cc b/src/source_language_protocol.cc index a309e18..2bf356e 100644 --- a/src/source_language_protocol.cc +++ b/src/source_language_protocol.cc @@ -330,8 +330,27 @@ Source::LanguageProtocolView::LanguageProtocolView(const boost::filesystem::path if(update_status_state) update_status_state(this); + 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(!build->project_path.empty() && boost::filesystem::exists(build->project_path/".flowconfig", ec)) { + auto executable=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_thread=std::thread([this] { auto capabilities=client->initialize(this); + + if(!flow_coverage_executable.empty()) + add_flow_coverage_tooltips(); + dispatcher.post([this, capabilities] { this->capabilities=capabilities; @@ -413,6 +432,16 @@ Source::LanguageProtocolView::~LanguageProtocolView() { client=nullptr; } +bool Source::LanguageProtocolView::save() { + if(!Source::View::save()) + return false; + + if(!flow_coverage_executable.empty()) + add_flow_coverage_tooltips(); + + return true; +} + void Source::LanguageProtocolView::setup_navigation_and_refactoring() { if(capabilities.document_formatting) { format_style=[this](bool continue_without_style_file) { @@ -865,9 +894,9 @@ void Source::LanguageProtocolView::unescape_text(std::string &text) { void Source::LanguageProtocolView::update_diagnostics(std::vector &&diagnostics) { dispatcher.post([this, diagnostics=std::move(diagnostics)] { clear_diagnostic_tooltips(); - size_t num_warnings=0; - size_t num_errors=0; - size_t num_fix_its=0; + num_warnings=0; + num_errors=0; + num_fix_its=0; for(auto &diagnostic: diagnostics) { if(diagnostic.uri==uri) { auto start=get_iter_at_line_pos(diagnostic.offsets.first.line, diagnostic.offsets.first.index); @@ -893,16 +922,13 @@ void Source::LanguageProtocolView::update_diagnostics(std::vectorget_insert()->get_iter(); - if(iter.ends_line()) { - auto next_iter=iter; - if(next_iter.forward_char()) - get_buffer()->remove_tag_by_name(severity_tag_name+"_underline", iter, next_iter); - } } } - status_diagnostics=std::make_tuple(num_warnings, num_errors, num_fix_its); + + for(auto &mark: flow_coverage_marks) + add_diagnostic_tooltip(mark.first->get_iter(), mark.second->get_iter(), flow_coverage_message, false); + + status_diagnostics=std::make_tuple(num_warnings+num_flow_coverage_warnings, num_errors, num_fix_its); if(update_status_diagnostics) update_status_diagnostics(this); }); @@ -1339,3 +1365,41 @@ void Source::LanguageProtocolView::setup_autocomplete() { return autocomplete_comment[index]; }; } + +void Source::LanguageProtocolView::add_flow_coverage_tooltips() { + 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 "+file_path.string(), "", &stderr_stream); + dispatcher.post([this, exit_status, stdout_stream] { + clear_diagnostic_tooltips(); + num_flow_coverage_warnings=0; + for(auto &mark: flow_coverage_marks) { + get_buffer()->delete_mark(mark.first); + get_buffer()->delete_mark(mark.second); + } + flow_coverage_marks.clear(); + + 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, flow_coverage_message, false); + ++num_flow_coverage_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_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 8b092af..e32221d 100644 --- a/src/source_language_protocol.h +++ b/src/source_language_protocol.h @@ -87,6 +87,8 @@ namespace Source { LanguageProtocolView(const boost::filesystem::path &file_path, Glib::RefPtr language, std::string language_id_); ~LanguageProtocolView(); std::string uri; + + bool save() override; void update_diagnostics(std::vector &&diagnostics); @@ -123,5 +125,11 @@ namespace Source { std::vector autocomplete_insert; std::list, Glib::RefPtr>> autocomplete_marks; bool autocomplete_keep_marks = false; + + boost::filesystem::path flow_coverage_executable; + std::vector, Glib::RefPtr>> flow_coverage_marks; + const std::string flow_coverage_message="Not covered by Flow"; + size_t num_warnings=0, num_errors=0, num_fix_its=0, num_flow_coverage_warnings=0; + void add_flow_coverage_tooltips(); }; } // namespace Source