Implement LSP didSave notify and rename request
This commit is contained in:
parent
de3168ffa3
commit
802bb9c01f
5 changed files with 167 additions and 2 deletions
|
@ -40,10 +40,12 @@
|
||||||
void GDScriptTextDocument::_bind_methods() {
|
void GDScriptTextDocument::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
|
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
|
||||||
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
|
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
|
||||||
|
ClassDB::bind_method(D_METHOD("didSave"), &GDScriptTextDocument::didSave);
|
||||||
ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
|
ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
|
||||||
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
|
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
|
||||||
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
|
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
|
||||||
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
|
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
|
||||||
|
ClassDB::bind_method(D_METHOD("rename"), &GDScriptTextDocument::rename);
|
||||||
ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange);
|
ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange);
|
||||||
ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens);
|
ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens);
|
||||||
ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink);
|
ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink);
|
||||||
|
@ -72,6 +74,14 @@ void GDScriptTextDocument::didChange(const Variant &p_param) {
|
||||||
sync_script_content(doc.uri, doc.text);
|
sync_script_content(doc.uri, doc.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GDScriptTextDocument::didSave(const Variant &p_param) {
|
||||||
|
lsp::TextDocumentItem doc = load_document_item(p_param);
|
||||||
|
Dictionary dict = p_param;
|
||||||
|
String text = dict["text"];
|
||||||
|
|
||||||
|
sync_script_content(doc.uri, text);
|
||||||
|
}
|
||||||
|
|
||||||
lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) {
|
lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) {
|
||||||
lsp::TextDocumentItem doc;
|
lsp::TextDocumentItem doc;
|
||||||
Dictionary params = p_param;
|
Dictionary params = p_param;
|
||||||
|
@ -209,6 +219,14 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dictionary GDScriptTextDocument::rename(const Dictionary &p_params) {
|
||||||
|
lsp::TextDocumentPositionParams params;
|
||||||
|
params.load(p_params);
|
||||||
|
String new_name = p_params["newName"];
|
||||||
|
|
||||||
|
return GDScriptLanguageProtocol::get_singleton()->get_workspace()->rename(params, new_name);
|
||||||
|
}
|
||||||
|
|
||||||
Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
|
Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
|
||||||
lsp::CompletionItem item;
|
lsp::CompletionItem item;
|
||||||
item.load(p_params);
|
item.load(p_params);
|
||||||
|
@ -399,7 +417,11 @@ GDScriptTextDocument::~GDScriptTextDocument() {
|
||||||
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
|
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
|
||||||
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
|
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
|
||||||
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
|
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
|
||||||
|
|
||||||
EditorFileSystem::get_singleton()->update_file(path);
|
EditorFileSystem::get_singleton()->update_file(path);
|
||||||
|
Ref<GDScript> script = ResourceLoader::load(path);
|
||||||
|
script->load_source_code(path);
|
||||||
|
script->reload(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
|
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
|
||||||
|
|
|
@ -44,6 +44,7 @@ protected:
|
||||||
|
|
||||||
void didOpen(const Variant &p_param);
|
void didOpen(const Variant &p_param);
|
||||||
void didChange(const Variant &p_param);
|
void didChange(const Variant &p_param);
|
||||||
|
void didSave(const Variant &p_param);
|
||||||
|
|
||||||
void sync_script_content(const String &p_path, const String &p_content);
|
void sync_script_content(const String &p_path, const String &p_content);
|
||||||
void show_native_symbol_in_editor(const String &p_symbol_id);
|
void show_native_symbol_in_editor(const String &p_symbol_id);
|
||||||
|
@ -60,6 +61,7 @@ public:
|
||||||
Array documentSymbol(const Dictionary &p_params);
|
Array documentSymbol(const Dictionary &p_params);
|
||||||
Array completion(const Dictionary &p_params);
|
Array completion(const Dictionary &p_params);
|
||||||
Dictionary resolve(const Dictionary &p_params);
|
Dictionary resolve(const Dictionary &p_params);
|
||||||
|
Dictionary rename(const Dictionary &p_params);
|
||||||
Array foldingRange(const Dictionary &p_params);
|
Array foldingRange(const Dictionary &p_params);
|
||||||
Array codeLens(const Dictionary &p_params);
|
Array codeLens(const Dictionary &p_params);
|
||||||
Array documentLink(const Dictionary &p_params);
|
Array documentLink(const Dictionary &p_params);
|
||||||
|
|
|
@ -115,6 +115,36 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lsp::DocumentSymbol *GDScriptWorkspace::get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier) {
|
||||||
|
for (int i = 0; i < p_parent->children.size(); ++i) {
|
||||||
|
const lsp::DocumentSymbol *parameter_symbol = &p_parent->children[i];
|
||||||
|
if (!parameter_symbol->detail.empty() && parameter_symbol->name == symbol_identifier) {
|
||||||
|
return parameter_symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lsp::DocumentSymbol *GDScriptWorkspace::get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier) {
|
||||||
|
const lsp::DocumentSymbol *class_symbol = &p_parser->get_symbols();
|
||||||
|
|
||||||
|
for (int i = 0; i < class_symbol->children.size(); ++i) {
|
||||||
|
if (class_symbol->children[i].kind == lsp::SymbolKind::Function || class_symbol->children[i].kind == lsp::SymbolKind::Class) {
|
||||||
|
const lsp::DocumentSymbol *function_symbol = &class_symbol->children[i];
|
||||||
|
|
||||||
|
for (int l = 0; l < function_symbol->children.size(); ++l) {
|
||||||
|
const lsp::DocumentSymbol *local = &function_symbol->children[l];
|
||||||
|
if (!local->detail.empty() && local->name == p_symbol_identifier) {
|
||||||
|
return local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void GDScriptWorkspace::reload_all_workspace_scripts() {
|
void GDScriptWorkspace::reload_all_workspace_scripts() {
|
||||||
List<String> paths;
|
List<String> paths;
|
||||||
list_script_files("res://", paths);
|
list_script_files("res://", paths);
|
||||||
|
@ -347,6 +377,50 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dictionary GDScriptWorkspace::rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name) {
|
||||||
|
Error err;
|
||||||
|
String path = get_file_path(p_doc_pos.textDocument.uri);
|
||||||
|
|
||||||
|
lsp::WorkspaceEdit edit;
|
||||||
|
|
||||||
|
List<String> paths;
|
||||||
|
list_script_files("res://", paths);
|
||||||
|
|
||||||
|
const lsp::DocumentSymbol *reference_symbol = resolve_symbol(p_doc_pos);
|
||||||
|
if (reference_symbol) {
|
||||||
|
String identifier = reference_symbol->name;
|
||||||
|
|
||||||
|
for (List<String>::Element *PE = paths.front(); PE; PE = PE->next()) {
|
||||||
|
Vector<String> content = FileAccess::get_file_as_string(PE->get(), &err).split("\n");
|
||||||
|
for (int i = 0; i < content.size(); ++i) {
|
||||||
|
String line = content[i];
|
||||||
|
|
||||||
|
int character = line.find(identifier);
|
||||||
|
while (character > -1) {
|
||||||
|
lsp::TextDocumentPositionParams params;
|
||||||
|
|
||||||
|
lsp::TextDocumentIdentifier text_doc;
|
||||||
|
text_doc.uri = get_file_uri(PE->get());
|
||||||
|
|
||||||
|
params.textDocument = text_doc;
|
||||||
|
params.position.line = i;
|
||||||
|
params.position.character = character;
|
||||||
|
|
||||||
|
const lsp::DocumentSymbol *other_symbol = resolve_symbol(params);
|
||||||
|
|
||||||
|
if (other_symbol == reference_symbol) {
|
||||||
|
edit.add_change(text_doc.uri, i, character, character + identifier.length(), new_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
character = line.find(identifier, character + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return edit.to_json();
|
||||||
|
}
|
||||||
|
|
||||||
Error GDScriptWorkspace::parse_local_script(const String &p_path) {
|
Error GDScriptWorkspace::parse_local_script(const String &p_path) {
|
||||||
Error err;
|
Error err;
|
||||||
String content = FileAccess::get_file_as_string(p_path, &err);
|
String content = FileAccess::get_file_as_string(p_path, &err);
|
||||||
|
@ -477,6 +551,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
|
||||||
|
|
||||||
if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) {
|
if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) {
|
||||||
symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location));
|
symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location));
|
||||||
|
|
||||||
|
if (symbol && symbol->kind == lsp::SymbolKind::Function && symbol->name != symbol_identifier) {
|
||||||
|
symbol = get_parameter_symbol(symbol, symbol_identifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -488,6 +566,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
symbol = parser->get_member_symbol(symbol_identifier);
|
symbol = parser->get_member_symbol(symbol_identifier);
|
||||||
|
|
||||||
|
if (!symbol) {
|
||||||
|
symbol = get_local_symbol(parser, symbol_identifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ class GDScriptWorkspace : public Reference {
|
||||||
private:
|
private:
|
||||||
void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners);
|
void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners);
|
||||||
Node *_get_owner_scene_node(String p_path);
|
Node *_get_owner_scene_node(String p_path);
|
||||||
|
const lsp::DocumentSymbol *get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier);
|
||||||
|
const lsp::DocumentSymbol *get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
@ -89,6 +91,7 @@ public:
|
||||||
void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
|
void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
|
||||||
Dictionary generate_script_api(const String &p_path);
|
Dictionary generate_script_api(const String &p_path);
|
||||||
Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature);
|
Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature);
|
||||||
|
Dictionary rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name);
|
||||||
|
|
||||||
void did_delete_files(const Dictionary &p_params);
|
void did_delete_files(const Dictionary &p_params);
|
||||||
|
|
||||||
|
|
|
@ -254,6 +254,62 @@ struct TextEdit {
|
||||||
String newText;
|
String newText;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The edits to be applied.
|
||||||
|
*/
|
||||||
|
struct WorkspaceEdit {
|
||||||
|
/**
|
||||||
|
* Holds changes to existing resources.
|
||||||
|
*/
|
||||||
|
Map<String, Vector<TextEdit>> changes;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ Dictionary to_json() const {
|
||||||
|
Dictionary dict;
|
||||||
|
|
||||||
|
Dictionary out_changes;
|
||||||
|
for (Map<String, Vector<TextEdit>>::Element *E = changes.front(); E; E = E->next()) {
|
||||||
|
Array edits;
|
||||||
|
for (int i = 0; i < E->get().size(); ++i) {
|
||||||
|
Dictionary text_edit;
|
||||||
|
text_edit["range"] = E->get()[i].range.to_json();
|
||||||
|
text_edit["newText"] = E->get()[i].newText;
|
||||||
|
edits.push_back(text_edit);
|
||||||
|
}
|
||||||
|
out_changes[E->key()] = edits;
|
||||||
|
}
|
||||||
|
dict["changes"] = out_changes;
|
||||||
|
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void add_change(const String &uri, const int &line, const int &start_character, const int &end_character, const String &new_text) {
|
||||||
|
if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) {
|
||||||
|
Vector<TextEdit> edit_list = E->value();
|
||||||
|
for (int i = 0; i < edit_list.size(); ++i) {
|
||||||
|
TextEdit edit = edit_list[i];
|
||||||
|
if (edit.range.start.character == start_character) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TextEdit new_edit;
|
||||||
|
new_edit.newText = new_text;
|
||||||
|
new_edit.range.start.line = line;
|
||||||
|
new_edit.range.start.character = start_character;
|
||||||
|
new_edit.range.end.line = line;
|
||||||
|
new_edit.range.end.character = end_character;
|
||||||
|
|
||||||
|
if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) {
|
||||||
|
E->value().push_back(new_edit);
|
||||||
|
} else {
|
||||||
|
Vector<TextEdit> edit_list;
|
||||||
|
edit_list.push_back(new_edit);
|
||||||
|
changes.insert(uri, edit_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a reference to a command.
|
* Represents a reference to a command.
|
||||||
* Provides a title which will be used to represent a command in the UI.
|
* Provides a title which will be used to represent a command in the UI.
|
||||||
|
@ -485,7 +541,7 @@ struct TextDocumentSyncOptions {
|
||||||
* If present save notifications are sent to the server. If omitted the notification should not be
|
* If present save notifications are sent to the server. If omitted the notification should not be
|
||||||
* sent.
|
* sent.
|
||||||
*/
|
*/
|
||||||
bool save = false;
|
SaveOptions save;
|
||||||
|
|
||||||
Dictionary to_json() {
|
Dictionary to_json() {
|
||||||
Dictionary dict;
|
Dictionary dict;
|
||||||
|
@ -493,7 +549,7 @@ struct TextDocumentSyncOptions {
|
||||||
dict["willSave"] = willSave;
|
dict["willSave"] = willSave;
|
||||||
dict["openClose"] = openClose;
|
dict["openClose"] = openClose;
|
||||||
dict["change"] = change;
|
dict["change"] = change;
|
||||||
dict["save"] = save;
|
dict["save"] = save.to_json();
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue