mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +00:00 
			
		
		
		
	Remove variant and clean up
This commit is contained in:
		
							parent
							
								
									4d519dcbcb
								
							
						
					
					
						commit
						fa9df5bcef
					
				@ -656,18 +656,18 @@ ClangCompleteManager::ClangCompleteManager(Project* project,
 | 
				
			|||||||
      on_dropped_(on_dropped),
 | 
					      on_dropped_(on_dropped),
 | 
				
			||||||
      preloaded_sessions_(kMaxPreloadedSessions),
 | 
					      preloaded_sessions_(kMaxPreloadedSessions),
 | 
				
			||||||
      completion_sessions_(kMaxCompletionSessions) {
 | 
					      completion_sessions_(kMaxCompletionSessions) {
 | 
				
			||||||
  new std::thread([&]() {
 | 
					  std::thread([&]() {
 | 
				
			||||||
    SetThreadName("comp-query");
 | 
					    SetThreadName("comp-query");
 | 
				
			||||||
    CompletionQueryMain(this);
 | 
					    CompletionQueryMain(this);
 | 
				
			||||||
  });
 | 
					  }).detach();
 | 
				
			||||||
  new std::thread([&]() {
 | 
					  std::thread([&]() {
 | 
				
			||||||
    SetThreadName("comp-preload");
 | 
					    SetThreadName("comp-preload");
 | 
				
			||||||
    CompletionPreloadMain(this);
 | 
					    CompletionPreloadMain(this);
 | 
				
			||||||
  });
 | 
					  }).detach();
 | 
				
			||||||
  new std::thread([&]() {
 | 
					  std::thread([&]() {
 | 
				
			||||||
    SetThreadName("diag-query");
 | 
					    SetThreadName("diag-query");
 | 
				
			||||||
    DiagnosticQueryMain(this);
 | 
					    DiagnosticQueryMain(this);
 | 
				
			||||||
  });
 | 
					  }).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClangCompleteManager::CodeComplete(
 | 
					void ClangCompleteManager::CodeComplete(
 | 
				
			||||||
@ -680,7 +680,6 @@ void ClangCompleteManager::CodeComplete(
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ClangCompleteManager::DiagnosticsUpdate(
 | 
					void ClangCompleteManager::DiagnosticsUpdate(
 | 
				
			||||||
    const lsRequestId& id,
 | 
					 | 
				
			||||||
    const lsTextDocumentIdentifier& document) {
 | 
					    const lsTextDocumentIdentifier& document) {
 | 
				
			||||||
  bool has = false;
 | 
					  bool has = false;
 | 
				
			||||||
  diagnostic_request_.Iterate([&](const DiagnosticRequest& request) {
 | 
					  diagnostic_request_.Iterate([&](const DiagnosticRequest& request) {
 | 
				
			||||||
 | 
				
			|||||||
@ -91,8 +91,7 @@ struct ClangCompleteManager {
 | 
				
			|||||||
                    const lsTextDocumentPositionParams& completion_location,
 | 
					                    const lsTextDocumentPositionParams& completion_location,
 | 
				
			||||||
                    const OnComplete& on_complete);
 | 
					                    const OnComplete& on_complete);
 | 
				
			||||||
  // Request a diagnostics update.
 | 
					  // Request a diagnostics update.
 | 
				
			||||||
  void DiagnosticsUpdate(const lsRequestId& request_id,
 | 
					  void DiagnosticsUpdate(const lsTextDocumentIdentifier& document);
 | 
				
			||||||
                         const lsTextDocumentIdentifier& document);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Notify the completion manager that |filename| has been viewed and we
 | 
					  // Notify the completion manager that |filename| has been viewed and we
 | 
				
			||||||
  // should begin preloading completion data.
 | 
					  // should begin preloading completion data.
 | 
				
			||||||
 | 
				
			|||||||
@ -172,7 +172,7 @@ void RunQueryDbThread(const std::string& bin_name,
 | 
				
			|||||||
                                      args);
 | 
					                                      args);
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      [](lsRequestId id) {
 | 
					      [](lsRequestId id) {
 | 
				
			||||||
        if (!std::holds_alternative<std::monostate>(id)) {
 | 
					        if (id.Valid()) {
 | 
				
			||||||
          Out_Error out;
 | 
					          Out_Error out;
 | 
				
			||||||
          out.id = id;
 | 
					          out.id = id;
 | 
				
			||||||
          out.error.code = lsErrorCodes::InternalError;
 | 
					          out.error.code = lsErrorCodes::InternalError;
 | 
				
			||||||
@ -243,7 +243,7 @@ void RunQueryDbThread(const std::string& bin_name,
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// |ipc| is connected to a server.
 | 
					// |ipc| is connected to a server.
 | 
				
			||||||
void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
					void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			||||||
  new std::thread([request_times]() {
 | 
					  std::thread([request_times]() {
 | 
				
			||||||
    SetThreadName("stdin");
 | 
					    SetThreadName("stdin");
 | 
				
			||||||
    auto* queue = QueueManager::instance();
 | 
					    auto* queue = QueueManager::instance();
 | 
				
			||||||
    while (true) {
 | 
					    while (true) {
 | 
				
			||||||
@ -257,7 +257,7 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			|||||||
        // Emit an error ResponseMessage if |id| is available.
 | 
					        // Emit an error ResponseMessage if |id| is available.
 | 
				
			||||||
        if (message) {
 | 
					        if (message) {
 | 
				
			||||||
          lsRequestId id = message->GetRequestId();
 | 
					          lsRequestId id = message->GetRequestId();
 | 
				
			||||||
          if (!std::holds_alternative<std::monostate>(id)) {
 | 
					          if (id.Valid()) {
 | 
				
			||||||
            Out_Error out;
 | 
					            Out_Error out;
 | 
				
			||||||
            out.id = id;
 | 
					            out.id = id;
 | 
				
			||||||
            out.error.code = lsErrorCodes::InvalidParams;
 | 
					            out.error.code = lsErrorCodes::InvalidParams;
 | 
				
			||||||
@ -279,12 +279,12 @@ void LaunchStdinLoop(std::unordered_map<MethodType, Timer>* request_times) {
 | 
				
			|||||||
      if (method_type == kMethodType_Exit)
 | 
					      if (method_type == kMethodType_Exit)
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  }).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
					void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
				
			||||||
                        MultiQueueWaiter* waiter) {
 | 
					                        MultiQueueWaiter* waiter) {
 | 
				
			||||||
  new std::thread([=]() {
 | 
					  std::thread([=]() {
 | 
				
			||||||
    SetThreadName("stdout");
 | 
					    SetThreadName("stdout");
 | 
				
			||||||
    auto* queue = QueueManager::instance();
 | 
					    auto* queue = QueueManager::instance();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -305,7 +305,7 @@ void LaunchStdoutThread(std::unordered_map<MethodType, Timer>* request_times,
 | 
				
			|||||||
        fflush(stdout);
 | 
					        fflush(stdout);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  }).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void LanguageServerMain(const std::string& bin_name,
 | 
					void LanguageServerMain(const std::string& bin_name,
 | 
				
			||||||
 | 
				
			|||||||
@ -393,8 +393,7 @@ void ParseFile(DiagnosticsEngine* diag_engine,
 | 
				
			|||||||
                                file_contents, &perf);
 | 
					                                file_contents, &perf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (indexes.empty()) {
 | 
					  if (indexes.empty()) {
 | 
				
			||||||
    if (g_config->index.enabled &&
 | 
					    if (g_config->index.enabled && request.id.Valid()) {
 | 
				
			||||||
        !std::holds_alternative<std::monostate>(request.id)) {
 | 
					 | 
				
			||||||
      Out_Error out;
 | 
					      Out_Error out;
 | 
				
			||||||
      out.id = request.id;
 | 
					      out.id = request.id;
 | 
				
			||||||
      out.error.code = lsErrorCodes::InternalError;
 | 
					      out.error.code = lsErrorCodes::InternalError;
 | 
				
			||||||
 | 
				
			|||||||
@ -29,21 +29,16 @@ std::string ElideLongPath(const std::string& path) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
size_t TrimCommonPathPrefix(const std::string& result,
 | 
					size_t TrimCommonPathPrefix(const std::string& result,
 | 
				
			||||||
                            const std::string& trimmer) {
 | 
					                            const std::string& trimmer) {
 | 
				
			||||||
  size_t i = 0;
 | 
					#ifdef _WIN32
 | 
				
			||||||
  while (i < result.size() && i < trimmer.size()) {
 | 
					  std::string s = result, t = trimmer;
 | 
				
			||||||
    char a = result[i];
 | 
					  std::transform(s.begin(), s.end(), s.begin(), ::tolower);
 | 
				
			||||||
    char b = trimmer[i];
 | 
					  std::transform(t.begin(), t.end(), t.begin(), ::tolower);
 | 
				
			||||||
#if defined(_WIN32)
 | 
					  if (s.compare(0, t.size(), t) == 0)
 | 
				
			||||||
    a = (char)tolower(a);
 | 
					    return t.size();
 | 
				
			||||||
    b = (char)tolower(b);
 | 
					#else
 | 
				
			||||||
 | 
					  if (result.compare(0, trimmer.size(), trimmer) == 0)
 | 
				
			||||||
 | 
					    return trimmer.size();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    if (a != b)
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    ++i;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (i == trimmer.size())
 | 
					 | 
				
			||||||
    return i;
 | 
					 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,21 +46,14 @@ size_t TrimCommonPathPrefix(const std::string& result,
 | 
				
			|||||||
bool TrimPath(Project* project,
 | 
					bool TrimPath(Project* project,
 | 
				
			||||||
              const std::string& project_root,
 | 
					              const std::string& project_root,
 | 
				
			||||||
              std::string* insert_path) {
 | 
					              std::string* insert_path) {
 | 
				
			||||||
  size_t start = 0;
 | 
					  size_t start = TrimCommonPathPrefix(*insert_path, project_root);
 | 
				
			||||||
  bool angle = false;
 | 
					  bool angle = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  size_t len = TrimCommonPathPrefix(*insert_path, project_root);
 | 
					  for (auto& include_dir : project->quote_include_directories)
 | 
				
			||||||
  if (len > start)
 | 
					    start = std::max(start, TrimCommonPathPrefix(*insert_path, include_dir));
 | 
				
			||||||
    start = len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  for (auto& include_dir : project->quote_include_directories) {
 | 
					 | 
				
			||||||
    len = TrimCommonPathPrefix(*insert_path, include_dir);
 | 
					 | 
				
			||||||
    if (len > start)
 | 
					 | 
				
			||||||
      start = len;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (auto& include_dir : project->angle_include_directories) {
 | 
					  for (auto& include_dir : project->angle_include_directories) {
 | 
				
			||||||
    len = TrimCommonPathPrefix(*insert_path, include_dir);
 | 
					    auto len = TrimCommonPathPrefix(*insert_path, include_dir);
 | 
				
			||||||
    if (len > start) {
 | 
					    if (len > start) {
 | 
				
			||||||
      start = len;
 | 
					      start = len;
 | 
				
			||||||
      angle = true;
 | 
					      angle = true;
 | 
				
			||||||
@ -115,8 +103,8 @@ void IncludeComplete::Rescan() {
 | 
				
			|||||||
                                          g_config->completion.includeBlacklist);
 | 
					                                          g_config->completion.includeBlacklist);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  is_scanning = true;
 | 
					  is_scanning = true;
 | 
				
			||||||
  new std::thread([this]() {
 | 
					  std::thread([this]() {
 | 
				
			||||||
                    SetThreadName("scan_includes");
 | 
					    SetThreadName("scan_includes");
 | 
				
			||||||
    Timer timer;
 | 
					    Timer timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    InsertStlIncludes();
 | 
					    InsertStlIncludes();
 | 
				
			||||||
@ -129,7 +117,7 @@ void IncludeComplete::Rescan() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    timer.ResetAndPrint("[perf] Scanning for includes");
 | 
					    timer.ResetAndPrint("[perf] Scanning for includes");
 | 
				
			||||||
    is_scanning = false;
 | 
					    is_scanning = false;
 | 
				
			||||||
  });
 | 
					  }).detach();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
 | 
					void IncludeComplete::InsertCompletionItem(const std::string& absolute_path,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										13
									
								
								src/lsp.cc
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/lsp.cc
									
									
									
									
									
								
							@ -275,6 +275,19 @@ bool lsTextEdit::operator==(const lsTextEdit& that) {
 | 
				
			|||||||
  return range == that.range && newText == that.newText;
 | 
					  return range == that.range && newText == that.newText;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Reflect(Writer& visitor, lsMarkedString& value) {
 | 
				
			||||||
 | 
					  // If there is a language, emit a `{language:string, value:string}` object. If
 | 
				
			||||||
 | 
					  // not, emit a string.
 | 
				
			||||||
 | 
					  if (value.language) {
 | 
				
			||||||
 | 
					    REFLECT_MEMBER_START();
 | 
				
			||||||
 | 
					    REFLECT_MEMBER(language);
 | 
				
			||||||
 | 
					    REFLECT_MEMBER(value);
 | 
				
			||||||
 | 
					    REFLECT_MEMBER_END();
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    Reflect(visitor, value.value);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string Out_ShowLogMessage::method() {
 | 
					std::string Out_ShowLogMessage::method() {
 | 
				
			||||||
  if (display_type == DisplayType::Log)
 | 
					  if (display_type == DisplayType::Log)
 | 
				
			||||||
    return "window/logMessage";
 | 
					    return "window/logMessage";
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/lsp.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/lsp.h
									
									
									
									
									
								
							@ -239,7 +239,7 @@ MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri);
 | 
				
			|||||||
struct lsVersionedTextDocumentIdentifier {
 | 
					struct lsVersionedTextDocumentIdentifier {
 | 
				
			||||||
  lsDocumentUri uri;
 | 
					  lsDocumentUri uri;
 | 
				
			||||||
  // The version number of this document.  number | null
 | 
					  // The version number of this document.  number | null
 | 
				
			||||||
  std::variant<std::monostate, int> version;
 | 
					  std::optional<int> version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
 | 
					  lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -325,12 +325,11 @@ MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces);
 | 
				
			|||||||
//
 | 
					//
 | 
				
			||||||
// Note that markdown strings will be sanitized - that means html will be
 | 
					// Note that markdown strings will be sanitized - that means html will be
 | 
				
			||||||
// escaped.
 | 
					// escaped.
 | 
				
			||||||
struct lsMarkedString1 {
 | 
					struct lsMarkedString {
 | 
				
			||||||
  std::string_view language;
 | 
					  std::optional<std::string> language;
 | 
				
			||||||
  std::string_view value;
 | 
					  std::string value;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
using lsMarkedString = std::variant<std::string_view, lsMarkedString1>;
 | 
					void Reflect(Writer& visitor, lsMarkedString& value);
 | 
				
			||||||
MAKE_REFLECT_STRUCT(lsMarkedString1, language, value);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct lsTextDocumentContentChangeEvent {
 | 
					struct lsTextDocumentContentChangeEvent {
 | 
				
			||||||
  // The range of the document that changed.
 | 
					  // The range of the document that changed.
 | 
				
			||||||
 | 
				
			|||||||
@ -87,7 +87,7 @@ struct Handler_CclsFreshenIndex : BaseMessageHandler<In_CclsFreshenIndex> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    Timer time;
 | 
					    Timer time;
 | 
				
			||||||
    // Send index requests for every file.
 | 
					    // Send index requests for every file.
 | 
				
			||||||
    project->Index(QueueManager::instance(), working_files, std::monostate());
 | 
					    project->Index(QueueManager::instance(), working_files, lsRequestId());
 | 
				
			||||||
    time.ResetAndPrint("[perf] Dispatched $ccls/freshenIndex index requests");
 | 
					    time.ResetAndPrint("[perf] Dispatched $ccls/freshenIndex index requests");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -518,12 +518,12 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
      LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers";
 | 
					      LOG_S(INFO) << "Starting " << g_config->index.threads << " indexers";
 | 
				
			||||||
      for (int i = 0; i < g_config->index.threads; i++) {
 | 
					      for (int i = 0; i < g_config->index.threads; i++) {
 | 
				
			||||||
        new std::thread([=]() {
 | 
					        std::thread([=]() {
 | 
				
			||||||
          SetThreadName("indexer" + std::to_string(i));
 | 
					          SetThreadName("indexer" + std::to_string(i));
 | 
				
			||||||
          Indexer_Main(diag_engine, file_consumer_shared, timestamp_manager,
 | 
					          Indexer_Main(diag_engine, file_consumer_shared, timestamp_manager,
 | 
				
			||||||
                       import_manager, import_pipeline_status, project,
 | 
					                       import_manager, import_pipeline_status, project,
 | 
				
			||||||
                       working_files, waiter);
 | 
					                       working_files, waiter);
 | 
				
			||||||
        });
 | 
					        }).detach();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Start scanning include directories before dispatching project
 | 
					      // Start scanning include directories before dispatching project
 | 
				
			||||||
 | 
				
			|||||||
@ -11,8 +11,8 @@ MAKE_REFLECT_STRUCT(In_Shutdown, id);
 | 
				
			|||||||
REGISTER_IN_MESSAGE(In_Shutdown);
 | 
					REGISTER_IN_MESSAGE(In_Shutdown);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Out_Shutdown : public lsOutMessage<Out_Shutdown> {
 | 
					struct Out_Shutdown : public lsOutMessage<Out_Shutdown> {
 | 
				
			||||||
  lsRequestId id;         // defaults to std::monostate (null)
 | 
					  lsRequestId id;
 | 
				
			||||||
  std::monostate result;  // null
 | 
					  JsonNull result;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result);
 | 
					MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -39,7 +39,6 @@ struct Handler_TextDocumentDidChange
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    clang_complete->NotifyEdit(path);
 | 
					    clang_complete->NotifyEdit(path);
 | 
				
			||||||
    clang_complete->DiagnosticsUpdate(
 | 
					    clang_complete->DiagnosticsUpdate(
 | 
				
			||||||
        std::monostate(),
 | 
					 | 
				
			||||||
        request->params.textDocument.AsTextDocumentIdentifier());
 | 
					        request->params.textDocument.AsTextDocumentIdentifier());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -5,41 +5,40 @@
 | 
				
			|||||||
namespace {
 | 
					namespace {
 | 
				
			||||||
MethodType kMethodType = "textDocument/hover";
 | 
					MethodType kMethodType = "textDocument/hover";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::pair<std::string_view, std::string_view> GetCommentsAndHover(
 | 
					// Find the comments for |sym|, if any.
 | 
				
			||||||
    QueryDatabase* db,
 | 
					std::optional<lsMarkedString> GetComments(QueryDatabase* db, SymbolRef sym) {
 | 
				
			||||||
    SymbolRef sym) {
 | 
					  std::optional<lsMarkedString> ret;
 | 
				
			||||||
  switch (sym.kind) {
 | 
					  WithEntity(db, sym, [&](const auto& entity) {
 | 
				
			||||||
    case SymbolKind::Type: {
 | 
					    if (const auto* def = entity.AnyDef())
 | 
				
			||||||
      if (const auto* def = db->GetType(sym).AnyDef()) {
 | 
					      if (!def->comments.empty()) {
 | 
				
			||||||
        return {def->comments, !def->hover.empty()
 | 
					        lsMarkedString m;
 | 
				
			||||||
                                   ? std::string_view(def->hover)
 | 
					        m.value = def->comments;
 | 
				
			||||||
                                   : std::string_view(def->detailed_name)};
 | 
					        ret = m;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					  });
 | 
				
			||||||
    }
 | 
					  return ret;
 | 
				
			||||||
    case SymbolKind::Func: {
 | 
					}
 | 
				
			||||||
      if (const auto* def = db->GetFunc(sym).AnyDef()) {
 | 
					
 | 
				
			||||||
        return {def->comments, !def->hover.empty()
 | 
					// Returns the hover or detailed name for `sym`, if any.
 | 
				
			||||||
                                   ? std::string_view(def->hover)
 | 
					std::optional<lsMarkedString> GetHoverOrName(QueryDatabase* db,
 | 
				
			||||||
                                   : std::string_view(def->detailed_name)};
 | 
					  const std::string& language,
 | 
				
			||||||
 | 
					  SymbolRef sym) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  std::optional<lsMarkedString> ret;
 | 
				
			||||||
 | 
					  WithEntity(db, sym, [&](const auto& entity) {
 | 
				
			||||||
 | 
					    if (const auto* def = entity.AnyDef()) {
 | 
				
			||||||
 | 
					      lsMarkedString m;
 | 
				
			||||||
 | 
					      m.language = language;
 | 
				
			||||||
 | 
					      if (!def->hover.empty()) {
 | 
				
			||||||
 | 
					        m.value = def->hover;
 | 
				
			||||||
 | 
					        ret = m;
 | 
				
			||||||
 | 
					      } else if (!def->detailed_name.empty()) {
 | 
				
			||||||
 | 
					        m.value = def->detailed_name;
 | 
				
			||||||
 | 
					        ret = m;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    case SymbolKind::Var: {
 | 
					  });
 | 
				
			||||||
      if (const auto* def = db->GetVar(sym).AnyDef()) {
 | 
					  return ret;
 | 
				
			||||||
        return {def->comments, !def->hover.empty()
 | 
					 | 
				
			||||||
                                   ? std::string_view(def->hover)
 | 
					 | 
				
			||||||
                                   : std::string_view(def->detailed_name)};
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    case SymbolKind::File:
 | 
					 | 
				
			||||||
    case SymbolKind::Invalid: {
 | 
					 | 
				
			||||||
      assert(false && "unexpected");
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return {"", ""};
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct In_TextDocumentHover : public RequestInMessage {
 | 
					struct In_TextDocumentHover : public RequestInMessage {
 | 
				
			||||||
@ -66,7 +65,7 @@ void Reflect(Writer& visitor, Out_TextDocumentHover& value) {
 | 
				
			|||||||
  if (value.result)
 | 
					  if (value.result)
 | 
				
			||||||
    REFLECT_MEMBER(result);
 | 
					    REFLECT_MEMBER(result);
 | 
				
			||||||
  else {
 | 
					  else {
 | 
				
			||||||
    // Empty std::optional<> is elided by the default serializer, we need to write
 | 
					    // Empty optional<> is elided by the default serializer, we need to write
 | 
				
			||||||
    // |null| to be compliant with the LSP.
 | 
					    // |null| to be compliant with the LSP.
 | 
				
			||||||
    visitor.Key("result");
 | 
					    visitor.Key("result");
 | 
				
			||||||
    visitor.Null();
 | 
					    visitor.Null();
 | 
				
			||||||
@ -77,11 +76,11 @@ void Reflect(Writer& visitor, Out_TextDocumentHover& value) {
 | 
				
			|||||||
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
 | 
					struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
 | 
				
			||||||
  MethodType GetMethodType() const override { return kMethodType; }
 | 
					  MethodType GetMethodType() const override { return kMethodType; }
 | 
				
			||||||
  void Run(In_TextDocumentHover* request) override {
 | 
					  void Run(In_TextDocumentHover* request) override {
 | 
				
			||||||
 | 
					    auto& params = request->params;
 | 
				
			||||||
    QueryFile* file;
 | 
					    QueryFile* file;
 | 
				
			||||||
    if (!FindFileOrFail(db, project, request->id,
 | 
					    if (!FindFileOrFail(db, project, request->id,
 | 
				
			||||||
                        request->params.textDocument.uri.GetPath(), &file)) {
 | 
					                        params.textDocument.uri.GetPath(), &file))
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WorkingFile* working_file =
 | 
					    WorkingFile* working_file =
 | 
				
			||||||
        working_files->GetFileByFilename(file->def->path);
 | 
					        working_files->GetFileByFilename(file->def->path);
 | 
				
			||||||
@ -90,25 +89,23 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
 | 
				
			|||||||
    out.id = request->id;
 | 
					    out.id = request->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (SymbolRef sym :
 | 
					    for (SymbolRef sym :
 | 
				
			||||||
         FindSymbolsAtLocation(working_file, file, request->params.position)) {
 | 
					         FindSymbolsAtLocation(working_file, file, params.position)) {
 | 
				
			||||||
      // Found symbol. Return hover.
 | 
					      // Found symbol. Return hover.
 | 
				
			||||||
      std::optional<lsRange> ls_range = GetLsRange(
 | 
					      std::optional<lsRange> ls_range = GetLsRange(
 | 
				
			||||||
          working_files->GetFileByFilename(file->def->path), sym.range);
 | 
					          working_files->GetFileByFilename(file->def->path), sym.range);
 | 
				
			||||||
      if (!ls_range)
 | 
					      if (!ls_range)
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      std::pair<std::string_view, std::string_view> comments_hover =
 | 
					      std::optional<lsMarkedString> comments = GetComments(db, sym);
 | 
				
			||||||
          GetCommentsAndHover(db, sym);
 | 
					      std::optional<lsMarkedString> hover =
 | 
				
			||||||
      if (comments_hover.first.size() || comments_hover.second.size()) {
 | 
					          GetHoverOrName(db, file->def->language, sym);
 | 
				
			||||||
 | 
					      if (comments || hover) {
 | 
				
			||||||
        out.result = Out_TextDocumentHover::Result();
 | 
					        out.result = Out_TextDocumentHover::Result();
 | 
				
			||||||
        if (comments_hover.first.size()) {
 | 
					 | 
				
			||||||
          out.result->contents.emplace_back(comments_hover.first);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (comments_hover.second.size()) {
 | 
					 | 
				
			||||||
          out.result->contents.emplace_back(lsMarkedString1{
 | 
					 | 
				
			||||||
              std::string_view(file->def->language), comments_hover.second});
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        out.result->range = *ls_range;
 | 
					        out.result->range = *ls_range;
 | 
				
			||||||
 | 
					        if (comments)
 | 
				
			||||||
 | 
					          out.result->contents.push_back(*comments);
 | 
				
			||||||
 | 
					        if (hover)
 | 
				
			||||||
 | 
					          out.result->contents.push_back(*hover);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ struct Handler_WorkspaceDidChangeConfiguration
 | 
				
			|||||||
                       std::to_string(project->entries.size()) + " files)");
 | 
					                       std::to_string(project->entries.size()) + " files)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    time.Reset();
 | 
					    time.Reset();
 | 
				
			||||||
    project->Index(QueueManager::instance(), working_files, std::monostate());
 | 
					    project->Index(QueueManager::instance(), working_files, lsRequestId());
 | 
				
			||||||
    time.ResetAndPrint(
 | 
					    time.ResetAndPrint(
 | 
				
			||||||
        "[perf] Dispatched workspace/didChangeConfiguration index requests");
 | 
					        "[perf] Dispatched workspace/didChangeConfiguration index requests");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,40 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
MethodType kMethodType_Unknown = "$unknown";
 | 
					MethodType kMethodType_Unknown = "$unknown";
 | 
				
			||||||
MethodType kMethodType_Exit = "exit";
 | 
					MethodType kMethodType_Exit = "exit";
 | 
				
			||||||
MethodType kMethodType_TextDocumentPublishDiagnostics = "textDocument/publishDiagnostics";
 | 
					MethodType kMethodType_TextDocumentPublishDiagnostics =
 | 
				
			||||||
MethodType kMethodType_CclsPublishInactiveRegions = "$ccls/publishInactiveRegions";
 | 
					    "textDocument/publishDiagnostics";
 | 
				
			||||||
MethodType kMethodType_CclsPublishSemanticHighlighting = "$ccls/publishSemanticHighlighting";
 | 
					MethodType kMethodType_CclsPublishInactiveRegions =
 | 
				
			||||||
 | 
					    "$ccls/publishInactiveRegions";
 | 
				
			||||||
 | 
					MethodType kMethodType_CclsPublishSemanticHighlighting =
 | 
				
			||||||
 | 
					    "$ccls/publishSemanticHighlighting";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Reflect(Reader& visitor, lsRequestId& value) {
 | 
				
			||||||
 | 
					  if (visitor.IsInt64()) {
 | 
				
			||||||
 | 
					    value.type = lsRequestId::kInt;
 | 
				
			||||||
 | 
					    value.value = visitor.GetInt64();
 | 
				
			||||||
 | 
					  } else if (visitor.IsInt()) {
 | 
				
			||||||
 | 
					    value.type = lsRequestId::kInt;
 | 
				
			||||||
 | 
					    value.value = visitor.GetInt();
 | 
				
			||||||
 | 
					  } else if (visitor.IsString()) {
 | 
				
			||||||
 | 
					    value.type = lsRequestId::kString;
 | 
				
			||||||
 | 
					    value.value = atoll(visitor.GetString().c_str());
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    value.type = lsRequestId::kNone;
 | 
				
			||||||
 | 
					    value.value = -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Reflect(Writer& visitor, lsRequestId& value) {
 | 
				
			||||||
 | 
					  switch (value.type) {
 | 
				
			||||||
 | 
					  case lsRequestId::kNone:
 | 
				
			||||||
 | 
					    visitor.Null();
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case lsRequestId::kInt:
 | 
				
			||||||
 | 
					    visitor.Int(value.value);
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case lsRequestId::kString:
 | 
				
			||||||
 | 
					    auto s = std::to_string(value.value);
 | 
				
			||||||
 | 
					    visitor.String(s.c_str(), s.length());
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										15
									
								
								src/method.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/method.h
									
									
									
									
									
								
							@ -12,7 +12,18 @@ extern MethodType kMethodType_TextDocumentPublishDiagnostics;
 | 
				
			|||||||
extern MethodType kMethodType_CclsPublishInactiveRegions;
 | 
					extern MethodType kMethodType_CclsPublishInactiveRegions;
 | 
				
			||||||
extern MethodType kMethodType_CclsPublishSemanticHighlighting;
 | 
					extern MethodType kMethodType_CclsPublishSemanticHighlighting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using lsRequestId = std::variant<std::monostate, int64_t, std::string>;
 | 
					struct lsRequestId {
 | 
				
			||||||
 | 
					  // The client can send the request id as an int or a string. We should output
 | 
				
			||||||
 | 
					  // the same format we received.
 | 
				
			||||||
 | 
					  enum Type { kNone, kInt, kString };
 | 
				
			||||||
 | 
					  Type type = kNone;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int value = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool Valid() const { return type != kNone; }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					void Reflect(Reader& visitor, lsRequestId& value);
 | 
				
			||||||
 | 
					void Reflect(Writer& visitor, lsRequestId& value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct InMessage {
 | 
					struct InMessage {
 | 
				
			||||||
  virtual ~InMessage() = default;
 | 
					  virtual ~InMessage() = default;
 | 
				
			||||||
@ -32,6 +43,6 @@ struct RequestInMessage : public InMessage {
 | 
				
			|||||||
// NotificationInMessage does not have |id|.
 | 
					// NotificationInMessage does not have |id|.
 | 
				
			||||||
struct NotificationInMessage : public InMessage {
 | 
					struct NotificationInMessage : public InMessage {
 | 
				
			||||||
  lsRequestId GetRequestId() const override {
 | 
					  lsRequestId GetRequestId() const override {
 | 
				
			||||||
    return std::monostate();
 | 
					    return lsRequestId();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,6 @@
 | 
				
			|||||||
#include <optional>
 | 
					#include <optional>
 | 
				
			||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <unordered_map>
 | 
					#include <unordered_map>
 | 
				
			||||||
#include <variant>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class QueueManager;
 | 
					class QueueManager;
 | 
				
			||||||
 | 
				
			|||||||
@ -140,6 +140,15 @@ void Reflect(Writer& visitor, NtString& value) {
 | 
				
			|||||||
  visitor.String(s ? s : "");
 | 
					  visitor.String(s ? s : "");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Reflect(Reader& visitor, JsonNull& value) {
 | 
				
			||||||
 | 
					  assert(visitor.Format() == SerializeFormat::Json);
 | 
				
			||||||
 | 
					  visitor.GetNull();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Reflect(Writer& visitor, JsonNull& value) {
 | 
				
			||||||
 | 
					  visitor.Null();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Move this to indexer.cc
 | 
					// TODO: Move this to indexer.cc
 | 
				
			||||||
void Reflect(Reader& visitor, IndexInclude& value) {
 | 
					void Reflect(Reader& visitor, IndexInclude& value) {
 | 
				
			||||||
  REFLECT_MEMBER_START();
 | 
					  REFLECT_MEMBER_START();
 | 
				
			||||||
@ -299,15 +308,6 @@ void Reflect(TVisitor& visitor, IndexFile& value) {
 | 
				
			|||||||
  REFLECT_MEMBER_END();
 | 
					  REFLECT_MEMBER_END();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Reflect(Reader& visitor, std::monostate&) {
 | 
					 | 
				
			||||||
  assert(visitor.Format() == SerializeFormat::Json);
 | 
					 | 
				
			||||||
  visitor.GetNull();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Reflect(Writer& visitor, std::monostate&) {
 | 
					 | 
				
			||||||
  visitor.Null();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Reflect(Reader& visitor, SerializeFormat& value) {
 | 
					void Reflect(Reader& visitor, SerializeFormat& value) {
 | 
				
			||||||
  std::string fmt = visitor.GetString();
 | 
					  std::string fmt = visitor.GetString();
 | 
				
			||||||
  value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json;
 | 
					  value = fmt[0] == 'b' ? SerializeFormat::Binary : SerializeFormat::Json;
 | 
				
			||||||
 | 
				
			|||||||
@ -13,11 +13,12 @@
 | 
				
			|||||||
#include <string>
 | 
					#include <string>
 | 
				
			||||||
#include <string_view>
 | 
					#include <string_view>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
#include <variant>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class SerializeFormat { Binary, Json };
 | 
					enum class SerializeFormat { Binary, Json };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct JsonNull {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Reader {
 | 
					class Reader {
 | 
				
			||||||
 public:
 | 
					 public:
 | 
				
			||||||
  virtual ~Reader() {}
 | 
					  virtual ~Reader() {}
 | 
				
			||||||
@ -168,20 +169,18 @@ void Reflect(Writer& visitor, std::string_view& view);
 | 
				
			|||||||
void Reflect(Reader& visitor, NtString& value);
 | 
					void Reflect(Reader& visitor, NtString& value);
 | 
				
			||||||
void Reflect(Writer& visitor, NtString& value);
 | 
					void Reflect(Writer& visitor, NtString& value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// std::monostate is used to represent JSON null
 | 
					void Reflect(Reader& visitor, JsonNull& value);
 | 
				
			||||||
void Reflect(Reader& visitor, std::monostate&);
 | 
					void Reflect(Writer& visitor, JsonNull& value);
 | 
				
			||||||
void Reflect(Writer& visitor, std::monostate&);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Reflect(Reader& visitor, SerializeFormat& value);
 | 
					void Reflect(Reader& visitor, SerializeFormat& value);
 | 
				
			||||||
void Reflect(Writer& visitor, SerializeFormat& value);
 | 
					void Reflect(Writer& visitor, SerializeFormat& value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//// Type constructors
 | 
					//// Type constructors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ReflectMember std::optional<T> is used to represent TypeScript std::optional properties
 | 
					// ReflectMember std::optional<T> is used to represent TypeScript optional properties
 | 
				
			||||||
// (in `key: value` context).
 | 
					// (in `key: value` context).
 | 
				
			||||||
// Reflect std::optional<T> is used for a different purpose, whether an object is
 | 
					// Reflect std::optional<T> is used for a different purpose, whether an object is
 | 
				
			||||||
// nullable (possibly in `value` context). For the nullable semantics,
 | 
					// nullable (possibly in `value` context).
 | 
				
			||||||
// std::variant<std::monostate, T> is recommended.
 | 
					 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void Reflect(Reader& visitor, std::optional<T>& value) {
 | 
					void Reflect(Reader& visitor, std::optional<T>& value) {
 | 
				
			||||||
  if (visitor.IsNull()) {
 | 
					  if (visitor.IsNull()) {
 | 
				
			||||||
@ -243,57 +242,6 @@ void ReflectMember(Writer& visitor, const char* name, Maybe<T>& value) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Helper struct to reflect std::variant
 | 
					 | 
				
			||||||
template <size_t N, typename... Ts>
 | 
					 | 
				
			||||||
struct ReflectVariant {
 | 
					 | 
				
			||||||
  // If T appears in Ts..., we should set the value of std::variant<Ts...> to
 | 
					 | 
				
			||||||
  // what we get from Reader.
 | 
					 | 
				
			||||||
  template <typename T>
 | 
					 | 
				
			||||||
  void ReflectTag(Reader& visitor, std::variant<Ts...>& value) {
 | 
					 | 
				
			||||||
    if constexpr (std::disjunction_v<std::is_same<T, Ts>...>) {
 | 
					 | 
				
			||||||
      T a;
 | 
					 | 
				
			||||||
      Reflect(visitor, a);
 | 
					 | 
				
			||||||
      value = std::move(a);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void operator()(Reader& visitor, std::variant<Ts...>& value) {
 | 
					 | 
				
			||||||
    // Based on tag dispatch, call different ReflectTag helper.
 | 
					 | 
				
			||||||
    if (visitor.IsNull())
 | 
					 | 
				
			||||||
      ReflectTag<std::monostate>(visitor, value);
 | 
					 | 
				
			||||||
    // It is possible that IsInt64() && IsInt(). We don't call ReflectTag<int>
 | 
					 | 
				
			||||||
    // if int is not in Ts...
 | 
					 | 
				
			||||||
    else if (std::disjunction_v<std::is_same<int, Ts>...> && visitor.IsInt())
 | 
					 | 
				
			||||||
      ReflectTag<int>(visitor, value);
 | 
					 | 
				
			||||||
    else if (visitor.IsInt64())
 | 
					 | 
				
			||||||
      ReflectTag<int64_t>(visitor, value);
 | 
					 | 
				
			||||||
    else if (visitor.IsString())
 | 
					 | 
				
			||||||
      ReflectTag<std::string>(visitor, value);
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      assert(0);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Check which type the variant contains and call corresponding Reflect.
 | 
					 | 
				
			||||||
  void operator()(Writer& visitor, std::variant<Ts...>& value) {
 | 
					 | 
				
			||||||
    if (value.index() == N - 1)
 | 
					 | 
				
			||||||
      Reflect(visitor, std::get<N - 1>(value));
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
      ReflectVariant<N - 1, Ts...>()(visitor, value);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Writer reflection on std::variant recurses. This is induction basis.
 | 
					 | 
				
			||||||
template <typename... Ts>
 | 
					 | 
				
			||||||
struct ReflectVariant<0, Ts...> {
 | 
					 | 
				
			||||||
  void operator()(Writer& visitor, std::variant<Ts...>& value) {}
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// std::variant
 | 
					 | 
				
			||||||
template <typename TVisitor, typename... Ts>
 | 
					 | 
				
			||||||
void Reflect(TVisitor& visitor, std::variant<Ts...>& value) {
 | 
					 | 
				
			||||||
  ReflectVariant<sizeof...(Ts), Ts...>()(visitor, value);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// std::vector
 | 
					// std::vector
 | 
				
			||||||
template <typename T>
 | 
					template <typename T>
 | 
				
			||||||
void Reflect(Reader& visitor, std::vector<T>& values) {
 | 
					void Reflect(Reader& visitor, std::vector<T>& values) {
 | 
				
			||||||
 | 
				
			|||||||
@ -24,19 +24,15 @@ lsPosition GetPositionForOffset(const std::string& content, int offset) {
 | 
				
			|||||||
  if (offset >= content.size())
 | 
					  if (offset >= content.size())
 | 
				
			||||||
    offset = (int)content.size() - 1;
 | 
					    offset = (int)content.size() - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  lsPosition result;
 | 
					  int line = 0, col = 0;
 | 
				
			||||||
  int i = 0;
 | 
					  int i = 0;
 | 
				
			||||||
  while (i < offset) {
 | 
					  for (; i < offset; i++) {
 | 
				
			||||||
    if (content[i] == '\n') {
 | 
					    if (content[i] == '\n')
 | 
				
			||||||
      result.line += 1;
 | 
					      line++, col = 0;
 | 
				
			||||||
      result.character = 0;
 | 
					    else
 | 
				
			||||||
    } else {
 | 
					      col++;
 | 
				
			||||||
      result.character += 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ++i;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  return {line, col};
 | 
				
			||||||
  return result;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::vector<std::string> ToLines(const std::string& content) {
 | 
					std::vector<std::string> ToLines(const std::string& content) {
 | 
				
			||||||
@ -511,8 +507,8 @@ void WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // version: number | null
 | 
					  // version: number | null
 | 
				
			||||||
  if (std::holds_alternative<int>(change.textDocument.version))
 | 
					  if (change.textDocument.version)
 | 
				
			||||||
    file->version = std::get<int>(change.textDocument.version);
 | 
					    file->version = *change.textDocument.version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
 | 
					  for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
 | 
				
			||||||
    // Per the spec replace everything if the rangeLength and range are not set.
 | 
					    // Per the spec replace everything if the rangeLength and range are not set.
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user