mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Backport recent update of completion
This commit is contained in:
		
							parent
							
								
									a7c89fbe21
								
							
						
					
					
						commit
						d45c057dd4
					
				@ -270,7 +270,8 @@ void BuildDetailString(CXCompletionString completion_string,
 | 
				
			|||||||
                       bool& do_insert,
 | 
					                       bool& do_insert,
 | 
				
			||||||
                       lsInsertTextFormat& format,
 | 
					                       lsInsertTextFormat& format,
 | 
				
			||||||
                       std::vector<std::string>* parameters,
 | 
					                       std::vector<std::string>* parameters,
 | 
				
			||||||
                       bool include_snippets) {
 | 
					                       bool include_snippets,
 | 
				
			||||||
 | 
					                       int& angle_stack) {
 | 
				
			||||||
  int num_chunks = clang_getNumCompletionChunks(completion_string);
 | 
					  int num_chunks = clang_getNumCompletionChunks(completion_string);
 | 
				
			||||||
  auto append = [&](const char* text) {
 | 
					  auto append = [&](const char* text) {
 | 
				
			||||||
    detail += text;
 | 
					    detail += text;
 | 
				
			||||||
@ -285,8 +286,11 @@ void BuildDetailString(CXCompletionString completion_string,
 | 
				
			|||||||
      case CXCompletionChunk_Optional: {
 | 
					      case CXCompletionChunk_Optional: {
 | 
				
			||||||
        CXCompletionString nested =
 | 
					        CXCompletionString nested =
 | 
				
			||||||
            clang_getCompletionChunkCompletionString(completion_string, i);
 | 
					            clang_getCompletionChunkCompletionString(completion_string, i);
 | 
				
			||||||
        BuildDetailString(nested, label, detail, insert, do_insert, format,
 | 
					        // Do not add text to insert string if we're in angle brackets.
 | 
				
			||||||
                          parameters, include_snippets);
 | 
					        bool should_insert = do_insert && angle_stack == 0;
 | 
				
			||||||
 | 
					        BuildDetailString(nested, label, detail, insert,
 | 
				
			||||||
 | 
					                          should_insert, format, parameters,
 | 
				
			||||||
 | 
					                          include_snippets, angle_stack);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -348,8 +352,8 @@ void BuildDetailString(CXCompletionString completion_string,
 | 
				
			|||||||
      case CXCompletionChunk_RightBracket: append("]"); break;
 | 
					      case CXCompletionChunk_RightBracket: append("]"); break;
 | 
				
			||||||
      case CXCompletionChunk_LeftBrace: append("{"); break;
 | 
					      case CXCompletionChunk_LeftBrace: append("{"); break;
 | 
				
			||||||
      case CXCompletionChunk_RightBrace: append("}"); break;
 | 
					      case CXCompletionChunk_RightBrace: append("}"); break;
 | 
				
			||||||
      case CXCompletionChunk_LeftAngle: append("<"); break;
 | 
					      case CXCompletionChunk_LeftAngle: append("<"); angle_stack++; break;
 | 
				
			||||||
      case CXCompletionChunk_RightAngle: append(">"); break;
 | 
					      case CXCompletionChunk_RightAngle: append(">"); angle_stack--; break;
 | 
				
			||||||
      case CXCompletionChunk_Comma: append(", "); break;
 | 
					      case CXCompletionChunk_Comma: append(", "); break;
 | 
				
			||||||
      case CXCompletionChunk_Colon: append(":"); break;
 | 
					      case CXCompletionChunk_Colon: append(":"); break;
 | 
				
			||||||
      case CXCompletionChunk_SemiColon: append(";"); break;
 | 
					      case CXCompletionChunk_SemiColon: append(";"); break;
 | 
				
			||||||
@ -366,7 +370,8 @@ void BuildDetailString(CXCompletionString completion_string,
 | 
				
			|||||||
void TryEnsureDocumentParsed(ClangCompleteManager* manager,
 | 
					void TryEnsureDocumentParsed(ClangCompleteManager* manager,
 | 
				
			||||||
                             std::shared_ptr<CompletionSession> session,
 | 
					                             std::shared_ptr<CompletionSession> session,
 | 
				
			||||||
                             std::unique_ptr<ClangTranslationUnit>* tu,
 | 
					                             std::unique_ptr<ClangTranslationUnit>* tu,
 | 
				
			||||||
                             ClangIndex* index) {
 | 
					                             ClangIndex* index,
 | 
				
			||||||
 | 
					                             bool emit_diag) {
 | 
				
			||||||
  // Nothing to do. We already have a translation unit.
 | 
					  // Nothing to do. We already have a translation unit.
 | 
				
			||||||
  if (*tu)
 | 
					  if (*tu)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
@ -414,11 +419,10 @@ void TryEnsureDocumentParsed(ClangCompleteManager* manager,
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void CompletionParseMain(ClangCompleteManager* completion_manager) {
 | 
					void CompletionPreloadMain(ClangCompleteManager* 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.
 | 
				
			||||||
    ClangCompleteManager::ParseRequest request =
 | 
					    auto request = completion_manager->preload_requests_.Dequeue();
 | 
				
			||||||
        completion_manager->parse_requests_.Dequeue();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If we don't get a session then that means we don't care about the file
 | 
					    // If we don't get a session then that means we don't care about the file
 | 
				
			||||||
    // anymore - abandon the request.
 | 
					    // anymore - abandon the request.
 | 
				
			||||||
@ -429,23 +433,23 @@ void CompletionParseMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
    if (!session)
 | 
					    if (!session)
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Note: we only preload completion. We emit diagnostics for the
 | 
				
			||||||
 | 
					    // completion preload though.
 | 
				
			||||||
 | 
					    CompletionSession::Tu* tu = &session->completion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If we've parsed it more recently than the request time, don't bother
 | 
					    // If we've parsed it more recently than the request time, don't bother
 | 
				
			||||||
    // reparsing.
 | 
					    // reparsing.
 | 
				
			||||||
    if (session->tu_last_parsed_at &&
 | 
					    if (tu->last_parsed_at && *tu->last_parsed_at > request.request_time)
 | 
				
			||||||
        *session->tu_last_parsed_at > request.request_time) {
 | 
					 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<ClangTranslationUnit> parsing;
 | 
					    std::unique_ptr<ClangTranslationUnit> parsing;
 | 
				
			||||||
    TryEnsureDocumentParsed(completion_manager, session, &parsing,
 | 
					    TryEnsureDocumentParsed(completion_manager, session, &parsing, &tu->index,
 | 
				
			||||||
                            &session->index);
 | 
					                            true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Activate new translation unit.
 | 
					    // Activate new translation unit.
 | 
				
			||||||
    // tu_last_parsed_at is only read by this thread, so it doesn't need to be
 | 
					    std::lock_guard<std::mutex> lock(tu->lock);
 | 
				
			||||||
    // under the mutex.
 | 
					    tu->last_parsed_at = std::chrono::high_resolution_clock::now();
 | 
				
			||||||
    session->tu_last_parsed_at = std::chrono::high_resolution_clock::now();
 | 
					    tu->tu = std::move(parsing);
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(session->tu_lock);
 | 
					 | 
				
			||||||
    session->tu = std::move(parsing);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -468,15 +472,15 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
        completion_manager->TryGetSession(path, true /*mark_as_completion*/,
 | 
					        completion_manager->TryGetSession(path, true /*mark_as_completion*/,
 | 
				
			||||||
                                          true /*create_if_needed*/);
 | 
					                                          true /*create_if_needed*/);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::lock_guard<std::mutex> lock(session->tu_lock);
 | 
					    std::lock_guard<std::mutex> lock(session->completion.lock);
 | 
				
			||||||
    Timer timer;
 | 
					    Timer timer;
 | 
				
			||||||
    TryEnsureDocumentParsed(completion_manager, session, &session->tu,
 | 
					    TryEnsureDocumentParsed(completion_manager, session, &session->completion.tu,
 | 
				
			||||||
                            &session->index);
 | 
					                            &session->completion.index, false);
 | 
				
			||||||
    timer.ResetAndPrint("[complete] TryEnsureDocumentParsed");
 | 
					    timer.ResetAndPrint("[complete] TryEnsureDocumentParsed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // It is possible we failed to create the document despite
 | 
					    // It is possible we failed to create the document despite
 | 
				
			||||||
    // |TryEnsureDocumentParsed|.
 | 
					    // |TryEnsureDocumentParsed|.
 | 
				
			||||||
    if (!session->tu)
 | 
					    if (!session->completion.tu)
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timer.Reset();
 | 
					    timer.Reset();
 | 
				
			||||||
@ -485,30 +489,21 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
    std::vector<CXUnsavedFile> unsaved = snapshot.AsUnsavedFiles();
 | 
					    std::vector<CXUnsavedFile> unsaved = snapshot.AsUnsavedFiles();
 | 
				
			||||||
    timer.ResetAndPrint("[complete] Creating WorkingFile snapshot");
 | 
					    timer.ResetAndPrint("[complete] Creating WorkingFile snapshot");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Emit code completion data.
 | 
					 | 
				
			||||||
    if (request->position) {
 | 
					 | 
				
			||||||
      // Language server is 0-based, clang is 1-based.
 | 
					 | 
				
			||||||
      unsigned line = request->position->line + 1;
 | 
					 | 
				
			||||||
      unsigned column = request->position->character + 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      timer.Reset();
 | 
					 | 
				
			||||||
    unsigned const kCompleteOptions =
 | 
					    unsigned const kCompleteOptions =
 | 
				
			||||||
        CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments;
 | 
					        CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments;
 | 
				
			||||||
    CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
 | 
					    CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
 | 
				
			||||||
          session->tu->cx_tu, session->file.filename.c_str(), line, column,
 | 
					        session->completion.tu->cx_tu, session->file.filename.c_str(),
 | 
				
			||||||
 | 
					        request->position.line + 1, request->position.character + 1,
 | 
				
			||||||
        unsaved.data(), (unsigned)unsaved.size(), kCompleteOptions);
 | 
					        unsaved.data(), (unsigned)unsaved.size(), kCompleteOptions);
 | 
				
			||||||
    timer.ResetAndPrint("[complete] clangCodeCompleteAt");
 | 
					    timer.ResetAndPrint("[complete] clangCodeCompleteAt");
 | 
				
			||||||
    if (!cx_results) {
 | 
					    if (!cx_results) {
 | 
				
			||||||
        if (request->on_complete)
 | 
					 | 
				
			||||||
      request->on_complete({}, false /*is_cached_result*/);
 | 
					      request->on_complete({}, false /*is_cached_result*/);
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        if (request->on_complete) {
 | 
					 | 
				
			||||||
    std::vector<lsCompletionItem> ls_result;
 | 
					    std::vector<lsCompletionItem> ls_result;
 | 
				
			||||||
          // this is a guess but can be larger in case of std::optional parameters,
 | 
					    // this is a guess but can be larger in case of std::optional
 | 
				
			||||||
          // as they may be expanded into multiple items
 | 
					    // parameters, as they may be expanded into multiple items
 | 
				
			||||||
    ls_result.reserve(cx_results->NumResults);
 | 
					    ls_result.reserve(cx_results->NumResults);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timer.Reset();
 | 
					    timer.Reset();
 | 
				
			||||||
@ -530,8 +525,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
      lsCompletionItem ls_completion_item;
 | 
					      lsCompletionItem ls_completion_item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      ls_completion_item.kind = GetCompletionKind(result.CursorKind);
 | 
					      ls_completion_item.kind = GetCompletionKind(result.CursorKind);
 | 
				
			||||||
            ls_completion_item.documentation = ToString(
 | 
					      ls_completion_item.documentation =
 | 
				
			||||||
                clang_getCompletionBriefComment(result.CompletionString));
 | 
					          ToString(clang_getCompletionBriefComment(result.CompletionString));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // label/detail/filterText/insertText/priority
 | 
					      // label/detail/filterText/insertText/priority
 | 
				
			||||||
      if (g_config->completion.detailedLabel) {
 | 
					      if (g_config->completion.detailedLabel) {
 | 
				
			||||||
@ -542,36 +537,35 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
        ls_result.push_back(ls_completion_item);
 | 
					        ls_result.push_back(ls_completion_item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // label/filterText/insertText
 | 
					        // label/filterText/insertText
 | 
				
			||||||
              BuildCompletionItemTexts(
 | 
					        BuildCompletionItemTexts(ls_result, result.CompletionString,
 | 
				
			||||||
                  ls_result, result.CompletionString,
 | 
					 | 
				
			||||||
                                 g_config->client.snippetSupport);
 | 
					                                 g_config->client.snippetSupport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (auto i = first_idx; i < ls_result.size(); ++i) {
 | 
					        for (auto i = first_idx; i < ls_result.size(); ++i) {
 | 
				
			||||||
          if (g_config->client.snippetSupport &&
 | 
					          if (g_config->client.snippetSupport &&
 | 
				
			||||||
                    ls_result[i].insertTextFormat ==
 | 
					              ls_result[i].insertTextFormat == lsInsertTextFormat::Snippet) {
 | 
				
			||||||
                        lsInsertTextFormat::Snippet) {
 | 
					 | 
				
			||||||
            ls_result[i].insertText += "$0";
 | 
					            ls_result[i].insertText += "$0";
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                ls_result[i].priority_ = GetCompletionPriority(
 | 
					          ls_result[i].priority_ =
 | 
				
			||||||
                    result.CompletionString, result.CursorKind,
 | 
					              GetCompletionPriority(result.CompletionString, result.CursorKind,
 | 
				
			||||||
                                    ls_result[i].filterText);
 | 
					                                    ls_result[i].filterText);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        bool do_insert = true;
 | 
					        bool do_insert = true;
 | 
				
			||||||
              BuildDetailString(
 | 
					        int angle_stack = 0;
 | 
				
			||||||
                  result.CompletionString, ls_completion_item.label,
 | 
					        BuildDetailString(result.CompletionString, ls_completion_item.label,
 | 
				
			||||||
                  ls_completion_item.detail, ls_completion_item.insertText,
 | 
					                          ls_completion_item.detail,
 | 
				
			||||||
                  do_insert, ls_completion_item.insertTextFormat,
 | 
					                          ls_completion_item.insertText, do_insert,
 | 
				
			||||||
 | 
					                          ls_completion_item.insertTextFormat,
 | 
				
			||||||
                          &ls_completion_item.parameters_,
 | 
					                          &ls_completion_item.parameters_,
 | 
				
			||||||
                  g_config->client.snippetSupport);
 | 
					                          g_config->client.snippetSupport, angle_stack);
 | 
				
			||||||
        if (g_config->client.snippetSupport &&
 | 
					        if (g_config->client.snippetSupport &&
 | 
				
			||||||
            ls_completion_item.insertTextFormat ==
 | 
					            ls_completion_item.insertTextFormat ==
 | 
				
			||||||
                lsInsertTextFormat::Snippet) {
 | 
					                lsInsertTextFormat::Snippet) {
 | 
				
			||||||
          ls_completion_item.insertText += "$0";
 | 
					          ls_completion_item.insertText += "$0";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
              ls_completion_item.priority_ = GetCompletionPriority(
 | 
					        ls_completion_item.priority_ =
 | 
				
			||||||
                  result.CompletionString, result.CursorKind,
 | 
					            GetCompletionPriority(result.CompletionString, result.CursorKind,
 | 
				
			||||||
                                  ls_completion_item.label);
 | 
					                                  ls_completion_item.label);
 | 
				
			||||||
        ls_result.push_back(ls_completion_item);
 | 
					        ls_result.push_back(ls_completion_item);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -582,35 +576,60 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
                        " completion results");
 | 
					                        " completion results");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    request->on_complete(ls_result, false /*is_cached_result*/);
 | 
					    request->on_complete(ls_result, false /*is_cached_result*/);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Make sure |ls_results| is destroyed before clearing |cx_results|.
 | 
					    // Make sure |ls_results| is destroyed before clearing |cx_results|.
 | 
				
			||||||
    clang_disposeCodeCompleteResults(cx_results);
 | 
					    clang_disposeCodeCompleteResults(cx_results);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Emit diagnostics.
 | 
					void DiagnosticQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			||||||
    if (request->emit_diagnostics) {
 | 
					  while (true) {
 | 
				
			||||||
      // TODO: before emitting diagnostics check if we have another completion
 | 
					    // Fetching the completion request blocks until we have a request.
 | 
				
			||||||
      // request and think about servicing that first, because it may be much
 | 
					    ClangCompleteManager::DiagnosticRequest request =
 | 
				
			||||||
      // faster than reparsing the document.
 | 
					        completion_manager->diagnostic_request_.Dequeue();
 | 
				
			||||||
      // TODO: have a separate thread for diagnostics?
 | 
					    std::string path = request.document.uri.GetPath();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::shared_ptr<CompletionSession> session =
 | 
				
			||||||
 | 
					        completion_manager->TryGetSession(path, true /*mark_as_completion*/,
 | 
				
			||||||
 | 
					                                          true /*create_if_needed*/);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // At this point, we must have a translation unit. Block until we have one.
 | 
				
			||||||
 | 
					    std::lock_guard<std::mutex> lock(session->diagnostics.lock);
 | 
				
			||||||
 | 
					    Timer timer;
 | 
				
			||||||
 | 
					    TryEnsureDocumentParsed(
 | 
				
			||||||
 | 
					        completion_manager, session, &session->diagnostics.tu,
 | 
				
			||||||
 | 
					        &session->diagnostics.index, false /*emit_diagnostics*/);
 | 
				
			||||||
 | 
					    timer.ResetAndPrint("[diagnostics] TryEnsureDocumentParsed");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // It is possible we failed to create the document despite
 | 
				
			||||||
 | 
					    // |TryEnsureDocumentParsed|.
 | 
				
			||||||
 | 
					    if (!session->diagnostics.tu)
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timer.Reset();
 | 
					    timer.Reset();
 | 
				
			||||||
      session->tu =
 | 
					    WorkingFiles::Snapshot snapshot =
 | 
				
			||||||
          ClangTranslationUnit::Reparse(std::move(session->tu), unsaved);
 | 
					        completion_manager->working_files_->AsSnapshot({StripFileType(path)});
 | 
				
			||||||
      timer.ResetAndPrint("[complete] clang_reparseTranslationUnit");
 | 
					    std::vector<CXUnsavedFile> unsaved = snapshot.AsUnsavedFiles();
 | 
				
			||||||
      if (!session->tu) {
 | 
					    timer.ResetAndPrint("[diagnostics] Creating WorkingFile snapshot");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Emit diagnostics.
 | 
				
			||||||
 | 
					    timer.Reset();
 | 
				
			||||||
 | 
					    session->diagnostics.tu = ClangTranslationUnit::Reparse(
 | 
				
			||||||
 | 
					        std::move(session->diagnostics.tu), unsaved);
 | 
				
			||||||
 | 
					    timer.ResetAndPrint("[diagnostics] clang_reparseTranslationUnit");
 | 
				
			||||||
 | 
					    if (!session->diagnostics.tu) {
 | 
				
			||||||
      LOG_S(ERROR) << "Reparsing translation unit for diagnostics failed for "
 | 
					      LOG_S(ERROR) << "Reparsing translation unit for diagnostics failed for "
 | 
				
			||||||
                   << path;
 | 
					                   << path;
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      size_t num_diagnostics = clang_getNumDiagnostics(session->tu->cx_tu);
 | 
					    size_t num_diagnostics =
 | 
				
			||||||
 | 
					        clang_getNumDiagnostics(session->diagnostics.tu->cx_tu);
 | 
				
			||||||
    std::vector<lsDiagnostic> ls_diagnostics;
 | 
					    std::vector<lsDiagnostic> ls_diagnostics;
 | 
				
			||||||
    ls_diagnostics.reserve(num_diagnostics);
 | 
					    ls_diagnostics.reserve(num_diagnostics);
 | 
				
			||||||
    for (unsigned i = 0; i < num_diagnostics; ++i) {
 | 
					    for (unsigned i = 0; i < num_diagnostics; ++i) {
 | 
				
			||||||
        CXDiagnostic cx_diag = clang_getDiagnostic(session->tu->cx_tu, i);
 | 
					      CXDiagnostic cx_diag =
 | 
				
			||||||
 | 
					          clang_getDiagnostic(session->diagnostics.tu->cx_tu, i);
 | 
				
			||||||
      std::optional<lsDiagnostic> diagnostic =
 | 
					      std::optional<lsDiagnostic> diagnostic =
 | 
				
			||||||
          BuildAndDisposeDiagnostic(cx_diag, path);
 | 
					          BuildAndDisposeDiagnostic(cx_diag, path);
 | 
				
			||||||
      // Filter messages like "too many errors emitted, stopping now
 | 
					      // Filter messages like "too many errors emitted, stopping now
 | 
				
			||||||
@ -619,51 +638,12 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
 | 
				
			|||||||
      if (diagnostic && diagnostic->range.start.line >= 0)
 | 
					      if (diagnostic && diagnostic->range.start.line >= 0)
 | 
				
			||||||
        ls_diagnostics.push_back(*diagnostic);
 | 
					        ls_diagnostics.push_back(*diagnostic);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
      completion_manager->on_diagnostic_(session->file.filename,
 | 
					    completion_manager->on_diagnostic_(session->file.filename, ls_diagnostics);
 | 
				
			||||||
                                         ls_diagnostics);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      /*
 | 
					 | 
				
			||||||
      timer.Reset();
 | 
					 | 
				
			||||||
      completion_manager->on_index_(session->tu.get(), unsaved,
 | 
					 | 
				
			||||||
                                    session->file.filename, session->file.args);
 | 
					 | 
				
			||||||
      timer.ResetAndPrint("[complete] Reindex file");
 | 
					 | 
				
			||||||
      */
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    continue;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}  // namespace
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CompletionSession::CompletionSession(const Project::Entry& file,
 | 
					 | 
				
			||||||
                                     WorkingFiles* working_files)
 | 
					 | 
				
			||||||
    : file(file),
 | 
					 | 
				
			||||||
      working_files(working_files),
 | 
					 | 
				
			||||||
      index(0 /*excludeDeclarationsFromPCH*/, 0 /*displayDiagnostics*/) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
CompletionSession::~CompletionSession() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ClangCompleteManager::ParseRequest::ParseRequest(const std::string& path)
 | 
					 | 
				
			||||||
    : request_time(std::chrono::high_resolution_clock::now()), path(path) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ClangCompleteManager::CompletionRequest::CompletionRequest(
 | 
					 | 
				
			||||||
    const lsRequestId& id,
 | 
					 | 
				
			||||||
    const lsTextDocumentIdentifier& document,
 | 
					 | 
				
			||||||
    bool emit_diagnostics)
 | 
					 | 
				
			||||||
    : id(id), document(document), emit_diagnostics(emit_diagnostics) {}
 | 
					 | 
				
			||||||
ClangCompleteManager::CompletionRequest::CompletionRequest(
 | 
					 | 
				
			||||||
    const lsRequestId& id,
 | 
					 | 
				
			||||||
    const lsTextDocumentIdentifier& document,
 | 
					 | 
				
			||||||
    const lsPosition& position,
 | 
					 | 
				
			||||||
    const OnComplete& on_complete,
 | 
					 | 
				
			||||||
    bool emit_diagnostics)
 | 
					 | 
				
			||||||
    : id(id),
 | 
					 | 
				
			||||||
      document(document),
 | 
					 | 
				
			||||||
      position(position),
 | 
					 | 
				
			||||||
      on_complete(on_complete),
 | 
					 | 
				
			||||||
      emit_diagnostics(emit_diagnostics) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ClangCompleteManager::ClangCompleteManager(Project* project,
 | 
					ClangCompleteManager::ClangCompleteManager(Project* project,
 | 
				
			||||||
                                           WorkingFiles* working_files,
 | 
					                                           WorkingFiles* working_files,
 | 
				
			||||||
                                           OnDiagnostic on_diagnostic,
 | 
					                                           OnDiagnostic on_diagnostic,
 | 
				
			||||||
@ -677,13 +657,16 @@ ClangCompleteManager::ClangCompleteManager(Project* project,
 | 
				
			|||||||
      preloaded_sessions_(kMaxPreloadedSessions),
 | 
					      preloaded_sessions_(kMaxPreloadedSessions),
 | 
				
			||||||
      completion_sessions_(kMaxCompletionSessions) {
 | 
					      completion_sessions_(kMaxCompletionSessions) {
 | 
				
			||||||
  new std::thread([&]() {
 | 
					  new std::thread([&]() {
 | 
				
			||||||
    SetThreadName("completequery");
 | 
					    SetThreadName("comp-query");
 | 
				
			||||||
    CompletionQueryMain(this);
 | 
					    CompletionQueryMain(this);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					 | 
				
			||||||
  new std::thread([&]() {
 | 
					  new std::thread([&]() {
 | 
				
			||||||
    SetThreadName("completeparse");
 | 
					    SetThreadName("comp-preload");
 | 
				
			||||||
    CompletionParseMain(this);
 | 
					    CompletionPreloadMain(this);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  new std::thread([&]() {
 | 
				
			||||||
 | 
					    SetThreadName("diag-query");
 | 
				
			||||||
 | 
					    DiagnosticQueryMain(this);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -693,14 +676,20 @@ void ClangCompleteManager::CodeComplete(
 | 
				
			|||||||
    const OnComplete& on_complete) {
 | 
					    const OnComplete& on_complete) {
 | 
				
			||||||
  completion_request_.PushBack(std::make_unique<CompletionRequest>(
 | 
					  completion_request_.PushBack(std::make_unique<CompletionRequest>(
 | 
				
			||||||
      id, completion_location.textDocument, completion_location.position,
 | 
					      id, completion_location.textDocument, completion_location.position,
 | 
				
			||||||
      on_complete, false));
 | 
					      on_complete));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClangCompleteManager::DiagnosticsUpdate(
 | 
					void ClangCompleteManager::DiagnosticsUpdate(
 | 
				
			||||||
    const lsRequestId& id,
 | 
					    const lsRequestId& id,
 | 
				
			||||||
    const lsTextDocumentIdentifier& document) {
 | 
					    const lsTextDocumentIdentifier& document) {
 | 
				
			||||||
  completion_request_.PushBack(
 | 
					  bool has = false;
 | 
				
			||||||
      std::make_unique<CompletionRequest>(id, document, true));
 | 
					  diagnostic_request_.Iterate([&](const DiagnosticRequest& request) {
 | 
				
			||||||
 | 
					    if (request.document.uri == document.uri)
 | 
				
			||||||
 | 
					      has = true;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  if (!has)
 | 
				
			||||||
 | 
					    diagnostic_request_.PushBack(DiagnosticRequest{document},
 | 
				
			||||||
 | 
					                                 true /*priority*/);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClangCompleteManager::NotifyView(const std::string& filename) {
 | 
					void ClangCompleteManager::NotifyView(const std::string& filename) {
 | 
				
			||||||
@ -712,7 +701,7 @@ void ClangCompleteManager::NotifyView(const std::string& filename) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Only reparse the file if we create a new CompletionSession.
 | 
					  // Only reparse the file if we create a new CompletionSession.
 | 
				
			||||||
  if (EnsureCompletionOrCreatePreloadSession(filename))
 | 
					  if (EnsureCompletionOrCreatePreloadSession(filename))
 | 
				
			||||||
    parse_requests_.PushBack(ParseRequest(filename), true);
 | 
					    preload_requests_.PushBack(PreloadRequest(filename), true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClangCompleteManager::NotifyEdit(const std::string& filename) {
 | 
					void ClangCompleteManager::NotifyEdit(const std::string& filename) {
 | 
				
			||||||
@ -731,7 +720,7 @@ void ClangCompleteManager::NotifySave(const std::string& filename) {
 | 
				
			|||||||
  //
 | 
					  //
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  EnsureCompletionOrCreatePreloadSession(filename);
 | 
					  EnsureCompletionOrCreatePreloadSession(filename);
 | 
				
			||||||
  parse_requests_.PushBack(ParseRequest(filename), true);
 | 
					  preload_requests_.PushBack(PreloadRequest(filename), true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClangCompleteManager::NotifyClose(const std::string& filename) {
 | 
					void ClangCompleteManager::NotifyClose(const std::string& filename) {
 | 
				
			||||||
 | 
				
			|||||||
@ -18,22 +18,26 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct CompletionSession
 | 
					struct CompletionSession
 | 
				
			||||||
    : public std::enable_shared_from_this<CompletionSession> {
 | 
					    : public std::enable_shared_from_this<CompletionSession> {
 | 
				
			||||||
  Project::Entry file;
 | 
					  // Translation unit for clang.
 | 
				
			||||||
  WorkingFiles* working_files;
 | 
					  struct Tu {
 | 
				
			||||||
  ClangIndex index;
 | 
					    ClangIndex index{0, 0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // When |tu| was last parsed.
 | 
					    // When |tu| was last parsed.
 | 
				
			||||||
    std::optional<std::chrono::time_point<std::chrono::high_resolution_clock>>
 | 
					    std::optional<std::chrono::time_point<std::chrono::high_resolution_clock>>
 | 
				
			||||||
      tu_last_parsed_at;
 | 
					        last_parsed_at;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Acquired when |tu| is being used.
 | 
					    // Acquired when |tu| is being used.
 | 
				
			||||||
  std::mutex tu_lock;
 | 
					    std::mutex lock;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  // The active translation unit.
 | 
					 | 
				
			||||||
    std::unique_ptr<ClangTranslationUnit> tu;
 | 
					    std::unique_ptr<ClangTranslationUnit> tu;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  CompletionSession(const Project::Entry& file, WorkingFiles* working_files);
 | 
					  Project::Entry file;
 | 
				
			||||||
  ~CompletionSession();
 | 
					  WorkingFiles* working_files;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Tu completion;
 | 
				
			||||||
 | 
					  Tu diagnostics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CompletionSession(const Project::Entry& file, WorkingFiles* wfiles)
 | 
				
			||||||
 | 
					      : file(file), working_files(wfiles) {}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ClangCompleteManager {
 | 
					struct ClangCompleteManager {
 | 
				
			||||||
@ -49,27 +53,30 @@ struct ClangCompleteManager {
 | 
				
			|||||||
                         bool is_cached_result)>;
 | 
					                         bool is_cached_result)>;
 | 
				
			||||||
  using OnDropped = std::function<void(lsRequestId request_id)>;
 | 
					  using OnDropped = std::function<void(lsRequestId request_id)>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct ParseRequest {
 | 
					  struct PreloadRequest {
 | 
				
			||||||
    ParseRequest(const std::string& path);
 | 
					    PreloadRequest(const std::string& path)
 | 
				
			||||||
 | 
					        : request_time(std::chrono::high_resolution_clock::now()), path(path) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
 | 
					    std::chrono::time_point<std::chrono::high_resolution_clock> request_time;
 | 
				
			||||||
    std::string path;
 | 
					    std::string path;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  struct CompletionRequest {
 | 
					  struct CompletionRequest {
 | 
				
			||||||
    CompletionRequest(const lsRequestId& id,
 | 
					 | 
				
			||||||
                      const lsTextDocumentIdentifier& document,
 | 
					 | 
				
			||||||
                      bool emit_diagnostics);
 | 
					 | 
				
			||||||
    CompletionRequest(const lsRequestId& id,
 | 
					    CompletionRequest(const lsRequestId& id,
 | 
				
			||||||
                      const lsTextDocumentIdentifier& document,
 | 
					                      const lsTextDocumentIdentifier& document,
 | 
				
			||||||
                      const lsPosition& position,
 | 
					                      const lsPosition& position,
 | 
				
			||||||
                      const OnComplete& on_complete,
 | 
					                      const OnComplete& on_complete)
 | 
				
			||||||
                      bool emit_diagnostics);
 | 
					        : id(id),
 | 
				
			||||||
 | 
					          document(document),
 | 
				
			||||||
 | 
					          position(position),
 | 
				
			||||||
 | 
					          on_complete(on_complete) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    lsRequestId id;
 | 
					    lsRequestId id;
 | 
				
			||||||
    lsTextDocumentIdentifier document;
 | 
					    lsTextDocumentIdentifier document;
 | 
				
			||||||
    std::optional<lsPosition> position;
 | 
					    lsPosition position;
 | 
				
			||||||
    OnComplete on_complete;  // May be null/empty.
 | 
					    OnComplete on_complete;
 | 
				
			||||||
    bool emit_diagnostics = false;
 | 
					  };
 | 
				
			||||||
 | 
					  struct DiagnosticRequest {
 | 
				
			||||||
 | 
					    lsTextDocumentIdentifier document;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ClangCompleteManager(Project* project,
 | 
					  ClangCompleteManager(Project* project,
 | 
				
			||||||
@ -138,9 +145,10 @@ struct ClangCompleteManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  // Request a code completion at the given location.
 | 
					  // Request a code completion at the given location.
 | 
				
			||||||
  ThreadedQueue<std::unique_ptr<CompletionRequest>> completion_request_;
 | 
					  ThreadedQueue<std::unique_ptr<CompletionRequest>> completion_request_;
 | 
				
			||||||
 | 
					  ThreadedQueue<DiagnosticRequest> diagnostic_request_;
 | 
				
			||||||
  // Parse requests. The path may already be parsed, in which case it should be
 | 
					  // Parse requests. The path may already be parsed, in which case it should be
 | 
				
			||||||
  // reparsed.
 | 
					  // reparsed.
 | 
				
			||||||
  ThreadedQueue<ParseRequest> parse_requests_;
 | 
					  ThreadedQueue<PreloadRequest> preload_requests_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Cached completion information, so we can give fast completion results when
 | 
					// Cached completion information, so we can give fast completion results when
 | 
				
			||||||
 | 
				
			|||||||
@ -123,7 +123,7 @@ static const std::vector<std::string> preprocessorKeywords = {
 | 
				
			|||||||
    "define", "undef", "include", "if",   "ifdef", "ifndef",
 | 
					    "define", "undef", "include", "if",   "ifdef", "ifndef",
 | 
				
			||||||
    "else",   "elif",  "endif",   "line", "error", "pragma"};
 | 
					    "else",   "elif",  "endif",   "line", "error", "pragma"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<lsCompletionItem> preprocessorKeywordCompletionItems(
 | 
					std::vector<lsCompletionItem> PreprocessorKeywordCompletionItems(
 | 
				
			||||||
    const std::smatch& match) {
 | 
					    const std::smatch& match) {
 | 
				
			||||||
  std::vector<lsCompletionItem> items;
 | 
					  std::vector<lsCompletionItem> items;
 | 
				
			||||||
  for (auto& keyword : preprocessorKeywords) {
 | 
					  for (auto& keyword : preprocessorKeywords) {
 | 
				
			||||||
@ -160,7 +160,8 @@ char* tofixedbase64(T input, char* out) {
 | 
				
			|||||||
// when given 1000+ completion items.
 | 
					// when given 1000+ completion items.
 | 
				
			||||||
void FilterAndSortCompletionResponse(
 | 
					void FilterAndSortCompletionResponse(
 | 
				
			||||||
    Out_TextDocumentComplete* complete_response,
 | 
					    Out_TextDocumentComplete* complete_response,
 | 
				
			||||||
    const std::string& complete_text) {
 | 
					    const std::string& complete_text,
 | 
				
			||||||
 | 
					    bool has_open_paren) {
 | 
				
			||||||
  if (!g_config->completion.filterAndSort)
 | 
					  if (!g_config->completion.filterAndSort)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -189,6 +190,10 @@ void FilterAndSortCompletionResponse(
 | 
				
			|||||||
      complete_response->result.isIncomplete = true;
 | 
					      complete_response->result.isIncomplete = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (has_open_paren)
 | 
				
			||||||
 | 
					      for (auto& item: items)
 | 
				
			||||||
 | 
					        item.insertText = item.label;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Set sortText. Note that this happens after resizing - we could do it
 | 
					    // Set sortText. Note that this happens after resizing - we could do it
 | 
				
			||||||
    // before, but then we should also sort by priority.
 | 
					    // before, but then we should also sort by priority.
 | 
				
			||||||
    char buf[16];
 | 
					    char buf[16];
 | 
				
			||||||
@ -236,6 +241,26 @@ void FilterAndSortCompletionResponse(
 | 
				
			|||||||
  finalize();
 | 
					  finalize();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns true if position is an points to a '(' character in |lines|. Skips
 | 
				
			||||||
 | 
					// whitespace.
 | 
				
			||||||
 | 
					bool IsOpenParenOrAngle(const std::vector<std::string>& lines,
 | 
				
			||||||
 | 
					  const lsPosition& position) {
 | 
				
			||||||
 | 
					  auto [c, l] = position;
 | 
				
			||||||
 | 
					  while (l < lines.size()) {
 | 
				
			||||||
 | 
					    const auto& line = lines[l];
 | 
				
			||||||
 | 
					    if (c >= line.size())
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    if (line[c] == '(' || line[c] == '<')
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    if (!isspace(line[c])) break;
 | 
				
			||||||
 | 
					    if (++c >= line.size()) {
 | 
				
			||||||
 | 
					      c = 0;
 | 
				
			||||||
 | 
					      l++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Handler_TextDocumentCompletion : MessageHandler {
 | 
					struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					  MethodType GetMethodType() const override { return kMethodType; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -306,13 +331,15 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    bool is_global_completion = false;
 | 
					    bool is_global_completion = false;
 | 
				
			||||||
    std::string existing_completion;
 | 
					    std::string existing_completion;
 | 
				
			||||||
 | 
					    lsPosition end_pos = request->params.position;
 | 
				
			||||||
    if (file) {
 | 
					    if (file) {
 | 
				
			||||||
      request->params.position = file->FindStableCompletionSource(
 | 
					      request->params.position = file->FindStableCompletionSource(
 | 
				
			||||||
          request->params.position, &is_global_completion,
 | 
					          request->params.position, &is_global_completion,
 | 
				
			||||||
          &existing_completion);
 | 
					          &existing_completion, &end_pos);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
 | 
					    ParseIncludeLineResult result = ParseIncludeLine(buffer_line);
 | 
				
			||||||
 | 
					    bool has_open_paren = IsOpenParenOrAngle(file->buffer_lines, end_pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (result.ok) {
 | 
					    if (result.ok) {
 | 
				
			||||||
      Out_TextDocumentComplete out;
 | 
					      Out_TextDocumentComplete out;
 | 
				
			||||||
@ -325,8 +352,8 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
                         [&result](std::string_view k) {
 | 
					                         [&result](std::string_view k) {
 | 
				
			||||||
                           return k == result.keyword;
 | 
					                           return k == result.keyword;
 | 
				
			||||||
                         })) {
 | 
					                         })) {
 | 
				
			||||||
          out.result.items = preprocessorKeywordCompletionItems(result.match);
 | 
					          out.result.items = PreprocessorKeywordCompletionItems(result.match);
 | 
				
			||||||
          FilterAndSortCompletionResponse(&out, result.keyword);
 | 
					          FilterAndSortCompletionResponse(&out, result.keyword, has_open_paren);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      } else if (result.keyword.compare("include") == 0) {
 | 
					      } else if (result.keyword.compare("include") == 0) {
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -340,7 +367,7 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
            if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\""))
 | 
					            if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\""))
 | 
				
			||||||
               out.result.items.push_back(item);
 | 
					               out.result.items.push_back(item);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        FilterAndSortCompletionResponse(&out, result.pattern);
 | 
					        FilterAndSortCompletionResponse(&out, result.pattern, has_open_paren);
 | 
				
			||||||
        DecorateIncludePaths(result.match, &out.result.items);
 | 
					        DecorateIncludePaths(result.match, &out.result.items);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -354,15 +381,15 @@ struct Handler_TextDocumentCompletion : MessageHandler {
 | 
				
			|||||||
      QueueManager::WriteStdout(kMethodType, out);
 | 
					      QueueManager::WriteStdout(kMethodType, out);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      ClangCompleteManager::OnComplete callback = std::bind(
 | 
					      ClangCompleteManager::OnComplete callback = std::bind(
 | 
				
			||||||
          [this, is_global_completion, existing_completion, request](
 | 
					          [this, request, is_global_completion, existing_completion,
 | 
				
			||||||
              const std::vector<lsCompletionItem>& results,
 | 
					           has_open_paren](const std::vector<lsCompletionItem>& results,
 | 
				
			||||||
                           bool is_cached_result) {
 | 
					                           bool is_cached_result) {
 | 
				
			||||||
            Out_TextDocumentComplete out;
 | 
					            Out_TextDocumentComplete out;
 | 
				
			||||||
            out.id = request->id;
 | 
					            out.id = request->id;
 | 
				
			||||||
            out.result.items = results;
 | 
					            out.result.items = results;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Emit completion results.
 | 
					            // Emit completion results.
 | 
				
			||||||
            FilterAndSortCompletionResponse(&out, existing_completion);
 | 
					            FilterAndSortCompletionResponse(&out, existing_completion, has_open_paren);
 | 
				
			||||||
            QueueManager::WriteStdout(kMethodType, out);
 | 
					            QueueManager::WriteStdout(kMethodType, out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Cache completion results.
 | 
					            // Cache completion results.
 | 
				
			||||||
 | 
				
			|||||||
@ -205,6 +205,15 @@ struct ThreadedQueue : public BaseThreadQueue {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  std::optional<T> TryPopFrontHigh() { return TryPopFrontHelper(2); }
 | 
					  std::optional<T> TryPopFrontHigh() { return TryPopFrontHelper(2); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  template <typename Fn>
 | 
				
			||||||
 | 
					  void Iterate(Fn fn) {
 | 
				
			||||||
 | 
					    std::lock_guard<std::mutex> lock(mutex_);
 | 
				
			||||||
 | 
					    for (auto& entry : priority_)
 | 
				
			||||||
 | 
					      fn(entry);
 | 
				
			||||||
 | 
					    for (auto& entry : queue_)
 | 
				
			||||||
 | 
					      fn(entry);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mutable std::mutex mutex_;
 | 
					  mutable std::mutex mutex_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
 | 
				
			|||||||
@ -415,7 +415,8 @@ std::string WorkingFile::FindClosestCallNameInBuffer(
 | 
				
			|||||||
lsPosition WorkingFile::FindStableCompletionSource(
 | 
					lsPosition WorkingFile::FindStableCompletionSource(
 | 
				
			||||||
    lsPosition position,
 | 
					    lsPosition position,
 | 
				
			||||||
    bool* is_global_completion,
 | 
					    bool* is_global_completion,
 | 
				
			||||||
    std::string* existing_completion) const {
 | 
					    std::string* existing_completion,
 | 
				
			||||||
 | 
					    lsPosition* replace_end_pos) const {
 | 
				
			||||||
  *is_global_completion = true;
 | 
					  *is_global_completion = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int start_offset = GetOffsetForPosition(position, buffer_content);
 | 
					  int start_offset = GetOffsetForPosition(position, buffer_content);
 | 
				
			||||||
@ -441,6 +442,14 @@ lsPosition WorkingFile::FindStableCompletionSource(
 | 
				
			|||||||
    --offset;
 | 
					    --offset;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *replace_end_pos = position;
 | 
				
			||||||
 | 
					  for (int i = start_offset; i < buffer_content.size(); i++) {
 | 
				
			||||||
 | 
					    char c = buffer_content[i];
 | 
				
			||||||
 | 
					    if (!isalnum(c) && c != '_') break;
 | 
				
			||||||
 | 
					    // We know that replace_end_pos and position are on the same line.
 | 
				
			||||||
 | 
					    replace_end_pos->character++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  *existing_completion = buffer_content.substr(offset, start_offset - offset);
 | 
					  *existing_completion = buffer_content.substr(offset, start_offset - offset);
 | 
				
			||||||
  return GetPositionForOffset(buffer_content, offset);
 | 
					  return GetPositionForOffset(buffer_content, offset);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -69,7 +69,8 @@ struct WorkingFile {
 | 
				
			|||||||
  // content the user has entered.
 | 
					  // content the user has entered.
 | 
				
			||||||
  lsPosition FindStableCompletionSource(lsPosition position,
 | 
					  lsPosition FindStableCompletionSource(lsPosition position,
 | 
				
			||||||
                                        bool* is_global_completion,
 | 
					                                        bool* is_global_completion,
 | 
				
			||||||
                                        std::string* existing_completion) const;
 | 
					                                        std::string* existing_completion,
 | 
				
			||||||
 | 
					                                        lsPosition* replace_end_pos) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 private:
 | 
				
			||||||
  // Compute index_to_buffer and buffer_to_index.
 | 
					  // Compute index_to_buffer and buffer_to_index.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user