Cache global completion results.

This commit is contained in:
Jacob Dufault 2017-05-26 00:10:55 -07:00
parent cdc268d549
commit 7840b7a015
4 changed files with 62 additions and 18 deletions

View File

@ -297,7 +297,6 @@ void CompletionQueryMain(CompletionManager* completion_manager) {
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;
std::cerr << std::endl;
std::cerr << "[complete] Completing at " << line << ":" << column << std::endl; std::cerr << "[complete] Completing at " << line << ":" << column << std::endl;
Timer timer; Timer timer;

View File

@ -1527,7 +1527,8 @@ bool QueryDbMainLoop(
WorkingFiles* working_files, WorkingFiles* working_files,
CompletionManager* completion_manager, CompletionManager* completion_manager,
IncludeCompletion* include_completion, IncludeCompletion* include_completion,
CodeCompleteCache* code_complete_cache, CodeCompleteCache* global_code_complete_cache,
CodeCompleteCache* non_global_code_complete_cache,
CodeCompleteCache* signature_cache) { CodeCompleteCache* signature_cache) {
IpcManager* ipc = IpcManager::instance(); IpcManager* ipc = IpcManager::instance();
@ -1967,7 +1968,8 @@ bool QueryDbMainLoop(
auto msg = static_cast<Ipc_TextDocumentComplete*>(message.get()); auto msg = static_cast<Ipc_TextDocumentComplete*>(message.get());
lsTextDocumentPositionParams& params = msg->params; lsTextDocumentPositionParams& params = msg->params;
WorkingFile* file = working_files->GetFileByFilename(params.textDocument.uri.GetPath()); std::string path = params.textDocument.uri.GetPath();
WorkingFile* file = working_files->GetFileByFilename(path);
// TODO: We should scan include directories to add any missing paths // TODO: We should scan include directories to add any missing paths
@ -2001,10 +2003,11 @@ bool QueryDbMainLoop(
ipc->SendOutMessageToClient(IpcId::TextDocumentCompletion, complete_response); ipc->SendOutMessageToClient(IpcId::TextDocumentCompletion, complete_response);
} }
else { else {
bool is_global_completion = false;
if (file) if (file)
params.position = file->FindStableCompletionSource(params.position); params.position = file->FindStableCompletionSource(params.position, &is_global_completion);
CompletionManager::OnComplete callback = std::bind([working_files, code_complete_cache](BaseIpcMessage* message, NonElidedVector<lsCompletionItem> results, NonElidedVector<lsDiagnostic> diagnostics) { CompletionManager::OnComplete callback = std::bind([working_files, global_code_complete_cache, non_global_code_complete_cache, is_global_completion](BaseIpcMessage* message, NonElidedVector<lsCompletionItem> results, NonElidedVector<lsDiagnostic> diagnostics) {
auto msg = static_cast<Ipc_TextDocumentComplete*>(message); auto msg = static_cast<Ipc_TextDocumentComplete*>(message);
auto ipc = IpcManager::instance(); auto ipc = IpcManager::instance();
@ -2022,23 +2025,46 @@ bool QueryDbMainLoop(
diagnostic_response.params.diagnostics = diagnostics; diagnostic_response.params.diagnostics = diagnostics;
ipc->SendOutMessageToClient(IpcId::TextDocumentPublishDiagnostics, diagnostic_response); ipc->SendOutMessageToClient(IpcId::TextDocumentPublishDiagnostics, diagnostic_response);
std::string path = msg->params.textDocument.uri.GetPath();
// Cache diagnostics so we can show fixits. // Cache diagnostics so we can show fixits.
WorkingFile* working_file = working_files->GetFileByFilename(msg->params.textDocument.uri.GetPath()); WorkingFile* working_file = working_files->GetFileByFilename(path);
if (working_file) if (working_file)
working_file->diagnostics = diagnostics; working_file->diagnostics = diagnostics;
// Cache completion results so if the user types backspace we can respond faster. // Cache completion results.
code_complete_cache->cached_path = msg->params.textDocument.uri.GetPath(); if (is_global_completion) {
code_complete_cache->cached_completion_position = msg->params.position; global_code_complete_cache->cached_path = path;
code_complete_cache->cached_results = results; global_code_complete_cache->cached_results = results;
code_complete_cache->cached_diagnostics = diagnostics; global_code_complete_cache->cached_diagnostics = diagnostics;
}
else {
non_global_code_complete_cache->cached_path = path;
non_global_code_complete_cache->cached_completion_position = msg->params.position;
non_global_code_complete_cache->cached_results = results;
non_global_code_complete_cache->cached_diagnostics = diagnostics;
}
delete message; delete message;
}, message.release(), std::placeholders::_1, std::placeholders::_2); }, message.release(), std::placeholders::_1, std::placeholders::_2);
if (code_complete_cache->IsCacheValid(params)) { if (is_global_completion && global_code_complete_cache->cached_path == path && !global_code_complete_cache->cached_results.empty()) {
std::cerr << "[complete] Early-returning cached global completion results at " << params.position.ToString() << std::endl;
CompletionManager::OnComplete update_global = std::bind([global_code_complete_cache](NonElidedVector<lsCompletionItem> results, NonElidedVector<lsDiagnostic> diagnostics) {
std::cerr << "[complete] Updated global completion cache" << std::endl;
// note: path is updated in the normal completion handler.
global_code_complete_cache->cached_results = results;
global_code_complete_cache->cached_diagnostics = diagnostics;
}, std::placeholders::_1, std::placeholders::_2);
completion_manager->CodeComplete(params, std::move(update_global));
// Note: callback will delete the message (ie, |params|) so we need to run completion_manager->CodeComplete before |callback|.
callback(global_code_complete_cache->cached_results, global_code_complete_cache->cached_diagnostics);
}
else if (non_global_code_complete_cache->IsCacheValid(params)) {
std::cerr << "[complete] Using cached completion results at " << params.position.ToString() << std::endl; std::cerr << "[complete] Using cached completion results at " << params.position.ToString() << std::endl;
callback(code_complete_cache->cached_results, code_complete_cache->cached_diagnostics); callback(non_global_code_complete_cache->cached_results, non_global_code_complete_cache->cached_diagnostics);
} }
else { else {
completion_manager->CodeComplete(params, std::move(callback)); completion_manager->CodeComplete(params, std::move(callback));
@ -2645,7 +2671,8 @@ void QueryDbMain(Config* config, MultiQueueWaiter* waiter) {
WorkingFiles working_files; WorkingFiles working_files;
CompletionManager completion_manager(config, &project, &working_files); CompletionManager completion_manager(config, &project, &working_files);
IncludeCompletion include_completion(config, &project); IncludeCompletion include_completion(config, &project);
CodeCompleteCache code_complete_cache; CodeCompleteCache global_code_complete_cache;
CodeCompleteCache non_global_code_complete_cache;
CodeCompleteCache signature_cache; CodeCompleteCache signature_cache;
FileConsumer::SharedState file_consumer_shared; FileConsumer::SharedState file_consumer_shared;
@ -2656,7 +2683,7 @@ void QueryDbMain(Config* config, MultiQueueWaiter* waiter) {
bool did_work = QueryDbMainLoop( bool did_work = QueryDbMainLoop(
config, &db, waiter, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed, config, &db, waiter, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed,
&project, &file_consumer_shared, &working_files, &project, &file_consumer_shared, &working_files,
&completion_manager, &include_completion, &code_complete_cache, &signature_cache); &completion_manager, &include_completion, &global_code_complete_cache, &non_global_code_complete_cache, &signature_cache);
if (!did_work) { if (!did_work) {
IpcManager* ipc = IpcManager::instance(); IpcManager* ipc = IpcManager::instance();
waiter->Wait({ waiter->Wait({

View File

@ -226,13 +226,28 @@ std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* a
// Returns a position which contains the most recent ., ->, :, or ( for code // Returns a position which contains the most recent ., ->, :, or ( for code
// completion purposes. // completion purposes.
lsPosition WorkingFile::FindStableCompletionSource(lsPosition position) const { lsPosition WorkingFile::FindStableCompletionSource(lsPosition position, bool* is_global_completion) const {
*is_global_completion = true;
int offset = GetOffsetForPosition(position, buffer_content); int offset = GetOffsetForPosition(position, buffer_content);
while (offset > 0) { while (offset > 0) {
char c = buffer_content[offset - 1]; char c = buffer_content[offset - 1];
if (!isalnum(c)) if (!isalnum(c)) {
// Global completion is everything except for dot (.), arrow (->), and
// double colon (::)
if (c == '.')
*is_global_completion = false;
if (offset > 2) {
char pc = buffer_content[offset - 2];
if (pc == ':' && c == ':')
*is_global_completion = false;
else if (pc == '-' && c == '>')
*is_global_completion = false;
}
break; break;
}
--offset; --offset;
} }

View File

@ -55,7 +55,10 @@ struct WorkingFile {
// Returns a relatively stable completion position (it jumps back until there // Returns a relatively stable completion position (it jumps back until there
// is a non-alphanumeric character). // is a non-alphanumeric character).
lsPosition FindStableCompletionSource(lsPosition position) const; //
// The out param |is_global_completion| is set to true if this looks like a
// global completion.
lsPosition FindStableCompletionSource(lsPosition position, bool* is_global_completion) const;
CXUnsavedFile AsUnsavedFile() const; CXUnsavedFile AsUnsavedFile() const;
}; };