mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
Semantic highlighting improvements.
- Semantic highlighting no longer disappears when switching between files. - Semantic highlighting for a symbol will remain stable as the file is edited. - Improved semantic highlighting colors. Progress indicator also now shows the number of remaining index jobs (not the total number).
This commit is contained in:
parent
9e6d33689f
commit
b2736f8822
@ -495,35 +495,6 @@ CompletionSession::CompletionSession(const Project::Entry& file,
|
|||||||
|
|
||||||
CompletionSession::~CompletionSession() {}
|
CompletionSession::~CompletionSession() {}
|
||||||
|
|
||||||
LruSessionCache::LruSessionCache(int max_entries) : max_entries_(max_entries) {}
|
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> LruSessionCache::TryGetEntry(
|
|
||||||
const std::string& filename) {
|
|
||||||
for (size_t i = 0; i < entries_.size(); ++i) {
|
|
||||||
if (entries_[i]->file.filename == filename)
|
|
||||||
return entries_[i];
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<CompletionSession> LruSessionCache::TryTakeEntry(
|
|
||||||
const std::string& filename) {
|
|
||||||
for (size_t i = 0; i < entries_.size(); ++i) {
|
|
||||||
if (entries_[i]->file.filename == filename) {
|
|
||||||
std::shared_ptr<CompletionSession> result = entries_[i];
|
|
||||||
entries_.erase(entries_.begin() + i);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LruSessionCache::InsertEntry(std::shared_ptr<CompletionSession> session) {
|
|
||||||
if (entries_.size() && entries_.size() >= max_entries_)
|
|
||||||
entries_.pop_back();
|
|
||||||
entries_.insert(entries_.begin(), session);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClangCompleteManager::ParseRequest::ParseRequest(const std::string& path)
|
ClangCompleteManager::ParseRequest::ParseRequest(const std::string& path)
|
||||||
: request_time(std::chrono::high_resolution_clock::now()), path(path) {}
|
: request_time(std::chrono::high_resolution_clock::now()), path(path) {}
|
||||||
|
|
||||||
@ -622,10 +593,10 @@ void ClangCompleteManager::NotifyClose(const std::string& filename) {
|
|||||||
|
|
||||||
// Take and drop. It's okay if we don't actually drop the file, it'll
|
// Take and drop. It's okay if we don't actually drop the file, it'll
|
||||||
// eventually get pushed out of the caches as the user opens other files.
|
// eventually get pushed out of the caches as the user opens other files.
|
||||||
auto preloaded_ptr = preloaded_sessions_.TryTakeEntry(filename);
|
auto preloaded_ptr = preloaded_sessions_.TryTake(filename);
|
||||||
LOG_IF_S(INFO, !!preloaded_ptr)
|
LOG_IF_S(INFO, !!preloaded_ptr)
|
||||||
<< "Dropped preloaded-based code completion session for " << filename;
|
<< "Dropped preloaded-based code completion session for " << filename;
|
||||||
auto completion_ptr = completion_sessions_.TryTakeEntry(filename);
|
auto completion_ptr = completion_sessions_.TryTake(filename);
|
||||||
LOG_IF_S(INFO, !!completion_ptr)
|
LOG_IF_S(INFO, !!completion_ptr)
|
||||||
<< "Dropped completion-based code completion session for " << filename;
|
<< "Dropped completion-based code completion session for " << filename;
|
||||||
|
|
||||||
@ -638,15 +609,15 @@ bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
|
|||||||
std::lock_guard<std::mutex> lock(sessions_lock_);
|
std::lock_guard<std::mutex> lock(sessions_lock_);
|
||||||
|
|
||||||
// Check for an existing CompletionSession.
|
// Check for an existing CompletionSession.
|
||||||
if (preloaded_sessions_.TryGetEntry(filename) ||
|
if (preloaded_sessions_.TryGet(filename) ||
|
||||||
completion_sessions_.TryGetEntry(filename)) {
|
completion_sessions_.TryGet(filename)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No CompletionSession, create new one.
|
// No CompletionSession, create new one.
|
||||||
auto session = std::make_shared<CompletionSession>(
|
auto session = std::make_shared<CompletionSession>(
|
||||||
project_->FindCompilationEntryForFile(filename), working_files_);
|
project_->FindCompilationEntryForFile(filename), working_files_);
|
||||||
preloaded_sessions_.InsertEntry(session);
|
preloaded_sessions_.Insert(session->file.filename, session);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,15 +629,15 @@ std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
|
|||||||
|
|
||||||
// Try to find a preloaded session.
|
// Try to find a preloaded session.
|
||||||
std::shared_ptr<CompletionSession> preloaded_session =
|
std::shared_ptr<CompletionSession> preloaded_session =
|
||||||
preloaded_sessions_.TryGetEntry(filename);
|
preloaded_sessions_.TryGet(filename);
|
||||||
|
|
||||||
if (preloaded_session) {
|
if (preloaded_session) {
|
||||||
// If this request is for a completion, we should move it to
|
// If this request is for a completion, we should move it to
|
||||||
// |completion_sessions|.
|
// |completion_sessions|.
|
||||||
if (mark_as_completion) {
|
if (mark_as_completion) {
|
||||||
assert(!completion_sessions_.TryGetEntry(filename));
|
assert(!completion_sessions_.TryGet(filename));
|
||||||
preloaded_sessions_.TryTakeEntry(filename);
|
preloaded_sessions_.TryTake(filename);
|
||||||
completion_sessions_.InsertEntry(preloaded_session);
|
completion_sessions_.Insert(filename, preloaded_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
return preloaded_session;
|
return preloaded_session;
|
||||||
@ -674,11 +645,11 @@ std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
|
|||||||
|
|
||||||
// Try to find a completion session. If none create one.
|
// Try to find a completion session. If none create one.
|
||||||
std::shared_ptr<CompletionSession> completion_session =
|
std::shared_ptr<CompletionSession> completion_session =
|
||||||
completion_sessions_.TryGetEntry(filename);
|
completion_sessions_.TryGet(filename);
|
||||||
if (!completion_session && create_if_needed) {
|
if (!completion_session && create_if_needed) {
|
||||||
completion_session = std::make_shared<CompletionSession>(
|
completion_session = std::make_shared<CompletionSession>(
|
||||||
project_->FindCompilationEntryForFile(filename), working_files_);
|
project_->FindCompilationEntryForFile(filename), working_files_);
|
||||||
completion_sessions_.InsertEntry(completion_session);
|
completion_sessions_.Insert(filename, completion_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
return completion_session;
|
return completion_session;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "clang_index.h"
|
#include "clang_index.h"
|
||||||
#include "clang_translation_unit.h"
|
#include "clang_translation_unit.h"
|
||||||
#include "language_server_api.h"
|
#include "language_server_api.h"
|
||||||
|
#include "lru_cache.h"
|
||||||
#include "project.h"
|
#include "project.h"
|
||||||
#include "threaded_queue.h"
|
#include "threaded_queue.h"
|
||||||
#include "working_files.h"
|
#include "working_files.h"
|
||||||
@ -33,21 +34,6 @@ struct CompletionSession
|
|||||||
~CompletionSession();
|
~CompletionSession();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LruSessionCache {
|
|
||||||
std::vector<std::shared_ptr<CompletionSession>> entries_;
|
|
||||||
int max_entries_;
|
|
||||||
|
|
||||||
LruSessionCache(int max_entries);
|
|
||||||
|
|
||||||
// Fetches the entry for |filename| and updates it's usage so it is less
|
|
||||||
// likely to be evicted.
|
|
||||||
std::shared_ptr<CompletionSession> TryGetEntry(const std::string& filename);
|
|
||||||
// TryGetEntry, except the return value captures ownership.
|
|
||||||
std::shared_ptr<CompletionSession> TryTakeEntry(const std::string& fiilename);
|
|
||||||
// Inserts an entry. Evicts the oldest unused entry if there is no space.
|
|
||||||
void InsertEntry(std::shared_ptr<CompletionSession> session);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ClangCompleteManager {
|
struct ClangCompleteManager {
|
||||||
using OnDiagnostic =
|
using OnDiagnostic =
|
||||||
std::function<void(std::string path,
|
std::function<void(std::string path,
|
||||||
@ -119,6 +105,8 @@ struct ClangCompleteManager {
|
|||||||
OnDiagnostic on_diagnostic_;
|
OnDiagnostic on_diagnostic_;
|
||||||
OnIndex on_index_;
|
OnIndex on_index_;
|
||||||
|
|
||||||
|
using LruSessionCache = LruCache<std::string, CompletionSession>;
|
||||||
|
|
||||||
// CompletionSession instances which are preloaded, ie, files which the user
|
// CompletionSession instances which are preloaded, ie, files which the user
|
||||||
// has viewed but not requested code completion for.
|
// has viewed but not requested code completion for.
|
||||||
LruSessionCache preloaded_sessions_;
|
LruSessionCache preloaded_sessions_;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "ipc_manager.h"
|
#include "ipc_manager.h"
|
||||||
#include "language_server_api.h"
|
#include "language_server_api.h"
|
||||||
#include "lex_utils.h"
|
#include "lex_utils.h"
|
||||||
|
#include "lru_cache.h"
|
||||||
#include "match.h"
|
#include "match.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
@ -144,9 +145,59 @@ void EmitInactiveLines(WorkingFile* working_file,
|
|||||||
IpcId::CqueryPublishInactiveRegions, out);
|
IpcId::CqueryPublishInactiveRegions, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Caches symbols for a single file for semantic highlighting to provide
|
||||||
|
// relatively stable ids. Only supports xxx files at a time.
|
||||||
|
struct SemanticHighlightSymbolCache {
|
||||||
|
struct Entry {
|
||||||
|
// The path this cache belongs to.
|
||||||
|
std::string path;
|
||||||
|
// Detailed symbol name to stable id.
|
||||||
|
using TNameToId = std::unordered_map<std::string, int>;
|
||||||
|
TNameToId detailed_type_name_to_stable_id;
|
||||||
|
TNameToId detailed_func_name_to_stable_id;
|
||||||
|
TNameToId detailed_var_name_to_stable_id;
|
||||||
|
|
||||||
|
explicit Entry(const std::string& path) : path(path) {}
|
||||||
|
|
||||||
|
int GetStableId(SymbolKind kind, const std::string& detailed_name) {
|
||||||
|
TNameToId* map = nullptr;
|
||||||
|
switch (kind) {
|
||||||
|
case SymbolKind::Type:
|
||||||
|
map = &detailed_type_name_to_stable_id;
|
||||||
|
break;
|
||||||
|
case SymbolKind::Func:
|
||||||
|
map = &detailed_func_name_to_stable_id;
|
||||||
|
break;
|
||||||
|
case SymbolKind::Var:
|
||||||
|
map = &detailed_var_name_to_stable_id;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(map);
|
||||||
|
auto it = map->find(detailed_name);
|
||||||
|
if (it != map->end())
|
||||||
|
return it->second;
|
||||||
|
return (*map)[detailed_name] = map->size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr static int kCacheSize = 10;
|
||||||
|
LruCache<std::string, Entry> cache_;
|
||||||
|
|
||||||
|
SemanticHighlightSymbolCache() : cache_(kCacheSize) {}
|
||||||
|
|
||||||
|
std::shared_ptr<Entry> GetCacheForFile(const std::string& path) {
|
||||||
|
return cache_.Get(path, [&]() { return std::make_shared<Entry>(path); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void EmitSemanticHighlighting(QueryDatabase* db,
|
void EmitSemanticHighlighting(QueryDatabase* db,
|
||||||
|
SemanticHighlightSymbolCache* semantic_cache,
|
||||||
WorkingFile* working_file,
|
WorkingFile* working_file,
|
||||||
QueryFile* file) {
|
QueryFile* file) {
|
||||||
|
assert(file->def);
|
||||||
auto map_symbol_kind_to_symbol_type = [](SymbolKind kind) {
|
auto map_symbol_kind_to_symbol_type = [](SymbolKind kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case SymbolKind::Type:
|
case SymbolKind::Type:
|
||||||
@ -161,11 +212,16 @@ void EmitSemanticHighlighting(QueryDatabase* db,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto semantic_cache_for_file =
|
||||||
|
semantic_cache->GetCacheForFile(file->def->path);
|
||||||
|
|
||||||
// Group symbols together.
|
// Group symbols together.
|
||||||
std::unordered_map<SymbolIdx, Out_CqueryPublishSemanticHighlighting::Symbol>
|
std::unordered_map<SymbolIdx, Out_CqueryPublishSemanticHighlighting::Symbol>
|
||||||
grouped_symbols;
|
grouped_symbols;
|
||||||
for (SymbolRef sym : file->def->all_symbols) {
|
for (SymbolRef sym : file->def->all_symbols) {
|
||||||
|
std::string detailed_name;
|
||||||
bool is_type_member = false;
|
bool is_type_member = false;
|
||||||
|
// This switch statement also filters out symbols that are not highlighted.
|
||||||
switch (sym.idx.kind) {
|
switch (sym.idx.kind) {
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
QueryFunc* func = &db->funcs[sym.idx.idx];
|
QueryFunc* func = &db->funcs[sym.idx.idx];
|
||||||
@ -174,6 +230,7 @@ void EmitSemanticHighlighting(QueryDatabase* db,
|
|||||||
if (func->def->is_operator)
|
if (func->def->is_operator)
|
||||||
continue; // applies to for loop
|
continue; // applies to for loop
|
||||||
is_type_member = func->def->declaring_type.has_value();
|
is_type_member = func->def->declaring_type.has_value();
|
||||||
|
detailed_name = func->def->short_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
@ -183,9 +240,14 @@ void EmitSemanticHighlighting(QueryDatabase* db,
|
|||||||
if (!var->def->is_local && !var->def->declaring_type)
|
if (!var->def->is_local && !var->def->declaring_type)
|
||||||
continue; // applies to for loop
|
continue; // applies to for loop
|
||||||
is_type_member = var->def->declaring_type.has_value();
|
is_type_member = var->def->declaring_type.has_value();
|
||||||
|
detailed_name = var->def->short_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SymbolKind::Type: {
|
case SymbolKind::Type: {
|
||||||
|
QueryType* type = &db->types[sym.idx.idx];
|
||||||
|
if (!type->def)
|
||||||
|
continue; // applies to for loop
|
||||||
|
detailed_name = type->def->detailed_name;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -199,8 +261,10 @@ void EmitSemanticHighlighting(QueryDatabase* db,
|
|||||||
it->second.ranges.push_back(*loc);
|
it->second.ranges.push_back(*loc);
|
||||||
} else {
|
} else {
|
||||||
Out_CqueryPublishSemanticHighlighting::Symbol symbol;
|
Out_CqueryPublishSemanticHighlighting::Symbol symbol;
|
||||||
|
symbol.stableId =
|
||||||
|
semantic_cache_for_file->GetStableId(sym.idx.kind, detailed_name);
|
||||||
symbol.type = map_symbol_kind_to_symbol_type(sym.idx.kind);
|
symbol.type = map_symbol_kind_to_symbol_type(sym.idx.kind);
|
||||||
symbol.is_type_member = is_type_member;
|
symbol.isTypeMember = is_type_member;
|
||||||
symbol.ranges.push_back(*loc);
|
symbol.ranges.push_back(*loc);
|
||||||
grouped_symbols[sym.idx] = symbol;
|
grouped_symbols[sym.idx] = symbol;
|
||||||
}
|
}
|
||||||
@ -1265,6 +1329,7 @@ bool QueryDb_ImportMain(Config* config,
|
|||||||
QueryDatabase* db,
|
QueryDatabase* db,
|
||||||
ImportManager* import_manager,
|
ImportManager* import_manager,
|
||||||
QueueManager* queue,
|
QueueManager* queue,
|
||||||
|
SemanticHighlightSymbolCache* semantic_cache,
|
||||||
WorkingFiles* working_files) {
|
WorkingFiles* working_files) {
|
||||||
EmitProgress(config, queue);
|
EmitProgress(config, queue);
|
||||||
|
|
||||||
@ -1369,7 +1434,7 @@ bool QueryDb_ImportMain(Config* config,
|
|||||||
QueryFileId file_id =
|
QueryFileId file_id =
|
||||||
db->usr_to_file[LowerPathIfCaseInsensitive(working_file->filename)];
|
db->usr_to_file[LowerPathIfCaseInsensitive(working_file->filename)];
|
||||||
QueryFile* file = &db->files[file_id.id];
|
QueryFile* file = &db->files[file_id.id];
|
||||||
EmitSemanticHighlighting(db, working_file, file);
|
EmitSemanticHighlighting(db, semantic_cache, working_file, file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1409,6 +1474,7 @@ bool QueryDbMainLoop(Config* config,
|
|||||||
FileConsumer::SharedState* file_consumer_shared,
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
ImportManager* import_manager,
|
ImportManager* import_manager,
|
||||||
TimestampManager* timestamp_manager,
|
TimestampManager* timestamp_manager,
|
||||||
|
SemanticHighlightSymbolCache* semantic_cache,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
ClangCompleteManager* clang_complete,
|
ClangCompleteManager* clang_complete,
|
||||||
IncludeComplete* include_complete,
|
IncludeComplete* include_complete,
|
||||||
@ -1870,7 +1936,7 @@ bool QueryDbMainLoop(Config* config,
|
|||||||
FindFileOrFail(db, nullopt, path, &file);
|
FindFileOrFail(db, nullopt, path, &file);
|
||||||
if (file && file->def) {
|
if (file && file->def) {
|
||||||
EmitInactiveLines(working_file, file->def->inactive_regions);
|
EmitInactiveLines(working_file, file->def->inactive_regions);
|
||||||
EmitSemanticHighlighting(db, working_file, file);
|
EmitSemanticHighlighting(db, semantic_cache, working_file, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
time.ResetAndPrint(
|
time.ResetAndPrint(
|
||||||
@ -2924,7 +2990,7 @@ bool QueryDbMainLoop(Config* config,
|
|||||||
has_work |= import_manager->HasActiveQuerydbImports();
|
has_work |= import_manager->HasActiveQuerydbImports();
|
||||||
has_work |= queue->HasWork();
|
has_work |= queue->HasWork();
|
||||||
has_work |= QueryDb_ImportMain(config, db, import_manager, queue,
|
has_work |= QueryDb_ImportMain(config, db, import_manager, queue,
|
||||||
working_files);
|
semantic_cache, working_files);
|
||||||
if (!has_work)
|
if (!has_work)
|
||||||
++idle_count;
|
++idle_count;
|
||||||
else
|
else
|
||||||
@ -2956,8 +3022,10 @@ bool QueryDbMainLoop(Config* config,
|
|||||||
// TODO: consider rate-limiting and checking for IPC messages so we don't
|
// TODO: consider rate-limiting and checking for IPC messages so we don't
|
||||||
// block requests / we can serve partial requests.
|
// block requests / we can serve partial requests.
|
||||||
|
|
||||||
if (QueryDb_ImportMain(config, db, import_manager, queue, working_files))
|
if (QueryDb_ImportMain(config, db, import_manager, queue, semantic_cache,
|
||||||
|
working_files)) {
|
||||||
did_work = true;
|
did_work = true;
|
||||||
|
}
|
||||||
|
|
||||||
return did_work;
|
return did_work;
|
||||||
}
|
}
|
||||||
@ -2968,6 +3036,7 @@ void RunQueryDbThread(const std::string& bin_name,
|
|||||||
QueueManager* queue) {
|
QueueManager* queue) {
|
||||||
bool exit_when_idle = false;
|
bool exit_when_idle = false;
|
||||||
Project project;
|
Project project;
|
||||||
|
SemanticHighlightSymbolCache semantic_cache;
|
||||||
WorkingFiles working_files;
|
WorkingFiles working_files;
|
||||||
FileConsumer::SharedState file_consumer_shared;
|
FileConsumer::SharedState file_consumer_shared;
|
||||||
|
|
||||||
@ -2993,7 +3062,7 @@ void RunQueryDbThread(const std::string& bin_name,
|
|||||||
bool did_work = QueryDbMainLoop(
|
bool did_work = QueryDbMainLoop(
|
||||||
config, &db, &exit_when_idle, waiter, queue, &project,
|
config, &db, &exit_when_idle, waiter, queue, &project,
|
||||||
&file_consumer_shared, &import_manager, ×tamp_manager,
|
&file_consumer_shared, &import_manager, ×tamp_manager,
|
||||||
&working_files, &clang_complete, &include_complete,
|
&semantic_cache, &working_files, &clang_complete, &include_complete,
|
||||||
global_code_complete_cache.get(), non_global_code_complete_cache.get(),
|
global_code_complete_cache.get(), non_global_code_complete_cache.get(),
|
||||||
signature_cache.get());
|
signature_cache.get());
|
||||||
|
|
||||||
|
@ -1517,8 +1517,9 @@ struct Out_CqueryPublishSemanticHighlighting
|
|||||||
: public lsOutMessage<Out_CqueryPublishSemanticHighlighting> {
|
: public lsOutMessage<Out_CqueryPublishSemanticHighlighting> {
|
||||||
enum class SymbolType { Type = 0, Function, Variable };
|
enum class SymbolType { Type = 0, Function, Variable };
|
||||||
struct Symbol {
|
struct Symbol {
|
||||||
|
std::size_t stableId = 0;
|
||||||
SymbolType type = SymbolType::Type;
|
SymbolType type = SymbolType::Type;
|
||||||
bool is_type_member = false;
|
bool isTypeMember = false;
|
||||||
NonElidedVector<lsRange> ranges;
|
NonElidedVector<lsRange> ranges;
|
||||||
};
|
};
|
||||||
struct Params {
|
struct Params {
|
||||||
@ -1531,7 +1532,8 @@ struct Out_CqueryPublishSemanticHighlighting
|
|||||||
MAKE_REFLECT_TYPE_PROXY(Out_CqueryPublishSemanticHighlighting::SymbolType, int);
|
MAKE_REFLECT_TYPE_PROXY(Out_CqueryPublishSemanticHighlighting::SymbolType, int);
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting::Symbol,
|
MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting::Symbol,
|
||||||
type,
|
type,
|
||||||
is_type_member,
|
isTypeMember,
|
||||||
|
stableId,
|
||||||
ranges);
|
ranges);
|
||||||
MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting::Params,
|
MAKE_REFLECT_STRUCT(Out_CqueryPublishSemanticHighlighting::Params,
|
||||||
uri,
|
uri,
|
||||||
|
Loading…
Reference in New Issue
Block a user