|
|
|
@ -119,6 +119,7 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize(Source::Lang |
|
|
|
capabilities.text_document_sync = static_cast<LanguageProtocol::Capabilities::TextDocumentSync>(capabilities_pt->second.get<int>("textDocumentSync", 0)); |
|
|
|
capabilities.text_document_sync = static_cast<LanguageProtocol::Capabilities::TextDocumentSync>(capabilities_pt->second.get<int>("textDocumentSync", 0)); |
|
|
|
capabilities.hover = capabilities_pt->second.get<bool>("hoverProvider", false); |
|
|
|
capabilities.hover = capabilities_pt->second.get<bool>("hoverProvider", false); |
|
|
|
capabilities.completion = capabilities_pt->second.find("completionProvider") != capabilities_pt->second.not_found() ? true : false; |
|
|
|
capabilities.completion = capabilities_pt->second.find("completionProvider") != capabilities_pt->second.not_found() ? true : false; |
|
|
|
|
|
|
|
capabilities.signature_help = capabilities_pt->second.find("signatureHelpProvider") != capabilities_pt->second.not_found() ? true : false; |
|
|
|
capabilities.definition = capabilities_pt->second.get<bool>("definitionProvider", false); |
|
|
|
capabilities.definition = capabilities_pt->second.get<bool>("definitionProvider", false); |
|
|
|
capabilities.references = capabilities_pt->second.get<bool>("referencesProvider", false); |
|
|
|
capabilities.references = capabilities_pt->second.get<bool>("referencesProvider", false); |
|
|
|
capabilities.document_highlight = capabilities_pt->second.get<bool>("documentHighlightProvider", false); |
|
|
|
capabilities.document_highlight = capabilities_pt->second.get<bool>("documentHighlightProvider", false); |
|
|
|
@ -433,6 +434,8 @@ void Source::LanguageProtocolView::initialize(bool setup) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Source::LanguageProtocolView::close() { |
|
|
|
void Source::LanguageProtocolView::close() { |
|
|
|
|
|
|
|
autocomplete_delayed_show_arguments_connection.disconnect(); |
|
|
|
|
|
|
|
|
|
|
|
if(initialize_thread.joinable()) |
|
|
|
if(initialize_thread.joinable()) |
|
|
|
initialize_thread.join(); |
|
|
|
initialize_thread.join(); |
|
|
|
|
|
|
|
|
|
|
|
@ -1145,6 +1148,50 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
autocomplete_insert.clear(); |
|
|
|
autocomplete_insert.clear(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(capabilities.signature_help) { |
|
|
|
|
|
|
|
// Activate argument completions
|
|
|
|
|
|
|
|
get_buffer()->signal_changed().connect([this] { |
|
|
|
|
|
|
|
if(!interactive_completion) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
if(!has_focus()) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
if(autocomplete_show_parameters) |
|
|
|
|
|
|
|
autocomplete.stop(); |
|
|
|
|
|
|
|
autocomplete_show_parameters = false; |
|
|
|
|
|
|
|
autocomplete_delayed_show_arguments_connection.disconnect(); |
|
|
|
|
|
|
|
autocomplete_delayed_show_arguments_connection = Glib::signal_timeout().connect([this]() { |
|
|
|
|
|
|
|
if(get_buffer()->get_has_selection()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if(!has_focus()) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if(is_possible_argument()) { |
|
|
|
|
|
|
|
autocomplete.stop(); |
|
|
|
|
|
|
|
autocomplete.run(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
}, 500); |
|
|
|
|
|
|
|
}, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Remove argument completions
|
|
|
|
|
|
|
|
if(!has_named_parameters()) { // Do not remove named parameters in for instance Python
|
|
|
|
|
|
|
|
signal_key_press_event().connect([this](GdkEventKey *key) { |
|
|
|
|
|
|
|
if(autocomplete_show_parameters && CompletionDialog::get() && CompletionDialog::get()->is_visible() && |
|
|
|
|
|
|
|
key->keyval != GDK_KEY_Down && key->keyval != GDK_KEY_Up && |
|
|
|
|
|
|
|
key->keyval != GDK_KEY_Return && key->keyval != GDK_KEY_KP_Enter && |
|
|
|
|
|
|
|
key->keyval != GDK_KEY_ISO_Left_Tab && key->keyval != GDK_KEY_Tab && |
|
|
|
|
|
|
|
(key->keyval < GDK_KEY_Shift_L || key->keyval > GDK_KEY_Hyper_R)) { |
|
|
|
|
|
|
|
get_buffer()->erase(CompletionDialog::get()->start_mark->get_iter(), get_buffer()->get_insert()->get_iter()); |
|
|
|
|
|
|
|
CompletionDialog::get()->hide(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
}, false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
autocomplete.is_continue_key = [](guint keyval) { |
|
|
|
autocomplete.is_continue_key = [](guint keyval) { |
|
|
|
if((keyval >= '0' && keyval <= '9') || (keyval >= 'a' && keyval <= 'z') || (keyval >= 'A' && keyval <= 'Z') || keyval == '_') |
|
|
|
if((keyval >= '0' && keyval <= '9') || (keyval >= 'a' && keyval <= 'z') || (keyval >= 'A' && keyval <= 'Z') || keyval == '_') |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
@ -1166,6 +1213,8 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
if(!is_code_iter(iter)) |
|
|
|
if(!is_code_iter(iter)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
autocomplete_show_parameters = false; |
|
|
|
|
|
|
|
|
|
|
|
std::string line = " " + get_line_before(); |
|
|
|
std::string line = " " + get_line_before(); |
|
|
|
const static std::regex dot_or_arrow(R"(^.*[a-zA-Z0-9_\)\]\>"'](\.)([a-zA-Z0-9_]*)$)"); |
|
|
|
const static std::regex dot_or_arrow(R"(^.*[a-zA-Z0-9_\)\]\>"'](\.)([a-zA-Z0-9_]*)$)"); |
|
|
|
const static std::regex colon_colon(R"(^.*::([a-zA-Z0-9_]*)$)"); |
|
|
|
const static std::regex colon_colon(R"(^.*::([a-zA-Z0-9_]*)$)"); |
|
|
|
@ -1195,6 +1244,12 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
if(autocomplete.prefix.size() == 0 || autocomplete.prefix[0] < '0' || autocomplete.prefix[0] > '9') |
|
|
|
if(autocomplete.prefix.size() == 0 || autocomplete.prefix[0] < '0' || autocomplete.prefix[0] > '9') |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else if(is_possible_argument()) { |
|
|
|
|
|
|
|
autocomplete_show_parameters = true; |
|
|
|
|
|
|
|
std::unique_lock<std::mutex> lock(autocomplete.prefix_mutex); |
|
|
|
|
|
|
|
autocomplete.prefix = ""; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
else if(!interactive_completion) { |
|
|
|
else if(!interactive_completion) { |
|
|
|
auto end_iter = get_buffer()->get_insert()->get_iter(); |
|
|
|
auto end_iter = get_buffer()->get_insert()->get_iter(); |
|
|
|
auto iter = end_iter; |
|
|
|
auto iter = end_iter; |
|
|
|
@ -1232,6 +1287,28 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
autocomplete_comment.clear(); |
|
|
|
autocomplete_comment.clear(); |
|
|
|
autocomplete_insert.clear(); |
|
|
|
autocomplete_insert.clear(); |
|
|
|
std::promise<void> result_processed; |
|
|
|
std::promise<void> result_processed; |
|
|
|
|
|
|
|
if(autocomplete_show_parameters) { |
|
|
|
|
|
|
|
if(!capabilities.signature_help) |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
client->write_request(this, "textDocument/signatureHelp", R"("textDocument":{"uri":"file://)" + file_path.string() + R"("}, "position": {"line": )" + std::to_string(line_number - 1) + ", \"character\": " + std::to_string(column - 1) + "}", [this, &result_processed](const boost::property_tree::ptree &result, bool error) {
|
|
|
|
|
|
|
|
if(!error) { |
|
|
|
|
|
|
|
auto signatures = result.get_child("signatures", boost::property_tree::ptree()); |
|
|
|
|
|
|
|
for(auto signature_it = signatures.begin(); signature_it != signatures.end(); ++signature_it) { |
|
|
|
|
|
|
|
auto parameters = signature_it->second.get_child("parameters", boost::property_tree::ptree()); |
|
|
|
|
|
|
|
for(auto parameter_it = parameters.begin(); parameter_it != parameters.end(); ++parameter_it) { |
|
|
|
|
|
|
|
auto label = parameter_it->second.get<std::string>("label", ""); |
|
|
|
|
|
|
|
auto insert = label; |
|
|
|
|
|
|
|
auto documentation = parameter_it->second.get<std::string>("documentation", ""); |
|
|
|
|
|
|
|
autocomplete.rows.emplace_back(std::move(label)); |
|
|
|
|
|
|
|
autocomplete_insert.emplace_back(std::move(insert)); |
|
|
|
|
|
|
|
autocomplete_comment.emplace_back(std::move(documentation)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
result_processed.set_value(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
client->write_request(this, "textDocument/completion", R"("textDocument":{"uri":"file://)" + file_path.string() + R"("}, "position": {"line": )" + std::to_string(line_number - 1) + ", \"character\": " + std::to_string(column - 1) + "}", [this, &result_processed](const boost::property_tree::ptree &result, bool error) {
|
|
|
|
client->write_request(this, "textDocument/completion", R"("textDocument":{"uri":"file://)" + file_path.string() + R"("}, "position": {"line": )" + std::to_string(line_number - 1) + ", \"character\": " + std::to_string(column - 1) + "}", [this, &result_processed](const boost::property_tree::ptree &result, bool error) {
|
|
|
|
if(!error) { |
|
|
|
if(!error) { |
|
|
|
auto begin = result.begin(); // rust language server is bugged
|
|
|
|
auto begin = result.begin(); // rust language server is bugged
|
|
|
|
@ -1287,6 +1364,7 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
} |
|
|
|
} |
|
|
|
result_processed.set_value(); |
|
|
|
result_processed.set_value(); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
result_processed.get_future().get(); |
|
|
|
result_processed.get_future().get(); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
@ -1342,6 +1420,20 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
if(hide_window) { |
|
|
|
if(hide_window) { |
|
|
|
Glib::ustring insert = autocomplete_insert[index]; |
|
|
|
Glib::ustring insert = autocomplete_insert[index]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(autocomplete_show_parameters) { |
|
|
|
|
|
|
|
if(has_named_parameters()) { // Do not select named parameters in for instance Python, instead add = after insert
|
|
|
|
|
|
|
|
get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert + '='); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert); |
|
|
|
|
|
|
|
int start_offset = CompletionDialog::get()->start_mark->get_iter().get_offset(); |
|
|
|
|
|
|
|
int end_offset = CompletionDialog::get()->start_mark->get_iter().get_offset() + insert.size(); |
|
|
|
|
|
|
|
get_buffer()->select_range(get_buffer()->get_iter_at_offset(start_offset), get_buffer()->get_iter_at_offset(end_offset)); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Do not insert function/template parameters if they already exist
|
|
|
|
// Do not insert function/template parameters if they already exist
|
|
|
|
auto iter = get_buffer()->get_insert()->get_iter(); |
|
|
|
auto iter = get_buffer()->get_insert()->get_iter(); |
|
|
|
if(*iter == '(' || *iter == '<') { |
|
|
|
if(*iter == '(' || *iter == '<') { |
|
|
|
@ -1398,6 +1490,12 @@ void Source::LanguageProtocolView::setup_autocomplete() { |
|
|
|
}; |
|
|
|
}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Source::LanguageProtocolView::has_named_parameters() { |
|
|
|
|
|
|
|
if(language_id == "python") // TODO: add more languages that supports named parameters
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Source::LanguageProtocolView::add_flow_coverage_tooltips(bool called_in_thread) { |
|
|
|
void Source::LanguageProtocolView::add_flow_coverage_tooltips(bool called_in_thread) { |
|
|
|
std::stringstream stdin_stream, stderr_stream; |
|
|
|
std::stringstream stdin_stream, stderr_stream; |
|
|
|
auto stdout_stream = std::make_shared<std::stringstream>(); |
|
|
|
auto stdout_stream = std::make_shared<std::stringstream>(); |
|
|
|
|