mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 15:45:08 +00:00
Refresh diagnostics 5 seconds after the last code completion.
This commit is contained in:
parent
00e452272f
commit
152e98363f
@ -14,6 +14,15 @@ struct AtomicObject {
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
void SetIfEmpty(std::unique_ptr<T> t) {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
if (value_)
|
||||
return;
|
||||
|
||||
value_ = std::move(t);
|
||||
cv_.notify_one();
|
||||
}
|
||||
|
||||
std::unique_ptr<T> Take() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (!value_) {
|
||||
|
@ -332,6 +332,48 @@ void CompletionParseMain(ClangCompleteManager* completion_manager) {
|
||||
}
|
||||
}
|
||||
|
||||
void CompletionDiagnosticsDelayedRefreshMain(ClangCompleteManager* completion_manager) {
|
||||
constexpr int kSecondsToWaitForDiagnosticsRefresh = 5;
|
||||
|
||||
// Refreshes diagnostics a few seconds after the final code completion, since
|
||||
// we don't get a language server request.
|
||||
while (true) {
|
||||
std::unique_lock<std::mutex> l(completion_manager->delayed_diagnostic_wakeup_mtx_);
|
||||
completion_manager->delayed_diagnostic_wakeup_cv_.wait(l);
|
||||
|
||||
// Check for spurious wakeup.
|
||||
if (!completion_manager->delayed_diagnostic_last_completion_position_)
|
||||
continue;
|
||||
|
||||
while (true) {
|
||||
// Get completion request info.
|
||||
if (!l.owns_lock())
|
||||
l.lock();
|
||||
auto time = *completion_manager->delayed_diagnostic_last_completion_time_;
|
||||
lsTextDocumentPositionParams location = *completion_manager->delayed_diagnostic_last_completion_position_;
|
||||
completion_manager->delayed_diagnostic_last_completion_time_.reset();
|
||||
completion_manager->delayed_diagnostic_last_completion_position_.reset();
|
||||
l.unlock();
|
||||
|
||||
// Wait five seconds. If there was another completion request, start the
|
||||
// waiting process over again.
|
||||
std::this_thread::sleep_for(std::chrono::seconds(kSecondsToWaitForDiagnosticsRefresh));
|
||||
l.lock();
|
||||
bool has_completion_since_sleeping = completion_manager->delayed_diagnostic_last_completion_position_.has_value();
|
||||
l.unlock();
|
||||
if (has_completion_since_sleeping)
|
||||
continue;
|
||||
|
||||
// Make completion request to get refreshed diagnostics.
|
||||
auto request = MakeUnique<ClangCompleteManager::CompletionRequest>();
|
||||
request->location = location;
|
||||
completion_manager->completion_request_.SetIfEmpty(std::move(request));
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||
while (true) {
|
||||
// Fetching the completion request blocks until we have a request.
|
||||
@ -371,45 +413,45 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||
std::cerr << "[complete] Got " << cx_results->NumResults << " results" << std::endl;
|
||||
|
||||
{
|
||||
NonElidedVector<lsCompletionItem> ls_result;
|
||||
ls_result.reserve(cx_results->NumResults);
|
||||
if (request->on_complete) {
|
||||
NonElidedVector<lsCompletionItem> ls_result;
|
||||
ls_result.reserve(cx_results->NumResults);
|
||||
|
||||
timer.Reset();
|
||||
for (unsigned i = 0; i < cx_results->NumResults; ++i) {
|
||||
CXCompletionResult& result = cx_results->Results[i];
|
||||
timer.Reset();
|
||||
for (unsigned i = 0; i < cx_results->NumResults; ++i) {
|
||||
CXCompletionResult& result = cx_results->Results[i];
|
||||
|
||||
// TODO: Try to figure out how we can hide base method calls without also
|
||||
// hiding method implementation assistance, ie,
|
||||
//
|
||||
// void Foo::* {
|
||||
// }
|
||||
//
|
||||
// TODO: Try to figure out how we can hide base method calls without also
|
||||
// hiding method implementation assistance, ie,
|
||||
//
|
||||
// void Foo::* {
|
||||
// }
|
||||
//
|
||||
|
||||
if (clang_getCompletionAvailability(result.CompletionString) == CXAvailability_NotAvailable)
|
||||
continue;
|
||||
if (clang_getCompletionAvailability(result.CompletionString) == CXAvailability_NotAvailable)
|
||||
continue;
|
||||
|
||||
// TODO: fill in more data
|
||||
lsCompletionItem ls_completion_item;
|
||||
// TODO: fill in more data
|
||||
lsCompletionItem ls_completion_item;
|
||||
|
||||
// kind/label/detail/docs/sortText
|
||||
ls_completion_item.kind = GetCompletionKind(result.CursorKind);
|
||||
BuildDetailString(result.CompletionString, ls_completion_item.label, ls_completion_item.detail, ls_completion_item.insertText, &ls_completion_item.parameters_);
|
||||
ls_completion_item.insertText += "$0";
|
||||
ls_completion_item.documentation = clang::ToString(clang_getCompletionBriefComment(result.CompletionString));
|
||||
ls_completion_item.sortText = (const char)uint64_t(GetCompletionPriority(result.CompletionString, result.CursorKind, ls_completion_item.label));
|
||||
// kind/label/detail/docs/sortText
|
||||
ls_completion_item.kind = GetCompletionKind(result.CursorKind);
|
||||
BuildDetailString(result.CompletionString, ls_completion_item.label, ls_completion_item.detail, ls_completion_item.insertText, &ls_completion_item.parameters_);
|
||||
ls_completion_item.insertText += "$0";
|
||||
ls_completion_item.documentation = clang::ToString(clang_getCompletionBriefComment(result.CompletionString));
|
||||
ls_completion_item.sortText = (const char)uint64_t(GetCompletionPriority(result.CompletionString, result.CursorKind, ls_completion_item.label));
|
||||
|
||||
ls_result.push_back(ls_completion_item);
|
||||
ls_result.push_back(ls_completion_item);
|
||||
}
|
||||
timer.ResetAndPrint("[complete] Building " + std::to_string(ls_result.size()) + " completion results");
|
||||
|
||||
request->on_complete(ls_result, false /*is_cached_result*/);
|
||||
timer.ResetAndPrint("[complete] Running user-given completion func");
|
||||
}
|
||||
timer.ResetAndPrint("[complete] Building " + std::to_string(ls_result.size()) + " completion results");
|
||||
|
||||
request->on_complete(ls_result, false /*is_cached_result*/);
|
||||
timer.ResetAndPrint("[complete] Running user-given completion func");
|
||||
|
||||
unsigned num_diagnostics = clang_codeCompleteGetNumDiagnostics(cx_results);
|
||||
NonElidedVector<lsDiagnostic> ls_diagnostics;
|
||||
std::cerr << "!! There are " + std::to_string(num_diagnostics) + " diagnostics to build\n";
|
||||
for (unsigned i = 0; i < num_diagnostics; ++i) {
|
||||
std::cerr << "!! Building diagnostic " + std::to_string(i) + "\n";
|
||||
CXDiagnostic cx_diag = clang_codeCompleteGetDiagnostic(cx_results, i);
|
||||
optional<lsDiagnostic> diagnostic = BuildAndDisposeDiagnostic(cx_diag, path);
|
||||
if (diagnostic)
|
||||
@ -423,6 +465,15 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
|
||||
clang_disposeCodeCompleteResults(cx_results);
|
||||
timer.ResetAndPrint("[complete] clang_disposeCodeCompleteResults");
|
||||
|
||||
if (request->is_user_completion) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(completion_manager->delayed_diagnostic_wakeup_mtx_);
|
||||
completion_manager->delayed_diagnostic_last_completion_position_ = request->location;
|
||||
completion_manager->delayed_diagnostic_last_completion_time_ = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
completion_manager->delayed_diagnostic_wakeup_cv_.notify_one();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -475,13 +526,16 @@ ClangCompleteManager::ClangCompleteManager(Config* config, Project* project, Wor
|
||||
new std::thread([&]() {
|
||||
SetCurrentThreadName("completequery");
|
||||
CompletionQueryMain(this);
|
||||
std::cerr << "!!! exiting completequery thread" << std::endl;
|
||||
});
|
||||
|
||||
new std::thread([&]() {
|
||||
SetCurrentThreadName("completediagnosticsrefresh");
|
||||
CompletionDiagnosticsDelayedRefreshMain(this);
|
||||
});
|
||||
|
||||
new std::thread([&]() {
|
||||
SetCurrentThreadName("completeparse");
|
||||
CompletionParseMain(this);
|
||||
std::cerr << "!!! exiting completeparse thread" << std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
@ -493,6 +547,7 @@ void ClangCompleteManager::CodeComplete(const lsTextDocumentPositionParams& comp
|
||||
auto request = MakeUnique<CompletionRequest>();
|
||||
request->location = completion_location;
|
||||
request->on_complete = on_complete;
|
||||
request->is_user_completion = true;
|
||||
completion_request_.Set(std::move(request));
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ struct ClangCompleteManager {
|
||||
struct CompletionRequest {
|
||||
lsTextDocumentPositionParams location;
|
||||
OnComplete on_complete;
|
||||
bool is_user_completion = false;
|
||||
};
|
||||
|
||||
ClangCompleteManager(Config* config, Project* project, WorkingFiles* working_files, OnDiagnostic on_diagnostic);
|
||||
@ -103,4 +104,10 @@ struct ClangCompleteManager {
|
||||
// Parse requests. The path may already be parsed, in which case it should be
|
||||
// reparsed.
|
||||
ThreadedQueue<ParseRequest> parse_requests_;
|
||||
// Used to wakeup the delayed diagnostics thread.
|
||||
std::mutex delayed_diagnostic_wakeup_mtx_;
|
||||
std::condition_variable delayed_diagnostic_wakeup_cv_;
|
||||
// Access under |delayed_diagnostic_wakeup_mtx_|.
|
||||
optional<lsTextDocumentPositionParams> delayed_diagnostic_last_completion_position_;
|
||||
optional<std::chrono::time_point<std::chrono::high_resolution_clock>> delayed_diagnostic_last_completion_time_;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user