mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-07 17:32:14 +00:00
Include variable type and function signature in qualified name (better outline and workspace symbol search). Also add WIP rename provider.
This commit is contained in:
parent
71d1b1ffc6
commit
031c0c2011
@ -356,6 +356,7 @@ lsSymbolInformation GetSymbolInfo(QueryableDatabase* db, WorkingFiles* working_f
|
|||||||
}
|
}
|
||||||
case SymbolKind::Func: {
|
case SymbolKind::Func: {
|
||||||
QueryableFuncDef* def = symbol.ResolveFunc(db);
|
QueryableFuncDef* def = symbol.ResolveFunc(db);
|
||||||
|
|
||||||
info.name = def->def.qualified_name;
|
info.name = def->def.qualified_name;
|
||||||
if (def->def.declaring_type.has_value()) {
|
if (def->def.declaring_type.has_value()) {
|
||||||
info.kind = lsSymbolKind::Method;
|
info.kind = lsSymbolKind::Method;
|
||||||
@ -368,7 +369,7 @@ lsSymbolInformation GetSymbolInfo(QueryableDatabase* db, WorkingFiles* working_f
|
|||||||
}
|
}
|
||||||
case SymbolKind::Var: {
|
case SymbolKind::Var: {
|
||||||
QueryableVarDef* def = symbol.ResolveVar(db);
|
QueryableVarDef* def = symbol.ResolveVar(db);
|
||||||
info.name = def->def.qualified_name;
|
info.name += def->def.qualified_name;
|
||||||
info.kind = lsSymbolKind::Variable;
|
info.kind = lsSymbolKind::Variable;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -433,6 +434,38 @@ void AddCodeLens(
|
|||||||
common->result->push_back(code_lens);
|
common->result->push_back(code_lens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lsWorkspaceEdit BuildWorkspaceEdit(QueryableDatabase* db, WorkingFiles* working_files, const std::vector<QueryableLocation>& locations, const std::string& new_text) {
|
||||||
|
std::unordered_map<QueryFileId, lsTextDocumentEdit> path_to_edit;
|
||||||
|
|
||||||
|
for (auto& location : locations) {
|
||||||
|
optional<lsLocation> ls_location = GetLsLocation(db, working_files, location);
|
||||||
|
if (!ls_location)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (path_to_edit.find(location.path) == path_to_edit.end()) {
|
||||||
|
path_to_edit[location.path] = lsTextDocumentEdit();
|
||||||
|
|
||||||
|
const std::string& path = db->files[location.path.id].def.usr;
|
||||||
|
path_to_edit[location.path].textDocument.uri = lsDocumentUri::FromPath(path);
|
||||||
|
|
||||||
|
WorkingFile* working_file = working_files->GetFileByFilename(path);
|
||||||
|
if (working_file)
|
||||||
|
path_to_edit[location.path].textDocument.version = working_file->version;
|
||||||
|
}
|
||||||
|
|
||||||
|
lsTextEdit edit;
|
||||||
|
edit.range = ls_location->range;
|
||||||
|
edit.newText = new_text;
|
||||||
|
path_to_edit[location.path].edits.push_back(edit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
lsWorkspaceEdit edit;
|
||||||
|
for (const auto& changes : path_to_edit)
|
||||||
|
edit.documentChanges.push_back(changes.second);
|
||||||
|
return edit;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
@ -536,6 +569,7 @@ std::unique_ptr<IpcMessageQueue> BuildIpcMessageQueue(const std::string& name, s
|
|||||||
RegisterId<Ipc_TextDocumentDidChange>(ipc.get());
|
RegisterId<Ipc_TextDocumentDidChange>(ipc.get());
|
||||||
RegisterId<Ipc_TextDocumentDidClose>(ipc.get());
|
RegisterId<Ipc_TextDocumentDidClose>(ipc.get());
|
||||||
RegisterId<Ipc_TextDocumentDidSave>(ipc.get());
|
RegisterId<Ipc_TextDocumentDidSave>(ipc.get());
|
||||||
|
RegisterId<Ipc_TextDocumentRename>(ipc.get());
|
||||||
RegisterId<Ipc_TextDocumentComplete>(ipc.get());
|
RegisterId<Ipc_TextDocumentComplete>(ipc.get());
|
||||||
RegisterId<Ipc_TextDocumentDefinition>(ipc.get());
|
RegisterId<Ipc_TextDocumentDefinition>(ipc.get());
|
||||||
RegisterId<Ipc_TextDocumentDocumentHighlight>(ipc.get());
|
RegisterId<Ipc_TextDocumentDocumentHighlight>(ipc.get());
|
||||||
@ -560,6 +594,7 @@ void RegisterMessageTypes() {
|
|||||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDidChange>();
|
MessageRegistry::instance()->Register<Ipc_TextDocumentDidChange>();
|
||||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDidClose>();
|
MessageRegistry::instance()->Register<Ipc_TextDocumentDidClose>();
|
||||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDidSave>();
|
MessageRegistry::instance()->Register<Ipc_TextDocumentDidSave>();
|
||||||
|
MessageRegistry::instance()->Register<Ipc_TextDocumentRename>();
|
||||||
MessageRegistry::instance()->Register<Ipc_TextDocumentComplete>();
|
MessageRegistry::instance()->Register<Ipc_TextDocumentComplete>();
|
||||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDefinition>();
|
MessageRegistry::instance()->Register<Ipc_TextDocumentDefinition>();
|
||||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentHighlight>();
|
MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentHighlight>();
|
||||||
@ -840,6 +875,37 @@ void QueryDbMainLoop(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case IpcId::TextDocumentRename: {
|
||||||
|
auto msg = static_cast<Ipc_TextDocumentRename*>(message.get());
|
||||||
|
|
||||||
|
QueryFileId file_id;
|
||||||
|
QueryableFile* file = FindFile(db, msg->params.textDocument.uri.GetPath(), &file_id);
|
||||||
|
if (!file) {
|
||||||
|
std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Out_TextDocumentRename response;
|
||||||
|
response.id = msg->id;
|
||||||
|
|
||||||
|
// TODO: consider refactoring into FindSymbolsAtLocation(file);
|
||||||
|
int target_line = msg->params.position.line + 1;
|
||||||
|
int target_column = msg->params.position.character + 1;
|
||||||
|
for (const SymbolRef& ref : file->def.all_symbols) {
|
||||||
|
if (ref.loc.range.start.line >= target_line && ref.loc.range.end.line <= target_line &&
|
||||||
|
ref.loc.range.start.column <= target_column && ref.loc.range.end.column >= target_column) {
|
||||||
|
|
||||||
|
// Found symbol. Return references to rename.
|
||||||
|
std::vector<QueryableLocation> uses = GetUsesOfSymbol(db, ref.idx);
|
||||||
|
response.result = BuildWorkspaceEdit(db, working_files, uses, msg->params.newName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Write(std::cerr);
|
||||||
|
SendOutMessageToClient(language_client, response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IpcId::TextDocumentCompletion: {
|
case IpcId::TextDocumentCompletion: {
|
||||||
// TODO: better performance
|
// TODO: better performance
|
||||||
auto msg = static_cast<Ipc_TextDocumentComplete*>(message.get());
|
auto msg = static_cast<Ipc_TextDocumentComplete*>(message.get());
|
||||||
@ -1320,6 +1386,8 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
|
|||||||
//response.result.capabilities.textDocumentSync->willSaveWaitUntil = true;
|
//response.result.capabilities.textDocumentSync->willSaveWaitUntil = true;
|
||||||
response.result.capabilities.textDocumentSync = lsTextDocumentSyncKind::Incremental;
|
response.result.capabilities.textDocumentSync = lsTextDocumentSyncKind::Incremental;
|
||||||
|
|
||||||
|
response.result.capabilities.renameProvider = true;
|
||||||
|
|
||||||
response.result.capabilities.completionProvider = lsCompletionOptions();
|
response.result.capabilities.completionProvider = lsCompletionOptions();
|
||||||
response.result.capabilities.completionProvider->resolveProvider = false;
|
response.result.capabilities.completionProvider->resolveProvider = false;
|
||||||
response.result.capabilities.completionProvider->triggerCharacters = { ".", "::", "->" };
|
response.result.capabilities.completionProvider->triggerCharacters = { ".", "::", "->" };
|
||||||
@ -1354,6 +1422,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
|
|||||||
case IpcId::TextDocumentDidChange:
|
case IpcId::TextDocumentDidChange:
|
||||||
case IpcId::TextDocumentDidClose:
|
case IpcId::TextDocumentDidClose:
|
||||||
case IpcId::TextDocumentDidSave:
|
case IpcId::TextDocumentDidSave:
|
||||||
|
case IpcId::TextDocumentRename:
|
||||||
case IpcId::TextDocumentCompletion:
|
case IpcId::TextDocumentCompletion:
|
||||||
case IpcId::TextDocumentDefinition:
|
case IpcId::TextDocumentDefinition:
|
||||||
case IpcId::TextDocumentDocumentHighlight:
|
case IpcId::TextDocumentDocumentHighlight:
|
||||||
|
@ -783,6 +783,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
ns->QualifiedName(decl->semanticContainer, var_def->def.short_name);
|
ns->QualifiedName(decl->semanticContainer, var_def->def.short_name);
|
||||||
var_def->def.hover = clang::ToString(clang_getTypeSpelling(clang_getCursorType(decl->cursor)));
|
var_def->def.hover = clang::ToString(clang_getTypeSpelling(clang_getCursorType(decl->cursor)));
|
||||||
|
|
||||||
|
// Include type in qualified name.
|
||||||
|
if (!var_def->def.hover.empty())
|
||||||
|
var_def->def.qualified_name = var_def->def.hover + " " + var_def->def.qualified_name;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
if (decl->isDefinition) {
|
if (decl->isDefinition) {
|
||||||
@ -890,6 +893,19 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
|||||||
// TODO: we should build this ourselves. It doesn't include parameter names for functions.
|
// TODO: we should build this ourselves. It doesn't include parameter names for functions.
|
||||||
func_def->def.hover = decl_cursor.get_type_description();
|
func_def->def.hover = decl_cursor.get_type_description();
|
||||||
|
|
||||||
|
|
||||||
|
// Update qualified name to include function signature
|
||||||
|
// TODO: make this less hideous
|
||||||
|
auto it = std::find(func_def->def.hover.begin(), func_def->def.hover.end(), '(');
|
||||||
|
if (it != func_def->def.hover.end()) {
|
||||||
|
std::string new_qualified_name;
|
||||||
|
new_qualified_name.resize(func_def->def.hover.size() + func_def->def.qualified_name.size() + 1);
|
||||||
|
std::copy(func_def->def.hover.begin(), it, new_qualified_name.begin());
|
||||||
|
std::copy(func_def->def.qualified_name.begin(), func_def->def.qualified_name.end(), new_qualified_name.begin() + std::distance(func_def->def.hover.begin(), it));
|
||||||
|
std::copy(it, func_def->def.hover.end(), new_qualified_name.begin() + std::distance(func_def->def.hover.begin(), it) + func_def->def.qualified_name.size());
|
||||||
|
func_def->def.qualified_name = new_qualified_name;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: return type
|
// TODO: return type
|
||||||
//decl_cursor.get_type_description()
|
//decl_cursor.get_type_description()
|
||||||
//func_def->def.return_type =
|
//func_def->def.return_type =
|
||||||
|
@ -18,6 +18,8 @@ const char* IpcIdToString(IpcId id) {
|
|||||||
return "textDocument/didClose";
|
return "textDocument/didClose";
|
||||||
case IpcId::TextDocumentDidSave:
|
case IpcId::TextDocumentDidSave:
|
||||||
return "textDocument/didSave";
|
return "textDocument/didSave";
|
||||||
|
case IpcId::TextDocumentRename:
|
||||||
|
return "textDocument/rename";
|
||||||
case IpcId::TextDocumentCompletion:
|
case IpcId::TextDocumentCompletion:
|
||||||
return "textDocument/completion";
|
return "textDocument/completion";
|
||||||
case IpcId::TextDocumentDefinition:
|
case IpcId::TextDocumentDefinition:
|
||||||
|
@ -14,6 +14,7 @@ enum class IpcId : int {
|
|||||||
TextDocumentDidChange,
|
TextDocumentDidChange,
|
||||||
TextDocumentDidClose,
|
TextDocumentDidClose,
|
||||||
TextDocumentDidSave,
|
TextDocumentDidSave,
|
||||||
|
TextDocumentRename,
|
||||||
TextDocumentCompletion,
|
TextDocumentCompletion,
|
||||||
TextDocumentDefinition,
|
TextDocumentDefinition,
|
||||||
TextDocumentDocumentHighlight,
|
TextDocumentDocumentHighlight,
|
||||||
|
@ -336,7 +336,7 @@ MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri);
|
|||||||
struct lsVersionedTextDocumentIdentifier {
|
struct lsVersionedTextDocumentIdentifier {
|
||||||
lsDocumentUri uri;
|
lsDocumentUri uri;
|
||||||
// The version number of this document.
|
// The version number of this document.
|
||||||
int version;
|
int version = 0;
|
||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsVersionedTextDocumentIdentifier, uri, version);
|
MAKE_REFLECT_STRUCT(lsVersionedTextDocumentIdentifier, uri, version);
|
||||||
|
|
||||||
@ -488,6 +488,17 @@ struct lsTextDocumentEdit {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits);
|
MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits);
|
||||||
|
|
||||||
|
struct lsWorkspaceEdit {
|
||||||
|
// Holds changes to existing resources.
|
||||||
|
// changes ? : { [uri:string]: TextEdit[]; };
|
||||||
|
|
||||||
|
// An array of `TextDocumentEdit`s to express changes to specific a specific
|
||||||
|
// version of a text document. Whether a client supports versioned document
|
||||||
|
// edits is expressed via `WorkspaceClientCapabilites.versionedWorkspaceEdit`.
|
||||||
|
std::vector<lsTextDocumentEdit> documentChanges;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(lsWorkspaceEdit, documentChanges);
|
||||||
|
|
||||||
// A document highlight kind.
|
// A document highlight kind.
|
||||||
enum class lsDocumentHighlightKind {
|
enum class lsDocumentHighlightKind {
|
||||||
// A textual occurrence.
|
// A textual occurrence.
|
||||||
@ -511,7 +522,6 @@ struct lsDocumentHighlight {
|
|||||||
};
|
};
|
||||||
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind);
|
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind);
|
||||||
|
|
||||||
// TODO: WorkspaceEdit
|
|
||||||
// TODO: DocumentFilter
|
// TODO: DocumentFilter
|
||||||
// TODO: DocumentSelector
|
// TODO: DocumentSelector
|
||||||
|
|
||||||
@ -1116,6 +1126,35 @@ MAKE_REFLECT_STRUCT(Ipc_TextDocumentDidSave, params);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Rename
|
||||||
|
struct Ipc_TextDocumentRename : public IpcMessage<Ipc_TextDocumentRename> {
|
||||||
|
struct Params {
|
||||||
|
// The document to format.
|
||||||
|
lsTextDocumentIdentifier textDocument;
|
||||||
|
|
||||||
|
// The position at which this request was sent.
|
||||||
|
lsPosition position;
|
||||||
|
|
||||||
|
// The new name of the symbol. If the given name is not valid the
|
||||||
|
// request must return a [ResponseError](#ResponseError) with an
|
||||||
|
// appropriate message set.
|
||||||
|
std::string newName;
|
||||||
|
};
|
||||||
|
const static IpcId kIpcId = IpcId::TextDocumentRename;
|
||||||
|
|
||||||
|
lsRequestId id;
|
||||||
|
Params params;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentRename::Params, textDocument, position, newName);
|
||||||
|
MAKE_REFLECT_STRUCT(Ipc_TextDocumentRename, id, params);
|
||||||
|
struct Out_TextDocumentRename : public lsOutMessage<Out_TextDocumentRename> {
|
||||||
|
lsRequestId id;
|
||||||
|
lsWorkspaceEdit result;
|
||||||
|
};
|
||||||
|
MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Code completion
|
// Code completion
|
||||||
|
@ -167,6 +167,7 @@ void WorkingFiles::OnOpen(const Ipc_TextDocumentDidOpen::Params& open) {
|
|||||||
|
|
||||||
// The file may already be open.
|
// The file may already be open.
|
||||||
if (WorkingFile* file = GetFileByFilename(filename)) {
|
if (WorkingFile* file = GetFileByFilename(filename)) {
|
||||||
|
file->version = open.textDocument.version;
|
||||||
file->content = content;
|
file->content = content;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -182,6 +183,7 @@ void WorkingFiles::OnChange(const Ipc_TextDocumentDidChange::Params& change) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file->version = change.textDocument.version;
|
||||||
//std::cerr << "VERSION " << change.textDocument.version << std::endl;
|
//std::cerr << "VERSION " << change.textDocument.version << std::endl;
|
||||||
|
|
||||||
for (const Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
|
for (const Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
|
||||||
|
@ -39,6 +39,7 @@ struct WorkingFile {
|
|||||||
Change(int disk_line, int delta);
|
Change(int disk_line, int delta);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int version = 0;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string content;
|
std::string content;
|
||||||
std::vector<Change> changes;
|
std::vector<Change> changes;
|
||||||
|
Loading…
Reference in New Issue
Block a user