Browse Source

Language protocol: added support for flow's typeCoverage instead of using the flow binary to find coverage warnings

merge-requests/398/head
eidheim 7 years ago
parent
commit
616f091962
  1. 105
      src/source_language_protocol.cc
  2. 10
      src/source_language_protocol.h

105
src/source_language_protocol.cc

@ -133,6 +133,7 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize(Source::Lang
capabilities.document_formatting = capabilities_pt->second.get<bool>("documentFormattingProvider", false); capabilities.document_formatting = capabilities_pt->second.get<bool>("documentFormattingProvider", false);
capabilities.document_range_formatting = capabilities_pt->second.get<bool>("documentRangeFormattingProvider", false); capabilities.document_range_formatting = capabilities_pt->second.get<bool>("documentRangeFormattingProvider", false);
capabilities.rename = capabilities_pt->second.get<bool>("renameProvider", false); capabilities.rename = capabilities_pt->second.get<bool>("renameProvider", false);
capabilities.type_coverage = capabilities_pt->second.get<bool>("typeCoverageProvider", false);
} }
write_notification("initialized", ""); write_notification("initialized", "");
@ -353,21 +354,6 @@ Source::LanguageProtocolView::LanguageProtocolView(const boost::filesystem::path
get_source_buffer()->set_language(language); get_source_buffer()->set_language(language);
get_source_buffer()->set_highlight_syntax(true); 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<Project::NpmBuild *>(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); initialize(true);
get_buffer()->signal_insert().connect([this](const Gtk::TextBuffer::iterator &start, const Glib::ustring &text_, int bytes) { 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); update_status_state(this);
initialize_thread = std::thread([this, setup] { initialize_thread = std::thread([this, setup] {
if(!flow_coverage_executable.empty())
update_flow_coverage();
auto capabilities = client->initialize(this); auto capabilities = client->initialize(this);
dispatcher.post([this, capabilities, setup] { dispatcher.post([this, capabilities, setup] {
@ -435,6 +418,8 @@ void Source::LanguageProtocolView::initialize(bool setup) {
if(update_status_state) if(update_status_state)
update_status_state(this); update_status_state(this);
} }
update_type_coverage();
}); });
}); });
} }
@ -445,9 +430,6 @@ void Source::LanguageProtocolView::close() {
if(initialize_thread.joinable()) if(initialize_thread.joinable())
initialize_thread.join(); initialize_thread.join();
if(flow_coverage_thread.joinable())
flow_coverage_thread.join();
autocomplete.state = Autocomplete::State::IDLE; autocomplete.state = Autocomplete::State::IDLE;
if(autocomplete.thread.joinable()) if(autocomplete.thread.joinable())
autocomplete.thread.join(); autocomplete.thread.join();
@ -473,19 +455,7 @@ bool Source::LanguageProtocolView::save() {
if(!Source::View::save()) if(!Source::View::save())
return false; return false;
if(!flow_coverage_executable.empty()) { update_type_coverage();
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();
});
}
return true; return true;
} }
@ -942,10 +912,10 @@ void Source::LanguageProtocolView::update_diagnostics(std::vector<LanguageProtoc
dispatcher.post([this, diagnostics = std::move(diagnostics)]() { dispatcher.post([this, diagnostics = std::move(diagnostics)]() {
diagnostic_offsets.clear(); diagnostic_offsets.clear();
diagnostic_tooltips.clear(); diagnostic_tooltips.clear();
if(flow_coverage_executable.empty()) if(!capabilities.type_coverage)
get_buffer()->remove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end()); get_buffer()->remove_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()); get_buffer()->remove_tag_by_name("def:error_underline", get_buffer()->begin(), get_buffer()->end());
flow_coverage_cleared_diagnostic_tooltips = true; if(!capabilities.type_coverage)
num_warnings = 0; num_warnings = 0;
num_errors = 0; num_errors = 0;
num_fix_its = 0; num_fix_its = 0;
@ -993,12 +963,12 @@ void Source::LanguageProtocolView::update_diagnostics(std::vector<LanguageProtoc
}); });
} }
for(auto &mark : flow_coverage_marks) for(auto &mark : type_coverage_marks)
add_diagnostic_tooltip(mark.first->get_iter(), mark.second->get_iter(), false, [](const Glib::RefPtr<Gtk::TextBuffer> &buffer) { add_diagnostic_tooltip(mark.first->get_iter(), mark.second->get_iter(), false, [](const Glib::RefPtr<Gtk::TextBuffer> &buffer) {
buffer->insert_at_cursor(flow_coverage_message); 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) if(update_status_diagnostics)
update_status_diagnostics(this); update_status_diagnostics(this);
}); });
@ -1510,45 +1480,44 @@ bool Source::LanguageProtocolView::has_named_parameters() {
return false; return false;
} }
void Source::LanguageProtocolView::update_flow_coverage() { void Source::LanguageProtocolView::update_type_coverage() {
std::stringstream stdin_stream, stderr_stream; if(capabilities.type_coverage) {
auto stdout_stream = std::make_shared<std::stringstream>(); client->write_request(this, "textDocument/typeCoverage", R"("textDocument": {"uri":")" + uri + "\"}", [this](const boost::property_tree::ptree &result, bool error) {
auto exit_status = Terminal::get().process(stdin_stream, *stdout_stream, flow_coverage_executable.string() + " coverage --json " + filesystem::escape_argument(file_path.string()), "", &stderr_stream); if(!error) {
std::vector<LanguageProtocol::Range> 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(...) {
}
}
dispatcher.post([this, exit_status, stdout_stream] { dispatcher.post([this, ranges = std::move(ranges)] {
if(!flow_coverage_cleared_diagnostic_tooltips) { num_warnings = 0;
diagnostic_offsets.clear(); for(auto &mark : type_coverage_marks) {
diagnostic_tooltips.clear(); get_buffer()->delete_mark(mark.first);
flow_coverage_cleared_diagnostic_tooltips = true; 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()); get_buffer()->remove_tag_by_name("def:warning_underline", get_buffer()->begin(), get_buffer()->end());
for(auto &range : ranges) {
num_flow_coverage_warnings = 0; 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);
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<int>("line") - 1, start_pt.get<int>("column") - 1);
auto end_pt = it->second.get_child("end");
auto end = get_iter_at_line_offset(end_pt.get<int>("line") - 1, end_pt.get<int>("column"));
add_diagnostic_tooltip(start, end, false, [](const Glib::RefPtr<Gtk::TextBuffer> &buffer) { add_diagnostic_tooltip(start, end, false, [](const Glib::RefPtr<Gtk::TextBuffer> &buffer) {
buffer->insert_at_cursor(flow_coverage_message); buffer->insert_at_cursor(flow_coverage_message);
}); });
++num_flow_coverage_warnings; type_coverage_marks.emplace_back(get_buffer()->create_mark(start), get_buffer()->create_mark(end));
flow_coverage_marks.emplace_back(get_buffer()->create_mark(start), get_buffer()->create_mark(end)); ++num_warnings;
}
}
catch(...) {
} }
}
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) if(update_status_diagnostics)
update_status_diagnostics(this); update_status_diagnostics(this);
}); });
}
});
}
} }

10
src/source_language_protocol.h

@ -95,6 +95,7 @@ namespace LanguageProtocol {
bool document_formatting; bool document_formatting;
bool document_range_formatting; bool document_range_formatting;
bool rename; bool rename;
bool type_coverage;
}; };
class Client { class Client {
@ -190,11 +191,8 @@ namespace Source {
bool has_named_parameters(); bool has_named_parameters();
boost::filesystem::path flow_coverage_executable; std::vector<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark>>> type_coverage_marks;
std::thread flow_coverage_thread; size_t num_warnings = 0, num_errors = 0, num_fix_its = 0;
bool flow_coverage_cleared_diagnostic_tooltips = false; void update_type_coverage();
std::vector<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark>>> flow_coverage_marks;
size_t num_warnings = 0, num_errors = 0, num_fix_its = 0, num_flow_coverage_warnings = 0;
void update_flow_coverage();
}; };
} // namespace Source } // namespace Source

Loading…
Cancel
Save