mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-21 23:25:07 +00:00
Remove WithFileContent & lex_utils.{cc,h}
This commit is contained in:
parent
da545f1139
commit
34dc1e93e9
@ -202,7 +202,6 @@ target_sources(ccls PRIVATE
|
|||||||
src/indexer.cc
|
src/indexer.cc
|
||||||
src/method.cc
|
src/method.cc
|
||||||
src/language.cc
|
src/language.cc
|
||||||
src/lex_utils.cc
|
|
||||||
src/log.cc
|
src/log.cc
|
||||||
src/lsp.cc
|
src/lsp.cc
|
||||||
src/match.cc
|
src/match.cc
|
||||||
|
@ -3,9 +3,11 @@
|
|||||||
#include "log.hh"
|
#include "log.hh"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
#include "timer.h"
|
|
||||||
#include "type_printer.h"
|
#include "type_printer.h"
|
||||||
|
|
||||||
|
#include <llvm/Support/Timer.h>
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -2016,7 +2018,8 @@ std::vector<std::unique_ptr<IndexFile>> ClangIndexer::Index(
|
|||||||
|
|
||||||
file = NormalizePath(file);
|
file = NormalizePath(file);
|
||||||
|
|
||||||
Timer timer;
|
Timer timer("parse", "parse tu");
|
||||||
|
timer.startTimer();
|
||||||
|
|
||||||
std::vector<CXUnsavedFile> unsaved_files;
|
std::vector<CXUnsavedFile> unsaved_files;
|
||||||
for (const FileContents& contents : file_contents) {
|
for (const FileContents& contents : file_contents) {
|
||||||
@ -2034,7 +2037,7 @@ std::vector<std::unique_ptr<IndexFile>> ClangIndexer::Index(
|
|||||||
if (!tu)
|
if (!tu)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
perf->index_parse = timer.ElapsedMicrosecondsAndReset();
|
timer.stopTimer();
|
||||||
|
|
||||||
return ParseWithTu(vfs, perf, tu.get(), &index, file, args, unsaved_files);
|
return ParseWithTu(vfs, perf, tu.get(), &index, file, args, unsaved_files);
|
||||||
}
|
}
|
||||||
@ -2048,6 +2051,7 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
|
|||||||
const std::vector<std::string>& args,
|
const std::vector<std::string>& args,
|
||||||
const std::vector<CXUnsavedFile>& file_contents) {
|
const std::vector<CXUnsavedFile>& file_contents) {
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
timer.startTimer();
|
||||||
|
|
||||||
IndexerCallbacks callback = {0};
|
IndexerCallbacks callback = {0};
|
||||||
// Available callbacks:
|
// Available callbacks:
|
||||||
@ -2085,13 +2089,12 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
|
|||||||
<< " failed with errno=" << index_result;
|
<< " failed with errno=" << index_result;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
clang_IndexAction_dispose(index_action);
|
clang_IndexAction_dispose(index_action);
|
||||||
|
|
||||||
ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu))
|
ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu))
|
||||||
.VisitChildren(&VisitMacroDefinitionAndExpansions, ¶m);
|
.VisitChildren(&VisitMacroDefinitionAndExpansions, ¶m);
|
||||||
|
|
||||||
perf->index_build = timer.ElapsedMicrosecondsAndReset();
|
timer.stopTimer();
|
||||||
|
|
||||||
std::unordered_map<std::string, int> inc_to_line;
|
std::unordered_map<std::string, int> inc_to_line;
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -27,8 +27,6 @@ struct IndexFunc;
|
|||||||
struct IndexVar;
|
struct IndexVar;
|
||||||
struct QueryFile;
|
struct QueryFile;
|
||||||
|
|
||||||
using RawId = uint32_t;
|
|
||||||
|
|
||||||
struct SymbolIdx {
|
struct SymbolIdx {
|
||||||
Usr usr;
|
Usr usr;
|
||||||
SymbolKind kind;
|
SymbolKind kind;
|
||||||
@ -153,19 +151,9 @@ struct TypeDef : NameMixin<TypeDef> {
|
|||||||
NtString hover;
|
NtString hover;
|
||||||
NtString comments;
|
NtString comments;
|
||||||
|
|
||||||
// While a class/type can technically have a separate declaration/definition,
|
|
||||||
// it doesn't really happen in practice. The declaration never contains
|
|
||||||
// comments or insightful information. The user always wants to jump from
|
|
||||||
// the declaration to the definition - never the other way around like in
|
|
||||||
// functions and (less often) variables.
|
|
||||||
//
|
|
||||||
// It's also difficult to identify a `class Foo;` statement with the clang
|
|
||||||
// indexer API (it's doable using cursor AST traversal), so we don't bother
|
|
||||||
// supporting the feature.
|
|
||||||
Maybe<Use> spell;
|
Maybe<Use> spell;
|
||||||
Maybe<Use> extent;
|
Maybe<Use> extent;
|
||||||
|
|
||||||
// Immediate parent types.
|
|
||||||
std::vector<Usr> bases;
|
std::vector<Usr> bases;
|
||||||
|
|
||||||
// Types, functions, and variables defined in this type.
|
// Types, functions, and variables defined in this type.
|
||||||
@ -221,8 +209,6 @@ struct VarDef : NameMixin<VarDef> {
|
|||||||
std::string detailed_name;
|
std::string detailed_name;
|
||||||
NtString hover;
|
NtString hover;
|
||||||
NtString comments;
|
NtString comments;
|
||||||
// TODO: definitions should be a list of ranges, since there can be more
|
|
||||||
// than one - when??
|
|
||||||
Maybe<Use> spell;
|
Maybe<Use> spell;
|
||||||
Maybe<Use> extent;
|
Maybe<Use> extent;
|
||||||
|
|
||||||
|
@ -1,87 +0,0 @@
|
|||||||
#include "lex_utils.h"
|
|
||||||
|
|
||||||
#include <doctest/doctest.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
// VSCode (UTF-16) disagrees with Emacs lsp-mode (UTF-8) on how to represent
|
|
||||||
// text documents.
|
|
||||||
// We use a UTF-8 iterator to approximate UTF-16 in the specification (weird).
|
|
||||||
// This is good enough and fails only for UTF-16 surrogate pairs.
|
|
||||||
int GetOffsetForPosition(lsPosition position, std::string_view content) {
|
|
||||||
size_t i = 0;
|
|
||||||
for (; position.line > 0 && i < content.size(); i++)
|
|
||||||
if (content[i] == '\n')
|
|
||||||
position.line--;
|
|
||||||
for (; position.character > 0 && i < content.size(); position.character--)
|
|
||||||
if (uint8_t(content[i++]) >= 128) {
|
|
||||||
// Skip 0b10xxxxxx
|
|
||||||
while (i < content.size() && uint8_t(content[i]) >= 128 &&
|
|
||||||
uint8_t(content[i]) < 192)
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return int(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view LexIdentifierAroundPos(lsPosition position,
|
|
||||||
std::string_view content) {
|
|
||||||
int start = GetOffsetForPosition(position, content);
|
|
||||||
int end = start + 1;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
// We search for :: before the cursor but not after to get the qualifier.
|
|
||||||
for (; start > 0; start--) {
|
|
||||||
c = content[start - 1];
|
|
||||||
if (isalnum(c) || c == '_')
|
|
||||||
;
|
|
||||||
else if (c == ':' && start > 1 && content[start - 2] == ':')
|
|
||||||
start--;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; end < (int)content.size(); end++)
|
|
||||||
if (c = content[end], !(isalnum(c) || c == '_'))
|
|
||||||
break;
|
|
||||||
|
|
||||||
return content.substr(start, end - start);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find discontinous |search| in |content|.
|
|
||||||
// Return |found| and the count of skipped chars before found.
|
|
||||||
int ReverseSubseqMatch(std::string_view pat,
|
|
||||||
std::string_view text,
|
|
||||||
int case_sensitivity) {
|
|
||||||
if (case_sensitivity == 1)
|
|
||||||
case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
|
|
||||||
int j = pat.size();
|
|
||||||
if (!j)
|
|
||||||
return text.size();
|
|
||||||
for (int i = text.size(); i--;)
|
|
||||||
if ((case_sensitivity ? text[i] == pat[j - 1]
|
|
||||||
: tolower(text[i]) == tolower(pat[j - 1])) &&
|
|
||||||
!--j)
|
|
||||||
return i;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_SUITE("Offset") {
|
|
||||||
TEST_CASE("past end") {
|
|
||||||
std::string content = "foo";
|
|
||||||
int offset = GetOffsetForPosition(lsPosition{10, 10}, content);
|
|
||||||
REQUIRE(offset <= content.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("in middle of content") {
|
|
||||||
std::string content = "abcdefghijk";
|
|
||||||
for (int i = 0; i < content.size(); ++i) {
|
|
||||||
int offset = GetOffsetForPosition(lsPosition{0, i}, content);
|
|
||||||
REQUIRE(i == offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("at end of content") {
|
|
||||||
REQUIRE(GetOffsetForPosition(lsPosition{0, 0}, "") == 0);
|
|
||||||
REQUIRE(GetOffsetForPosition(lsPosition{0, 1}, "a") == 1);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "lsp.h"
|
|
||||||
|
|
||||||
#include <string_view>
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
// Utility method to map |position| to an offset inside of |content|.
|
|
||||||
int GetOffsetForPosition(lsPosition position, std::string_view content);
|
|
||||||
|
|
||||||
std::string_view LexIdentifierAroundPos(lsPosition position,
|
|
||||||
std::string_view content);
|
|
||||||
|
|
||||||
int ReverseSubseqMatch(std::string_view pat,
|
|
||||||
std::string_view text,
|
|
||||||
int case_sensitivity);
|
|
@ -129,12 +129,10 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<MethodType, Timer> request_times;
|
|
||||||
|
|
||||||
// The thread that reads from stdin and dispatchs commands to the main thread.
|
// The thread that reads from stdin and dispatchs commands to the main thread.
|
||||||
pipeline::LaunchStdin(&request_times);
|
pipeline::LaunchStdin();
|
||||||
// The thread that writes responses from the main thread to stdout.
|
// The thread that writes responses from the main thread to stdout.
|
||||||
pipeline::LaunchStdout(&request_times);
|
pipeline::LaunchStdout();
|
||||||
// Main thread which also spawns indexer threads upon the "initialize" request.
|
// Main thread which also spawns indexer threads upon the "initialize" request.
|
||||||
pipeline::MainLoop();
|
pipeline::MainLoop();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
|
|
||||||
#include "lex_utils.h"
|
|
||||||
#include "log.hh"
|
#include "log.hh"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
|
@ -7,8 +7,6 @@
|
|||||||
#include "working_files.h"
|
#include "working_files.h"
|
||||||
using namespace ccls;
|
using namespace ccls;
|
||||||
|
|
||||||
#include "lex_utils.h"
|
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#include "lex_utils.h"
|
|
||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
#include "pipeline.hh"
|
#include "pipeline.hh"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
#include "clang_format.h"
|
|
||||||
#include "lex_utils.h"
|
|
||||||
#include "message_handler.h"
|
|
||||||
#include "pipeline.hh"
|
|
||||||
using namespace ccls;
|
|
||||||
#include "working_files.h"
|
|
||||||
|
|
||||||
#include <loguru.hpp>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
MethodType kMethodType = "textDocument/rangeFormatting";
|
|
||||||
|
|
||||||
struct lsTextDocumentRangeFormattingParams {
|
|
||||||
lsTextDocumentIdentifier textDocument;
|
|
||||||
lsRange range;
|
|
||||||
lsFormattingOptions options;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentRangeFormattingParams,
|
|
||||||
textDocument,
|
|
||||||
range,
|
|
||||||
options);
|
|
||||||
|
|
||||||
struct In_TextDocumentRangeFormatting : public RequestInMessage {
|
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
|
||||||
lsTextDocumentRangeFormattingParams params;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(In_TextDocumentRangeFormatting, id, params);
|
|
||||||
REGISTER_IN_MESSAGE(In_TextDocumentRangeFormatting);
|
|
||||||
|
|
||||||
struct Out_TextDocumentRangeFormatting
|
|
||||||
: public lsOutMessage<Out_TextDocumentRangeFormatting> {
|
|
||||||
lsRequestId id;
|
|
||||||
std::vector<lsTextEdit> result;
|
|
||||||
};
|
|
||||||
MAKE_REFLECT_STRUCT(Out_TextDocumentRangeFormatting, jsonrpc, id, result);
|
|
||||||
|
|
||||||
struct Handler_TextDocumentRangeFormatting
|
|
||||||
: BaseMessageHandler<In_TextDocumentRangeFormatting> {
|
|
||||||
MethodType GetMethodType() const override { return kMethodType; }
|
|
||||||
|
|
||||||
void Run(In_TextDocumentRangeFormatting* request) override {
|
|
||||||
Out_TextDocumentRangeFormatting response;
|
|
||||||
response.id = request->id;
|
|
||||||
#if USE_CLANG_CXX
|
|
||||||
QueryFile* file;
|
|
||||||
if (!FindFileOrFail(db, project, request->id,
|
|
||||||
request->params.textDocument.uri.GetPath(), &file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkingFile* working_file =
|
|
||||||
working_files->GetFileByFilename(file->def->path);
|
|
||||||
|
|
||||||
int start = GetOffsetForPosition(request->params.range.start,
|
|
||||||
working_file->buffer_content),
|
|
||||||
end = GetOffsetForPosition(request->params.range.end,
|
|
||||||
working_file->buffer_content);
|
|
||||||
response.result = ConvertClangReplacementsIntoTextEdits(
|
|
||||||
working_file->buffer_content,
|
|
||||||
ClangFormatDocument(working_file, start, end, request->params.options));
|
|
||||||
#else
|
|
||||||
LOG_S(WARNING) << "You must compile ccls with --use-clang-cxx to use "
|
|
||||||
"textDocument/rangeFormatting.";
|
|
||||||
// TODO: Fallback to execute the clang-format binary?
|
|
||||||
response.result = {};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pipeline::WriteStdout(kMethodType, response);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRangeFormatting);
|
|
||||||
} // namespace
|
|
@ -1,5 +1,4 @@
|
|||||||
#include "fuzzy_match.h"
|
#include "fuzzy_match.h"
|
||||||
#include "lex_utils.h"
|
|
||||||
#include "message_handler.h"
|
#include "message_handler.h"
|
||||||
#include "pipeline.hh"
|
#include "pipeline.hh"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "query_utils.h"
|
#include "query_utils.h"
|
||||||
#include "pipeline.hh"
|
#include "pipeline.hh"
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
#include <llvm/ADT/Twine.h>
|
#include <llvm/ADT/Twine.h>
|
||||||
#include <llvm/Support/Threading.h>
|
#include <llvm/Support/Threading.h>
|
||||||
|
#include <llvm/Support/Timer.h>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -237,14 +237,15 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
|
|||||||
|
|
||||||
// Write current index to disk if requested.
|
// Write current index to disk if requested.
|
||||||
LOG_S(INFO) << "store index for " << path;
|
LOG_S(INFO) << "store index for " << path;
|
||||||
Timer time;
|
|
||||||
{
|
{
|
||||||
|
Timer timer("write", "store index");
|
||||||
|
timer.startTimer();
|
||||||
std::string cache_path = GetCachePath(path);
|
std::string cache_path = GetCachePath(path);
|
||||||
WriteToFile(cache_path, curr->file_contents);
|
WriteToFile(cache_path, curr->file_contents);
|
||||||
WriteToFile(AppendSerializationFormat(cache_path),
|
WriteToFile(AppendSerializationFormat(cache_path),
|
||||||
Serialize(g_config->cacheFormat, *curr));
|
Serialize(g_config->cacheFormat, *curr));
|
||||||
|
timer.stopTimer();
|
||||||
}
|
}
|
||||||
perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset();
|
|
||||||
|
|
||||||
vfs->Reset(path_to_index);
|
vfs->Reset(path_to_index);
|
||||||
if (entry.id >= 0) {
|
if (entry.id >= 0) {
|
||||||
@ -255,7 +256,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
|
|||||||
|
|
||||||
// Build delta update.
|
// Build delta update.
|
||||||
IndexUpdate update = IndexUpdate::CreateDelta(prev.get(), curr.get());
|
IndexUpdate update = IndexUpdate::CreateDelta(prev.get(), curr.get());
|
||||||
perf.index_make_delta = time.ElapsedMicrosecondsAndReset();
|
|
||||||
LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")";
|
LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")";
|
||||||
|
|
||||||
on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
|
on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
|
||||||
@ -264,15 +264,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function returns true if e2e timing should be displayed for the given
|
|
||||||
// MethodId.
|
|
||||||
bool ShouldDisplayMethodTiming(MethodType type) {
|
|
||||||
return
|
|
||||||
type != kMethodType_TextDocumentPublishDiagnostics &&
|
|
||||||
type != kMethodType_CclsPublishInactiveRegions &&
|
|
||||||
type != kMethodType_Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
@ -316,20 +307,22 @@ void Main_OnIndexed(DB* db,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer time;
|
Timer timer("apply", "apply index");
|
||||||
|
timer.startTimer();
|
||||||
db->ApplyIndexUpdate(&response->update);
|
db->ApplyIndexUpdate(&response->update);
|
||||||
|
timer.stopTimer();
|
||||||
|
|
||||||
// Update indexed content, inactive lines, and semantic highlighting.
|
// Update indexed content, inactive lines, and semantic highlighting.
|
||||||
if (response->update.files_def_update) {
|
if (response->update.files_def_update) {
|
||||||
auto& update = *response->update.files_def_update;
|
auto& update = *response->update.files_def_update;
|
||||||
time.ResetAndPrint("apply index for " + update.value.path);
|
LOG_S(INFO) << "apply index for " << update.first.path;
|
||||||
if (WorkingFile* working_file =
|
if (WorkingFile* working_file =
|
||||||
working_files->GetFileByFilename(update.value.path)) {
|
working_files->GetFileByFilename(update.first.path)) {
|
||||||
// Update indexed content.
|
// Update indexed content.
|
||||||
working_file->SetIndexContent(update.file_content);
|
working_file->SetIndexContent(update.second);
|
||||||
|
|
||||||
// Inactive lines.
|
// Inactive lines.
|
||||||
EmitInactiveLines(working_file, update.value.inactive_regions);
|
EmitInactiveLines(working_file, update.first.inactive_regions);
|
||||||
|
|
||||||
// Semantic highlighting.
|
// Semantic highlighting.
|
||||||
int file_id =
|
int file_id =
|
||||||
@ -340,8 +333,8 @@ void Main_OnIndexed(DB* db,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
|
void LaunchStdin() {
|
||||||
std::thread([request_times]() {
|
std::thread([]() {
|
||||||
set_thread_name("stdin");
|
set_thread_name("stdin");
|
||||||
while (true) {
|
while (true) {
|
||||||
std::unique_ptr<InMessage> message;
|
std::unique_ptr<InMessage> message;
|
||||||
@ -367,7 +360,6 @@ void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
|
|||||||
|
|
||||||
// Cache |method_id| so we can access it after moving |message|.
|
// Cache |method_id| so we can access it after moving |message|.
|
||||||
MethodType method_type = message->GetMethodType();
|
MethodType method_type = message->GetMethodType();
|
||||||
(*request_times)[method_type] = Timer();
|
|
||||||
|
|
||||||
on_request->PushBack(std::move(message));
|
on_request->PushBack(std::move(message));
|
||||||
|
|
||||||
@ -379,7 +371,7 @@ void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
|
|||||||
}).detach();
|
}).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times) {
|
void LaunchStdout() {
|
||||||
std::thread([=]() {
|
std::thread([=]() {
|
||||||
set_thread_name("stdout");
|
set_thread_name("stdout");
|
||||||
|
|
||||||
@ -391,11 +383,6 @@ void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (auto& message : messages) {
|
for (auto& message : messages) {
|
||||||
if (ShouldDisplayMethodTiming(message.method)) {
|
|
||||||
Timer time = (*request_times)[message.method];
|
|
||||||
time.ResetAndPrint("[e2e] Running " + std::string(message.method));
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite(message.content.c_str(), message.content.size(), 1, stdout);
|
fwrite(message.content.c_str(), message.content.size(), 1, stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "method.h"
|
#include "method.h"
|
||||||
#include "query.h"
|
#include "query.h"
|
||||||
#include "timer.h"
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -17,8 +16,8 @@ struct lsBaseOutMessage;
|
|||||||
namespace ccls::pipeline {
|
namespace ccls::pipeline {
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times);
|
void LaunchStdin();
|
||||||
void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times);
|
void LaunchStdout();
|
||||||
void Indexer_Main(DiagnosticsEngine* diag_engine,
|
void Indexer_Main(DiagnosticsEngine* diag_engine,
|
||||||
VFS* vfs,
|
VFS* vfs,
|
||||||
Project* project,
|
Project* project,
|
||||||
|
@ -148,7 +148,7 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
|
|||||||
return a.range.start < b.range.start;
|
return a.range.start < b.range.start;
|
||||||
});
|
});
|
||||||
|
|
||||||
return QueryFile::DefUpdate(def, indexed.file_contents);
|
return {std::move(def), std::move(indexed.file_contents)};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if an element with the same file is found.
|
// Returns true if an element with the same file is found.
|
||||||
@ -342,11 +342,11 @@ void DB::ApplyIndexUpdate(IndexUpdate* u) {
|
|||||||
|
|
||||||
int DB::Update(QueryFile::DefUpdate&& u) {
|
int DB::Update(QueryFile::DefUpdate&& u) {
|
||||||
int id = files.size();
|
int id = files.size();
|
||||||
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.value.path), id);
|
auto it = name2file_id.try_emplace(LowerPathIfInsensitive(u.first.path), id);
|
||||||
if (it.second)
|
if (it.second)
|
||||||
files.emplace_back().id = id;
|
files.emplace_back().id = id;
|
||||||
QueryFile& existing = files[it.first->second];
|
QueryFile& existing = files[it.first->second];
|
||||||
existing.def = u.value;
|
existing.def = u.first;
|
||||||
return existing.id;
|
return existing.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
src/query.h
17
src/query.h
@ -7,21 +7,6 @@
|
|||||||
#include <llvm/ADT/SmallVector.h>
|
#include <llvm/ADT/SmallVector.h>
|
||||||
#include <llvm/ADT/StringMap.h>
|
#include <llvm/ADT/StringMap.h>
|
||||||
|
|
||||||
struct QueryFile;
|
|
||||||
struct QueryType;
|
|
||||||
struct QueryFunc;
|
|
||||||
struct QueryVar;
|
|
||||||
struct DB;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct WithFileContent {
|
|
||||||
T value;
|
|
||||||
std::string file_content;
|
|
||||||
|
|
||||||
WithFileContent(const T& value, const std::string& file_content)
|
|
||||||
: value(value), file_content(file_content) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct QueryFile {
|
struct QueryFile {
|
||||||
struct Def {
|
struct Def {
|
||||||
std::string path;
|
std::string path;
|
||||||
@ -39,7 +24,7 @@ struct QueryFile {
|
|||||||
std::vector<std::string> dependencies;
|
std::vector<std::string> dependencies;
|
||||||
};
|
};
|
||||||
|
|
||||||
using DefUpdate = WithFileContent<Def>;
|
using DefUpdate = std::pair<Def, std::string>;
|
||||||
|
|
||||||
int id = -1;
|
int id = -1;
|
||||||
std::optional<Def> def;
|
std::optional<Def> def;
|
||||||
|
18
src/utils.cc
18
src/utils.cc
@ -134,6 +134,24 @@ std::optional<int64_t> LastWriteTime(const std::string& filename) {
|
|||||||
return Status.getLastModificationTime().time_since_epoch().count();
|
return Status.getLastModificationTime().time_since_epoch().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find discontinous |search| in |content|.
|
||||||
|
// Return |found| and the count of skipped chars before found.
|
||||||
|
int ReverseSubseqMatch(std::string_view pat,
|
||||||
|
std::string_view text,
|
||||||
|
int case_sensitivity) {
|
||||||
|
if (case_sensitivity == 1)
|
||||||
|
case_sensitivity = std::any_of(pat.begin(), pat.end(), isupper) ? 2 : 0;
|
||||||
|
int j = pat.size();
|
||||||
|
if (!j)
|
||||||
|
return text.size();
|
||||||
|
for (int i = text.size(); i--;)
|
||||||
|
if ((case_sensitivity ? text[i] == pat[j - 1]
|
||||||
|
: tolower(text[i]) == tolower(pat[j - 1])) &&
|
||||||
|
!--j)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetDefaultResourceDirectory() {
|
std::string GetDefaultResourceDirectory() {
|
||||||
return DEFAULT_RESOURCE_DIRECTORY;
|
return DEFAULT_RESOURCE_DIRECTORY;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,10 @@ std::optional<std::string> ReadContent(const std::string& filename);
|
|||||||
void WriteToFile(const std::string& filename, const std::string& content);
|
void WriteToFile(const std::string& filename, const std::string& content);
|
||||||
std::optional<int64_t> LastWriteTime(const std::string& filename);
|
std::optional<int64_t> LastWriteTime(const std::string& filename);
|
||||||
|
|
||||||
|
int ReverseSubseqMatch(std::string_view pat,
|
||||||
|
std::string_view text,
|
||||||
|
int case_sensitivity);
|
||||||
|
|
||||||
// http://stackoverflow.com/a/38140932
|
// http://stackoverflow.com/a/38140932
|
||||||
//
|
//
|
||||||
// struct SomeHashKey {
|
// struct SomeHashKey {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "working_files.h"
|
#include "working_files.h"
|
||||||
|
|
||||||
#include "lex_utils.h"
|
|
||||||
#include "log.hh"
|
#include "log.hh"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
|
||||||
@ -545,3 +544,46 @@ WorkingFiles::Snapshot WorkingFiles::AsSnapshot(
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VSCode (UTF-16) disagrees with Emacs lsp-mode (UTF-8) on how to represent
|
||||||
|
// text documents.
|
||||||
|
// We use a UTF-8 iterator to approximate UTF-16 in the specification (weird).
|
||||||
|
// This is good enough and fails only for UTF-16 surrogate pairs.
|
||||||
|
int GetOffsetForPosition(lsPosition position, std::string_view content) {
|
||||||
|
size_t i = 0;
|
||||||
|
for (; position.line > 0 && i < content.size(); i++)
|
||||||
|
if (content[i] == '\n')
|
||||||
|
position.line--;
|
||||||
|
for (; position.character > 0 && i < content.size(); position.character--)
|
||||||
|
if (uint8_t(content[i++]) >= 128) {
|
||||||
|
// Skip 0b10xxxxxx
|
||||||
|
while (i < content.size() && uint8_t(content[i]) >= 128 &&
|
||||||
|
uint8_t(content[i]) < 192)
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return int(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view LexIdentifierAroundPos(lsPosition position,
|
||||||
|
std::string_view content) {
|
||||||
|
int start = GetOffsetForPosition(position, content);
|
||||||
|
int end = start + 1;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
// We search for :: before the cursor but not after to get the qualifier.
|
||||||
|
for (; start > 0; start--) {
|
||||||
|
c = content[start - 1];
|
||||||
|
if (isalnum(c) || c == '_')
|
||||||
|
;
|
||||||
|
else if (c == ':' && start > 1 && content[start - 2] == ':')
|
||||||
|
start--;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; end < (int)content.size(); end++)
|
||||||
|
if (c = content[end], !(isalnum(c) || c == '_'))
|
||||||
|
break;
|
||||||
|
|
||||||
|
return content.substr(start, end - start);
|
||||||
|
}
|
||||||
|
@ -117,3 +117,8 @@ struct WorkingFiles {
|
|||||||
std::vector<std::unique_ptr<WorkingFile>> files;
|
std::vector<std::unique_ptr<WorkingFile>> files;
|
||||||
std::mutex files_mutex; // Protects |files|.
|
std::mutex files_mutex; // Protects |files|.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int GetOffsetForPosition(lsPosition position, std::string_view content);
|
||||||
|
|
||||||
|
std::string_view LexIdentifierAroundPos(lsPosition position,
|
||||||
|
std::string_view content);
|
||||||
|
Loading…
Reference in New Issue
Block a user