diff options
Diffstat (limited to 'modules/gdscript/language_server')
8 files changed, 76 insertions, 54 deletions
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 36806d2f73..2a3db4f508 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -48,17 +48,17 @@ lsp::Position GodotPosition::to_lsp(const Vector<String> &p_lines) const { lsp::Position res; // Special case: `line = 0` -> root class (range covers everything). - if (this->line <= 0) { + if (line <= 0) { return res; } // Special case: `line = p_lines.size() + 1` -> root class (range covers everything). - if (this->line >= p_lines.size() + 1) { + if (line >= p_lines.size() + 1) { res.line = p_lines.size(); return res; } - res.line = this->line - 1; + res.line = line - 1; // Note: character outside of `pos_line.length()-1` is valid. - res.character = this->column - 1; + res.character = column - 1; String pos_line = p_lines[res.line]; if (pos_line.contains("\t")) { @@ -67,7 +67,7 @@ lsp::Position GodotPosition::to_lsp(const Vector<String> &p_lines) const { int in_col = 1; int res_char = 0; - while (res_char < pos_line.size() && in_col < this->column) { + while (res_char < pos_line.size() && in_col < column) { if (pos_line[res_char] == '\t') { in_col += tab_size; res_char++; @@ -191,7 +191,7 @@ void ExtendGDScriptParser::update_symbols() { void ExtendGDScriptParser::update_document_links(const String &p_code) { document_links.clear(); - GDScriptTokenizer scr_tokenizer; + GDScriptTokenizerText scr_tokenizer; Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); scr_tokenizer.set_source_code(p_code); while (true) { @@ -211,7 +211,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) { String value = const_val; lsp::DocumentLink link; link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(scr_path); - link.range = GodotRange(GodotPosition(token.start_line, token.start_column), GodotPosition(token.end_line, token.end_column)).to_lsp(this->lines); + link.range = GodotRange(GodotPosition(token.start_line, token.start_column), GodotPosition(token.end_line, token.end_column)).to_lsp(lines); document_links.push_back(link); } } @@ -222,7 +222,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) { lsp::Range ExtendGDScriptParser::range_of_node(const GDScriptParser::Node *p_node) const { GodotPosition start(p_node->start_line, p_node->start_column); GodotPosition end(p_node->end_line, p_node->end_column); - return GodotRange(start, end).to_lsp(this->lines); + return GodotRange(start, end).to_lsp(lines); } void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol) { @@ -394,8 +394,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p symbol.name = m.enum_value.identifier->name; symbol.kind = lsp::SymbolKind::EnumMember; symbol.deprecated = false; - symbol.range.start = GodotPosition(m.enum_value.line, m.enum_value.leftmost_column).to_lsp(this->lines); - symbol.range.end = GodotPosition(m.enum_value.line, m.enum_value.rightmost_column).to_lsp(this->lines); + symbol.range.start = GodotPosition(m.enum_value.line, m.enum_value.leftmost_column).to_lsp(lines); + symbol.range.end = GodotPosition(m.enum_value.line, m.enum_value.rightmost_column).to_lsp(lines); symbol.selectionRange = range_of_node(m.enum_value.identifier); symbol.documentation = m.enum_value.doc_data.description; symbol.uri = uri; @@ -430,8 +430,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p child.name = value.identifier->name; child.kind = lsp::SymbolKind::EnumMember; child.deprecated = false; - child.range.start = GodotPosition(value.line, value.leftmost_column).to_lsp(this->lines); - child.range.end = GodotPosition(value.line, value.rightmost_column).to_lsp(this->lines); + child.range.start = GodotPosition(value.line, value.leftmost_column).to_lsp(lines); + child.range.end = GodotPosition(value.line, value.rightmost_column).to_lsp(lines); child.selectionRange = range_of_node(value.identifier); child.documentation = value.doc_data.description; child.uri = uri; @@ -510,7 +510,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN node_stack.push_back(p_func->body); while (!node_stack.is_empty()) { - GDScriptParser::Node *node = node_stack[0]; + GDScriptParser::Node *node = node_stack.front()->get(); node_stack.pop_front(); switch (node->type) { diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index 8489fc08c1..03d830741b 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -105,7 +105,7 @@ Error GDScriptLanguageProtocol::LSPeer::handle_data() { Error GDScriptLanguageProtocol::LSPeer::send_data() { int sent = 0; - if (!res_queue.is_empty()) { + while (!res_queue.is_empty()) { CharString c_res = res_queue[0]; if (res_sent < c_res.size()) { Error err = connection->put_partial_data((const uint8_t *)c_res.get_data() + res_sent, c_res.size() - res_sent - 1, sent); @@ -229,7 +229,9 @@ void GDScriptLanguageProtocol::initialized(const Variant &p_params) { notify_client("gdscript/capabilities", capabilities.to_json()); } -void GDScriptLanguageProtocol::poll() { +void GDScriptLanguageProtocol::poll(int p_limit_usec) { + uint64_t target_ticks = OS::get_singleton()->get_ticks_usec() + p_limit_usec; + if (server->is_connection_available()) { on_client_connected(); } @@ -244,16 +246,22 @@ void GDScriptLanguageProtocol::poll() { E = clients.begin(); continue; } else { - if (peer->connection->get_available_bytes() > 0) { + Error err = OK; + while (peer->connection->get_available_bytes() > 0) { latest_client_id = E->key; - Error err = peer->handle_data(); - if (err != OK && err != ERR_BUSY) { - on_client_disconnected(E->key); - E = clients.begin(); - continue; + err = peer->handle_data(); + if (err != OK || OS::get_singleton()->get_ticks_usec() >= target_ticks) { + break; } } - Error err = peer->send_data(); + + if (err != OK && err != ERR_BUSY) { + on_client_disconnected(E->key); + E = clients.begin(); + continue; + } + + err = peer->send_data(); if (err != OK && err != ERR_BUSY) { on_client_disconnected(E->key); E = clients.begin(); diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index a4d9dc6b1d..f29abaa337 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -105,7 +105,7 @@ public: _FORCE_INLINE_ Ref<GDScriptTextDocument> get_text_document() { return text_document; } _FORCE_INLINE_ bool is_initialized() const { return _initialized; } - void poll(); + void poll(int p_limit_usec); Error start(int p_port, const IPAddress &p_bind_ip); void stop(); diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 053be7eec2..3df26ea576 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -44,6 +44,7 @@ GDScriptLanguageServer::GDScriptLanguageServer() { _EDITOR_DEF("network/language_server/enable_smart_resolve", true); _EDITOR_DEF("network/language_server/show_native_symbols_in_editor", false); _EDITOR_DEF("network/language_server/use_thread", use_thread); + _EDITOR_DEF("network/language_server/poll_limit_usec", poll_limit_usec); } void GDScriptLanguageServer::_notification(int p_what) { @@ -58,15 +59,20 @@ void GDScriptLanguageServer::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { if (started && !use_thread) { - protocol.poll(); + protocol.poll(poll_limit_usec); } } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (!EditorSettings::get_singleton()->check_changed_settings_in_group("network/language_server")) { + break; + } + String remote_host = String(_EDITOR_GET("network/language_server/remote_host")); int remote_port = (GDScriptLanguageServer::port_override > -1) ? GDScriptLanguageServer::port_override : (int)_EDITOR_GET("network/language_server/remote_port"); bool remote_use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); - if (remote_host != host || remote_port != port || remote_use_thread != use_thread) { + int remote_poll_limit = (int)_EDITOR_GET("network/language_server/poll_limit_usec"); + if (remote_host != host || remote_port != port || remote_use_thread != use_thread || remote_poll_limit != poll_limit_usec) { stop(); start(); } @@ -79,7 +85,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) { GDScriptLanguageServer *self = static_cast<GDScriptLanguageServer *>(p_userdata); while (self->thread_running) { // Poll 20 times per second - self->protocol.poll(); + self->protocol.poll(self->poll_limit_usec); OS::get_singleton()->delay_usec(50000); } } @@ -88,6 +94,7 @@ void GDScriptLanguageServer::start() { host = String(_EDITOR_GET("network/language_server/remote_host")); port = (GDScriptLanguageServer::port_override > -1) ? GDScriptLanguageServer::port_override : (int)_EDITOR_GET("network/language_server/remote_port"); use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); + poll_limit_usec = (int)_EDITOR_GET("network/language_server/poll_limit_usec"); if (protocol.start(port, IPAddress(host)) == OK) { EditorNode::get_log()->add_message("--- GDScript language server started on port " + itos(port) + " ---", EditorLog::MSG_TYPE_EDITOR); if (use_thread) { diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h index e845d139bf..4ae5ab6cbf 100644 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ b/modules/gdscript/language_server/gdscript_language_server.h @@ -34,7 +34,7 @@ #include "../gdscript_parser.h" #include "gdscript_language_protocol.h" -#include "editor/editor_plugin.h" +#include "editor/plugins/editor_plugin.h" class GDScriptLanguageServer : public EditorPlugin { GDCLASS(GDScriptLanguageServer, EditorPlugin); @@ -47,6 +47,7 @@ class GDScriptLanguageServer : public EditorPlugin { bool use_thread = false; String host = "127.0.0.1"; int port = 6005; + int poll_limit_usec = 100000; static void thread_main(void *p_userdata); private: diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 44f605232d..2224bb0040 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -114,7 +114,7 @@ void GDScriptTextDocument::didSave(const Variant &p_param) { scr->update_exports(); ScriptEditor::get_singleton()->reload_scripts(true); ScriptEditor::get_singleton()->update_docs_from_script(scr); - ScriptEditor::get_singleton()->trigger_live_script_reload(); + ScriptEditor::get_singleton()->trigger_live_script_reload(scr->get_path()); } } @@ -315,9 +315,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) { Vector<String> param_symbols = query.split(SYMBOL_SEPERATOR, false); if (param_symbols.size() >= 2) { - String class_ = param_symbols[0]; - StringName class_name = class_; - String member_name = param_symbols[param_symbols.size() - 1]; + StringName class_name = param_symbols[0]; + const String &member_name = param_symbols[param_symbols.size() - 1]; String inner_class_name; if (param_symbols.size() >= 3) { inner_class_name = param_symbols[1]; @@ -422,7 +421,7 @@ Array GDScriptTextDocument::definition(const Dictionary &p_params) { lsp::TextDocumentPositionParams params; params.load(p_params); List<const lsp::DocumentSymbol *> symbols; - Array arr = this->find_symbols(params, symbols); + Array arr = find_symbols(params, symbols); return arr; } @@ -430,7 +429,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) { lsp::TextDocumentPositionParams params; params.load(p_params); List<const lsp::DocumentSymbol *> symbols; - Array arr = this->find_symbols(params, symbols); + Array arr = find_symbols(params, symbols); if (arr.is_empty() && !symbols.is_empty() && !symbols.front()->get()->native_class.is_empty()) { // Find a native symbol const lsp::DocumentSymbol *symbol = symbols.front()->get(); if (GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) { @@ -457,7 +456,7 @@ Variant GDScriptTextDocument::declaration(const Dictionary &p_params) { id = "class_global:" + symbol->native_class + ":" + symbol->name; break; } - call_deferred(SNAME("show_native_symbol_in_editor"), id); + callable_mp(this, &GDScriptTextDocument::show_native_symbol_in_editor).call_deferred(id); } else { notify_client_show_symbol(symbol); } @@ -491,7 +490,7 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { - ScriptEditor::get_singleton()->call_deferred(SNAME("_help_class_goto"), p_symbol_id); + callable_mp(ScriptEditor::get_singleton(), &ScriptEditor::goto_help).call_deferred(p_symbol_id); DisplayServer::get_singleton()->window_move_to_foreground(); } diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 81933c8c87..09defdf8cd 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -223,7 +223,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(path); String err_msg = "Failed parse script " + path; if (S) { - err_msg += "\n" + S->value->get_errors()[0].message; + err_msg += "\n" + S->value->get_errors().front()->get().message; } ERR_CONTINUE_MSG(err != OK, err_msg); } @@ -233,18 +233,25 @@ void GDScriptWorkspace::reload_all_workspace_scripts() { void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) { Error err; Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err); - if (OK == err) { - dir->list_dir_begin(); - String file_name = dir->get_next(); - while (file_name.length()) { - if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") { - list_script_files(p_root_dir.path_join(file_name), r_files); - } else if (file_name.ends_with(".gd")) { - String script_file = p_root_dir.path_join(file_name); - r_files.push_back(script_file); - } - file_name = dir->get_next(); + if (OK != err) { + return; + } + + // Ignore scripts in directories with a .gdignore file. + if (dir->file_exists(".gdignore")) { + return; + } + + dir->list_dir_begin(); + String file_name = dir->get_next(); + while (file_name.length()) { + if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") { + list_script_files(p_root_dir.path_join(file_name), r_files); + } else if (file_name.ends_with(".gd")) { + String script_file = p_root_dir.path_join(file_name); + r_files.push_back(script_file); } + file_name = dir->get_next(); } } @@ -612,8 +619,8 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { _get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners); - for (int i = 0; i < owners.size(); i++) { - NodePath owner_path = owners[i]; + for (const String &owner : owners) { + NodePath owner_path = owner; Ref<Resource> 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)); @@ -641,7 +648,7 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S while (!stack.is_empty()) { current = Object::cast_to<Node>(stack.pop_back()); Ref<GDScript> scr = current->get_script(); - if (scr.is_valid() && scr->get_path() == path) { + if (scr.is_valid() && GDScript::is_canonically_equal_paths(scr->get_path(), path)) { break; } for (int i = 0; i < current->get_child_count(); ++i) { @@ -650,7 +657,7 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S } Ref<GDScript> scr = current->get_script(); - if (!scr.is_valid() || scr->get_path() != path) { + if (!scr.is_valid() || !GDScript::is_canonically_equal_paths(scr->get_path(), path)) { current = owner_scene_node; } } @@ -688,7 +695,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu } else { ScriptLanguage::LookupResult ret; - if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").find("new(") > -1) { + if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").contains("new(")) { symbol_identifier = "_init"; } if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) { diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h index e09adb74bd..13c2693390 100644 --- a/modules/gdscript/language_server/godot_lsp.h +++ b/modules/gdscript/language_server/godot_lsp.h @@ -200,7 +200,7 @@ struct LocationLink { /** * The range that should be selected and revealed when this link is being followed, e.g the name of a function. - * Must be contained by the the `targetRange`. See also `DocumentSymbol#range` + * Must be contained by the `targetRange`. See also `DocumentSymbol#range` */ Range targetSelectionRange; }; @@ -236,7 +236,7 @@ struct ReferenceContext { /** * Include the declaration of the current symbol. */ - bool includeDeclaration; + bool includeDeclaration = false; }; struct ReferenceParams : TextDocumentPositionParams { |