mirror of
https://github.com/MaskRay/ccls.git
synced 2025-01-31 18:00:26 +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: {
|
||||
QueryableFuncDef* def = symbol.ResolveFunc(db);
|
||||
|
||||
info.name = def->def.qualified_name;
|
||||
if (def->def.declaring_type.has_value()) {
|
||||
info.kind = lsSymbolKind::Method;
|
||||
@ -368,7 +369,7 @@ lsSymbolInformation GetSymbolInfo(QueryableDatabase* db, WorkingFiles* working_f
|
||||
}
|
||||
case SymbolKind::Var: {
|
||||
QueryableVarDef* def = symbol.ResolveVar(db);
|
||||
info.name = def->def.qualified_name;
|
||||
info.name += def->def.qualified_name;
|
||||
info.kind = lsSymbolKind::Variable;
|
||||
break;
|
||||
}
|
||||
@ -433,6 +434,38 @@ void AddCodeLens(
|
||||
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
|
||||
|
||||
|
||||
@ -536,6 +569,7 @@ std::unique_ptr<IpcMessageQueue> BuildIpcMessageQueue(const std::string& name, s
|
||||
RegisterId<Ipc_TextDocumentDidChange>(ipc.get());
|
||||
RegisterId<Ipc_TextDocumentDidClose>(ipc.get());
|
||||
RegisterId<Ipc_TextDocumentDidSave>(ipc.get());
|
||||
RegisterId<Ipc_TextDocumentRename>(ipc.get());
|
||||
RegisterId<Ipc_TextDocumentComplete>(ipc.get());
|
||||
RegisterId<Ipc_TextDocumentDefinition>(ipc.get());
|
||||
RegisterId<Ipc_TextDocumentDocumentHighlight>(ipc.get());
|
||||
@ -560,6 +594,7 @@ void RegisterMessageTypes() {
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDidChange>();
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDidClose>();
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDidSave>();
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentRename>();
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentComplete>();
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDefinition>();
|
||||
MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentHighlight>();
|
||||
@ -840,6 +875,37 @@ void QueryDbMainLoop(
|
||||
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: {
|
||||
// TODO: better performance
|
||||
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 = lsTextDocumentSyncKind::Incremental;
|
||||
|
||||
response.result.capabilities.renameProvider = true;
|
||||
|
||||
response.result.capabilities.completionProvider = lsCompletionOptions();
|
||||
response.result.capabilities.completionProvider->resolveProvider = false;
|
||||
response.result.capabilities.completionProvider->triggerCharacters = { ".", "::", "->" };
|
||||
@ -1354,6 +1422,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
|
||||
case IpcId::TextDocumentDidChange:
|
||||
case IpcId::TextDocumentDidClose:
|
||||
case IpcId::TextDocumentDidSave:
|
||||
case IpcId::TextDocumentRename:
|
||||
case IpcId::TextDocumentCompletion:
|
||||
case IpcId::TextDocumentDefinition:
|
||||
case IpcId::TextDocumentDocumentHighlight:
|
||||
|
@ -783,6 +783,9 @@ void indexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) {
|
||||
ns->QualifiedName(decl->semanticContainer, var_def->def.short_name);
|
||||
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) {
|
||||
@ -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.
|
||||
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
|
||||
//decl_cursor.get_type_description()
|
||||
//func_def->def.return_type =
|
||||
|
@ -18,6 +18,8 @@ const char* IpcIdToString(IpcId id) {
|
||||
return "textDocument/didClose";
|
||||
case IpcId::TextDocumentDidSave:
|
||||
return "textDocument/didSave";
|
||||
case IpcId::TextDocumentRename:
|
||||
return "textDocument/rename";
|
||||
case IpcId::TextDocumentCompletion:
|
||||
return "textDocument/completion";
|
||||
case IpcId::TextDocumentDefinition:
|
||||
|
@ -14,6 +14,7 @@ enum class IpcId : int {
|
||||
TextDocumentDidChange,
|
||||
TextDocumentDidClose,
|
||||
TextDocumentDidSave,
|
||||
TextDocumentRename,
|
||||
TextDocumentCompletion,
|
||||
TextDocumentDefinition,
|
||||
TextDocumentDocumentHighlight,
|
||||
|
@ -336,7 +336,7 @@ MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri);
|
||||
struct lsVersionedTextDocumentIdentifier {
|
||||
lsDocumentUri uri;
|
||||
// The version number of this document.
|
||||
int version;
|
||||
int version = 0;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsVersionedTextDocumentIdentifier, uri, version);
|
||||
|
||||
@ -488,6 +488,17 @@ struct lsTextDocumentEdit {
|
||||
};
|
||||
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.
|
||||
enum class lsDocumentHighlightKind {
|
||||
// A textual occurrence.
|
||||
@ -511,7 +522,6 @@ struct lsDocumentHighlight {
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind);
|
||||
|
||||
// TODO: WorkspaceEdit
|
||||
// TODO: DocumentFilter
|
||||
// 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
|
||||
|
@ -167,6 +167,7 @@ void WorkingFiles::OnOpen(const Ipc_TextDocumentDidOpen::Params& open) {
|
||||
|
||||
// The file may already be open.
|
||||
if (WorkingFile* file = GetFileByFilename(filename)) {
|
||||
file->version = open.textDocument.version;
|
||||
file->content = content;
|
||||
return;
|
||||
}
|
||||
@ -182,6 +183,7 @@ void WorkingFiles::OnChange(const Ipc_TextDocumentDidChange::Params& change) {
|
||||
return;
|
||||
}
|
||||
|
||||
file->version = change.textDocument.version;
|
||||
//std::cerr << "VERSION " << change.textDocument.version << std::endl;
|
||||
|
||||
for (const Ipc_TextDocumentDidChange::lsTextDocumentContentChangeEvent& diff : change.contentChanges) {
|
||||
|
@ -39,6 +39,7 @@ struct WorkingFile {
|
||||
Change(int disk_line, int delta);
|
||||
};
|
||||
|
||||
int version = 0;
|
||||
std::string filename;
|
||||
std::string content;
|
||||
std::vector<Change> changes;
|
||||
|
Loading…
Reference in New Issue
Block a user