mirror of
https://github.com/MaskRay/ccls.git
synced 2025-03-31 05:52:09 +00:00
Preload code completion, maintain LRU cache for multiple completion files.
This commit is contained in:
parent
2e3e1e0427
commit
cdc268d549
@ -238,9 +238,9 @@ void BuildDetailString(CXCompletionString completion_string, std::string& label,
|
|||||||
|
|
||||||
void EnsureDocumentParsed(CompletionSession* session,
|
void EnsureDocumentParsed(CompletionSession* session,
|
||||||
std::unique_ptr<clang::TranslationUnit>* tu,
|
std::unique_ptr<clang::TranslationUnit>* tu,
|
||||||
std::unique_ptr<clang::Index>* index) {
|
clang::Index* index) {
|
||||||
// Nothing to do. We already have a translation unit and an index.
|
// Nothing to do. We already have a translation unit.
|
||||||
if (*tu && *index)
|
if (*tu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<std::string> args = session->file.args;
|
std::vector<std::string> args = session->file.args;
|
||||||
@ -249,40 +249,51 @@ void EnsureDocumentParsed(CompletionSession* session,
|
|||||||
std::vector<CXUnsavedFile> unsaved = session->working_files->AsUnsavedFiles();
|
std::vector<CXUnsavedFile> unsaved = session->working_files->AsUnsavedFiles();
|
||||||
|
|
||||||
std::cerr << "[complete] Creating completion session with arguments " << StringJoin(args) << std::endl;
|
std::cerr << "[complete] Creating completion session with arguments " << StringJoin(args) << std::endl;
|
||||||
*index = MakeUnique<clang::Index>(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/);
|
*tu = MakeUnique<clang::TranslationUnit>(index, session->file.filename, args, unsaved, Flags());
|
||||||
*tu = MakeUnique<clang::TranslationUnit>(index->get(), session->file.filename, args, unsaved, Flags());
|
|
||||||
std::cerr << "[complete] Done creating active; did_fail=" << (*tu)->did_fail << std::endl;
|
std::cerr << "[complete] Done creating active; did_fail=" << (*tu)->did_fail << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionParseMain(CompletionManager* completion_manager) {
|
void CompletionParseMain(CompletionManager* completion_manager) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Fetching the completion request blocks until we have a request.
|
// Fetching the completion request blocks until we have a request.
|
||||||
std::unique_ptr<std::string> path = completion_manager->reparse_request.Take();
|
CompletionManager::ParseRequest request = completion_manager->parse_requests_.Dequeue();
|
||||||
|
|
||||||
CompletionSession* session = completion_manager->GetOrOpenSession(*path);
|
// If we don't get a session then that means we don't care about the file
|
||||||
|
// anymore - abandon the request.
|
||||||
|
CompletionSession* session = completion_manager->TryGetSession(request.path, false /*create_if_needed*/);
|
||||||
|
if (!session)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If we've parsed it more recently than the request time, don't bother
|
||||||
|
// reparsing.
|
||||||
|
if (session->tu_last_parsed_at &&
|
||||||
|
*session->tu_last_parsed_at > request.request_time) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<clang::TranslationUnit> parsing;
|
std::unique_ptr<clang::TranslationUnit> parsing;
|
||||||
std::unique_ptr<clang::Index> parsing_index;
|
EnsureDocumentParsed(session, &parsing, &session->index);
|
||||||
|
|
||||||
EnsureDocumentParsed(session, &parsing, &parsing_index);
|
// Activate new translation unit.
|
||||||
|
// tu_last_parsed_at is only read by this thread, so it doesn't need to be under the mutex.
|
||||||
// Swap out active.
|
session->tu_last_parsed_at = std::chrono::high_resolution_clock::now();
|
||||||
std::lock_guard<std::mutex> lock(session->usage_lock);
|
std::lock_guard<std::mutex> lock(session->tu_lock);
|
||||||
session->active = std::move(parsing);
|
session->tu = std::move(parsing);
|
||||||
session->active_index = std::move(parsing_index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionQueryMain(CompletionManager* completion_manager) {
|
void CompletionQueryMain(CompletionManager* completion_manager) {
|
||||||
while (true) {
|
while (true) {
|
||||||
// Fetching the completion request blocks until we have a request.
|
// Fetching the completion request blocks until we have a request.
|
||||||
std::unique_ptr<CompletionManager::CompletionRequest> request = completion_manager->completion_request.Take();
|
std::unique_ptr<CompletionManager::CompletionRequest> request = completion_manager->completion_request_.Take();
|
||||||
|
std::string path = request->location.textDocument.uri.GetPath();
|
||||||
|
|
||||||
|
CompletionSession* session = completion_manager->TryGetSession(path, true /*create_if_needed*/);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(session->tu_lock);
|
||||||
|
EnsureDocumentParsed(session, &session->tu, &session->index);
|
||||||
|
|
||||||
CompletionSession* session = completion_manager->GetOrOpenSession(request->location.textDocument.uri.GetPath());
|
// Language server is 0-based, clang is 1-based.
|
||||||
std::lock_guard<std::mutex> lock(session->usage_lock);
|
|
||||||
|
|
||||||
EnsureDocumentParsed(session, &session->active, &session->active_index);
|
|
||||||
|
|
||||||
unsigned line = request->location.position.line + 1;
|
unsigned line = request->location.position.line + 1;
|
||||||
unsigned column = request->location.position.character + 1;
|
unsigned column = request->location.position.character + 1;
|
||||||
|
|
||||||
@ -291,18 +302,18 @@ void CompletionQueryMain(CompletionManager* completion_manager) {
|
|||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
|
|
||||||
std::vector<CXUnsavedFile> unsaved = completion_manager->working_files->AsUnsavedFiles();
|
std::vector<CXUnsavedFile> unsaved = completion_manager->working_files_->AsUnsavedFiles();
|
||||||
timer.ResetAndPrint("[complete] Fetching unsaved files");
|
timer.ResetAndPrint("[complete] Fetching unsaved files");
|
||||||
|
|
||||||
timer.Reset();
|
timer.Reset();
|
||||||
unsigned const kCompleteOptions = CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments;
|
unsigned const kCompleteOptions = CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments;
|
||||||
CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
|
CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
|
||||||
session->active->cx_tu,
|
session->tu->cx_tu,
|
||||||
session->file.filename.c_str(), line, column,
|
session->file.filename.c_str(), line, column,
|
||||||
unsaved.data(), (unsigned)unsaved.size(),
|
unsaved.data(), (unsigned)unsaved.size(),
|
||||||
kCompleteOptions);
|
kCompleteOptions);
|
||||||
if (!cx_results) {
|
if (!cx_results) {
|
||||||
std::cerr << "[complete] Code completion failed" << std::endl;
|
timer.ResetAndPrint("[complete] Code completion failed");
|
||||||
request->on_complete({}, {});
|
request->on_complete({}, {});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -355,6 +366,7 @@ void CompletionQueryMain(CompletionManager* completion_manager) {
|
|||||||
}
|
}
|
||||||
timer.ResetAndPrint("[complete] Build diagnostics");
|
timer.ResetAndPrint("[complete] Build diagnostics");
|
||||||
|
|
||||||
|
|
||||||
clang_disposeCodeCompleteResults(cx_results);
|
clang_disposeCodeCompleteResults(cx_results);
|
||||||
timer.ResetAndPrint("[complete] clang_disposeCodeCompleteResults");
|
timer.ResetAndPrint("[complete] clang_disposeCodeCompleteResults");
|
||||||
|
|
||||||
@ -367,12 +379,32 @@ void CompletionQueryMain(CompletionManager* completion_manager) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CompletionSession::CompletionSession(const Project::Entry& file, WorkingFiles* working_files)
|
CompletionSession::CompletionSession(const Project::Entry& file, WorkingFiles* working_files)
|
||||||
: file(file), working_files(working_files) {}
|
: file(file), working_files(working_files), index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/) {}
|
||||||
|
|
||||||
CompletionSession::~CompletionSession() {}
|
CompletionSession::~CompletionSession() {}
|
||||||
|
|
||||||
|
LruSessionCache::LruSessionCache(int max_entries) : max_entries_(max_entries) {}
|
||||||
|
|
||||||
|
CompletionSession* LruSessionCache::TryGetEntry(const std::string& filename) {
|
||||||
|
for (int i = 0; i < entries_.size(); ++i) {
|
||||||
|
if (entries_[i]->file.filename == filename)
|
||||||
|
return entries_[i].get();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LruSessionCache::InsertEntry(std::unique_ptr<CompletionSession> session) {
|
||||||
|
if (entries_.size() >= max_entries_)
|
||||||
|
entries_.pop_back();
|
||||||
|
entries_.insert(entries_.begin(), std::move(session));
|
||||||
|
}
|
||||||
|
|
||||||
|
CompletionManager::ParseRequest::ParseRequest(const std::string& path)
|
||||||
|
: path(path), request_time(std::chrono::high_resolution_clock::now()) {}
|
||||||
|
|
||||||
CompletionManager::CompletionManager(Config* config, Project* project, WorkingFiles* working_files)
|
CompletionManager::CompletionManager(Config* config, Project* project, WorkingFiles* working_files)
|
||||||
: config(config), project(project), working_files(working_files) {
|
: config_(config), project_(project), working_files_(working_files),
|
||||||
|
view_sessions_(kMaxViewSessions), edit_sessions_(kMaxEditSessions) {
|
||||||
new std::thread([&]() {
|
new std::thread([&]() {
|
||||||
SetCurrentThreadName("completequery");
|
SetCurrentThreadName("completequery");
|
||||||
CompletionQueryMain(this);
|
CompletionQueryMain(this);
|
||||||
@ -385,47 +417,81 @@ CompletionManager::CompletionManager(Config* config, Project* project, WorkingFi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CompletionManager::CodeComplete(const lsTextDocumentPositionParams& completion_location, const OnComplete& on_complete) {
|
void CompletionManager::CodeComplete(const lsTextDocumentPositionParams& completion_location, const OnComplete& on_complete) {
|
||||||
|
// completion thread will create the CompletionSession if needed.
|
||||||
|
|
||||||
auto request = MakeUnique<CompletionRequest>();
|
auto request = MakeUnique<CompletionRequest>();
|
||||||
request->location = completion_location;
|
request->location = completion_location;
|
||||||
request->on_complete = on_complete;
|
request->on_complete = on_complete;
|
||||||
completion_request.Set(std::move(request));
|
completion_request_.Set(std::move(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
CompletionSession* CompletionManager::GetOrOpenSession(const std::string& filename) {
|
void CompletionManager::NotifyView(const std::string& filename) {
|
||||||
// Try to find existing session.
|
//
|
||||||
for (auto& session : sessions) {
|
// On view, we reparse only if the file has not been parsed. The existence of
|
||||||
if (session->file.filename == filename)
|
// a CompletionSession instance implies the file is already parsed or will be
|
||||||
return session.get();
|
// parsed soon.
|
||||||
}
|
//
|
||||||
|
|
||||||
// Create new session. Note that this will block.
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
std::cerr << "[complete] Creating new code completion session for " << filename << std::endl;
|
|
||||||
optional<Project::Entry> entry = project->FindCompilationEntryForFile(filename);
|
if (view_sessions_.TryGetEntry(filename))
|
||||||
if (!entry) {
|
return;
|
||||||
std::cerr << "[complete] Unable to find compilation entry" << std::endl;
|
|
||||||
entry = Project::Entry();
|
std::cerr << "[complete] Creating new edit code completion session for " << filename << std::endl;
|
||||||
entry->filename = filename;
|
view_sessions_.InsertEntry(MakeUnique<CompletionSession>(
|
||||||
}
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
else {
|
parse_requests_.Enqueue(ParseRequest(filename));
|
||||||
std::cerr << "[complete] Found compilation entry" << std::endl;
|
|
||||||
}
|
|
||||||
sessions.push_back(MakeUnique<CompletionSession>(*entry, working_files));
|
|
||||||
return sessions[sessions.size() - 1].get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompletionManager::UpdateActiveSession(const std::string& filename) {
|
void CompletionManager::NotifyEdit(const std::string& filename) {
|
||||||
// Drop all sessions except for |filename|.
|
//
|
||||||
for (auto& session : sessions) {
|
// On edit, we reparse only if the file has not been parsed. The existence of
|
||||||
if (session->file.filename == filename)
|
// a CompletionSession instance implies the file is already parsed or will be
|
||||||
continue;
|
// parsed soon.
|
||||||
|
//
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(session->usage_lock);
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
session->active.reset();
|
|
||||||
session->active_index.reset();
|
if (edit_sessions_.TryGetEntry(filename))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::cerr << "[complete] Creating new edit code completion session for " << filename << std::endl;
|
||||||
|
edit_sessions_.InsertEntry(MakeUnique<CompletionSession>(
|
||||||
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
|
parse_requests_.PriorityEnqueue(ParseRequest(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompletionManager::NotifySave(const std::string& filename) {
|
||||||
|
//
|
||||||
|
// On save, always reparse.
|
||||||
|
//
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
|
|
||||||
|
if (!edit_sessions_.TryGetEntry(filename)) {
|
||||||
|
std::cerr << "[complete] Creating new edit code completion session for " << filename << std::endl;
|
||||||
|
edit_sessions_.InsertEntry(MakeUnique<CompletionSession>(
|
||||||
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reparse |filename|.
|
parse_requests_.PriorityEnqueue(ParseRequest(filename));
|
||||||
// TODO: Instead of actually reparsing it, see if we can hook into the
|
}
|
||||||
// indexer and steal the translation unit from there..
|
|
||||||
reparse_request.Set(MakeUnique<std::string>(filename));
|
CompletionSession* CompletionManager::TryGetSession(const std::string& filename, bool create_if_needed) {
|
||||||
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
|
|
||||||
|
CompletionSession* session = edit_sessions_.TryGetEntry(filename);
|
||||||
|
|
||||||
|
if (!session)
|
||||||
|
session = view_sessions_.TryGetEntry(filename);
|
||||||
|
|
||||||
|
if (!session && create_if_needed) {
|
||||||
|
// Create new session. Default to edited_sessions_ since invoking code
|
||||||
|
// completion almost certainly implies an edit.
|
||||||
|
edit_sessions_.InsertEntry(MakeUnique<CompletionSession>(
|
||||||
|
project_->FindCompilationEntryForFile(filename), working_files_));
|
||||||
|
session = edit_sessions_.TryGetEntry(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
}
|
}
|
@ -3,66 +3,101 @@
|
|||||||
#include "libclangmm/Index.h"
|
#include "libclangmm/Index.h"
|
||||||
#include "libclangmm/TranslationUnit.h"
|
#include "libclangmm/TranslationUnit.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
|
#include "threaded_queue.h"
|
||||||
#include "working_files.h"
|
#include "working_files.h"
|
||||||
|
|
||||||
#include <clang-c/Index.h>
|
#include <clang-c/Index.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
// TODO: rename this file to clang_completion.h/cc
|
// TODO: rename this file to clang_completion.h/cc
|
||||||
|
|
||||||
struct CompletionSession {
|
struct CompletionSession {
|
||||||
Project::Entry file;
|
Project::Entry file;
|
||||||
WorkingFiles* working_files;
|
WorkingFiles* working_files;
|
||||||
|
clang::Index index;
|
||||||
|
|
||||||
// Acquired when the session is being used.
|
// When |tu| was last parsed.
|
||||||
std::mutex usage_lock;
|
optional<std::chrono::time_point<std::chrono::high_resolution_clock>> tu_last_parsed_at;
|
||||||
|
|
||||||
|
// Acquired when |tu| is being used.
|
||||||
|
std::mutex tu_lock;
|
||||||
|
|
||||||
// The active translation unit.
|
// The active translation unit.
|
||||||
std::unique_ptr<clang::TranslationUnit> active;
|
std::unique_ptr<clang::TranslationUnit> tu;
|
||||||
std::unique_ptr<clang::Index> active_index;
|
|
||||||
|
|
||||||
// Updated translation unit. If |is_updated_ready| is true, then |updated|
|
|
||||||
// contains more recent state than |active| and the two should be swapped.
|
|
||||||
//
|
|
||||||
// TODO: implement this. Needs changes in Refresh and CodeComplete.
|
|
||||||
//bool is_updated_ready = false;
|
|
||||||
//std::unique_ptr<clang::TranslationUnit> updated;
|
|
||||||
//std::unique_ptr<clang::Index> updated_index;
|
|
||||||
|
|
||||||
CompletionSession(const Project::Entry& file, WorkingFiles* working_files);
|
CompletionSession(const Project::Entry& file, WorkingFiles* working_files);
|
||||||
~CompletionSession();
|
~CompletionSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CompletionManager {
|
struct LruSessionCache {
|
||||||
std::vector<std::unique_ptr<CompletionSession>> sessions;
|
std::vector<std::unique_ptr<CompletionSession>> entries_;
|
||||||
Config* config;
|
int max_entries_;
|
||||||
Project* project;
|
|
||||||
WorkingFiles* working_files;
|
|
||||||
|
|
||||||
|
LruSessionCache(int max_entries);
|
||||||
|
|
||||||
|
// Fetches the entry for |filename| and updates it's usage so it is less
|
||||||
|
// likely to be evicted.
|
||||||
|
CompletionSession* TryGetEntry(const std::string& filename);
|
||||||
|
// Inserts an entry. Evicts the oldest unused entry if there is no space.
|
||||||
|
void InsertEntry(std::unique_ptr<CompletionSession> session);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompletionManager {
|
||||||
using OnComplete = std::function<void(NonElidedVector<lsCompletionItem> results, NonElidedVector<lsDiagnostic> diagnostics)>;
|
using OnComplete = std::function<void(NonElidedVector<lsCompletionItem> results, NonElidedVector<lsDiagnostic> diagnostics)>;
|
||||||
|
|
||||||
|
struct ParseRequest {
|
||||||
|
ParseRequest(const std::string& path);
|
||||||
|
|
||||||
|
std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
|
||||||
|
std::string path;
|
||||||
|
};
|
||||||
struct CompletionRequest {
|
struct CompletionRequest {
|
||||||
lsTextDocumentPositionParams location;
|
lsTextDocumentPositionParams location;
|
||||||
OnComplete on_complete;
|
OnComplete on_complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
AtomicObject<CompletionRequest> completion_request;
|
|
||||||
|
|
||||||
// Request that the given path be reparsed.
|
|
||||||
AtomicObject<std::string> reparse_request;
|
|
||||||
|
|
||||||
CompletionManager(Config* config, Project* project, WorkingFiles* working_files);
|
CompletionManager(Config* config, Project* project, WorkingFiles* working_files);
|
||||||
|
|
||||||
// Start a code completion at the given location. |on_complete| will run when
|
// Start a code completion at the given location. |on_complete| will run when
|
||||||
// completion results are available. |on_complete| may run on any thread.
|
// completion results are available. |on_complete| may run on any thread.
|
||||||
void CodeComplete(const lsTextDocumentPositionParams& completion_location, const OnComplete& on_complete);
|
void CodeComplete(const lsTextDocumentPositionParams& completion_location,
|
||||||
|
const OnComplete& on_complete);
|
||||||
|
|
||||||
CompletionSession* GetOrOpenSession(const std::string& filename);
|
// Notify the completion manager that |filename| has been viewed and we
|
||||||
|
// should begin preloading completion data.
|
||||||
|
void NotifyView(const std::string& filename);
|
||||||
|
// Notify the completion manager that |filename| has been edited.
|
||||||
|
void NotifyEdit(const std::string& filename);
|
||||||
|
// Notify the completion manager that |filename| has been saved. This
|
||||||
|
// triggers a reparse.
|
||||||
|
void NotifySave(const std::string& filename);
|
||||||
|
|
||||||
// Set the new active session. We will drop clang state for all other
|
CompletionSession* TryGetSession(const std::string& filename, bool create_if_needed);
|
||||||
// sessions and begin reparsing the session for |filename| to ensure
|
|
||||||
// completions are always fast.
|
// TODO: make these configurable.
|
||||||
void UpdateActiveSession(const std::string& filename);
|
const int kMaxViewSessions = 3;
|
||||||
|
const int kMaxEditSessions = 10;
|
||||||
|
|
||||||
|
// Global state.
|
||||||
|
Config* config_;
|
||||||
|
Project* project_;
|
||||||
|
WorkingFiles* working_files_;
|
||||||
|
|
||||||
|
// Sessions which have never had a real text-edit applied, but are preloaded
|
||||||
|
// to give a fast initial experience.
|
||||||
|
LruSessionCache view_sessions_;
|
||||||
|
// Completion sessions which have been edited.
|
||||||
|
LruSessionCache edit_sessions_;
|
||||||
|
// Mutex which protects |view_sessions_| and |edit_sessions_|.
|
||||||
|
std::mutex sessions_lock_;
|
||||||
|
|
||||||
|
// Request a code completion at the given location.
|
||||||
|
AtomicObject<CompletionRequest> completion_request_;
|
||||||
|
// Parse requests. The path may already be parsed, in which case it should be
|
||||||
|
// reparsed.
|
||||||
|
ThreadedQueue<ParseRequest> parse_requests_;
|
||||||
};
|
};
|
@ -1869,27 +1869,31 @@ bool QueryDbMainLoop(
|
|||||||
|
|
||||||
Timer time;
|
Timer time;
|
||||||
auto msg = static_cast<Ipc_TextDocumentDidOpen*>(message.get());
|
auto msg = static_cast<Ipc_TextDocumentDidOpen*>(message.get());
|
||||||
|
std::string path = msg->params.textDocument.uri.GetPath();
|
||||||
WorkingFile* working_file = working_files->OnOpen(msg->params);
|
WorkingFile* working_file = working_files->OnOpen(msg->params);
|
||||||
optional<std::string> cached_file_contents = LoadCachedFileContents(config, msg->params.textDocument.uri.GetPath());
|
optional<std::string> cached_file_contents = LoadCachedFileContents(config, path);
|
||||||
if (cached_file_contents)
|
if (cached_file_contents)
|
||||||
working_file->SetIndexContent(*cached_file_contents);
|
working_file->SetIndexContent(*cached_file_contents);
|
||||||
else
|
else
|
||||||
working_file->SetIndexContent(working_file->buffer_content);
|
working_file->SetIndexContent(working_file->buffer_content);
|
||||||
|
|
||||||
std::unique_ptr<IndexFile> cache = LoadCachedIndex(config, msg->params.textDocument.uri.GetPath());
|
std::unique_ptr<IndexFile> cache = LoadCachedIndex(config, path);
|
||||||
if (cache && !cache->skipped_by_preprocessor.empty())
|
if (cache && !cache->skipped_by_preprocessor.empty())
|
||||||
PublishInactiveLines(working_file, cache->skipped_by_preprocessor);
|
PublishInactiveLines(working_file, cache->skipped_by_preprocessor);
|
||||||
|
|
||||||
time.ResetAndPrint("[querydb] Loading cached index file for DidOpen (blocks CodeLens)");
|
time.ResetAndPrint("[querydb] Loading cached index file for DidOpen (blocks CodeLens)");
|
||||||
|
|
||||||
include_completion->AddFile(working_file->filename);
|
include_completion->AddFile(working_file->filename);
|
||||||
|
completion_manager->NotifyView(path);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case IpcId::TextDocumentDidChange: {
|
case IpcId::TextDocumentDidChange: {
|
||||||
auto msg = static_cast<Ipc_TextDocumentDidChange*>(message.get());
|
auto msg = static_cast<Ipc_TextDocumentDidChange*>(message.get());
|
||||||
|
std::string path = msg->params.textDocument.uri.GetPath();
|
||||||
working_files->OnChange(msg->params);
|
working_files->OnChange(msg->params);
|
||||||
|
completion_manager->NotifyEdit(path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1927,7 +1931,8 @@ bool QueryDbMainLoop(
|
|||||||
|
|
||||||
queue_do_index->PriorityEnqueue(Index_DoIndex(index_type, project->FindCompilationEntryForFile(path), working_file->buffer_content, true /*is_interactive*/));
|
queue_do_index->PriorityEnqueue(Index_DoIndex(index_type, project->FindCompilationEntryForFile(path), working_file->buffer_content, true /*is_interactive*/));
|
||||||
}
|
}
|
||||||
completion_manager->UpdateActiveSession(path);
|
|
||||||
|
completion_manager->NotifySave(path);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2416,8 +2421,11 @@ bool QueryDbMainLoop(
|
|||||||
response.id = msg->id;
|
response.id = msg->id;
|
||||||
|
|
||||||
lsDocumentUri file_as_uri = msg->params.textDocument.uri;
|
lsDocumentUri file_as_uri = msg->params.textDocument.uri;
|
||||||
|
std::string path = file_as_uri.GetPath();
|
||||||
|
|
||||||
QueryFile* file = FindFile(db, file_as_uri.GetPath());
|
completion_manager->NotifyView(path);
|
||||||
|
|
||||||
|
QueryFile* file = FindFile(db, path);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
|
std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
|
||||||
break;
|
break;
|
||||||
|
@ -25,7 +25,9 @@ TranslationUnit::TranslationUnit(Index* index,
|
|||||||
|
|
||||||
//std::cerr << "Parsing " << filepath << " with args " << StringJoin(args) << std::endl;
|
//std::cerr << "Parsing " << filepath << " with args " << StringJoin(args) << std::endl;
|
||||||
|
|
||||||
//CXErrorCode error_code = clang_parseTranslationUnit2FullArgv(
|
//cx_tu = clang_createTranslationUnitFromSourceFile(
|
||||||
|
// index->cx_index, filepath.c_str(), args.size(), args.data(), (unsigned)unsaved_files.size(), unsaved_files.data());
|
||||||
|
|
||||||
CXErrorCode error_code = clang_parseTranslationUnit2(
|
CXErrorCode error_code = clang_parseTranslationUnit2(
|
||||||
index->cx_index, filepath.c_str(), args.data(), (int)args.size(),
|
index->cx_index, filepath.c_str(), args.data(), (int)args.size(),
|
||||||
unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
|
unsaved_files.data(), (unsigned)unsaved_files.size(), flags, &cx_tu);
|
||||||
|
@ -50,7 +50,12 @@ struct MultiQueueWaiter {
|
|||||||
template <class T>
|
template <class T>
|
||||||
struct ThreadedQueue : public BaseThreadQueue {
|
struct ThreadedQueue : public BaseThreadQueue {
|
||||||
public:
|
public:
|
||||||
ThreadedQueue(MultiQueueWaiter* waiter) : waiter_(waiter) {}
|
ThreadedQueue() {
|
||||||
|
owned_waiter_ = MakeUnique<MultiQueueWaiter>();
|
||||||
|
waiter_ = owned_waiter_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ThreadedQueue(MultiQueueWaiter* waiter) : waiter_(waiter) {}
|
||||||
|
|
||||||
// Add an element to the front of the queue.
|
// Add an element to the front of the queue.
|
||||||
void PriorityEnqueue(T&& t) {
|
void PriorityEnqueue(T&& t) {
|
||||||
@ -88,27 +93,23 @@ public:
|
|||||||
return priority_.empty() && queue_.empty();
|
return priority_.empty() && queue_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Get the first element from the queue. Blocks until one is available.
|
||||||
// Get the "front"-element.
|
|
||||||
// If the queue is empty, wait untill an element is avaiable.
|
|
||||||
T Dequeue() {
|
T Dequeue() {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
while (priority_.empty() && queue_.empty()) {
|
waiter_->cv.wait(lock, [&]() {
|
||||||
// release lock as long as the wait and reaquire it afterwards.
|
return !priority_.empty() || !queue_.empty();
|
||||||
cv_.wait(lock);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (!priority_.empty()) {
|
if (!priority_.empty()) {
|
||||||
auto val = std::move(priority_.front());
|
auto val = std::move(priority_.front());
|
||||||
priority_.pop();
|
priority_.pop();
|
||||||
return val;
|
return std::move(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto val = std::move(queue_.front());
|
auto val = std::move(queue_.front());
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
return val;
|
return std::move(val);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Get the first element from the queue without blocking. Returns a null
|
// Get the first element from the queue without blocking. Returns a null
|
||||||
// value if the queue is empty.
|
// value if the queue is empty.
|
||||||
@ -133,4 +134,5 @@ public:
|
|||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
std::queue<T> queue_;
|
std::queue<T> queue_;
|
||||||
MultiQueueWaiter* waiter_;
|
MultiQueueWaiter* waiter_;
|
||||||
|
std::unique_ptr<MultiQueueWaiter> owned_waiter_;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user