Remove WithFileContent & lex_utils.{cc,h}

This commit is contained in:
Fangrui Song 2018-05-31 20:06:09 -07:00
parent da545f1139
commit 34dc1e93e9
19 changed files with 100 additions and 254 deletions

View File

@ -202,7 +202,6 @@ target_sources(ccls PRIVATE
src/indexer.cc
src/method.cc
src/language.cc
src/lex_utils.cc
src/log.cc
src/lsp.cc
src/match.cc

View File

@ -3,9 +3,11 @@
#include "log.hh"
#include "platform.h"
#include "serializer.h"
#include "timer.h"
#include "type_printer.h"
#include <llvm/Support/Timer.h>
using namespace llvm;
#include <assert.h>
#include <inttypes.h>
#include <limits.h>
@ -2016,7 +2018,8 @@ std::vector<std::unique_ptr<IndexFile>> ClangIndexer::Index(
file = NormalizePath(file);
Timer timer;
Timer timer("parse", "parse tu");
timer.startTimer();
std::vector<CXUnsavedFile> unsaved_files;
for (const FileContents& contents : file_contents) {
@ -2034,7 +2037,7 @@ std::vector<std::unique_ptr<IndexFile>> ClangIndexer::Index(
if (!tu)
return {};
perf->index_parse = timer.ElapsedMicrosecondsAndReset();
timer.stopTimer();
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<CXUnsavedFile>& file_contents) {
Timer timer;
timer.startTimer();
IndexerCallbacks callback = {0};
// Available callbacks:
@ -2085,13 +2089,12 @@ std::vector<std::unique_ptr<IndexFile>> ParseWithTu(
<< " failed with errno=" << index_result;
return {};
}
clang_IndexAction_dispose(index_action);
ClangCursor(clang_getTranslationUnitCursor(tu->cx_tu))
.VisitChildren(&VisitMacroDefinitionAndExpansions, &param);
perf->index_build = timer.ElapsedMicrosecondsAndReset();
timer.stopTimer();
std::unordered_map<std::string, int> inc_to_line;
// TODO

View File

@ -27,8 +27,6 @@ struct IndexFunc;
struct IndexVar;
struct QueryFile;
using RawId = uint32_t;
struct SymbolIdx {
Usr usr;
SymbolKind kind;
@ -153,19 +151,9 @@ struct TypeDef : NameMixin<TypeDef> {
NtString hover;
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> extent;
// Immediate parent types.
std::vector<Usr> bases;
// Types, functions, and variables defined in this type.
@ -221,8 +209,6 @@ struct VarDef : NameMixin<VarDef> {
std::string detailed_name;
NtString hover;
NtString comments;
// TODO: definitions should be a list of ranges, since there can be more
// than one - when??
Maybe<Use> spell;
Maybe<Use> extent;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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.
pipeline::LaunchStdin(&request_times);
pipeline::LaunchStdin();
// 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.
pipeline::MainLoop();
}

View File

@ -1,6 +1,5 @@
#include "message_handler.h"
#include "lex_utils.h"
#include "log.hh"
#include "project.h"
#include "query_utils.h"

View File

@ -7,8 +7,6 @@
#include "working_files.h"
using namespace ccls;
#include "lex_utils.h"
#include <regex>
namespace {

View File

@ -1,4 +1,3 @@
#include "lex_utils.h"
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"

View File

@ -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

View File

@ -1,5 +1,4 @@
#include "fuzzy_match.h"
#include "lex_utils.h"
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"

View File

@ -11,10 +11,10 @@
#include "project.h"
#include "query_utils.h"
#include "pipeline.hh"
#include "timer.h"
#include <llvm/ADT/Twine.h>
#include <llvm/Support/Threading.h>
#include <llvm/Support/Timer.h>
using namespace llvm;
#include <thread>
@ -237,14 +237,15 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
// Write current index to disk if requested.
LOG_S(INFO) << "store index for " << path;
Timer time;
{
Timer timer("write", "store index");
timer.startTimer();
std::string cache_path = GetCachePath(path);
WriteToFile(cache_path, curr->file_contents);
WriteToFile(AppendSerializationFormat(cache_path),
Serialize(g_config->cacheFormat, *curr));
timer.stopTimer();
}
perf.index_save_to_disk = time.ElapsedMicrosecondsAndReset();
vfs->Reset(path_to_index);
if (entry.id >= 0) {
@ -255,7 +256,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
// Build delta update.
IndexUpdate update = IndexUpdate::CreateDelta(prev.get(), curr.get());
perf.index_make_delta = time.ElapsedMicrosecondsAndReset();
LOG_S(INFO) << "built index for " << path << " (is_delta=" << !!prev << ")";
on_indexed->PushBack({std::move(update), perf}, request.is_interactive);
@ -264,15 +264,6 @@ bool Indexer_Parse(DiagnosticsEngine* diag_engine,
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
void Init() {
@ -316,20 +307,22 @@ void Main_OnIndexed(DB* db,
return;
}
Timer time;
Timer timer("apply", "apply index");
timer.startTimer();
db->ApplyIndexUpdate(&response->update);
timer.stopTimer();
// Update indexed content, inactive lines, and semantic highlighting.
if (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 =
working_files->GetFileByFilename(update.value.path)) {
working_files->GetFileByFilename(update.first.path)) {
// Update indexed content.
working_file->SetIndexContent(update.file_content);
working_file->SetIndexContent(update.second);
// Inactive lines.
EmitInactiveLines(working_file, update.value.inactive_regions);
EmitInactiveLines(working_file, update.first.inactive_regions);
// Semantic highlighting.
int file_id =
@ -340,8 +333,8 @@ void Main_OnIndexed(DB* db,
}
}
void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
std::thread([request_times]() {
void LaunchStdin() {
std::thread([]() {
set_thread_name("stdin");
while (true) {
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|.
MethodType method_type = message->GetMethodType();
(*request_times)[method_type] = Timer();
on_request->PushBack(std::move(message));
@ -379,7 +371,7 @@ void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times) {
}).detach();
}
void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times) {
void LaunchStdout() {
std::thread([=]() {
set_thread_name("stdout");
@ -391,11 +383,6 @@ void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times) {
}
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);
fflush(stdout);
}

View File

@ -2,7 +2,6 @@
#include "method.h"
#include "query.h"
#include "timer.h"
#include <string>
#include <unordered_map>
@ -17,8 +16,8 @@ struct lsBaseOutMessage;
namespace ccls::pipeline {
void Init();
void LaunchStdin(std::unordered_map<MethodType, Timer>* request_times);
void LaunchStdout(std::unordered_map<MethodType, Timer>* request_times);
void LaunchStdin();
void LaunchStdout();
void Indexer_Main(DiagnosticsEngine* diag_engine,
VFS* vfs,
Project* project,

View File

@ -148,7 +148,7 @@ QueryFile::DefUpdate BuildFileDefUpdate(const IndexFile& indexed) {
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.
@ -342,11 +342,11 @@ void DB::ApplyIndexUpdate(IndexUpdate* u) {
int DB::Update(QueryFile::DefUpdate&& u) {
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)
files.emplace_back().id = id;
QueryFile& existing = files[it.first->second];
existing.def = u.value;
existing.def = u.first;
return existing.id;
}

View File

@ -7,21 +7,6 @@
#include <llvm/ADT/SmallVector.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 Def {
std::string path;
@ -39,7 +24,7 @@ struct QueryFile {
std::vector<std::string> dependencies;
};
using DefUpdate = WithFileContent<Def>;
using DefUpdate = std::pair<Def, std::string>;
int id = -1;
std::optional<Def> def;

View File

@ -134,6 +134,24 @@ std::optional<int64_t> LastWriteTime(const std::string& filename) {
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() {
return DEFAULT_RESOURCE_DIRECTORY;
}

View File

@ -58,6 +58,10 @@ std::optional<std::string> ReadContent(const std::string& filename);
void WriteToFile(const std::string& filename, const std::string& content);
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
//
// struct SomeHashKey {

View File

@ -1,6 +1,5 @@
#include "working_files.h"
#include "lex_utils.h"
#include "log.hh"
#include "position.h"
@ -545,3 +544,46 @@ WorkingFiles::Snapshot WorkingFiles::AsSnapshot(
}
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);
}

View File

@ -117,3 +117,8 @@ struct WorkingFiles {
std::vector<std::unique_ptr<WorkingFile>> 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);