2018-02-12 09:01:02 +00:00
|
|
|
#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 <ctype.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <functional>
|
|
|
|
|
2017-12-06 05:03:38 +00:00
|
|
|
namespace {
|
2018-03-22 04:05:25 +00:00
|
|
|
MethodType kMethodType = "workspace/symbol";
|
2017-12-19 05:31:19 +00:00
|
|
|
|
|
|
|
// Lookup |symbol| in |db| and insert the value into |result|.
|
2018-04-30 02:51:25 +00:00
|
|
|
bool AddSymbol(
|
2018-05-30 06:56:14 +00:00
|
|
|
DB* db,
|
2018-04-30 02:51:25 +00:00
|
|
|
WorkingFiles* working_files,
|
2018-05-30 06:56:14 +00:00
|
|
|
SymbolIdx sym,
|
2018-04-30 02:51:25 +00:00
|
|
|
bool use_detailed,
|
2018-05-30 06:56:14 +00:00
|
|
|
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>>* result) {
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<lsSymbolInformation> info =
|
2018-05-30 06:56:14 +00:00
|
|
|
GetSymbolInfo(db, working_files, sym, true);
|
2017-12-19 05:31:19 +00:00
|
|
|
if (!info)
|
2017-12-24 03:23:29 +00:00
|
|
|
return false;
|
2017-12-19 05:31:19 +00:00
|
|
|
|
2018-02-11 04:01:10 +00:00
|
|
|
Use loc;
|
2018-05-30 06:56:14 +00:00
|
|
|
if (Maybe<Use> location = GetDefinitionExtent(db, sym))
|
2018-02-09 05:11:35 +00:00
|
|
|
loc = *location;
|
|
|
|
else {
|
2018-05-30 06:56:14 +00:00
|
|
|
auto decls = GetNonDefDeclarations(db, sym);
|
2017-12-19 05:31:19 +00:00
|
|
|
if (decls.empty())
|
2017-12-24 03:23:29 +00:00
|
|
|
return false;
|
2018-02-09 05:11:35 +00:00
|
|
|
loc = decls[0];
|
2017-12-19 05:31:19 +00:00
|
|
|
}
|
|
|
|
|
2018-03-31 03:16:33 +00:00
|
|
|
std::optional<lsLocation> ls_location = GetLsLocation(db, working_files, loc);
|
2017-12-19 05:31:19 +00:00
|
|
|
if (!ls_location)
|
2017-12-24 03:23:29 +00:00
|
|
|
return false;
|
2017-12-19 05:31:19 +00:00
|
|
|
info->location = *ls_location;
|
2018-05-30 06:56:14 +00:00
|
|
|
result->emplace_back(*info, int(use_detailed), sym);
|
2017-12-24 03:23:29 +00:00
|
|
|
return true;
|
2017-12-19 05:31:19 +00:00
|
|
|
}
|
|
|
|
|
2018-03-22 05:01:21 +00:00
|
|
|
struct In_WorkspaceSymbol : public RequestInMessage {
|
2018-03-22 04:05:25 +00:00
|
|
|
MethodType GetMethodType() const override { return kMethodType; }
|
2018-01-19 08:56:09 +00:00
|
|
|
struct Params {
|
|
|
|
std::string query;
|
|
|
|
};
|
|
|
|
Params params;
|
2017-12-06 04:39:44 +00:00
|
|
|
};
|
2018-03-22 04:05:25 +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);
|
|
|
|
|
2017-12-24 03:23:29 +00:00
|
|
|
///// Fuzzy matching
|
|
|
|
|
2018-03-22 04:05:25 +00:00
|
|
|
struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
|
|
|
|
MethodType GetMethodType() const override { return kMethodType; }
|
|
|
|
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;
|
|
|
|
|
2018-04-30 02:51:25 +00:00
|
|
|
// {symbol info, matching detailed_name or short_name, index}
|
2018-05-30 06:56:14 +00:00
|
|
|
std::vector<std::tuple<lsSymbolInformation, int, SymbolIdx>> cands;
|
2018-04-30 02:51:25 +00:00
|
|
|
bool sensitive = g_config->workspaceSymbol.caseSensitivity;
|
2017-12-06 03:32:33 +00:00
|
|
|
|
2018-04-30 02:51:25 +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;
|
2018-01-05 18:06:15 +00:00
|
|
|
|
2018-05-30 06:56:14 +00:00
|
|
|
auto Add = [&](SymbolIdx sym) {
|
|
|
|
std::string_view detailed_name = db->GetSymbolName(sym, true);
|
2018-04-30 02:51:25 +00:00
|
|
|
int pos =
|
|
|
|
ReverseSubseqMatch(query_without_space, detailed_name, sensitive);
|
2018-05-30 06:56:14 +00:00
|
|
|
return pos >= 0 &&
|
|
|
|
AddSymbol(db, working_files, sym,
|
|
|
|
detailed_name.find(':', pos) != std::string::npos,
|
|
|
|
&cands) &&
|
|
|
|
cands.size() >= g_config->workspaceSymbol.maxNum;
|
|
|
|
};
|
|
|
|
for (auto& func : db->funcs)
|
|
|
|
if (Add({func.usr, SymbolKind::Func}))
|
|
|
|
goto done_add;
|
|
|
|
for (auto& type : db->types)
|
|
|
|
if (Add({type.usr, SymbolKind::Type}))
|
|
|
|
goto done_add;
|
|
|
|
for (auto& var : db->vars)
|
|
|
|
if (var.def.size() && !var.def[0].is_local() &&
|
|
|
|
Add({var.usr, SymbolKind::Var}))
|
|
|
|
goto done_add;
|
|
|
|
done_add:
|
2017-12-06 03:32:33 +00:00
|
|
|
|
2018-04-04 06:05:41 +00:00
|
|
|
if (g_config->workspaceSymbol.sort && query.size() <= FuzzyMatcher::kMaxPat) {
|
2018-01-07 21:08:18 +00:00
|
|
|
// Sort results with a fuzzy matching algorithm.
|
|
|
|
int longest = 0;
|
2018-05-30 06:56:14 +00:00
|
|
|
for (auto& cand : cands)
|
2018-04-30 02:51:25 +00:00
|
|
|
longest = std::max(
|
2018-05-30 06:56:14 +00:00
|
|
|
longest, int(db->GetSymbolName(std::get<2>(cand), true).size()));
|
2018-04-14 18:57:23 +00:00
|
|
|
FuzzyMatcher fuzzy(query, g_config->workspaceSymbol.caseSensitivity);
|
2018-05-30 06:56:14 +00:00
|
|
|
for (auto& cand : cands)
|
|
|
|
std::get<1>(cand) = fuzzy.Match(
|
|
|
|
db->GetSymbolName(std::get<2>(cand), std::get<1>(cand)));
|
|
|
|
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());
|
|
|
|
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-07 21:08:18 +00:00
|
|
|
}
|
2018-01-11 02:43:01 +00:00
|
|
|
} else {
|
2018-05-30 06:56:14 +00:00
|
|
|
out.result.reserve(cands.size());
|
|
|
|
for (auto& cand : cands)
|
|
|
|
out.result.push_back(std::get<0>(cand));
|
2017-12-24 06:49:45 +00:00
|
|
|
}
|
2018-01-07 21:08:18 +00:00
|
|
|
|
2018-05-28 00:50:02 +00:00
|
|
|
pipeline::WriteStdout(kMethodType, out);
|
2017-12-06 03:32:33 +00:00
|
|
|
}
|
|
|
|
};
|
2018-03-22 04:05:25 +00:00
|
|
|
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);
|
2017-12-24 03:23:29 +00:00
|
|
|
} // namespace
|