Browse Source

Language client: improved support for autocomplete text edits

merge-requests/413/head
eidheim 3 years ago
parent
commit
89efcacb4f
  1. 105
      src/source_language_protocol.cpp
  2. 1
      src/source_language_protocol.hpp

105
src/source_language_protocol.cpp

@ -1774,7 +1774,7 @@ void Source::LanguageProtocolView::setup_autocomplete() {
auto insert = label;
if(!using_named_parameters || used_named_parameters.find(get_token(insert)) == used_named_parameters.end()) {
autocomplete->rows.emplace_back(std::move(label));
autocomplete_rows.emplace_back(AutocompleteRow{std::move(insert), {}, LanguageProtocol::Documentation(parameter.child_optional("documentation")), {}, {}});
autocomplete_rows.emplace_back(AutocompleteRow{std::move(insert), {}, {}, LanguageProtocol::Documentation(parameter.child_optional("documentation")), {}, {}});
}
}
parameter_position++;
@ -1825,9 +1825,16 @@ void Source::LanguageProtocolView::setup_autocomplete() {
}
auto insert = item.string_or("insertText", "");
boost::optional<LanguageProtocol::TextEdit> text_edit;
if(insert.empty()) {
if(auto text_edit = item.object_optional("textEdit"))
insert = text_edit->string_or("newText", "");
if(auto text_edit_json = item.object_optional("textEdit")) {
insert = text_edit_json->string_or("newText", "");
try {
text_edit = LanguageProtocol::TextEdit(*text_edit_json);
}
catch(...) {
}
}
}
if(insert.empty())
insert = label;
@ -1841,7 +1848,7 @@ void Source::LanguageProtocolView::setup_autocomplete() {
item_object = std::make_shared<JSON>(JSON::make_owner(std::move(item)));
autocomplete->rows.emplace_back(std::move(label));
autocomplete_rows.emplace_back(AutocompleteRow{std::move(insert), std::move(detail), std::move(documentation), std::move(item_object), std::move(additional_text_edits)});
autocomplete_rows.emplace_back(AutocompleteRow{std::move(insert), std::move(text_edit), std::move(detail), std::move(documentation), std::move(item_object), std::move(additional_text_edits)});
}
}
}
@ -1852,7 +1859,7 @@ void Source::LanguageProtocolView::setup_autocomplete() {
for(auto &snippet : *snippets) {
if(starts_with(snippet.prefix, prefix)) {
autocomplete->rows.emplace_back(snippet.prefix);
autocomplete_rows.emplace_back(AutocompleteRow{snippet.body, {}, LanguageProtocol::Documentation(snippet.description), {}, {}});
autocomplete_rows.emplace_back(AutocompleteRow{snippet.body, {}, {}, LanguageProtocol::Documentation(snippet.description), {}, {}});
}
}
}
@ -1877,10 +1884,17 @@ void Source::LanguageProtocolView::setup_autocomplete() {
};
autocomplete->on_select = [this](unsigned int index, const std::string &text, bool hide_window) {
auto insert = hide_window ? autocomplete_rows[index].insert : text;
get_buffer()->erase(CompletionDialog::get()->start_mark->get_iter(), get_buffer()->get_insert()->get_iter());
if(!hide_window) {
get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), text);
return;
}
auto insert = std::move(autocomplete_rows[index].insert); // autocomplete_rows will be cleared after insert_snippet (see autocomplete->on_hide)
auto text_edit = std::move(autocomplete_rows[index].text_edit);
auto additional_text_edits = std::move(autocomplete_rows[index].additional_text_edits);
// Do not insert function/template parameters if they already exist
{
auto iter = get_buffer()->get_insert()->get_iter();
@ -1891,54 +1905,47 @@ void Source::LanguageProtocolView::setup_autocomplete() {
}
}
// Do not instert ?. after ., instead replace . with ?.
if(1 < insert.size() && insert[0] == '?' && insert[1] == '.') {
auto iter = get_buffer()->get_insert()->get_iter();
auto prev = iter;
if(prev.backward_char() && *prev == '.') {
get_buffer()->erase(prev, iter);
}
}
if(hide_window) {
if(autocomplete_show_arguments) {
if(auto symbol = get_named_parameter_symbol()) { // Do not select named parameters in for instance Python
auto named_parameter = get_token(insert);
if(!named_parameter.empty()) {
get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), named_parameter + *symbol);
return;
}
if(autocomplete_show_arguments) {
if(auto symbol = get_named_parameter_symbol()) { // Do not select named parameters in for instance Python
auto named_parameter = get_token(insert);
if(!named_parameter.empty()) {
get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), named_parameter + *symbol);
return;
}
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;
}
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;
}
auto additional_text_edits = std::move(autocomplete_rows[index].additional_text_edits); // autocomplete_rows will be cleared after insert_snippet (see autocomplete->on_hide)
get_buffer()->begin_user_action();
get_buffer()->begin_user_action();
if(text_edit) {
auto start = get_iter_at_line_pos(text_edit->range.start.line, text_edit->range.start.character);
auto end = get_iter_at_line_pos(text_edit->range.end.line, text_edit->range.end.character);
get_buffer()->erase(start, std::min(end, get_buffer()->get_insert()->get_iter()));
start = get_iter_at_line_pos(text_edit->range.start.line, text_edit->range.start.character);
insert_snippet(start, insert);
}
else
insert_snippet(CompletionDialog::get()->start_mark->get_iter(), insert);
for(auto it = additional_text_edits.rbegin(); it != additional_text_edits.rend(); ++it) {
auto start = get_iter_at_line_pos(it->range.start.line, it->range.start.character);
auto end = get_iter_at_line_pos(it->range.end.line, it->range.end.character);
get_buffer()->erase(start, end);
start = get_iter_at_line_pos(it->range.start.line, it->range.start.character);
get_buffer()->insert(start, it->new_text);
}
get_buffer()->end_user_action();
for(auto it = additional_text_edits.rbegin(); it != additional_text_edits.rend(); ++it) {
auto start = get_iter_at_line_pos(it->range.start.line, it->range.start.character);
auto end = get_iter_at_line_pos(it->range.end.line, it->range.end.character);
get_buffer()->erase(start, end);
start = get_iter_at_line_pos(it->range.start.line, it->range.start.character);
get_buffer()->insert(start, it->new_text);
}
get_buffer()->end_user_action();
auto iter = get_buffer()->get_insert()->get_iter();
if(*iter == ')' && iter.backward_char() && *iter == '(') { // If no arguments, try signatureHelp
last_keyval = '(';
if(is_js) // Workaround for typescript-language-server
autocomplete_possibly_no_arguments = true;
autocomplete->run();
}
auto iter = get_buffer()->get_insert()->get_iter();
if(*iter == ')' && iter.backward_char() && *iter == '(') { // If no arguments, try signatureHelp
last_keyval = '(';
if(is_js) // Workaround for typescript-language-server
autocomplete_possibly_no_arguments = true;
autocomplete->run();
}
else
get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), insert);
};
autocomplete->set_tooltip_buffer = [this](unsigned int index) -> std::function<void(Tooltip & tooltip)> {

1
src/source_language_protocol.hpp

@ -275,6 +275,7 @@ namespace Source {
struct AutocompleteRow {
std::string insert;
boost::optional<LanguageProtocol::TextEdit> text_edit;
std::string detail;
LanguageProtocol::Documentation documentation;
/// CompletionItem for completionItem/resolve

Loading…
Cancel
Save