diff options
Diffstat (limited to 'modules/gdscript/language_server')
9 files changed, 302 insertions, 87 deletions
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 15236d900d..d106b3b541 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -32,7 +32,6 @@  #include "../gdscript.h"  #include "../gdscript_analyzer.h" -#include "core/io/json.h"  #include "gdscript_language_protocol.h"  #include "gdscript_workspace.h" @@ -40,8 +39,7 @@ void ExtendGDScriptParser::update_diagnostics() {  	diagnostics.clear();  	const List<ParserError> &errors = get_errors(); -	for (const List<ParserError>::Element *E = errors.front(); E != nullptr; E = E->next()) { -		const ParserError &error = E->get(); +	for (const ParserError &error : errors) {  		lsp::Diagnostic diagnostic;  		diagnostic.severity = lsp::DiagnosticSeverity::Error;  		diagnostic.message = error.message; @@ -62,8 +60,7 @@ void ExtendGDScriptParser::update_diagnostics() {  	}  	const List<GDScriptWarning> &warnings = get_warnings(); -	for (const List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { -		const GDScriptWarning &warning = E->get(); +	for (const GDScriptWarning &warning : warnings) {  		lsp::Diagnostic diagnostic;  		diagnostic.severity = lsp::DiagnosticSeverity::Warning;  		diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message(); @@ -153,9 +150,9 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p  	}  	r_symbol.kind = lsp::SymbolKind::Class;  	r_symbol.deprecated = false; -	r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->start_line); -	r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_class->start_column); -	r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line); +	r_symbol.range.start.line = p_class->start_line; +	r_symbol.range.start.character = p_class->start_column; +	r_symbol.range.end.line = lines.size();  	r_symbol.selectionRange.start.line = r_symbol.range.start.line;  	r_symbol.detail = "class " + r_symbol.name;  	bool is_root_class = &r_symbol == &class_symbol; @@ -168,7 +165,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p  			case ClassNode::Member::VARIABLE: {  				lsp::DocumentSymbol symbol;  				symbol.name = m.variable->identifier->name; -				symbol.kind = lsp::SymbolKind::Variable; +				symbol.kind = m.variable->property == VariableNode::PropertyStyle::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property;  				symbol.deprecated = false;  				symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line);  				symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column); @@ -183,7 +180,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p  					symbol.detail += ": " + m.get_datatype().to_string();  				}  				if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) { -					symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value); +					symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string();  				}  				symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line)); @@ -224,10 +221,10 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p  							}  						}  					} else { -						value_text = JSON::print(default_value); +						value_text = default_value.to_json_string();  					}  				} else { -					value_text = JSON::print(default_value); +					value_text = default_value.to_json_string();  				}  				if (!value_text.is_empty()) {  					symbol.detail += " = " + value_text; @@ -320,7 +317,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN  	const String uri = get_uri();  	r_symbol.name = p_func->identifier->name; -	r_symbol.kind = lsp::SymbolKind::Function; +	r_symbol.kind = p_func->is_static ? lsp::SymbolKind::Function : lsp::SymbolKind::Method;  	r_symbol.detail = "func " + String(p_func->identifier->name) + "(";  	r_symbol.deprecated = false;  	r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->start_line); @@ -353,8 +350,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN  			parameters += ": " + parameter->get_datatype().to_string();  		}  		if (parameter->default_value != nullptr) { -			String value = JSON::print(parameter->default_value->reduced_value); -			parameters += " = " + value; +			parameters += " = " + parameter->default_value->reduced_value.to_json_string();  		}  	}  	r_symbol.detail += parameters + ")"; @@ -469,8 +465,8 @@ String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {  	}  	String doc; -	for (List<String>::Element *E = doc_lines.front(); E; E = E->next()) { -		doc += E->get() + "\n"; +	for (const String &E : doc_lines) { +		doc += E + "\n";  	}  	return doc;  } @@ -697,7 +693,9 @@ Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::Functio  	ERR_FAIL_NULL_V(p_func, func);  	func["name"] = p_func->identifier->name;  	func["return_type"] = p_func->get_datatype().to_string(); -	func["rpc_mode"] = p_func->rpc_mode; +	func["rpc_mode"] = p_func->rpc_config.rpc_mode; +	func["rpc_transfer_mode"] = p_func->rpc_config.transfer_mode; +	func["rpc_transfer_channel"] = p_func->rpc_config.channel;  	Array parameters;  	for (int i = 0; i < p_func->parameters.size(); i++) {  		Dictionary arg; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index c16a7fa889..b6c48468f5 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -31,7 +31,6 @@  #include "gdscript_language_protocol.h"  #include "core/config/project_settings.h" -#include "core/io/json.h"  #include "editor/doc_tools.h"  #include "editor/editor_log.h"  #include "editor/editor_node.h" @@ -129,13 +128,13 @@ Error GDScriptLanguageProtocol::on_client_connected() {  	peer->connection = tcp_peer;  	clients.set(next_client_id, peer);  	next_client_id++; -	EditorNode::get_log()->add_message("Connection Taken", EditorLog::MSG_TYPE_EDITOR); +	EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);  	return OK;  }  void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) {  	clients.erase(p_client_id); -	EditorNode::get_log()->add_message("Disconnected", EditorLog::MSG_TYPE_EDITOR); +	EditorNode::get_log()->add_message("[LSP] Disconnected", EditorLog::MSG_TYPE_EDITOR);  }  String GDScriptLanguageProtocol::process_message(const String &p_text) { @@ -194,7 +193,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {  				vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id));  		Ref<LSPeer> peer = clients.get(latest_client_id);  		if (peer != nullptr) { -			String msg = JSON::print(request); +			String msg = Variant(request).to_json_string();  			msg = format_output(msg);  			(*peer)->res_queue.push_back(msg.utf8());  		} @@ -280,7 +279,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia  	ERR_FAIL_COND(peer == nullptr);  	Dictionary message = make_notification(p_method, p_params); -	String msg = JSON::print(message); +	String msg = Variant(message).to_json_string();  	msg = format_output(msg);  	peer->res_queue.push_back(msg.utf8());  } @@ -294,10 +293,10 @@ bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const {  }  GDScriptLanguageProtocol::GDScriptLanguageProtocol() { -	server.instance(); +	server.instantiate();  	singleton = this; -	workspace.instance(); -	text_document.instance(); +	workspace.instantiate(); +	text_document.instantiate();  	set_scope("textDocument", text_document.ptr());  	set_scope("completionItem", text_document.ptr());  	set_scope("workspace", workspace.ptr()); diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index 969c38eab6..5a2dd55c46 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -28,8 +28,8 @@  /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */  /*************************************************************************/ -#ifndef GDSCRIPT_PROTOCAL_SERVER_H -#define GDSCRIPT_PROTOCAL_SERVER_H +#ifndef GDSCRIPT_LANGUAGE_PROTOCOL_H +#define GDSCRIPT_LANGUAGE_PROTOCOL_H  #include "core/io/stream_peer.h"  #include "core/io/stream_peer_tcp.h" @@ -37,7 +37,13 @@  #include "gdscript_text_document.h"  #include "gdscript_workspace.h"  #include "lsp.hpp" + +#include "modules/modules_enabled.gen.h" +#ifdef MODULE_JSONRPC_ENABLED  #include "modules/jsonrpc/jsonrpc.h" +#else +#error "Can't build GDScript LSP without JSONRPC module." +#endif  #define LSP_MAX_BUFFER_SIZE 4194304  #define LSP_MAX_CLIENTS 8 @@ -108,4 +114,4 @@ public:  	GDScriptLanguageProtocol();  }; -#endif +#endif // GDSCRIPT_LANGUAGE_PROTOCOL_H diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 33597c286f..c47164d95b 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -101,7 +101,7 @@ void GDScriptLanguageServer::stop() {  }  void register_lsp_types() { -	ClassDB::register_class<GDScriptLanguageProtocol>(); -	ClassDB::register_class<GDScriptTextDocument>(); -	ClassDB::register_class<GDScriptWorkspace>(); +	GDREGISTER_CLASS(GDScriptLanguageProtocol); +	GDREGISTER_CLASS(GDScriptTextDocument); +	GDREGISTER_CLASS(GDScriptWorkspace);  } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 030633274c..03b1e3fa44 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -40,11 +40,14 @@  void GDScriptTextDocument::_bind_methods() {  	ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); +	ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose);  	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("documentSymbol"), &GDScriptTextDocument::documentSymbol);  	ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);  	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("codeLens"), &GDScriptTextDocument::codeLens);  	ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink); @@ -61,6 +64,11 @@ void GDScriptTextDocument::didOpen(const Variant &p_param) {  	sync_script_content(doc.uri, doc.text);  } +void GDScriptTextDocument::didClose(const Variant &p_param) { +	// Left empty on purpose. Godot does nothing special on closing a document, +	// but it satisfies LSP clients that require didClose be implemented. +} +  void GDScriptTextDocument::didChange(const Variant &p_param) {  	lsp::TextDocumentItem doc = load_document_item(p_param);  	Dictionary dict = p_param; @@ -73,6 +81,20 @@ void GDScriptTextDocument::didChange(const Variant &p_param) {  	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); + +	/*String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(doc.uri); + +	Ref<GDScript> script = ResourceLoader::load(path); +	script->load_source_code(path); +	script->reload(true);*/ +} +  lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_param) {  	lsp::TextDocumentItem doc;  	Dictionary params = p_param; @@ -151,8 +173,7 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {  		int i = 0;  		arr.resize(options.size()); -		for (const List<ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) { -			const ScriptCodeCompletionOption &option = E->get(); +		for (const ScriptCodeCompletionOption &option : options) {  			lsp::CompletionItem item;  			item.label = option.display;  			item.data = request_data; @@ -210,6 +231,14 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {  	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) {  	lsp::CompletionItem item;  	item.load(p_params); @@ -262,8 +291,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {  		}  	} else if (item.kind == lsp::CompletionItemKind::Event) {  		if (params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter && (params.context.triggerCharacter == "(")) { -			const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; -			item.insertText = quote_style + item.label + quote_style; +			const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; +			item.insertText = item.label.quote(quote_style);  		}  	} @@ -288,8 +317,8 @@ Array GDScriptTextDocument::documentLink(const Dictionary &p_params) {  	List<lsp::DocumentLink> links;  	GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links); -	for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) { -		ret.push_back(E->get().to_json()); +	for (const lsp::DocumentLink &E : links) { +		ret.push_back(E.to_json());  	}  	return ret;  } @@ -316,8 +345,8 @@ Variant GDScriptTextDocument::hover(const Dictionary &p_params) {  		Array contents;  		List<const lsp::DocumentSymbol *> list;  		GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(params, list); -		for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) { -			if (const lsp::DocumentSymbol *s = E->get()) { +		for (const lsp::DocumentSymbol *&E : list) { +			if (const lsp::DocumentSymbol *s = E) {  				contents.push_back(s->render().value);  			}  		} @@ -367,7 +396,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) {  					id = "class_global:" + symbol->native_class + ":" + symbol->name;  					break;  			} -			call_deferred("show_native_symbol_in_editor", id); +			call_deferred(SNAME("show_native_symbol_in_editor"), id);  		} else {  			notify_client_show_symbol(symbol);  		} @@ -400,11 +429,19 @@ GDScriptTextDocument::~GDScriptTextDocument() {  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);  	GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); +  	EditorFileSystem::get_singleton()->update_file(path); +	Error error; +	Ref<GDScript> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error); +	if (error == OK) { +		if (script->load_source_code(path) == OK) { +			script->reload(true); +		} +	}  }  void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { -	ScriptEditor::get_singleton()->call_deferred("_help_class_goto", p_symbol_id); +	ScriptEditor::get_singleton()->call_deferred(SNAME("_help_class_goto"), p_symbol_id);  	DisplayServer::get_singleton()->window_move_to_foreground();  } @@ -424,8 +461,8 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &  	} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {  		List<const lsp::DocumentSymbol *> list;  		GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(p_location, list); -		for (List<const lsp::DocumentSymbol *>::Element *E = list.front(); E; E = E->next()) { -			if (const lsp::DocumentSymbol *s = E->get()) { +		for (const lsp::DocumentSymbol *&E : list) { +			if (const lsp::DocumentSymbol *s = E) {  				if (!s->uri.is_empty()) {  					lsp::Location location;  					location.uri = s->uri; diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 17f1d5d5e3..9021c84a3f 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -43,7 +43,9 @@ protected:  	FileAccess *file_checker;  	void didOpen(const Variant &p_param); +	void didClose(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 show_native_symbol_in_editor(const String &p_symbol_id); @@ -60,6 +62,7 @@ public:  	Array documentSymbol(const Dictionary &p_params);  	Array completion(const Dictionary &p_params);  	Dictionary resolve(const Dictionary &p_params); +	Dictionary rename(const Dictionary &p_params);  	Array foldingRange(const Dictionary &p_params);  	Array codeLens(const Dictionary &p_params);  	Array documentLink(const Dictionary &p_params); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 9b7b2b36b4..1512b4bb89 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -116,11 +116,40 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_  	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.is_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.is_empty() && local->name == p_symbol_identifier) { +					return local; +				} +			} +		} +	} + +	return nullptr; +} +  void GDScriptWorkspace::reload_all_workspace_scripts() {  	List<String> paths;  	list_script_files("res://", paths); -	for (List<String>::Element *E = paths.front(); E; E = E->next()) { -		const String &path = E->get(); +	for (const String &path : paths) {  		Error err;  		String content = FileAccess::get_file_as_string(path, &err);  		ERR_CONTINUE(err != OK); @@ -188,7 +217,9 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) {  			E->get()->get_symbols().symbol_tree_as_list(E->key(), script_symbols);  			for (int i = 0; i < script_symbols.size(); ++i) {  				if (query.is_subsequence_ofi(script_symbols[i].name)) { -					arr.push_back(script_symbols[i].to_json()); +					lsp::DocumentedSymbolInformation symbol = script_symbols[i]; +					symbol.location.uri = get_file_uri(symbol.location.uri); +					arr.push_back(symbol.to_json());  				}  			}  		} @@ -230,18 +261,13 @@ Error GDScriptWorkspace::initialize() {  			class_symbol.children.push_back(symbol);  		} -		Vector<DocData::PropertyDoc> properties; -		properties.append_array(class_data.properties); -		const int theme_prop_start_idx = properties.size(); -		properties.append_array(class_data.theme_properties); -  		for (int i = 0; i < class_data.properties.size(); i++) {  			const DocData::PropertyDoc &data = class_data.properties[i];  			lsp::DocumentSymbol symbol;  			symbol.name = data.name;  			symbol.native_class = class_name;  			symbol.kind = lsp::SymbolKind::Property; -			symbol.detail = String(i >= theme_prop_start_idx ? "<Theme> var" : "var") + " " + class_name + "." + data.name; +			symbol.detail = "var " + class_name + "." + data.name;  			if (data.enumeration.length()) {  				symbol.detail += ": " + data.enumeration;  			} else { @@ -251,6 +277,17 @@ Error GDScriptWorkspace::initialize() {  			class_symbol.children.push_back(symbol);  		} +		for (int i = 0; i < class_data.theme_properties.size(); i++) { +			const DocData::ThemeItemDoc &data = class_data.theme_properties[i]; +			lsp::DocumentSymbol symbol; +			symbol.name = data.name; +			symbol.native_class = class_name; +			symbol.kind = lsp::SymbolKind::Property; +			symbol.detail = "<Theme> var " + class_name + "." + data.name + ": " + data.type; +			symbol.documentation = data.description; +			class_symbol.children.push_back(symbol); +		} +  		Vector<DocData::MethodDoc> methods_signals;  		methods_signals.append_array(class_data.methods);  		const int signal_start_idx = methods_signals.size(); @@ -349,6 +386,50 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont  	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()) { +			PackedStringArray 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 err;  	String content = FileAccess::get_file_as_string(p_path, &err); @@ -424,7 +505,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {  		RES owner_res = ResourceLoader::load(owner_path);  		if (Object::cast_to<PackedScene>(owner_res.ptr())) {  			Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); -			owner_scene_node = owner_packed_scene->instance(); +			owner_scene_node = owner_packed_scene->instantiate();  			break;  		}  	} @@ -439,8 +520,31 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S  	if (const ExtendGDScriptParser *parser = get_parse_result(path)) {  		Node *owner_scene_node = _get_owner_scene_node(path); + +		Array stack; +		Node *current = nullptr; +		if (owner_scene_node != nullptr) { +			stack.push_back(owner_scene_node); + +			while (!stack.is_empty()) { +				current = stack.pop_back(); +				Ref<GDScript> script = current->get_script(); +				if (script.is_valid() && script->get_path() == path) { +					break; +				} +				for (int i = 0; i < current->get_child_count(); ++i) { +					stack.push_back(current->get_child(i)); +				} +			} + +			Ref<GDScript> script = current->get_script(); +			if (!script.is_valid() || script->get_path() != path) { +				current = owner_scene_node; +			} +		} +  		String code = parser->get_text_for_completion(p_params.position); -		GDScriptLanguage::get_singleton()->complete_code(code, path, owner_scene_node, r_options, forced, call_hint); +		GDScriptLanguage::get_singleton()->complete_code(code, path, current, r_options, forced, call_hint);  		if (owner_scene_node) {  			memdelete(owner_scene_node);  		} @@ -477,10 +581,16 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu  						String target_script_path = path;  						if (!ret.script.is_null()) {  							target_script_path = ret.script->get_path(); +						} else if (!ret.class_path.is_empty()) { +							target_script_path = ret.class_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)); + +							if (symbol && symbol->kind == lsp::SymbolKind::Function && symbol->name != symbol_identifier) { +								symbol = get_parameter_symbol(symbol, symbol_identifier); +							}  						}  					} else { @@ -492,6 +602,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu  					}  				} else {  					symbol = parser->get_member_symbol(symbol_identifier); + +					if (!symbol) { +						symbol = get_local_symbol(parser, symbol_identifier); +					}  				}  			}  		} @@ -557,8 +671,8 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::N  void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) {  	if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) {  		const List<lsp::DocumentLink> &links = parser->get_document_links(); -		for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) { -			r_list.push_back(E->get()); +		for (const lsp::DocumentLink &E : links) { +			r_list.push_back(E);  		}  	}  } @@ -585,8 +699,7 @@ Error GDScriptWorkspace::resolve_signature(const lsp::TextDocumentPositionParams  				GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(text_pos, symbols);  			} -			for (List<const lsp::DocumentSymbol *>::Element *E = symbols.front(); E; E = E->next()) { -				const lsp::DocumentSymbol *symbol = E->get(); +			for (const lsp::DocumentSymbol *const &symbol : symbols) {  				if (symbol->kind == lsp::SymbolKind::Method || symbol->kind == lsp::SymbolKind::Function) {  					lsp::SignatureInformation signature_info;  					signature_info.label = symbol->detail; diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 8b166a873c..9496677449 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -52,6 +52,8 @@ protected:  	const lsp::DocumentSymbol *get_native_symbol(const String &p_class, const String &p_member = "") const;  	const lsp::DocumentSymbol *get_script_symbol(const String &p_path) const; +	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);  	void reload_all_workspace_scripts(); @@ -90,6 +92,7 @@ public:  	Dictionary generate_script_api(const String &p_path);  	Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature);  	void did_delete_files(const Dictionary &p_params); +	Dictionary rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name);  	GDScriptWorkspace();  	~GDScriptWorkspace(); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index a7dcfdb22d..9ac6c6bd4e 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -255,6 +255,62 @@ struct TextEdit {  };  /** + * 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.   * Provides a title which will be used to represent a command in the UI.   * Commands are identified by a string identifier. @@ -486,7 +542,7 @@ struct TextDocumentSyncOptions {  	 * If present save notifications are sent to the server. If omitted the notification should not be  	 * sent.  	 */ -	bool save = false; +	SaveOptions save;  	Dictionary to_json() {  		Dictionary dict; @@ -494,7 +550,7 @@ struct TextDocumentSyncOptions {  		dict["willSave"] = willSave;  		dict["openClose"] = openClose;  		dict["change"] = change; -		dict["save"] = save; +		dict["save"] = save.to_json();  		return dict;  	}  }; @@ -1018,32 +1074,32 @@ struct CompletionList {   * A symbol kind.   */  namespace SymbolKind { -static const int File = 0; -static const int Module = 1; -static const int Namespace = 2; -static const int Package = 3; -static const int Class = 4; -static const int Method = 5; -static const int Property = 6; -static const int Field = 7; -static const int Constructor = 8; -static const int Enum = 9; -static const int Interface = 10; -static const int Function = 11; -static const int Variable = 12; -static const int Constant = 13; -static const int String = 14; -static const int Number = 15; -static const int Boolean = 16; -static const int Array = 17; -static const int Object = 18; -static const int Key = 19; -static const int Null = 20; -static const int EnumMember = 21; -static const int Struct = 22; -static const int Event = 23; -static const int Operator = 24; -static const int TypeParameter = 25; +static const int File = 1; +static const int Module = 2; +static const int Namespace = 3; +static const int Package = 4; +static const int Class = 5; +static const int Method = 6; +static const int Property = 7; +static const int Field = 8; +static const int Constructor = 9; +static const int Enum = 10; +static const int Interface = 11; +static const int Function = 12; +static const int Variable = 13; +static const int Constant = 14; +static const int String = 15; +static const int Number = 16; +static const int Boolean = 17; +static const int Array = 18; +static const int Object = 19; +static const int Key = 20; +static const int Null = 21; +static const int EnumMember = 22; +static const int Struct = 23; +static const int Event = 24; +static const int Operator = 25; +static const int TypeParameter = 26;  }; // namespace SymbolKind  /**  |