ccls/src/messages/workspace_symbol.cc

134 lines
4.2 KiB
C++
Raw Normal View History

#include "fuzzy_match.h"
2017-12-06 03:32:33 +00:00
#include "message_handler.h"
2018-05-28 00:50:02 +00:00
#include "pipeline.hh"
2017-12-06 03:32:33 +00:00
#include "query_utils.h"
2018-05-28 00:50:02 +00:00
using namespace ccls;
2017-12-06 03:32:33 +00:00
2017-12-29 16:29:47 +00:00
#include <algorithm>
2018-08-09 17:08:14 +00:00
#include <ctype.h>
2017-12-29 16:29:47 +00:00
#include <functional>
2018-08-09 17:08:14 +00:00
#include <limits.h>
2017-12-29 16:29:47 +00:00
namespace {
MethodType kMethodType = "workspace/symbol";
// Lookup |symbol| in |db| and insert the value into |result|.
bool AddSymbol(
2018-08-09 17:08:14 +00:00
DB *db, WorkingFiles *working_files, SymbolIdx sym, bool use_detailed,
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> *result) {
2018-03-31 03:16:33 +00:00
std::optional<lsSymbolInformation> info =
GetSymbolInfo(db, working_files, sym, true);
if (!info)
return false;
Use loc;
if (Maybe<Use> location = GetDefinitionExtent(db, sym))
2018-02-09 05:11:35 +00:00
loc = *location;
else {
auto decls = GetNonDefDeclarations(db, sym);
if (decls.empty())
return false;
2018-02-09 05:11:35 +00:00
loc = decls[0];
}
2018-03-31 03:16:33 +00:00
std::optional<lsLocation> ls_location = GetLsLocation(db, working_files, loc);
if (!ls_location)
return false;
info->location = *ls_location;
result->emplace_back(*info, int(use_detailed), sym);
return true;
}
2018-03-22 05:01:21 +00:00
struct In_WorkspaceSymbol : public RequestInMessage {
MethodType GetMethodType() const override { return kMethodType; }
struct Params {
std::string query;
};
Params params;
2017-12-06 04:39:44 +00:00
};
MAKE_REFLECT_STRUCT(In_WorkspaceSymbol::Params, query);
MAKE_REFLECT_STRUCT(In_WorkspaceSymbol, id, params);
REGISTER_IN_MESSAGE(In_WorkspaceSymbol);
2017-12-06 04:39:44 +00:00
struct Out_WorkspaceSymbol : public lsOutMessage<Out_WorkspaceSymbol> {
lsRequestId id;
2017-12-12 05:20:29 +00:00
std::vector<lsSymbolInformation> result;
2017-12-06 04:39:44 +00:00
};
MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result);
///// Fuzzy matching
struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
MethodType GetMethodType() const override { return kMethodType; }
2018-08-09 17:08:14 +00:00
void Run(In_WorkspaceSymbol *request) override {
2017-12-06 03:32:33 +00:00
Out_WorkspaceSymbol out;
out.id = request->id;
std::string query = request->params.query;
// {symbol info, matching detailed_name or short_name, index}
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> cands;
bool sensitive = g_config->workspaceSymbol.caseSensitivity;
2017-12-06 03:32:33 +00:00
// Find subsequence matches.
std::string query_without_space;
query_without_space.reserve(query.size());
for (char c : query)
if (!isspace(c))
query_without_space += c;
auto Add = [&](SymbolIdx sym) {
std::string_view detailed_name = db->GetSymbolName(sym, true);
int pos =
2018-08-09 17:08:14 +00:00
ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
return pos >= 0 &&
AddSymbol(db, working_files, sym,
detailed_name.find(':', pos) != std::string::npos,
&cands) &&
cands.size() >= g_config->workspaceSymbol.maxNum;
};
2018-08-09 17:08:14 +00:00
for (auto &func : db->funcs)
if (Add({func.usr, SymbolKind::Func}))
goto done_add;
2018-08-09 17:08:14 +00:00
for (auto &type : db->types)
if (Add({type.usr, SymbolKind::Type}))
goto done_add;
2018-08-09 17:08:14 +00:00
for (auto &var : db->vars)
if (var.def.size() && !var.def[0].is_local() &&
Add({var.usr, SymbolKind::Var}))
goto done_add;
2018-08-09 17:08:14 +00:00
done_add:
2017-12-06 03:32:33 +00:00
2018-08-09 17:08:14 +00:00
if (g_config->workspaceSymbol.sort &&
query.size() <= FuzzyMatcher::kMaxPat) {
// Sort results with a fuzzy matching algorithm.
int longest = 0;
2018-08-09 17:08:14 +00:00
for (auto &cand : cands)
longest = std::max(
longest, int(db->GetSymbolName(std::get<2>(cand), true).size()));
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
2018-08-09 17:08:14 +00:00
for (auto &cand : cands)
std::get<1>(cand) = fuzzy.Match(
db->GetSymbolName(std::get<2>(cand), std::get<1>(cand)));
2018-08-09 17:08:14 +00:00
std::sort(cands.begin(), cands.end(), [](const auto &l, const auto &r) {
return std::get<1>(l) > std::get<1>(r);
});
out.result.reserve(cands.size());
2018-08-09 17:08:14 +00:00
for (auto &cand : cands) {
// Discard awful candidates.
if (std::get<1>(cand) <= FuzzyMatcher::kMinScore)
break;
out.result.push_back(std::get<0>(cand));
}
2018-01-11 02:43:01 +00:00
} else {
out.result.reserve(cands.size());
2018-08-09 17:08:14 +00:00
for (auto &cand : cands)
out.result.push_back(std::get<0>(cand));
}
2018-05-28 00:50:02 +00:00
pipeline::WriteStdout(kMethodType, out);
2017-12-06 03:32:33 +00:00
}
};
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);
2018-08-09 17:08:14 +00:00
} // namespace