diff --git a/src/project.cc b/src/project.cc index 93ced8c..e07f6db 100644 --- a/src/project.cc +++ b/src/project.cc @@ -683,12 +683,18 @@ void Project::LanguageProtocol::show_symbols() { auto client = ::LanguageProtocol::Client::get(*project_path, language_id); auto capabilities = client->initialize(nullptr); - if(!capabilities.workspace_symbol) { + auto view = Notebook::get().get_current_view(); + auto language_protocol_view = dynamic_cast(view); + + if(!capabilities.workspace_symbol && !capabilities.document_symbol) { + Info::get().print("Language server does not support workspace/symbol or textDocument/documentSymbol"); + return; + } + else if(!language_protocol_view && !capabilities.workspace_symbol) { Info::get().print("Language server does not support workspace/symbol"); return; } - auto view = Notebook::get().get_current_view(); if(view) { auto dialog_iter = view->get_iter_for_dialog(); SelectionDialog::create(view, view->get_buffer()->create_mark(dialog_iter), true, true); @@ -701,18 +707,56 @@ void Project::LanguageProtocol::show_symbols() { }; auto offsets = std::make_shared>(); - SelectionDialog::get()->on_search_entry_changed = [client, project_path, offsets](const std::string &text) { - if(text.size() > 1) - return; - else { - offsets->clear(); - SelectionDialog::get()->erase_rows(); - if(text.empty()) + if(capabilities.workspace_symbol) { + SelectionDialog::get()->on_search_entry_changed = [client, project_path, offsets](const std::string &text) { + if(text.size() > 1) return; - } + else { + offsets->clear(); + SelectionDialog::get()->erase_rows(); + if(text.empty()) + return; + } + std::vector names; + std::promise result_processed; + client->write_request(nullptr, "workspace/symbol", R"("query":")" + text + '"', [&result_processed, &names, offsets, project_path](const boost::property_tree::ptree &result, bool error) { + if(!error) { + for(auto it = result.begin(); it != result.end(); ++it) { + auto name = it->second.get("name", ""); + if(!name.empty()) { + auto location_it = it->second.find("location"); + if(location_it != it->second.not_found()) { + auto file = location_it->second.get("uri", ""); + if(file.size() > 7) { + file.erase(0, 7); + auto range_it = location_it->second.find("range"); + if(range_it != location_it->second.not_found()) { + auto start_it = range_it->second.find("start"); + if(start_it != range_it->second.not_found()) { + try { + offsets->emplace_back(Source::Offset(start_it->second.get("line"), start_it->second.get("character"), file)); + names.emplace_back(name); + } + catch(...) { + } + } + } + } + } + } + } + } + result_processed.set_value(); + }); + result_processed.get_future().get(); + for(size_t c = 0; c < offsets->size() && c < names.size(); ++c) + SelectionDialog::get()->add_row(filesystem::get_relative_path((*offsets)[c].file_path, *project_path).string() + ':' + std::to_string((*offsets)[c].line + 1) + ':' + std::to_string((*offsets)[c].index + 1) + ": " + names[c]); + }; + } + else { std::vector names; std::promise result_processed; - client->write_request(nullptr, "workspace/symbol", R"("query":")" + text + '"', [&result_processed, &names, offsets, project_path](const boost::property_tree::ptree &result, bool error) { + client->write_request(nullptr, "textDocument/documentSymbol", R"("textDocument":{"uri":")" + language_protocol_view->uri + "\"}", [&result_processed, &names, offsets, project_path](const boost::property_tree::ptree &result, bool error) { if(!error) { for(auto it = result.begin(); it != result.end(); ++it) { auto name = it->second.get("name", ""); @@ -743,8 +787,8 @@ void Project::LanguageProtocol::show_symbols() { }); result_processed.get_future().get(); for(size_t c = 0; c < offsets->size() && c < names.size(); ++c) - SelectionDialog::get()->add_row(filesystem::get_relative_path((*offsets)[c].file_path, *project_path).string() + ':' + std::to_string((*offsets)[c].line + 1) + ':' + std::to_string((*offsets)[c].index + 1) + ": " + names[c]); - }; + SelectionDialog::get()->add_row(std::to_string((*offsets)[c].line + 1) + ':' + std::to_string((*offsets)[c].index + 1) + ": " + names[c]); + } SelectionDialog::get()->on_select = [offsets](unsigned int index, const std::string &text, bool hide_window) { auto &offset = (*offsets)[index]; diff --git a/src/source_language_protocol.cc b/src/source_language_protocol.cc index 6c2889b..1c57fb7 100644 --- a/src/source_language_protocol.cc +++ b/src/source_language_protocol.cc @@ -98,6 +98,7 @@ LanguageProtocol::Capabilities LanguageProtocol::Client::initialize(Source::Lang capabilities.references = capabilities_pt->second.get("referencesProvider", false); capabilities.document_highlight = capabilities_pt->second.get("documentHighlightProvider", false); capabilities.workspace_symbol = capabilities_pt->second.get("workspaceSymbolProvider", false); + capabilities.document_symbol = capabilities_pt->second.get("documentSymbolProvider", false); capabilities.document_formatting = capabilities_pt->second.get("documentFormattingProvider", false); capabilities.document_range_formatting = capabilities_pt->second.get("documentRangeFormattingProvider", false); capabilities.rename = capabilities_pt->second.get("renameProvider", false); diff --git a/src/source_language_protocol.h b/src/source_language_protocol.h index d070af7..a532eae 100644 --- a/src/source_language_protocol.h +++ b/src/source_language_protocol.h @@ -34,6 +34,7 @@ namespace LanguageProtocol { bool references; bool document_highlight; bool workspace_symbol; + bool document_symbol; bool document_formatting; bool document_range_formatting; bool rename;