summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/language_server
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/language_server')
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp26
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp26
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h2
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp13
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h3
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp15
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp41
-rw-r--r--modules/gdscript/language_server/godot_lsp.h4
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 {