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:
Jacob Dufault 2017-04-14 01:21:03 -07:00
parent 71d1b1ffc6
commit 031c0c2011
7 changed files with 133 additions and 3 deletions

View File

@ -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:

View File

@ -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 =

View File

@ -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:

View File

@ -14,6 +14,7 @@ enum class IpcId : int {
TextDocumentDidChange,
TextDocumentDidClose,
TextDocumentDidSave,
TextDocumentRename,
TextDocumentCompletion,
TextDocumentDefinition,
TextDocumentDocumentHighlight,

View File

@ -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

View File

@ -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) {

View File

@ -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;