Browse Source

Language protocol: added argument completions for Python. Also removed unnecessary copy of text buffer.

merge-requests/389/head
eidheim 7 years ago
parent
commit
27d4c3ea5f
  1. 9
      src/autocomplete.cc
  2. 9
      src/autocomplete.h
  3. 14
      src/source.cc
  4. 4
      src/source.h
  5. 30
      src/source_clang.cc
  6. 4
      src/source_clang.h
  7. 190
      src/source_language_protocol.cc
  8. 5
      src/source_language_protocol.h

9
src/autocomplete.cc

@ -1,8 +1,8 @@
#include "autocomplete.h" #include "autocomplete.h"
#include "selection_dialog.h" #include "selection_dialog.h"
Autocomplete::Autocomplete(Gtk::TextView *view, bool &interactive_completion, guint &last_keyval, bool strip_word) Autocomplete::Autocomplete(Gtk::TextView *view, bool &interactive_completion, guint &last_keyval, bool pass_buffer_and_strip_word)
: view(view), interactive_completion(interactive_completion), strip_word(strip_word), state(State::IDLE) { : view(view), interactive_completion(interactive_completion), pass_buffer_and_strip_word(pass_buffer_and_strip_word) {
view->get_buffer()->signal_changed().connect([this, &last_keyval] { view->get_buffer()->signal_changed().connect([this, &last_keyval] {
if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) { if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) {
cancel_reparse(); cancel_reparse();
@ -56,12 +56,13 @@ void Autocomplete::run() {
if(thread.joinable()) if(thread.joinable())
thread.join(); thread.join();
auto buffer = view->get_buffer()->get_text();
auto iter = view->get_buffer()->get_insert()->get_iter(); auto iter = view->get_buffer()->get_insert()->get_iter();
auto line_nr = iter.get_line() + 1; auto line_nr = iter.get_line() + 1;
auto column_nr = iter.get_line_index() + 1; auto column_nr = iter.get_line_index() + 1;
if(strip_word) { Glib::ustring buffer;
if(pass_buffer_and_strip_word) {
auto pos = iter.get_offset() - 1; auto pos = iter.get_offset() - 1;
buffer = view->get_buffer()->get_text();
while(pos >= 0 && ((buffer[pos] >= 'a' && buffer[pos] <= 'z') || (buffer[pos] >= 'A' && buffer[pos] <= 'Z') || while(pos >= 0 && ((buffer[pos] >= 'a' && buffer[pos] <= 'z') || (buffer[pos] >= 'A' && buffer[pos] <= 'Z') ||
(buffer[pos] >= '0' && buffer[pos] <= '9') || buffer[pos] == '_')) { (buffer[pos] >= '0' && buffer[pos] <= '9') || buffer[pos] == '_')) {
buffer.replace(pos, 1, " "); buffer.replace(pos, 1, " ");

9
src/autocomplete.h

@ -7,8 +7,9 @@
class Autocomplete { class Autocomplete {
Gtk::TextView *view; Gtk::TextView *view;
bool &interactive_completion; bool &interactive_completion;
/// Some libraries/utilities, like libclang, require that autocomplete is started at the beginning of a word /// If text_view buffer should be passed to add_rows. Empty buffer is passed if not.
bool strip_word; /// Also, some utilities, like libclang, require that autocomplete is started at the beginning of a word.
bool pass_buffer_and_strip_word;
Dispatcher dispatcher; Dispatcher dispatcher;
@ -20,7 +21,7 @@ public:
std::vector<std::string> rows; std::vector<std::string> rows;
Tooltips tooltips; Tooltips tooltips;
std::atomic<State> state; std::atomic<State> state = {State::IDLE};
std::thread thread; std::thread thread;
@ -48,7 +49,7 @@ public:
std::function<std::string(unsigned int)> get_tooltip = [](unsigned int index) { return std::string(); }; std::function<std::string(unsigned int)> get_tooltip = [](unsigned int index) { return std::string(); };
Autocomplete(Gtk::TextView *view, bool &interactive_completion, guint &last_keyval, bool strip_word); Autocomplete(Gtk::TextView *view, bool &interactive_completion, guint &last_keyval, bool pass_buffer_and_strip_word);
void run(); void run();
void stop(); void stop();

14
src/source.cc

@ -113,7 +113,7 @@ std::string Source::FixIt::string(const Glib::RefPtr<Gtk::TextBuffer> &buffer) {
std::set<Source::View *> Source::View::non_deleted_views; std::set<Source::View *> Source::View::non_deleted_views;
std::set<Source::View *> Source::View::views; std::set<Source::View *> Source::View::views;
Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<Gsv::Language> &language, bool is_generic_view) : BaseView(file_path, language), SpellCheckView(file_path, language), DiffView(file_path, language), parsed(true) { Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<Gsv::Language> &language, bool is_generic_view) : BaseView(file_path, language), SpellCheckView(file_path, language), DiffView(file_path, language) {
non_deleted_views.emplace(this); non_deleted_views.emplace(this);
views.emplace(this); views.emplace(this);
@ -1318,6 +1318,18 @@ bool Source::View::is_templated_function(Gtk::TextIter iter, Gtk::TextIter &pare
return false; return false;
} }
bool Source::View::is_possible_argument() {
auto iter = get_buffer()->get_insert()->get_iter();
if(iter.backward_char() && (!interactive_completion || last_keyval == '(' || last_keyval == ',' || last_keyval == ' ' ||
last_keyval == GDK_KEY_Return || last_keyval == GDK_KEY_KP_Enter)) {
while((*iter == ' ' || *iter == '\t' || *iter == '\n' || *iter == '\r') && iter.backward_char()) {
}
if(*iter == '(' || *iter == ',')
return true;
}
return false;
}
bool Source::View::on_key_press_event(GdkEventKey *key) { bool Source::View::on_key_press_event(GdkEventKey *key) {
class Guard { class Guard {
public: public:

4
src/source.h

@ -87,7 +87,7 @@ namespace Source {
virtual void full_reparse() { full_reparse_needed = false; } virtual void full_reparse() { full_reparse_needed = false; }
protected: protected:
std::atomic<bool> parsed; std::atomic<bool> parsed = {true};
Tooltips diagnostic_tooltips; Tooltips diagnostic_tooltips;
Tooltips type_tooltips; Tooltips type_tooltips;
sigc::connection delayed_tooltips_connection; sigc::connection delayed_tooltips_connection;
@ -122,6 +122,8 @@ namespace Source {
bool find_close_symbol_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter, unsigned int positive_char, unsigned int negative_char); bool find_close_symbol_forward(Gtk::TextIter iter, Gtk::TextIter &found_iter, unsigned int positive_char, unsigned int negative_char);
long symbol_count(Gtk::TextIter iter, unsigned int positive_char, unsigned int negative_char); long symbol_count(Gtk::TextIter iter, unsigned int positive_char, unsigned int negative_char);
bool is_templated_function(Gtk::TextIter iter, Gtk::TextIter &parenthesis_end_iter); bool is_templated_function(Gtk::TextIter iter, Gtk::TextIter &parenthesis_end_iter);
/// If insert is at an possible argument. Also based on last key press.
bool is_possible_argument();
bool on_key_press_event(GdkEventKey *key) override; bool on_key_press_event(GdkEventKey *key) override;
bool on_key_press_event_basic(GdkEventKey *key); bool on_key_press_event_basic(GdkEventKey *key);

30
src/source_clang.cc

@ -485,9 +485,9 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
return; return;
if(!has_focus()) if(!has_focus())
return; return;
if(show_arguments) if(show_parameters)
autocomplete.stop(); autocomplete.stop();
show_arguments = false; show_parameters = false;
delayed_show_arguments_connection.disconnect(); delayed_show_arguments_connection.disconnect();
delayed_show_arguments_connection = Glib::signal_timeout().connect([this]() { delayed_show_arguments_connection = Glib::signal_timeout().connect([this]() {
if(get_buffer()->get_has_selection()) if(get_buffer()->get_has_selection())
@ -496,7 +496,7 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
return false; return false;
if(!has_focus()) if(!has_focus())
return false; return false;
if(is_possible_parameter()) { if(is_possible_argument()) {
autocomplete.stop(); autocomplete.stop();
autocomplete.run(); autocomplete.run();
} }
@ -506,7 +506,7 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
// Remove argument completions // Remove argument completions
signal_key_press_event().connect([this](GdkEventKey *key) { signal_key_press_event().connect([this](GdkEventKey *key) {
if(show_arguments && CompletionDialog::get() && CompletionDialog::get()->is_visible() && if(show_parameters && CompletionDialog::get() && CompletionDialog::get()->is_visible() &&
key->keyval != GDK_KEY_Down && key->keyval != GDK_KEY_Up && 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_Return && key->keyval != GDK_KEY_KP_Enter &&
key->keyval != GDK_KEY_ISO_Left_Tab && key->keyval != GDK_KEY_Tab && key->keyval != GDK_KEY_ISO_Left_Tab && key->keyval != GDK_KEY_Tab &&
@ -538,7 +538,7 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
if(!is_code_iter(iter)) if(!is_code_iter(iter))
return false; return false;
show_arguments = false; 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_]*)$)");
@ -569,8 +569,8 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
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_parameter()) { else if(is_possible_argument()) {
show_arguments = true; show_parameters = true;
std::unique_lock<std::mutex> lock(autocomplete.prefix_mutex); std::unique_lock<std::mutex> lock(autocomplete.prefix_mutex);
autocomplete.prefix = ""; autocomplete.prefix = "";
return true; return true;
@ -631,7 +631,7 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
auto result = code_complete_results->get(i); auto result = code_complete_results->get(i);
if(result.available()) { if(result.available()) {
std::string text; std::string text;
if(show_arguments) { if(show_parameters) {
class Recursive { class Recursive {
public: public:
static void f(const clangmm::CompletionString &completion_string, std::string &text) { static void f(const clangmm::CompletionString &completion_string, std::string &text) {
@ -741,7 +741,7 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
if(hide_window) { if(hide_window) {
size_t start_pos = std::string::npos; size_t start_pos = std::string::npos;
size_t end_pos = std::string::npos; size_t end_pos = std::string::npos;
if(show_arguments) { if(show_parameters) {
start_pos = 0; start_pos = 0;
end_pos = row.size(); end_pos = row.size();
} }
@ -798,18 +798,6 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
}; };
} }
bool Source::ClangViewAutocomplete::is_possible_parameter() {
auto iter = get_buffer()->get_insert()->get_iter();
if(iter.backward_char() && (!interactive_completion || last_keyval == '(' || last_keyval == ',' || last_keyval == ' ' ||
last_keyval == GDK_KEY_Return || last_keyval == GDK_KEY_KP_Enter)) {
while((*iter == ' ' || *iter == '\t' || *iter == '\n' || *iter == '\r') && iter.backward_char()) {
}
if(*iter == '(' || *iter == ',')
return true;
}
return false;
}
const std::unordered_map<std::string, std::string> &Source::ClangViewAutocomplete::autocomplete_manipulators_map() { const std::unordered_map<std::string, std::string> &Source::ClangViewAutocomplete::autocomplete_manipulators_map() {
//TODO: feel free to add more //TODO: feel free to add more
static std::unordered_map<std::string, std::string> map = { static std::unordered_map<std::string, std::string> map = {

4
src/source_clang.h

@ -68,8 +68,8 @@ namespace Source {
sigc::connection delayed_show_arguments_connection; sigc::connection delayed_show_arguments_connection;
private: private:
bool is_possible_parameter(); std::atomic<bool> show_parameters = {false};
bool show_arguments;
const std::unordered_map<std::string, std::string> &autocomplete_manipulators_map(); const std::unordered_map<std::string, std::string> &autocomplete_manipulators_map();
}; };

190
src/source_language_protocol.cc

@ -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,61 +1287,84 @@ 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;
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(autocomplete_show_parameters) {
if(!error) { if(!capabilities.signature_help)
auto begin = result.begin(); // rust language server is bugged return;
auto end = result.end(); 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) {
auto items_it = result.find("items"); // correct if(!error) {
if(items_it != result.not_found()) { auto signatures = result.get_child("signatures", boost::property_tree::ptree());
begin = items_it->second.begin(); for(auto signature_it = signatures.begin(); signature_it != signatures.end(); ++signature_it) {
end = items_it->second.end(); 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));
}
}
} }
for(auto it = begin; it != end; ++it) { result_processed.set_value();
auto label = it->second.get<std::string>("label", ""); });
auto detail = it->second.get<std::string>("detail", ""); }
auto documentation = it->second.get<std::string>("documentation", ""); else {
auto insert = it->second.get<std::string>("insertText", ""); 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(!insert.empty()) { if(!error) {
// In case ( is missing in insert but is present in label auto begin = result.begin(); // rust language server is bugged
if(label.size() > insert.size() && label.back() == ')' && insert.find('(') == std::string::npos) { auto end = result.end();
auto pos = label.find('('); auto items_it = result.find("items"); // correct
if(pos != std::string::npos && pos == insert.size() && pos + 1 < label.size()) { if(items_it != result.not_found()) {
if(pos + 2 == label.size()) // If no parameters begin = items_it->second.begin();
insert += "()"; end = items_it->second.end();
else }
insert += "(${1:" + label.substr(pos + 1, label.size() - 1 - (pos + 1)) + "})"; for(auto it = begin; it != end; ++it) {
auto label = it->second.get<std::string>("label", "");
auto detail = it->second.get<std::string>("detail", "");
auto documentation = it->second.get<std::string>("documentation", "");
auto insert = it->second.get<std::string>("insertText", "");
if(!insert.empty()) {
// In case ( is missing in insert but is present in label
if(label.size() > insert.size() && label.back() == ')' && insert.find('(') == std::string::npos) {
auto pos = label.find('(');
if(pos != std::string::npos && pos == insert.size() && pos + 1 < label.size()) {
if(pos + 2 == label.size()) // If no parameters
insert += "()";
else
insert += "(${1:" + label.substr(pos + 1, label.size() - 1 - (pos + 1)) + "})";
}
} }
} }
} else {
else { insert = label;
insert = label; auto kind = it->second.get<int>("kind", 0);
auto kind = it->second.get<int>("kind", 0); if(kind >= 2 && kind <= 3) {
if(kind >= 2 && kind <= 3) { bool found_bracket = false;
bool found_bracket = false; for(auto &chr : insert) {
for(auto &chr : insert) { if(chr == '(' || chr == '{') {
if(chr == '(' || chr == '{') { found_bracket = true;
found_bracket = true; break;
break; }
} }
if(!found_bracket)
insert += "(${1:})";
} }
if(!found_bracket)
insert += "(${1:})";
} }
} if(!label.empty()) {
if(!label.empty()) { autocomplete.rows.emplace_back(std::move(label));
autocomplete.rows.emplace_back(std::move(label)); autocomplete_comment.emplace_back(std::move(detail));
autocomplete_comment.emplace_back(std::move(detail)); if(!documentation.empty()) {
if(!documentation.empty()) { if(!autocomplete_comment.back().empty())
if(!autocomplete_comment.back().empty()) autocomplete_comment.back() += "\n\n";
autocomplete_comment.back() += "\n\n"; autocomplete_comment.back() += documentation;
autocomplete_comment.back() += documentation; }
autocomplete_insert.emplace_back(std::move(insert));
} }
autocomplete_insert.emplace_back(std::move(insert));
} }
} }
} 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>();

5
src/source_language_protocol.h

@ -66,6 +66,7 @@ namespace LanguageProtocol {
TextDocumentSync text_document_sync; TextDocumentSync text_document_sync;
bool hover; bool hover;
bool completion; bool completion;
bool signature_help;
bool definition; bool definition;
bool references; bool references;
bool document_highlight; bool document_highlight;
@ -162,6 +163,10 @@ namespace Source {
std::vector<std::string> autocomplete_comment; std::vector<std::string> autocomplete_comment;
std::vector<std::string> autocomplete_insert; std::vector<std::string> autocomplete_insert;
std::list<std::pair<Glib::RefPtr<Gtk::TextBuffer::Mark>, Glib::RefPtr<Gtk::TextBuffer::Mark>>> argument_marks; std::list<std::pair<Glib::RefPtr<Gtk::TextBuffer::Mark>, Glib::RefPtr<Gtk::TextBuffer::Mark>>> argument_marks;
bool autocomplete_show_parameters = false;
sigc::connection autocomplete_delayed_show_arguments_connection;
bool has_named_parameters();
boost::filesystem::path flow_coverage_executable; boost::filesystem::path flow_coverage_executable;
std::vector<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark>>> flow_coverage_marks; std::vector<std::pair<Glib::RefPtr<Gtk::TextMark>, Glib::RefPtr<Gtk::TextMark>>> flow_coverage_marks;

Loading…
Cancel
Save