Browse Source

Language protocol: added additional capabilities checks

merge-requests/365/head
eidheim 8 years ago
parent
commit
980de5de1c
  1. 512
      src/source_language_protocol.cc
  2. 7
      src/source_language_protocol.h

512
src/source_language_protocol.cc

@ -84,8 +84,15 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize(Source::Lang
auto capabilities_pt=result.find("capabilities"); auto capabilities_pt=result.find("capabilities");
if(capabilities_pt!=result.not_found()) { if(capabilities_pt!=result.not_found()) {
capabilities.text_document_sync=static_cast<LanguageProtocol::Capabilities::TextDocumentSync>(capabilities_pt->second.get<unsigned>("textDocumentSync", 0)); capabilities.text_document_sync=static_cast<LanguageProtocol::Capabilities::TextDocumentSync>(capabilities_pt->second.get<unsigned>("textDocumentSync", 0));
capabilities.hover=capabilities_pt->second.get<bool>("hoverProvider", false);
capabilities.completion=capabilities_pt->second.find("completionProvider")!=capabilities_pt->second.not_found()?true:false;
capabilities.definition=capabilities_pt->second.get<bool>("definitionProvider", 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);
capabilities.workspace_symbol=capabilities_pt->second.get<bool>("workspaceSymbolProvider", false); capabilities.workspace_symbol=capabilities_pt->second.get<bool>("workspaceSymbolProvider", false);
capabilities.document_formatting=capabilities_pt->second.get<bool>("documentFormattingProvider", false);
capabilities.document_range_formatting=capabilities_pt->second.get<bool>("documentRangeFormattingProvider", false);
capabilities.rename=capabilities_pt->second.get<bool>("renameProvider", false);
} }
write_notification("initialized", ""); write_notification("initialized", "");
@ -369,176 +376,182 @@ Source::LanguageProtocolView::~LanguageProtocolView() {
} }
void Source::LanguageProtocolView::setup_navigation_and_refactoring() { void Source::LanguageProtocolView::setup_navigation_and_refactoring() {
format_style=[this](bool continue_without_style_file) { if(capabilities.document_formatting) {
if(!continue_without_style_file) format_style=[this](bool continue_without_style_file) {
return; if(!continue_without_style_file)
return;
class Replace {
public: class Replace {
Offset start, end; public:
std::string text; Offset start, end;
}; std::string text;
std::vector<Replace> replaces; };
std::promise<void> result_processed; std::vector<Replace> replaces;
client->write_request("textDocument/formatting", "\"textDocument\":{\"uri\":\""+uri+"\"},\"options\":{\"tabSize\":"+std::to_string(tab_size)+",\"insertSpaces\":"+(tab_char==' '?"true":"false")+"}", [&replaces, &result_processed](const boost::property_tree::ptree &result, bool error) { std::promise<void> result_processed;
if(!error) { client->write_request("textDocument/formatting", "\"textDocument\":{\"uri\":\""+uri+"\"},\"options\":{\"tabSize\":"+std::to_string(tab_size)+",\"insertSpaces\":"+(tab_char==' '?"true":"false")+"}", [&replaces, &result_processed](const boost::property_tree::ptree &result, bool error) {
for(auto it=result.begin();it!=result.end();++it) { if(!error) {
auto range_it=it->second.find("range"); for(auto it=result.begin();it!=result.end();++it) {
auto text_it=it->second.find("newText"); auto range_it=it->second.find("range");
if(range_it!=it->second.not_found() && text_it!=it->second.not_found()) { auto text_it=it->second.find("newText");
auto start_it=range_it->second.find("start"); if(range_it!=it->second.not_found() && text_it!=it->second.not_found()) {
auto end_it=range_it->second.find("end"); auto start_it=range_it->second.find("start");
if(start_it!=range_it->second.not_found() && end_it!=range_it->second.not_found()) { auto end_it=range_it->second.find("end");
try { if(start_it!=range_it->second.not_found() && end_it!=range_it->second.not_found()) {
replaces.emplace_back(Replace{Offset(start_it->second.get<unsigned>("line"), start_it->second.get<unsigned>("character")), try {
Offset(end_it->second.get<unsigned>("line"), end_it->second.get<unsigned>("character")), replaces.emplace_back(Replace{Offset(start_it->second.get<unsigned>("line"), start_it->second.get<unsigned>("character")),
text_it->second.get_value<std::string>()}); Offset(end_it->second.get<unsigned>("line"), end_it->second.get<unsigned>("character")),
text_it->second.get_value<std::string>()});
}
catch(...) {}
} }
catch(...) {}
} }
} }
} }
result_processed.set_value();
});
result_processed.get_future().get();
get_buffer()->begin_user_action();
for(auto it=replaces.rbegin();it!=replaces.rend();++it) {
auto start=get_iter_at_line_pos(it->start.line, it->start.index);
auto end=get_iter_at_line_pos(it->end.line, it->end.index);
get_buffer()->erase(start, end);
start=get_iter_at_line_pos(it->start.line, it->start.index);
unescape_text(it->text);
get_buffer()->insert(start, it->text);
} }
result_processed.set_value(); get_buffer()->end_user_action();
}); };
result_processed.get_future().get(); }
get_buffer()->begin_user_action();
for(auto it=replaces.rbegin();it!=replaces.rend();++it) {
auto start=get_iter_at_line_pos(it->start.line, it->start.index);
auto end=get_iter_at_line_pos(it->end.line, it->end.index);
get_buffer()->erase(start, end);
start=get_iter_at_line_pos(it->start.line, it->start.index);
unescape_text(it->text);
get_buffer()->insert(start, it->text);
}
get_buffer()->end_user_action();
};
get_declaration_location=[this]() { if(capabilities.definition) {
auto offset=get_declaration(get_buffer()->get_insert()->get_iter()); get_declaration_location=[this]() {
if(!offset) auto offset=get_declaration(get_buffer()->get_insert()->get_iter());
Info::get().print("No declaration found"); if(!offset)
return offset; Info::get().print("No declaration found");
}; return offset;
};
}
get_usages=[this] { if(capabilities.references) {
auto iter=get_buffer()->get_insert()->get_iter(); get_usages=[this] {
std::vector<std::pair<Offset, std::string>> usages; auto iter=get_buffer()->get_insert()->get_iter();
std::vector<Offset> end_offsets; std::vector<std::pair<Offset, std::string>> usages;
std::promise<void> result_processed; std::vector<Offset> end_offsets;
client->write_request("textDocument/references", "\"textDocument\":{\"uri\":\""+uri+"\"}, \"position\": {\"line\": "+std::to_string(iter.get_line())+", \"character\": "+std::to_string(iter.get_line_offset())+"}, \"context\": {\"includeDeclaration\": true}", [&usages, &end_offsets, &result_processed](const boost::property_tree::ptree &result, bool error) { std::promise<void> result_processed;
if(!error) { client->write_request("textDocument/references", "\"textDocument\":{\"uri\":\""+uri+"\"}, \"position\": {\"line\": "+std::to_string(iter.get_line())+", \"character\": "+std::to_string(iter.get_line_offset())+"}, \"context\": {\"includeDeclaration\": true}", [&usages, &end_offsets, &result_processed](const boost::property_tree::ptree &result, bool error) {
try { if(!error) {
for(auto it=result.begin();it!=result.end();++it) { try {
auto path=it->second.get<std::string>("uri", ""); for(auto it=result.begin();it!=result.end();++it) {
if(path.size()>=7) { auto path=it->second.get<std::string>("uri", "");
path.erase(0, 7); if(path.size()>=7) {
auto range_it=it->second.find("range"); path.erase(0, 7);
if(range_it!=it->second.not_found()) { auto range_it=it->second.find("range");
auto start_it=range_it->second.find("start"); if(range_it!=it->second.not_found()) {
auto end_it=range_it->second.find("end"); auto start_it=range_it->second.find("start");
if(start_it!=range_it->second.not_found() && end_it!=range_it->second.not_found()) { auto end_it=range_it->second.find("end");
usages.emplace_back(std::make_pair(Offset(start_it->second.get<unsigned>("line"), start_it->second.get<unsigned>("character"), path), "")); if(start_it!=range_it->second.not_found() && end_it!=range_it->second.not_found()) {
end_offsets.emplace_back(end_it->second.get<unsigned>("line"), end_it->second.get<unsigned>("character")); usages.emplace_back(std::make_pair(Offset(start_it->second.get<unsigned>("line"), start_it->second.get<unsigned>("character"), path), ""));
end_offsets.emplace_back(end_it->second.get<unsigned>("line"), end_it->second.get<unsigned>("character"));
}
} }
} }
} }
} }
catch(...) {
usages.clear();
end_offsets.clear();
}
} }
catch(...) { result_processed.set_value();
usages.clear(); });
end_offsets.clear(); result_processed.get_future().get();
}
} auto embolden_token=[](std::string &line_, unsigned token_start_pos, unsigned token_end_pos) {
result_processed.set_value(); Glib::ustring line=line_;
}); if(token_start_pos>=line.size() || token_end_pos>=line.size())
result_processed.get_future().get(); return;
auto embolden_token=[](std::string &line_, unsigned token_start_pos, unsigned token_end_pos) { //markup token as bold
Glib::ustring line=line_; size_t pos=0;
if(token_start_pos>=line.size() || token_end_pos>=line.size()) while((pos=line.find('&', pos))!=Glib::ustring::npos) {
return; size_t pos2=line.find(';', pos+2);
if(token_start_pos>pos) {
//markup token as bold token_start_pos+=pos2-pos;
size_t pos=0; token_end_pos+=pos2-pos;
while((pos=line.find('&', pos))!=Glib::ustring::npos) { }
size_t pos2=line.find(';', pos+2); else if(token_end_pos>pos)
if(token_start_pos>pos) { token_end_pos+=pos2-pos;
token_start_pos+=pos2-pos; else
token_end_pos+=pos2-pos; break;
pos=pos2+1;
} }
else if(token_end_pos>pos) line.insert(token_end_pos, "</b>");
token_end_pos+=pos2-pos; line.insert(token_start_pos, "<b>");
else
break; size_t start_pos=0;
pos=pos2+1; while(start_pos<line.size() && (line[start_pos]==' ' || line[start_pos]=='\t'))
} ++start_pos;
line.insert(token_end_pos, "</b>"); if(start_pos>0)
line.insert(token_start_pos, "<b>"); line.erase(0, start_pos);
size_t start_pos=0; line_=line.raw();
while(start_pos<line.size() && (line[start_pos]==' ' || line[start_pos]=='\t')) };
++start_pos;
if(start_pos>0)
line.erase(0, start_pos);
line_=line.raw(); std::map<boost::filesystem::path, std::vector<std::string>> file_lines;
}; size_t c=static_cast<size_t>(-1);
for(auto &usage: usages) {
std::map<boost::filesystem::path, std::vector<std::string>> file_lines; ++c;
size_t c=static_cast<size_t>(-1); auto view_it=views.end();
for(auto &usage: usages) { for(auto it=views.begin();it!=views.end();++it) {
++c; if(usage.first.file_path==(*it)->file_path) {
auto view_it=views.end(); view_it=it;
for(auto it=views.begin();it!=views.end();++it) { break;
if(usage.first.file_path==(*it)->file_path) { }
view_it=it;
break;
} }
} if(view_it!=views.end()) {
if(view_it!=views.end()) { if(usage.first.line<static_cast<unsigned>((*view_it)->get_buffer()->get_line_count())) {
if(usage.first.line<static_cast<unsigned>((*view_it)->get_buffer()->get_line_count())) { auto start=(*view_it)->get_buffer()->get_iter_at_line(usage.first.line);
auto start=(*view_it)->get_buffer()->get_iter_at_line(usage.first.line); auto end=start;
auto end=start; end.forward_to_line_end();
end.forward_to_line_end(); usage.second=(*view_it)->get_buffer()->get_text(start, end);
usage.second=(*view_it)->get_buffer()->get_text(start, end); embolden_token(usage.second, usage.first.index, end_offsets[c].index);
embolden_token(usage.second, usage.first.index, end_offsets[c].index); }
} }
} else {
else { auto it=file_lines.find(usage.first.file_path);
auto it=file_lines.find(usage.first.file_path); if(it==file_lines.end()) {
if(it==file_lines.end()) { std::ifstream ifs(usage.first.file_path.string());
std::ifstream ifs(usage.first.file_path.string()); if(ifs) {
if(ifs) { std::vector<std::string> lines;
std::vector<std::string> lines; std::string line;
std::string line; while(std::getline(ifs, line)) {
while(std::getline(ifs, line)) { if(!line.empty() && line.back()=='\r')
if(!line.empty() && line.back()=='\r') line.pop_back();
line.pop_back(); lines.emplace_back(line);
lines.emplace_back(line); }
auto pair=file_lines.emplace(usage.first.file_path, lines);
it=pair.first;
}
else {
auto pair=file_lines.emplace(usage.first.file_path, std::vector<std::string>());
it=pair.first;
} }
auto pair=file_lines.emplace(usage.first.file_path, lines);
it=pair.first;
} }
else {
auto pair=file_lines.emplace(usage.first.file_path, std::vector<std::string>()); if(usage.first.line<it->second.size()) {
it=pair.first; usage.second=it->second[usage.first.line];
embolden_token(usage.second, usage.first.index, end_offsets[c].index);
} }
} }
if(usage.first.line<it->second.size()) {
usage.second=it->second[usage.first.line];
embolden_token(usage.second, usage.first.index, end_offsets[c].index);
}
} }
}
if(usages.empty())
if(usages.empty()) Info::get().print("No symbol found at current cursor location");
Info::get().print("No symbol found at current cursor location");
return usages;
return usages; };
}; }
get_token_spelling=[this]() -> std::string { get_token_spelling=[this]() -> std::string {
auto start=get_buffer()->get_insert()->get_iter(); auto start=get_buffer()->get_insert()->get_iter();
@ -555,114 +568,116 @@ void Source::LanguageProtocolView::setup_navigation_and_refactoring() {
return get_buffer()->get_text(start, end); return get_buffer()->get_text(start, end);
}; };
rename_similar_tokens=[this](const std::string &text) { if(capabilities.rename) {
class Usages { rename_similar_tokens=[this](const std::string &text) {
public: class Usages {
boost::filesystem::path path; public:
std::vector<std::pair<Offset, Offset>> offsets; boost::filesystem::path path;
}; std::vector<std::pair<Offset, Offset>> offsets;
};
auto previous_text=get_token_spelling();
if(previous_text.empty()) auto previous_text=get_token_spelling();
return; if(previous_text.empty())
return;
auto iter=get_buffer()->get_insert()->get_iter();
std::vector<Usages> usages; auto iter=get_buffer()->get_insert()->get_iter();
std::promise<void> result_processed; std::vector<Usages> usages;
client->write_request("textDocument/rename", "\"textDocument\":{\"uri\":\""+uri+"\"}, \"position\": {\"line\": "+std::to_string(iter.get_line())+", \"character\": "+std::to_string(iter.get_line_offset())+"}, \"newName\": \""+text+"\"", [&usages, &result_processed](const boost::property_tree::ptree &result, bool error) { std::promise<void> result_processed;
if(!error) { client->write_request("textDocument/rename", "\"textDocument\":{\"uri\":\""+uri+"\"}, \"position\": {\"line\": "+std::to_string(iter.get_line())+", \"character\": "+std::to_string(iter.get_line_offset())+"}, \"newName\": \""+text+"\"", [&usages, &result_processed](const boost::property_tree::ptree &result, bool error) {
try { if(!error) {
auto changes_it=result.find("changes"); try {
if(changes_it!=result.not_found()) { auto changes_it=result.find("changes");
for(auto file_it=changes_it->second.begin();file_it!=changes_it->second.end();++file_it) { if(changes_it!=result.not_found()) {
auto path=file_it->first; for(auto file_it=changes_it->second.begin();file_it!=changes_it->second.end();++file_it) {
if(path.size()>=7) { auto path=file_it->first;
path.erase(0, 7); if(path.size()>=7) {
usages.emplace_back(Usages{path, std::vector<std::pair<Offset, Offset>>()}); path.erase(0, 7);
for(auto edit_it=file_it->second.begin();edit_it!=file_it->second.end();++edit_it) { usages.emplace_back(Usages{path, std::vector<std::pair<Offset, Offset>>()});
auto range_it=edit_it->second.find("range"); for(auto edit_it=file_it->second.begin();edit_it!=file_it->second.end();++edit_it) {
if(range_it!=edit_it->second.not_found()) { auto range_it=edit_it->second.find("range");
auto start_it=range_it->second.find("start"); if(range_it!=edit_it->second.not_found()) {
auto end_it=range_it->second.find("end"); auto start_it=range_it->second.find("start");
if(start_it!=range_it->second.not_found() && end_it!=range_it->second.not_found()) auto end_it=range_it->second.find("end");
usages.back().offsets.emplace_back(std::make_pair(Offset(start_it->second.get<unsigned>("line"), start_it->second.get<unsigned>("character")), if(start_it!=range_it->second.not_found() && end_it!=range_it->second.not_found())
Offset(end_it->second.get<unsigned>("line"), end_it->second.get<unsigned>("character")))); usages.back().offsets.emplace_back(std::make_pair(Offset(start_it->second.get<unsigned>("line"), start_it->second.get<unsigned>("character")),
Offset(end_it->second.get<unsigned>("line"), end_it->second.get<unsigned>("character"))));
}
} }
} }
} }
} }
} }
catch(...) {
usages.clear();
}
} }
catch(...) { result_processed.set_value();
usages.clear(); });
} result_processed.get_future().get();
}
result_processed.set_value(); std::vector<Usages*> usages_renamed;
}); for(auto &usage: usages) {
result_processed.get_future().get(); auto view_it=views.end();
for(auto it=views.begin();it!=views.end();++it) {
std::vector<Usages*> usages_renamed; if((*it)->file_path==usage.path) {
for(auto &usage: usages) { view_it=it;
auto view_it=views.end(); break;
for(auto it=views.begin();it!=views.end();++it) { }
if((*it)->file_path==usage.path) {
view_it=it;
break;
}
}
if(view_it!=views.end()) {
(*view_it)->get_buffer()->begin_user_action();
for(auto offset_it=usage.offsets.rbegin();offset_it!=usage.offsets.rend();++offset_it) {
auto start_iter=(*view_it)->get_iter_at_line_pos(offset_it->first.line, offset_it->first.index);
auto end_iter=(*view_it)->get_iter_at_line_pos(offset_it->second.line, offset_it->second.index);
(*view_it)->get_buffer()->erase(start_iter, end_iter);
start_iter=(*view_it)->get_iter_at_line_pos(offset_it->first.line, offset_it->first.index);
(*view_it)->get_buffer()->insert(start_iter, text);
} }
(*view_it)->get_buffer()->end_user_action(); if(view_it!=views.end()) {
(*view_it)->save(); (*view_it)->get_buffer()->begin_user_action();
usages_renamed.emplace_back(&usage); for(auto offset_it=usage.offsets.rbegin();offset_it!=usage.offsets.rend();++offset_it) {
} auto start_iter=(*view_it)->get_iter_at_line_pos(offset_it->first.line, offset_it->first.index);
else { auto end_iter=(*view_it)->get_iter_at_line_pos(offset_it->second.line, offset_it->second.index);
Glib::ustring buffer; (*view_it)->get_buffer()->erase(start_iter, end_iter);
{ start_iter=(*view_it)->get_iter_at_line_pos(offset_it->first.line, offset_it->first.index);
std::ifstream stream(usage.path.string(), std::ifstream::binary); (*view_it)->get_buffer()->insert(start_iter, text);
if(stream) }
buffer.assign(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>()); (*view_it)->get_buffer()->end_user_action();
(*view_it)->save();
usages_renamed.emplace_back(&usage);
} }
std::ofstream stream(usage.path.string(), std::ifstream::binary); else {
if(!buffer.empty() && stream) { Glib::ustring buffer;
std::vector<size_t> lines_start_pos={0}; {
for(size_t c=0;c<buffer.size();++c) { std::ifstream stream(usage.path.string(), std::ifstream::binary);
if(buffer[c]=='\n') if(stream)
lines_start_pos.emplace_back(c+1); buffer.assign(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
} }
for(auto offset_it=usage.offsets.rbegin();offset_it!=usage.offsets.rend();++offset_it) { std::ofstream stream(usage.path.string(), std::ifstream::binary);
auto start_line=offset_it->first.line; if(!buffer.empty() && stream) {
auto end_line=offset_it->second.line; std::vector<size_t> lines_start_pos={0};
if(start_line<lines_start_pos.size() && end_line<lines_start_pos.size()) { for(size_t c=0;c<buffer.size();++c) {
auto start=lines_start_pos[start_line]+offset_it->first.index; if(buffer[c]=='\n')
auto end=lines_start_pos[end_line]+offset_it->second.index; lines_start_pos.emplace_back(c+1);
if(start<buffer.size() && end<=buffer.size()) }
buffer.replace(start, end-start, text); for(auto offset_it=usage.offsets.rbegin();offset_it!=usage.offsets.rend();++offset_it) {
auto start_line=offset_it->first.line;
auto end_line=offset_it->second.line;
if(start_line<lines_start_pos.size() && end_line<lines_start_pos.size()) {
auto start=lines_start_pos[start_line]+offset_it->first.index;
auto end=lines_start_pos[end_line]+offset_it->second.index;
if(start<buffer.size() && end<=buffer.size())
buffer.replace(start, end-start, text);
}
} }
stream.write(buffer.data(), buffer.bytes());
usages_renamed.emplace_back(&usage);
} }
stream.write(buffer.data(), buffer.bytes()); else
usages_renamed.emplace_back(&usage); Terminal::get().print("Error: could not write to file "+usage.path.string()+'\n', true);
} }
else
Terminal::get().print("Error: could not write to file "+usage.path.string()+'\n', true);
} }
}
if(!usages_renamed.empty()) {
if(!usages_renamed.empty()) { Terminal::get().print("Renamed ");
Terminal::get().print("Renamed "); Terminal::get().print(previous_text, true);
Terminal::get().print(previous_text, true); Terminal::get().print(" to ");
Terminal::get().print(" to "); Terminal::get().print(text, true);
Terminal::get().print(text, true); Terminal::get().print("\n");
Terminal::get().print("\n"); }
} };
}; }
goto_next_diagnostic=[this]() { goto_next_diagnostic=[this]() {
auto insert_offset=get_buffer()->get_insert()->get_iter().get_offset(); auto insert_offset=get_buffer()->get_insert()->get_iter().get_offset();
@ -790,6 +805,9 @@ void Source::LanguageProtocolView::show_diagnostic_tooltips(const Gdk::Rectangle
} }
void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rectangle) { void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rectangle) {
if(!capabilities.hover)
return;
Gtk::TextIter iter; Gtk::TextIter iter;
int location_x, location_y; int location_x, location_y;
window_to_buffer_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_x, location_y); window_to_buffer_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, rectangle.get_x(), rectangle.get_y(), location_x, location_y);
@ -817,7 +835,7 @@ void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rect
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "Type: "+value, "def:note"); tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), "Type: "+value, "def:note");
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
if(language_id=="rust") { if(language_id=="rust" && capabilities.definition) {
if(Debug::LLDB::get().is_stopped()) { if(Debug::LLDB::get().is_stopped()) {
Glib::ustring value_type="Value"; Glib::ustring value_type="Value";
@ -867,6 +885,9 @@ void Source::LanguageProtocolView::show_type_tooltips(const Gdk::Rectangle &rect
} }
void Source::LanguageProtocolView::tag_similar_symbols() { void Source::LanguageProtocolView::tag_similar_symbols() {
if(!capabilities.document_highlight && !capabilities.references)
return;
auto iter=get_buffer()->get_insert()->get_iter(); auto iter=get_buffer()->get_insert()->get_iter();
std::vector<std::pair<Offset, Offset>> offsets; std::vector<std::pair<Offset, Offset>> offsets;
std::promise<void> result_processed; std::promise<void> result_processed;
@ -931,6 +952,9 @@ Source::Offset Source::LanguageProtocolView::get_declaration(const Gtk::TextIter
} }
void Source::LanguageProtocolView::setup_autocomplete() { void Source::LanguageProtocolView::setup_autocomplete() {
if(!capabilities.completion)
return;
non_interactive_completion=[this] { non_interactive_completion=[this] {
if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) if(CompletionDialog::get() && CompletionDialog::get()->is_visible())
return; return;

7
src/source_language_protocol.h

@ -28,8 +28,15 @@ namespace LanguageProtocol {
FULL, FULL,
INCREMENTAL }; INCREMENTAL };
TextDocumentSync text_document_sync; TextDocumentSync text_document_sync;
bool hover;
bool completion;
bool definition;
bool references;
bool document_highlight; bool document_highlight;
bool workspace_symbol; bool workspace_symbol;
bool document_formatting;
bool document_range_formatting;
bool rename;
}; };
class Client { class Client {

Loading…
Cancel
Save