mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	First iteration of code completion off the main thread. Still one race condition but hopefully it shouldn't happen too often.
This commit is contained in:
		
							parent
							
								
									c6dead848e
								
							
						
					
					
						commit
						5e8e13380d
					
				
							
								
								
									
										32
									
								
								src/atomic_object.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/atomic_object.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <condition_variable>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// A object which can be stored and taken from atomically.
 | 
				
			||||||
 | 
					template <class T>
 | 
				
			||||||
 | 
					struct AtomicObject {
 | 
				
			||||||
 | 
					  void Set(std::unique_ptr<T> t) {
 | 
				
			||||||
 | 
					    std::lock_guard<std::mutex> lock(mutex_);
 | 
				
			||||||
 | 
					    value_ = std::move(t);
 | 
				
			||||||
 | 
					    cv_.notify_one();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::unique_ptr<T> Take() {
 | 
				
			||||||
 | 
					    std::unique_lock<std::mutex> lock(mutex_);
 | 
				
			||||||
 | 
					    while (!value_) {
 | 
				
			||||||
 | 
					      // release lock as long as the wait and reaquire it afterwards.
 | 
				
			||||||
 | 
					      cv_.wait(lock);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return std::move(value_);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 private:
 | 
				
			||||||
 | 
					  std::unique_ptr<T> value_;
 | 
				
			||||||
 | 
					  mutable std::mutex mutex_;
 | 
				
			||||||
 | 
					  std::condition_variable cv_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -4,6 +4,7 @@
 | 
				
			|||||||
#include "timer.h"
 | 
					#include "timer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <thread>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
unsigned Flags() {
 | 
					unsigned Flags() {
 | 
				
			||||||
@ -191,8 +192,138 @@ std::string BuildDetailString(CXCompletionString completion_string) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return detail;
 | 
					  return detail;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CompletionMain(CompletionManager* completion_manager) {
 | 
				
			||||||
 | 
					  while (true) {
 | 
				
			||||||
 | 
					    std::unique_ptr<CompletionManager::CompletionRequest> request = completion_manager->completion_request.Take();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    NonElidedVector<lsCompletionItem> ls_result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    CompletionSession* session = completion_manager->GetOrOpenSession(request->location.textDocument.uri.GetPath());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned line = request->location.position.line + 1;
 | 
				
			||||||
 | 
					    unsigned column = request->location.position.character + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::cerr << std::endl;
 | 
				
			||||||
 | 
					    std::cerr << "Completing at " << line << ":" << column << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO/FIXME
 | 
				
			||||||
 | 
					    // TODO/FIXME
 | 
				
			||||||
 | 
					    // TODO/FIXME NOT THREAD SAFE
 | 
				
			||||||
 | 
					    // TODO/FIXME
 | 
				
			||||||
 | 
					    // TODO/FIXME
 | 
				
			||||||
 | 
					    std::vector<CXUnsavedFile> unsaved = completion_manager->working_files->AsUnsavedFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Timer timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer.Reset();
 | 
				
			||||||
 | 
					    CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
 | 
				
			||||||
 | 
					      session->active->cx_tu,
 | 
				
			||||||
 | 
					      session->file.filename.c_str(), line, column,
 | 
				
			||||||
 | 
					      unsaved.data(), unsaved.size(),
 | 
				
			||||||
 | 
					      CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments);
 | 
				
			||||||
 | 
					    if (!cx_results) {
 | 
				
			||||||
 | 
					      std::cerr << "Code completion failed" << std::endl;
 | 
				
			||||||
 | 
					      request->on_complete(ls_result);
 | 
				
			||||||
 | 
					      continue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    timer.ResetAndPrint("clangCodeCompleteAt");
 | 
				
			||||||
 | 
					    std::cerr << "Got " << cx_results->NumResults << " results" << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: for comments we could hack the unsaved buffer and transform // into ///
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ls_result.reserve(cx_results->NumResults);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    timer.Reset();
 | 
				
			||||||
 | 
					    for (unsigned i = 0; i < cx_results->NumResults; ++i) {
 | 
				
			||||||
 | 
					      CXCompletionResult& result = cx_results->Results[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      //unsigned int is_incomplete;
 | 
				
			||||||
 | 
					      //CXCursorKind kind = clang_codeCompleteGetContainerKind(cx_results, &is_incomplete);
 | 
				
			||||||
 | 
					      //std::cerr << "clang_codeCompleteGetContainerKind kind=" << kind << " is_incomplete=" << is_incomplete << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // CXCursor_InvalidCode fo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      //clang_codeCompleteGetContexts
 | 
				
			||||||
 | 
					      //CXCompletionContext
 | 
				
			||||||
 | 
					      // clang_codeCompleteGetContexts
 | 
				
			||||||
 | 
					      //
 | 
				
			||||||
 | 
					      //CXCursorKind kind;
 | 
				
			||||||
 | 
					      //CXString str = clang_getCompletionParent(result.CompletionString, &kind);
 | 
				
			||||||
 | 
					      //std::cerr << "clang_getCompletionParent kind=" << kind << ", str=" << clang::ToString(str) << std::endl;
 | 
				
			||||||
 | 
					      // if global don't append now, append to end later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // also clang_codeCompleteGetContainerKind
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // TODO: fill in more data
 | 
				
			||||||
 | 
					      lsCompletionItem ls_completion_item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // kind/label/detail/docs
 | 
				
			||||||
 | 
					      ls_completion_item.kind = GetCompletionKind(result.CursorKind);
 | 
				
			||||||
 | 
					      ls_completion_item.label = BuildLabelString(result.CompletionString);
 | 
				
			||||||
 | 
					      ls_completion_item.detail = BuildDetailString(result.CompletionString);
 | 
				
			||||||
 | 
					      ls_completion_item.documentation = clang::ToString(clang_getCompletionBriefComment(result.CompletionString));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // Priority
 | 
				
			||||||
 | 
					      int priority = clang_getCompletionPriority(result.CompletionString);
 | 
				
			||||||
 | 
					      if (result.CursorKind == CXCursor_Destructor) {
 | 
				
			||||||
 | 
					        priority *= 100;
 | 
				
			||||||
 | 
					        //std::cerr << "Bumping[destructor] " << ls_completion_item.label << std::endl;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (result.CursorKind == CXCursor_ConversionFunction ||
 | 
				
			||||||
 | 
					        (result.CursorKind == CXCursor_CXXMethod && StartsWith(ls_completion_item.label, "operator"))) {
 | 
				
			||||||
 | 
					        //std::cerr << "Bumping[conversion] " << ls_completion_item.label << std::endl;
 | 
				
			||||||
 | 
					        priority *= 100;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (clang_getCompletionAvailability(result.CompletionString) != CXAvailability_Available) {
 | 
				
			||||||
 | 
					        //std::cerr << "Bumping[notavailable] " << ls_completion_item.label << std::endl;
 | 
				
			||||||
 | 
					        priority *= 100;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      //std::cerr << "Adding kind=" << result.CursorKind << ", priority=" << ls_completion_item.priority_ << ", label=" << ls_completion_item.label << std::endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // TODO: we can probably remove priority_ and our sort.
 | 
				
			||||||
 | 
					      ls_completion_item.sortText = uint64_t(priority);// std::to_string(ls_completion_item.priority_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      ls_result.push_back(ls_completion_item);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    timer.ResetAndPrint("Building " + std::to_string(ls_result.size()) + " completion results");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clang_disposeCodeCompleteResults(cx_results);
 | 
				
			||||||
 | 
					    timer.ResetAndPrint("clang_disposeCodeCompleteResults ");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    request->on_complete(ls_result);
 | 
				
			||||||
 | 
					    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // we should probably main two translation units, one for
 | 
				
			||||||
 | 
					    // serving current requests, and one that is reparsing (follow qtcreator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // todo: we need to run code completion on a separate thread from querydb
 | 
				
			||||||
 | 
					    // so thread layout looks like:
 | 
				
			||||||
 | 
					    //    - stdin                   # Reads data from stdin
 | 
				
			||||||
 | 
					    //    - stdout                  # Pushes data to stdout
 | 
				
			||||||
 | 
					    //    - querydb                 # Resolves index database queries.
 | 
				
			||||||
 | 
					    //    - complete_responder      # Handles low-latency code complete requests.
 | 
				
			||||||
 | 
					    //    - complete_parser         # Parses most recent document for future code complete requests.
 | 
				
			||||||
 | 
					    //    - indexer (many)          # Runs index jobs (for querydb updates)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // use clang_codeCompleteAt
 | 
				
			||||||
 | 
					    //CXUnsavedFile
 | 
				
			||||||
 | 
					    // we need to setup CXUnsavedFile
 | 
				
			||||||
 | 
					    // The key to doing that is via
 | 
				
			||||||
 | 
					    //  - textDocument/didOpen
 | 
				
			||||||
 | 
					    //  - textDocument/didChange
 | 
				
			||||||
 | 
					    //  - textDocument/didClose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // probably don't need
 | 
				
			||||||
 | 
					    //  - textDocument/willSave
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CompletionSession::CompletionSession(const CompilationEntry& file, WorkingFiles* working_files) : file(file) {
 | 
					CompletionSession::CompletionSession(const CompilationEntry& file, WorkingFiles* working_files) : file(file) {
 | 
				
			||||||
  std::vector<CXUnsavedFile> unsaved = working_files->AsUnsavedFiles();
 | 
					  std::vector<CXUnsavedFile> unsaved = working_files->AsUnsavedFiles();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -235,123 +366,17 @@ void CompletionSession::Refresh(std::vector<CXUnsavedFile>& unsaved) {
 | 
				
			|||||||
  active->ReparseTranslationUnit(unsaved);
 | 
					  active->ReparseTranslationUnit(unsaved);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CompletionManager::CompletionManager(Project* project, WorkingFiles* working_files) : project(project), working_files(working_files) {}
 | 
					CompletionManager::CompletionManager(Project* project, WorkingFiles* working_files) : project(project), working_files(working_files) {
 | 
				
			||||||
 | 
					  new std::thread([&]() {
 | 
				
			||||||
 | 
					    CompletionMain(this);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NonElidedVector<lsCompletionItem> CompletionManager::CodeComplete(const lsTextDocumentPositionParams& completion_location) {
 | 
					void CompletionManager::CodeComplete(const lsTextDocumentPositionParams& completion_location, const OnComplete& on_complete) {
 | 
				
			||||||
  NonElidedVector<lsCompletionItem> ls_result;
 | 
					  auto request = MakeUnique<CompletionRequest>();
 | 
				
			||||||
 | 
					  request->location = completion_location;
 | 
				
			||||||
  CompletionSession* session = GetOrOpenSession(completion_location.textDocument.uri.GetPath());
 | 
					  request->on_complete = on_complete;
 | 
				
			||||||
 | 
					  completion_request.Set(std::move(request));
 | 
				
			||||||
  unsigned line = completion_location.position.line + 1;
 | 
					 | 
				
			||||||
  unsigned column = completion_location.position.character + 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::cerr << std::endl;
 | 
					 | 
				
			||||||
  //std::cerr << "Completing at " << line << ":" << column << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<CXUnsavedFile> unsaved = working_files->AsUnsavedFiles();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Timer timer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  timer.Reset();
 | 
					 | 
				
			||||||
  CXCodeCompleteResults* cx_results = clang_codeCompleteAt(
 | 
					 | 
				
			||||||
    session->active->cx_tu,
 | 
					 | 
				
			||||||
    session->file.filename.c_str(), line, column,
 | 
					 | 
				
			||||||
    unsaved.data(), unsaved.size(),
 | 
					 | 
				
			||||||
    CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeBriefComments);
 | 
					 | 
				
			||||||
  if (!cx_results) {
 | 
					 | 
				
			||||||
    std::cerr << "Code completion failed" << std::endl;
 | 
					 | 
				
			||||||
    return ls_result;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  timer.ResetAndPrint("clangCodeCompleteAt");
 | 
					 | 
				
			||||||
  std::cerr << "Got " << cx_results->NumResults << " results" << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // TODO: for comments we could hack the unsaved buffer and transform // into ///
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ls_result.reserve(cx_results->NumResults);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  timer.Reset();
 | 
					 | 
				
			||||||
  for (unsigned i = 0; i < cx_results->NumResults; ++i) {
 | 
					 | 
				
			||||||
    CXCompletionResult& result = cx_results->Results[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //unsigned int is_incomplete;
 | 
					 | 
				
			||||||
    //CXCursorKind kind = clang_codeCompleteGetContainerKind(cx_results, &is_incomplete);
 | 
					 | 
				
			||||||
    //std::cerr << "clang_codeCompleteGetContainerKind kind=" << kind << " is_incomplete=" << is_incomplete << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // CXCursor_InvalidCode fo
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    //clang_codeCompleteGetContexts
 | 
					 | 
				
			||||||
    //CXCompletionContext
 | 
					 | 
				
			||||||
    // clang_codeCompleteGetContexts
 | 
					 | 
				
			||||||
    //
 | 
					 | 
				
			||||||
    //CXCursorKind kind;
 | 
					 | 
				
			||||||
    //CXString str = clang_getCompletionParent(result.CompletionString, &kind);
 | 
					 | 
				
			||||||
    //std::cerr << "clang_getCompletionParent kind=" << kind << ", str=" << clang::ToString(str) << std::endl;
 | 
					 | 
				
			||||||
    // if global don't append now, append to end later
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // also clang_codeCompleteGetContainerKind
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO: fill in more data
 | 
					 | 
				
			||||||
    lsCompletionItem ls_completion_item;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // kind/label/detail/docs
 | 
					 | 
				
			||||||
    ls_completion_item.kind = GetCompletionKind(result.CursorKind);
 | 
					 | 
				
			||||||
    ls_completion_item.label = BuildLabelString(result.CompletionString);
 | 
					 | 
				
			||||||
    ls_completion_item.detail = BuildDetailString(result.CompletionString);
 | 
					 | 
				
			||||||
    ls_completion_item.documentation = clang::ToString(clang_getCompletionBriefComment(result.CompletionString));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Priority
 | 
					 | 
				
			||||||
    int priority = clang_getCompletionPriority(result.CompletionString);
 | 
					 | 
				
			||||||
    if (result.CursorKind == CXCursor_Destructor) {
 | 
					 | 
				
			||||||
      priority *= 100;
 | 
					 | 
				
			||||||
      //std::cerr << "Bumping[destructor] " << ls_completion_item.label << std::endl;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (result.CursorKind == CXCursor_ConversionFunction ||
 | 
					 | 
				
			||||||
      (result.CursorKind == CXCursor_CXXMethod && StartsWith(ls_completion_item.label, "operator"))) {
 | 
					 | 
				
			||||||
      //std::cerr << "Bumping[conversion] " << ls_completion_item.label << std::endl;
 | 
					 | 
				
			||||||
      priority *= 100;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (clang_getCompletionAvailability(result.CompletionString) != CXAvailability_Available) {
 | 
					 | 
				
			||||||
      //std::cerr << "Bumping[notavailable] " << ls_completion_item.label << std::endl;
 | 
					 | 
				
			||||||
      priority *= 100;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    //std::cerr << "Adding kind=" << result.CursorKind << ", priority=" << ls_completion_item.priority_ << ", label=" << ls_completion_item.label << std::endl;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // TODO: we can probably remove priority_ and our sort.
 | 
					 | 
				
			||||||
    ls_completion_item.sortText = uint64_t(priority);// std::to_string(ls_completion_item.priority_);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ls_result.push_back(ls_completion_item);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  timer.ResetAndPrint("Building completion results");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  clang_disposeCodeCompleteResults(cx_results);
 | 
					 | 
				
			||||||
  timer.ResetAndPrint("clang_disposeCodeCompleteResults ");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return ls_result;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // we should probably main two translation units, one for
 | 
					 | 
				
			||||||
  // serving current requests, and one that is reparsing (follow qtcreator)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // todo: we need to run code completion on a separate thread from querydb
 | 
					 | 
				
			||||||
  // so thread layout looks like:
 | 
					 | 
				
			||||||
  //    - stdin                   # Reads data from stdin
 | 
					 | 
				
			||||||
  //    - stdout                  # Pushes data to stdout
 | 
					 | 
				
			||||||
  //    - querydb                 # Resolves index database queries.
 | 
					 | 
				
			||||||
  //    - complete_responder      # Handles low-latency code complete requests.
 | 
					 | 
				
			||||||
  //    - complete_parser         # Parses most recent document for future code complete requests.
 | 
					 | 
				
			||||||
  //    - indexer (many)          # Runs index jobs (for querydb updates)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // use clang_codeCompleteAt
 | 
					 | 
				
			||||||
  //CXUnsavedFile
 | 
					 | 
				
			||||||
  // we need to setup CXUnsavedFile
 | 
					 | 
				
			||||||
  // The key to doing that is via
 | 
					 | 
				
			||||||
  //  - textDocument/didOpen
 | 
					 | 
				
			||||||
  //  - textDocument/didChange
 | 
					 | 
				
			||||||
  //  - textDocument/didClose
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // probably don't need
 | 
					 | 
				
			||||||
  //  - textDocument/willSave
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CompletionSession* CompletionManager::GetOrOpenSession(const std::string& filename) {
 | 
					CompletionSession* CompletionManager::GetOrOpenSession(const std::string& filename) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					#include "atomic_object.h"
 | 
				
			||||||
#include "language_server_api.h"
 | 
					#include "language_server_api.h"
 | 
				
			||||||
#include "libclangmm/CompletionString.h"
 | 
					#include "libclangmm/CompletionString.h"
 | 
				
			||||||
#include "libclangmm/Index.h"
 | 
					#include "libclangmm/Index.h"
 | 
				
			||||||
@ -7,6 +8,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <clang-c/Index.h>
 | 
					#include <clang-c/Index.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct CompletionSession {
 | 
					struct CompletionSession {
 | 
				
			||||||
  CompilationEntry file;
 | 
					  CompilationEntry file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,12 +36,18 @@ struct CompletionManager {
 | 
				
			|||||||
  Project* project;
 | 
					  Project* project;
 | 
				
			||||||
  WorkingFiles* working_files;
 | 
					  WorkingFiles* working_files;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  using OnComplete = std::function<void(NonElidedVector<lsCompletionItem> results)>;
 | 
				
			||||||
 | 
					  struct CompletionRequest {
 | 
				
			||||||
 | 
					    lsTextDocumentPositionParams location;
 | 
				
			||||||
 | 
					    OnComplete on_complete;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  AtomicObject<CompletionRequest> completion_request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  CompletionManager(Project* project, WorkingFiles* working_files);
 | 
					  CompletionManager(Project* project, WorkingFiles* working_files);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // This all should run on complete_responder thread. This will internally run a child thread to
 | 
					  // Start a code completion at the given location. |on_complete| will run when
 | 
				
			||||||
  // reparse.
 | 
					  // completion results are available. |on_complete| may run on any thread.
 | 
				
			||||||
  NonElidedVector<lsCompletionItem> CodeComplete(const lsTextDocumentPositionParams& completion_location);
 | 
					  void CodeComplete(const lsTextDocumentPositionParams& completion_location, const OnComplete& on_complete);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 private:
 | 
					 | 
				
			||||||
  CompletionSession* GetOrOpenSession(const std::string& filename);
 | 
					  CompletionSession* GetOrOpenSession(const std::string& filename);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -20,6 +20,7 @@
 | 
				
			|||||||
#include <rapidjson/ostreamwrapper.h>
 | 
					#include <rapidjson/ostreamwrapper.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <fstream>
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
@ -999,13 +1000,6 @@ void IndexMain(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1170,16 +1164,27 @@ void QueryDbMainLoop(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case IpcId::TextDocumentCompletion: {
 | 
					    case IpcId::TextDocumentCompletion: {
 | 
				
			||||||
      // TODO: better performance
 | 
					 | 
				
			||||||
      auto msg = static_cast<Ipc_TextDocumentComplete*>(message.get());
 | 
					      auto msg = static_cast<Ipc_TextDocumentComplete*>(message.get());
 | 
				
			||||||
      Out_TextDocumentComplete response;
 | 
					      lsTextDocumentPositionParams params = msg->params;
 | 
				
			||||||
      response.id = msg->id;
 | 
					
 | 
				
			||||||
      response.result.isIncomplete = false;
 | 
					      CompletionManager::OnComplete callback = std::bind([](BaseIpcMessage* message, const NonElidedVector<lsCompletionItem>& results) {
 | 
				
			||||||
      response.result.items = completion_manager->CodeComplete(msg->params);
 | 
					        auto msg = static_cast<Ipc_TextDocumentComplete*>(message);
 | 
				
			||||||
 | 
					        auto ipc = IpcManager::instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Out_TextDocumentComplete response;
 | 
				
			||||||
 | 
					        response.id = msg->id;
 | 
				
			||||||
 | 
					        response.result.isIncomplete = false;
 | 
				
			||||||
 | 
					        response.result.items = results;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Timer timer;
 | 
				
			||||||
 | 
					        ipc->SendOutMessageToClient(response);
 | 
				
			||||||
 | 
					        timer.ResetAndPrint("Writing completion results");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        delete message;
 | 
				
			||||||
 | 
					      }, message.release(), std::placeholders::_1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      completion_manager->CodeComplete(params, std::move(callback));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Timer timer;
 | 
					 | 
				
			||||||
      ipc->SendOutMessageToClient(response);
 | 
					 | 
				
			||||||
      timer.ResetAndPrint("Writing completion results");
 | 
					 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user