diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp deleted file mode 100644 index 06c66ba..0000000 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ /dev/null @@ -1,818 +0,0 @@ -/**************************************************************************/ -/* gdscript_extend_parser.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "gdscript_extend_parser.h" - -#include "../gdscript.h" -#include "core/io/json.h" -#include "gdscript_language_protocol.h" -#include "gdscript_workspace.h" - -void ExtendGDScriptParser::update_diagnostics() { - diagnostics.clear(); - - if (has_error()) { - lsp::Diagnostic diagnostic; - diagnostic.severity = lsp::DiagnosticSeverity::Error; - diagnostic.message = get_error(); - diagnostic.source = "gdscript"; - diagnostic.code = -1; - lsp::Range range; - lsp::Position pos; - int line = LINE_NUMBER_TO_INDEX(get_error_line()); - const String &line_text = get_lines()[line]; - pos.line = line; - pos.character = line_text.length() - line_text.strip_edges(true, false).length(); - range.start = pos; - range.end = range.start; - range.end.character = line_text.strip_edges(false).length(); - diagnostic.range = range; - diagnostics.push_back(diagnostic); - } - - const List &warnings = get_warnings(); - for (const List::Element *E = warnings.front(); E; E = E->next()) { - const GDScriptWarning &warning = E->get(); - lsp::Diagnostic diagnostic; - diagnostic.severity = lsp::DiagnosticSeverity::Warning; - diagnostic.message = "(" + warning.get_name() + "): " + warning.get_message(); - diagnostic.source = "gdscript"; - diagnostic.code = warning.code; - lsp::Range range; - lsp::Position pos; - int line = LINE_NUMBER_TO_INDEX(warning.line); - const String &line_text = get_lines()[line]; - pos.line = line; - pos.character = line_text.length() - line_text.strip_edges(true, false).length(); - range.start = pos; - range.end = pos; - range.end.character = line_text.strip_edges(false).length(); - diagnostic.range = range; - diagnostics.push_back(diagnostic); - } -} - -void ExtendGDScriptParser::update_symbols() { - members.clear(); - - const GDScriptParser::Node *head = get_parse_tree(); - - -if (head && head->type == Node::TYPE_CLASS) { - const GDScriptParser::ClassNode *gdclass = static_cast(head); - - parse_class_symbol(gdclass, class_symbol); - - for (int i = 0; i < class_symbol.children.size(); i++) { - const lsp::DocumentSymbol &symbol = class_symbol.children[i]; - members.set(symbol.name, &symbol); - - // cache level one inner classes - if (symbol.kind == lsp::SymbolKind::Class) { - ClassMembers inner_class; - for (int j = 0; j < symbol.children.size(); j++) { - const lsp::DocumentSymbol &s = symbol.children[j]; - inner_class.set(s.name, &s); - } - inner_classes.set(symbol.name, inner_class); - } - } - } -} - -void ExtendGDScriptParser::update_document_links(const String &p_code) { - document_links.clear(); - - GDScriptTokenizerText tokenizer; - FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES); - tokenizer.set_code(p_code); - while (true) { - GDScriptTokenizerText::Token token = tokenizer.get_token(); - if (token == GDScriptTokenizer::TK_EOF || token == GDScriptTokenizer::TK_ERROR) { - break; - } else if (token == GDScriptTokenizer::TK_CONSTANT) { - const Variant &const_val = tokenizer.get_token_constant(); - if (const_val.get_type() == Variant::STRING) { - String path = const_val; - bool exists = fs->file_exists(path); - if (!exists) { - path = get_path().get_base_dir() + "/" + path; - exists = fs->file_exists(path); - } - if (exists) { - String value = const_val; - lsp::DocumentLink link; - link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path); - link.range.start.line = LINE_NUMBER_TO_INDEX(tokenizer.get_token_line()); - link.range.end.line = link.range.start.line; - link.range.end.character = LINE_NUMBER_TO_INDEX(tokenizer.get_token_column()); - link.range.start.character = link.range.end.character - value.length(); - document_links.push_back(link); - } - } - } - tokenizer.advance(); - } -} - -void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol) { - const String uri = get_uri(); - - r_symbol.uri = uri; - r_symbol.script_path = path; - r_symbol.children.clear(); - r_symbol.name = p_class->name; - if (r_symbol.name.empty()) { - r_symbol.name = path.get_file(); - } - r_symbol.kind = lsp::SymbolKind::Class; - r_symbol.deprecated = false; - r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_class->line); - r_symbol.range.start.character = p_class->column; - r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_class->end_line); - 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; - r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class); - - for (int i = 0; i < p_class->variables.size(); ++i) { - const GDScriptParser::ClassNode::Member &m = p_class->variables[i]; - - lsp::DocumentSymbol symbol; - symbol.name = m.identifier; - symbol.kind = m.setter == "" && m.getter == "" ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property; - symbol.deprecated = false; - const int line = LINE_NUMBER_TO_INDEX(m.line); - symbol.range.start.line = line; - symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length(); - symbol.range.end.line = line; - symbol.range.end.character = lines[line].length(); - symbol.selectionRange.start.line = symbol.range.start.line; - if (m._export.type != Variant::NIL) { - symbol.detail += "export "; - } - symbol.detail += "var " + m.identifier; - if (m.data_type.kind != GDScriptParser::DataType::UNRESOLVED) { - symbol.detail += ": " + m.data_type.to_string(); - } - if (m.default_value.get_type() != Variant::NIL) { - symbol.detail += " = " + JSON::print(m.default_value); - } - - symbol.documentation = parse_documentation(line); - symbol.uri = uri; - symbol.script_path = path; - - r_symbol.children.push_back(symbol); - } - - for (int i = 0; i < p_class->_signals.size(); ++i) { - const GDScriptParser::ClassNode::Signal &signal = p_class->_signals[i]; - - lsp::DocumentSymbol symbol; - symbol.name = signal.name; - symbol.kind = lsp::SymbolKind::Event; - symbol.deprecated = false; - const int line = LINE_NUMBER_TO_INDEX(signal.line); - symbol.range.start.line = line; - symbol.range.start.character = lines[line].length() - lines[line].strip_edges(true, false).length(); - symbol.range.end.line = symbol.range.start.line; - symbol.range.end.character = lines[line].length(); - symbol.selectionRange.start.line = symbol.range.start.line; - symbol.documentation = parse_documentation(line); - symbol.uri = uri; - symbol.script_path = path; - symbol.detail = "signal " + signal.name + "("; - for (int j = 0; j < signal.arguments.size(); j++) { - if (j > 0) { - symbol.detail += ", "; - } - symbol.detail += signal.arguments[j]; - } - symbol.detail += ")"; - - r_symbol.children.push_back(symbol); - } - - for (RBMap::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { - lsp::DocumentSymbol symbol; - const GDScriptParser::ClassNode::Constant &c = E->value(); - - ERR_FAIL_COND(c.expression->type != Node::TYPE_CONSTANT); - - const GDScriptParser::ConstantNode *node = static_cast(c.expression); - - symbol.name = E->key(); - symbol.kind = lsp::SymbolKind::Constant; - symbol.deprecated = false; - const int line = LINE_NUMBER_TO_INDEX(E->get().expression->line); - symbol.range.start.line = line; - symbol.range.start.character = E->get().expression->column; - symbol.range.end.line = symbol.range.start.line; - symbol.range.end.character = lines[line].length(); - symbol.selectionRange.start.line = symbol.range.start.line; - symbol.documentation = parse_documentation(line); - symbol.uri = uri; - symbol.script_path = path; - - symbol.detail = "const " + symbol.name; - if (c.type.kind != GDScriptParser::DataType::UNRESOLVED) { - symbol.detail += ": " + c.type.to_string(); - } - - String value_text; - if (node->value.get_type() == Variant::OBJECT) { - RES res = node->value; - if (res.is_valid() && !res->get_path().empty()) { - value_text = "preload(\"" + res->get_path() + "\")"; - if (symbol.documentation.empty()) { - if (RBMap::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) { - symbol.documentation = S->get()->class_symbol.documentation; - } - } - } else { - value_text = JSON::print(node->value); - } - } else { - value_text = JSON::print(node->value); - } - if (!value_text.empty()) { - symbol.detail += " = " + value_text; - } - - r_symbol.children.push_back(symbol); - } - - for (int i = 0; i < p_class->functions.size(); ++i) { - const GDScriptParser::FunctionNode *func = p_class->functions[i]; - lsp::DocumentSymbol symbol; - parse_function_symbol(func, symbol); - r_symbol.children.push_back(symbol); - } - - for (int i = 0; i < p_class->static_functions.size(); ++i) { - const GDScriptParser::FunctionNode *func = p_class->static_functions[i]; - lsp::DocumentSymbol symbol; - parse_function_symbol(func, symbol); - r_symbol.children.push_back(symbol); - } - - for (int i = 0; i < p_class->subclasses.size(); ++i) { - const GDScriptParser::ClassNode *subclass = p_class->subclasses[i]; - lsp::DocumentSymbol symbol; - parse_class_symbol(subclass, symbol); - r_symbol.children.push_back(symbol); - } -} - -void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol) { - const String uri = get_uri(); - - r_symbol.name = p_func->name; - r_symbol.kind = p_func->_static ? lsp::SymbolKind::Function : lsp::SymbolKind::Method; - r_symbol.detail = "func " + p_func->name + "("; - r_symbol.deprecated = false; - const int line = LINE_NUMBER_TO_INDEX(p_func->line); - r_symbol.range.start.line = line; - r_symbol.range.start.character = p_func->column; - r_symbol.range.end.line = MAX(p_func->body->end_line - 2, r_symbol.range.start.line); - r_symbol.range.end.character = lines[r_symbol.range.end.line].length(); - r_symbol.selectionRange.start.line = r_symbol.range.start.line; - r_symbol.documentation = parse_documentation(line); - r_symbol.uri = uri; - r_symbol.script_path = path; - - String arguments; - for (int i = 0; i < p_func->arguments.size(); i++) { - lsp::DocumentSymbol symbol; - symbol.kind = lsp::SymbolKind::Variable; - symbol.name = p_func->arguments[i]; - symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->body->line); - symbol.range.start.character = p_func->body->column; - symbol.range.end = symbol.range.start; - symbol.uri = uri; - symbol.script_path = path; - r_symbol.children.push_back(symbol); - if (i > 0) { - arguments += ", "; - } - arguments += String(p_func->arguments[i]); - if (p_func->argument_types[i].kind != GDScriptParser::DataType::UNRESOLVED) { - arguments += ": " + p_func->argument_types[i].to_string(); - } - int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size()); - if (default_value_idx >= 0) { - const GDScriptParser::Node *current_defval_node = p_func->default_values[default_value_idx]; - const GDScriptParser::ConstantNode *const_node = NULL; - - if (current_defval_node->type == Node::TYPE_OPERATOR) { - const GDScriptParser::OperatorNode *operator_node = static_cast(current_defval_node); - - if (operator_node->next->type == Node::TYPE_CONSTANT) { - const_node = static_cast(operator_node->next); - } - } else if (current_defval_node->type == Node::TYPE_CONSTANT) { - const_node = static_cast(current_defval_node); - } - - if (const_node) { - String value = JSON::print(const_node->value); - arguments += " = " + value; - } - } - } - r_symbol.detail += arguments + ")"; - if (p_func->return_type.kind != GDScriptParser::DataType::UNRESOLVED) { - r_symbol.detail += " -> " + p_func->return_type.to_string(); - } - - List function_blocks; - List block_stack; - block_stack.push_back(p_func->body); - - while (!block_stack.empty()) { - GDScriptParser::BlockNode *block = block_stack[0]; - block_stack.pop_front(); - - function_blocks.push_back(block); - for (const List::Element *E = block->sub_blocks.front(); E; E = E->next()) { - block_stack.push_back(E->get()); - } - } - - for (const List::Element *B = function_blocks.front(); B; B = B->next()) { - for (const RBMap::Element *E = B->get()->variables.front(); E; E = E->next()) { - lsp::DocumentSymbol symbol; - const GDScriptParser::LocalVarNode *var = E->value(); - symbol.name = E->key(); - symbol.kind = lsp::SymbolKind::Variable; - symbol.range.start.line = LINE_NUMBER_TO_INDEX(E->get()->line); - symbol.range.start.character = E->get()->column; - symbol.range.end.line = symbol.range.start.line; - symbol.range.end.character = lines[symbol.range.end.line].length(); - symbol.uri = uri; - symbol.script_path = path; - symbol.detail = "var " + symbol.name; - if (var->datatype.kind != GDScriptParser::DataType::UNRESOLVED) { - symbol.detail += ": " + var->datatype.to_string(); - } - symbol.documentation = parse_documentation(line); - r_symbol.children.push_back(symbol); - } - } -} - -String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) { - ERR_FAIL_INDEX_V(p_line, lines.size(), String()); - - List doc_lines; - - if (!p_docs_down) { // inline comment - String inline_comment = lines[p_line]; - int comment_start = inline_comment.find("#"); - if (comment_start != -1) { - inline_comment = inline_comment.substr(comment_start, inline_comment.length()).strip_edges(); - if (inline_comment.length() > 1) { - doc_lines.push_back(inline_comment.substr(1, inline_comment.length())); - } - } - } - - int step = p_docs_down ? 1 : -1; - int start_line = p_docs_down ? p_line : p_line - 1; - for (int i = start_line; true; i += step) { - if (i < 0 || i >= lines.size()) { - break; - } - - String line_comment = lines[i].strip_edges(true, false); - if (line_comment.begins_with("#")) { - line_comment = line_comment.substr(1, line_comment.length()); - if (p_docs_down) { - doc_lines.push_back(line_comment); - } else { - doc_lines.push_front(line_comment); - } - } else { - if (i > 0 && i < lines.size() - 1) { - String next_line = lines[i + step].strip_edges(true, false); - if (next_line.begins_with("#")) { - continue; - } - } - break; - } - } - - String doc; - for (List::Element *E = doc_lines.front(); E; E = E->next()) { - doc += E->get() + "\n"; - } - return doc; -} - -String ExtendGDScriptParser::get_text_for_completion(const lsp::Position &p_cursor) const { - String longthing; - int len = lines.size(); - for (int i = 0; i < len; i++) { - if (i == p_cursor.line) { - longthing += lines[i].substr(0, p_cursor.character); - longthing += String::chr(0xFFFF); //not unicode, represents the cursor - longthing += lines[i].substr(p_cursor.character, lines[i].size()); - } else { - longthing += lines[i]; - } - - if (i != len - 1) { - longthing += "\n"; - } - } - - return longthing; -} - -String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol, bool p_func_required) const { - String longthing; - int len = lines.size(); - for (int i = 0; i < len; i++) { - if (i == p_cursor.line) { - String line = lines[i]; - String first_part = line.substr(0, p_cursor.character); - String last_part = line.substr(p_cursor.character + 1, lines[i].length()); - if (!p_symbol.empty()) { - String left_cursor_text; - for (int c = p_cursor.character - 1; c >= 0; c--) { - left_cursor_text = line.substr(c, p_cursor.character - c); - if (p_symbol.begins_with(left_cursor_text)) { - first_part = line.substr(0, c); - first_part += p_symbol; - break; - } - } - } - - longthing += first_part; - longthing += String::chr(0xFFFF); //not unicode, represents the cursor - if (p_func_required) { - longthing += "("; // tell the parser this is a function call - } - longthing += last_part; - } else { - longthing += lines[i]; - } - - if (i != len - 1) { - longthing += "\n"; - } - } - - return longthing; -} - -String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const { - ERR_FAIL_INDEX_V(p_position.line, lines.size(), ""); - String line = lines[p_position.line]; - if (line.empty()) { - return ""; - } - ERR_FAIL_INDEX_V(p_position.character, line.size(), ""); - - int start_pos = p_position.character; - for (int c = p_position.character; c >= 0; c--) { - start_pos = c; - CharType ch = line[c]; - bool valid_char = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'; - if (!valid_char) { - break; - } - } - - int end_pos = p_position.character; - for (int c = p_position.character; c < line.length(); c++) { - CharType ch = line[c]; - bool valid_char = (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_'; - if (!valid_char) { - break; - } - end_pos = c; - } - if (start_pos < end_pos) { - p_offset.x = start_pos - p_position.character; - p_offset.y = end_pos - p_position.character; - return line.substr(start_pos + 1, end_pos - start_pos); - } - - return ""; -} - -String ExtendGDScriptParser::get_uri() const { - return GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path); -} - -const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const { - const lsp::DocumentSymbol *ret = nullptr; - if (p_line < p_parent.range.start.line) { - return ret; - } else if (p_parent.range.start.line == p_line) { - return &p_parent; - } else { - for (int i = 0; i < p_parent.children.size(); i++) { - ret = search_symbol_defined_at_line(p_line, p_parent.children[i]); - if (ret) { - break; - } - } - } - return ret; -} - -Error ExtendGDScriptParser::get_left_function_call(const lsp::Position &p_position, lsp::Position &r_func_pos, int &r_arg_index) const { - ERR_FAIL_INDEX_V(p_position.line, lines.size(), ERR_INVALID_PARAMETER); - - int bracket_stack = 0; - int index = 0; - - bool found = false; - for (int l = p_position.line; l >= 0; --l) { - String line = lines[l]; - int c = line.length() - 1; - if (l == p_position.line) { - c = MIN(c, p_position.character - 1); - } - - while (c >= 0) { - const CharType &character = line[c]; - if (character == ')') { - ++bracket_stack; - } else if (character == '(') { - --bracket_stack; - if (bracket_stack < 0) { - found = true; - } - } - if (bracket_stack <= 0 && character == ',') { - ++index; - } - --c; - if (found) { - r_func_pos.character = c; - break; - } - } - - if (found) { - r_func_pos.line = l; - r_arg_index = index; - return OK; - } - } - - return ERR_METHOD_NOT_FOUND; -} - -const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int p_line) const { - if (p_line <= 0) { - return &class_symbol; - } - return search_symbol_defined_at_line(p_line, class_symbol); -} - -const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String &p_name, const String &p_subclass) const { - if (p_subclass.empty()) { - const lsp::DocumentSymbol *const *ptr = members.getptr(p_name); - if (ptr) { - return *ptr; - } - } else { - if (const ClassMembers *_class = inner_classes.getptr(p_subclass)) { - const lsp::DocumentSymbol *const *ptr = _class->getptr(p_name); - if (ptr) { - return *ptr; - } - } - } - - return nullptr; -} - -const List &ExtendGDScriptParser::get_document_links() const { - return document_links; -} - -const Array &ExtendGDScriptParser::get_member_completions() { - if (member_completions.empty()) { - const String *name = members.next(nullptr); - while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); - lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(path, *name); - member_completions.push_back(item.to_json()); - - name = members.next(name); - } - - const String *_class = inner_classes.next(nullptr); - while (_class) { - const ClassMembers *inner_class = inner_classes.getptr(*_class); - const String *member_name = inner_class->next(nullptr); - while (member_name) { - const lsp::DocumentSymbol *symbol = inner_class->get(*member_name); - lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(*_class, *member_name)); - member_completions.push_back(item.to_json()); - - member_name = inner_class->next(member_name); - } - - _class = inner_classes.next(_class); - } - } - - return member_completions; -} - -Dictionary ExtendGDScriptParser::dump_function_api(const GDScriptParser::FunctionNode *p_func) const { - Dictionary func; - ERR_FAIL_NULL_V(p_func, func); - func["name"] = p_func->name; - func["return_type"] = p_func->return_type.to_string(); - Array arguments; - for (int i = 0; i < p_func->arguments.size(); i++) { - Dictionary arg; - arg["name"] = p_func->arguments[i]; - arg["type"] = p_func->argument_types[i].to_string(); - int default_value_idx = i - (p_func->arguments.size() - p_func->default_values.size()); - - if (default_value_idx >= 0) { - const GDScriptParser::Node *current_defval_node = p_func->default_values[default_value_idx]; - const GDScriptParser::ConstantNode *const_node = NULL; - - if (current_defval_node->type == Node::TYPE_OPERATOR) { - const GDScriptParser::OperatorNode *operator_node = static_cast(current_defval_node); - - if (operator_node->next->type == Node::TYPE_CONSTANT) { - const_node = static_cast(operator_node->next); - } - } else if (current_defval_node->type == Node::TYPE_CONSTANT) { - const_node = static_cast(current_defval_node); - } - - if (const_node) { - arg["default_value"] = const_node->value; - } - } - - arguments.push_back(arg); - } - if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(p_func->line))) { - func["signature"] = symbol->detail; - func["description"] = symbol->documentation; - } - func["arguments"] = arguments; - return func; -} - -Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode *p_class) const { - Dictionary class_api; - - ERR_FAIL_NULL_V(p_class, class_api); - - class_api["name"] = String(p_class->name); - class_api["path"] = path; - Array extends_class; - for (int i = 0; i < p_class->extends_class.size(); i++) { - extends_class.append(String(p_class->extends_class[i])); - } - class_api["extends_class"] = extends_class; - class_api["extends_file"] = String(p_class->extends_file); - class_api["icon"] = String(p_class->icon_path); - - if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(p_class->line))) { - class_api["signature"] = symbol->detail; - class_api["description"] = symbol->documentation; - } - - Array subclasses; - for (int i = 0; i < p_class->subclasses.size(); i++) { - subclasses.push_back(dump_class_api(p_class->subclasses[i])); - } - class_api["sub_classes"] = subclasses; - - Array constants; - for (RBMap::Element *E = p_class->constant_expressions.front(); E; E = E->next()) { - const GDScriptParser::ClassNode::Constant &c = E->value(); - - ERR_FAIL_COND_V(c.expression->type != Node::TYPE_CONSTANT, class_api); - - const GDScriptParser::ConstantNode *node = static_cast(c.expression); - - Dictionary api; - api["name"] = E->key(); - api["value"] = node->value; - api["data_type"] = node->datatype.to_string(); - if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(node->line))) { - api["signature"] = symbol->detail; - api["description"] = symbol->documentation; - } - constants.push_back(api); - } - class_api["constants"] = constants; - - Array members; - for (int i = 0; i < p_class->variables.size(); ++i) { - const GDScriptParser::ClassNode::Member &m = p_class->variables[i]; - Dictionary api; - api["name"] = m.identifier; - api["data_type"] = m.data_type.to_string(); - api["default_value"] = m.default_value; - api["setter"] = String(m.setter); - api["getter"] = String(m.getter); - api["export"] = m._export.type != Variant::NIL; - if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.line))) { - api["signature"] = symbol->detail; - api["description"] = symbol->documentation; - } - members.push_back(api); - } - class_api["members"] = members; - - Array signals; - for (int i = 0; i < p_class->_signals.size(); ++i) { - const GDScriptParser::ClassNode::Signal &signal = p_class->_signals[i]; - Dictionary api; - api["name"] = signal.name; - Array args; - for (int j = 0; j < signal.arguments.size(); j++) { - args.append(signal.arguments[j]); - } - api["arguments"] = args; - if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(signal.line))) { - api["signature"] = symbol->detail; - api["description"] = symbol->documentation; - } - signals.push_back(api); - } - class_api["signals"] = signals; - - Array methods; - for (int i = 0; i < p_class->functions.size(); ++i) { - methods.append(dump_function_api(p_class->functions[i])); - } - class_api["methods"] = methods; - - Array static_functions; - for (int i = 0; i < p_class->static_functions.size(); ++i) { - static_functions.append(dump_function_api(p_class->static_functions[i])); - } - class_api["static_functions"] = static_functions; - - return class_api; -} - -Dictionary ExtendGDScriptParser::generate_api() const { - Dictionary api; - const GDScriptParser::Node *head = get_parse_tree(); - if (head && head->type == Node::TYPE_CLASS) { - const GDScriptParser::ClassNode *gdclass = static_cast(head); - api = dump_class_api(gdclass); - } - return api; -} - -Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) { - path = p_path; - lines = p_code.split("\n"); - - Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, nullptr, false); - update_diagnostics(); - update_symbols(); - update_document_links(p_code); - return err; -} diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h deleted file mode 100644 index 28e0b53..0000000 --- a/modules/gdscript/language_server/gdscript_extend_parser.h +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************/ -/* gdscript_extend_parser.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef GDSCRIPT_EXTEND_PARSER_H -#define GDSCRIPT_EXTEND_PARSER_H - -#include "../gdscript_parser.h" -#include "core/variant/variant.h" -#include "lsp.hpp" - -#ifndef LINE_NUMBER_TO_INDEX -#define LINE_NUMBER_TO_INDEX(p_line) ((p_line)-1) -#endif - -#ifndef SYMBOL_SEPERATOR -#define SYMBOL_SEPERATOR "::" -#endif - -#ifndef JOIN_SYMBOLS -#define JOIN_SYMBOLS(p_path, name) ((p_path) + SYMBOL_SEPERATOR + (name)) -#endif - -typedef HashMap ClassMembers; - -class ExtendGDScriptParser : public GDScriptParser { - String path; - Vector lines; - - lsp::DocumentSymbol class_symbol; - Vector diagnostics; - List document_links; - ClassMembers members; - HashMap inner_classes; - - void update_diagnostics(); - - void update_symbols(); - void update_document_links(const String &p_code); - void parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol); - void parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol); - - Dictionary dump_function_api(const GDScriptParser::FunctionNode *p_func) const; - Dictionary dump_class_api(const GDScriptParser::ClassNode *p_class) const; - - String parse_documentation(int p_line, bool p_docs_down = false); - const lsp::DocumentSymbol *search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const; - - Array member_completions; - -public: - _FORCE_INLINE_ const String &get_path() const { return path; } - _FORCE_INLINE_ const Vector &get_lines() const { return lines; } - _FORCE_INLINE_ const lsp::DocumentSymbol &get_symbols() const { return class_symbol; } - _FORCE_INLINE_ const Vector &get_diagnostics() const { return diagnostics; } - _FORCE_INLINE_ const ClassMembers &get_members() const { return members; } - _FORCE_INLINE_ const HashMap &get_inner_classes() const { return inner_classes; } - - Error get_left_function_call(const lsp::Position &p_position, lsp::Position &r_func_pos, int &r_arg_index) const; - - String get_text_for_completion(const lsp::Position &p_cursor) const; - String get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol = "", bool p_func_required = false) const; - String get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const; - String get_uri() const; - - const lsp::DocumentSymbol *get_symbol_defined_at_line(int p_line) const; - const lsp::DocumentSymbol *get_member_symbol(const String &p_name, const String &p_subclass = "") const; - const List &get_document_links() const; - - const Array &get_member_completions(); - Dictionary generate_api() const; - - Error parse(const String &p_code, const String &p_path); -}; - -#endif // GDSCRIPT_EXTEND_PARSER_H diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp deleted file mode 100644 index 86990d5..0000000 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/**************************************************************************/ -/* gdscript_language_protocol.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "gdscript_language_protocol.h" - -#include "core/io/json.h" -#include "core/config/project_settings.h" -#include "editor/editor_log.h" -#include "editor/editor_node.h" -#include "editor/editor_settings.h" -#include "editor/editor_help.h" - -GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = nullptr; - -Error GDScriptLanguageProtocol::LSPeer::handle_data() { - int read = 0; - // Read headers - if (!has_header) { - while (true) { - if (req_pos >= LSP_MAX_BUFFER_SIZE) { - req_pos = 0; - ERR_FAIL_COND_V_MSG(true, ERR_OUT_OF_MEMORY, "Response header too big"); - } - Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); - if (err != OK) { - return FAILED; - } else if (read != 1) { // Busy, wait until next poll - return ERR_BUSY; - } - char *r = (char *)req_buf; - int l = req_pos; - - // End of headers - if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') { - r[l - 3] = '\0'; // Null terminate to read string - String header; - header.parse_utf8(r); - content_length = header.substr(16).to_int(); - has_header = true; - req_pos = 0; - break; - } - req_pos++; - } - } - if (has_header) { - while (req_pos < content_length) { - if (req_pos >= LSP_MAX_BUFFER_SIZE) { - req_pos = 0; - has_header = false; - ERR_FAIL_COND_V_MSG(req_pos >= LSP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big"); - } - Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); - if (err != OK) { - return FAILED; - } else if (read != 1) { - return ERR_BUSY; - } - req_pos++; - } - - // Parse data - String msg; - msg.parse_utf8((const char *)req_buf, req_pos); - - // Reset to read again - req_pos = 0; - has_header = false; - - // Response - String output = GDScriptLanguageProtocol::get_singleton()->process_message(msg); - if (!output.empty()) { - res_queue.push_back(output.utf8()); - } - } - return OK; -} - -Error GDScriptLanguageProtocol::LSPeer::send_data() { - int sent = 0; - if (!res_queue.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); - if (err != OK) { - return err; - } - res_sent += sent; - } - // Response sent - if (res_sent >= c_res.size() - 1) { - res_sent = 0; - res_queue.remove(0); - } - } - return OK; -} - -Error GDScriptLanguageProtocol::on_client_connected() { - Ref tcp_peer = server->take_connection(); - ERR_FAIL_COND_V_MSG(clients.size() >= LSP_MAX_CLIENTS, FAILED, "Max client limits reached"); - Ref peer = memnew(LSPeer); - peer->connection = tcp_peer; - clients.set(next_client_id, peer); - next_client_id++; - EditorNode::get_log()->add_message("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); -} - -String GDScriptLanguageProtocol::process_message(const String &p_text) { - String ret = process_string(p_text); - if (ret.empty()) { - return ret; - } else { - return format_output(ret); - } -} - -String GDScriptLanguageProtocol::format_output(const String &p_text) { - String header = "Content-Length: "; - CharString charstr = p_text.utf8(); - size_t len = charstr.length(); - header += itos(len); - header += "\r\n\r\n"; - - return header + p_text; -} - -void GDScriptLanguageProtocol::_bind_methods() { - ClassDB::bind_method(D_METHOD("initialize", "params"), &GDScriptLanguageProtocol::initialize); - ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized); - ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected); - ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected); - ClassDB::bind_method(D_METHOD("notify_client", "method", "params", "client_id"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled); - ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document); - ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace); - ClassDB::bind_method(D_METHOD("is_initialized"), &GDScriptLanguageProtocol::is_initialized); -} - -Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { - lsp::InitializeResult ret; - - String root_uri = p_params["rootUri"]; - String root = p_params["rootPath"]; - bool is_same_workspace; -#ifndef WINDOWS_ENABLED - is_same_workspace = root.to_lower() == workspace->root.to_lower(); -#else - is_same_workspace = root.replace("\\", "/").to_lower() == workspace->root.to_lower(); -#endif - - if (root_uri.length() && is_same_workspace) { - workspace->root_uri = root_uri; - } else { - String r_root = workspace->root; - r_root = r_root.lstrip("/"); - workspace->root_uri = "file:///" + r_root; - - Dictionary params; - params["path"] = workspace->root; - Dictionary request = make_notification("gdscript_client/changeWorkspace", params); - - ERR_FAIL_COND_V_MSG(!clients.has(latest_client_id), ret.to_json(), - vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id)); - Ref peer = clients.get(latest_client_id); - if (peer != nullptr) { - String msg = JSON::print(request); - msg = format_output(msg); - (*peer)->res_queue.push_back(msg.utf8()); - } - } - - if (!_initialized) { - workspace->initialize(); - text_document->initialize(); - _initialized = true; - } - - return ret.to_json(); -} - -void GDScriptLanguageProtocol::initialized(const Variant &p_params) { - lsp::GodotCapabilities capabilities; - - DocData *doc = EditorHelp::get_doc_data(); - for (RBMap::Element *E = doc->class_list.front(); E; E = E->next()) { - lsp::GodotNativeClassInfo gdclass; - gdclass.name = E->get().name; - gdclass.class_doc = &(E->get()); - if (ClassDB::ClassInfo *ptr = ClassDB::classes.getptr(StringName(E->get().name))) { - gdclass.class_info = ptr; - } - capabilities.native_classes.push_back(gdclass); - } - - notify_client("gdscript/capabilities", capabilities.to_json()); -} - -void GDScriptLanguageProtocol::poll() { - if (server->is_connection_available()) { - on_client_connected(); - } - const int *id = nullptr; - while ((id = clients.next(id))) { - Ref peer = clients.get(*id); - StreamPeerTCP::Status status = peer->connection->get_status(); - if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) { - on_client_disconnected(*id); - id = nullptr; - } else { - if (peer->connection->get_available_bytes() > 0) { - latest_client_id = *id; - Error err = peer->handle_data(); - if (err != OK && err != ERR_BUSY) { - on_client_disconnected(*id); - id = nullptr; - } - } - Error err = peer->send_data(); - if (err != OK && err != ERR_BUSY) { - on_client_disconnected(*id); - id = nullptr; - } - } - } -} - -Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) { - return server->listen(p_port, p_bind_ip); -} - -void GDScriptLanguageProtocol::stop() { - const int *id = nullptr; - while ((id = clients.next(id))) { - Ref peer = clients.get(*id); - peer->connection->disconnect_from_host(); - } - - server->stop(); -} - -void GDScriptLanguageProtocol::notify_client(const String &p_method, const Variant &p_params, int p_client_id) { - if (p_client_id == -1) { - ERR_FAIL_COND_MSG(latest_client_id == -1, - "GDScript LSP: Can't notify client as none was connected."); - p_client_id = latest_client_id; - } - ERR_FAIL_COND(!clients.has(p_client_id)); - Ref peer = clients.get(p_client_id); - ERR_FAIL_COND(peer == nullptr); - - Dictionary message = make_notification(p_method, p_params); - String msg = JSON::print(message); - msg = format_output(msg); - peer->res_queue.push_back(msg.utf8()); -} - -void GDScriptLanguageProtocol::request_client(const String &p_method, const Variant &p_params, int p_client_id) { - if (p_client_id == -1) { - ERR_FAIL_COND_MSG(latest_client_id == -1, - "GDScript LSP: Can't notify client as none was connected."); - p_client_id = latest_client_id; - } - ERR_FAIL_COND(!clients.has(p_client_id)); - Ref peer = clients.get(p_client_id); - ERR_FAIL_COND(peer == nullptr); - - Dictionary message = make_request(p_method, p_params, next_server_id); - next_server_id++; - String msg = JSON::print(message); - msg = format_output(msg); - peer->res_queue.push_back(msg.utf8()); -} - -bool GDScriptLanguageProtocol::is_smart_resolve_enabled() const { - return bool(_EDITOR_GET("network/language_server/enable_smart_resolve")); -} - -bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const { - return bool(_EDITOR_GET("network/language_server/show_native_symbols_in_editor")); -} - -GDScriptLanguageProtocol::GDScriptLanguageProtocol() { - server.instance(); - singleton = this; - workspace.instance(); - text_document.instance(); - set_scope("textDocument", text_document.ptr()); - set_scope("completionItem", text_document.ptr()); - set_scope("workspace", workspace.ptr()); - workspace->root = ProjectSettings::get_singleton()->get_resource_path(); -} diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h deleted file mode 100644 index 8c06ade..0000000 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************************/ -/* gdscript_language_protocol.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef GDSCRIPT_LANGUAGE_PROTOCOL_H -#define GDSCRIPT_LANGUAGE_PROTOCOL_H - -#include "core/io/stream_peer.h" -#include "core/io/stream_peer_tcp.h" -#include "core/io/tcp_server.h" -#include "gdscript_text_document.h" -#include "gdscript_workspace.h" -#include "lsp.hpp" -#include "modules/jsonrpc/jsonrpc.h" - -#define LSP_MAX_BUFFER_SIZE 4194304 -#define LSP_MAX_CLIENTS 8 - -class GDScriptLanguageProtocol : public JSONRPC { - GDCLASS(GDScriptLanguageProtocol, JSONRPC) - -private: - struct LSPeer : Reference { - Ref connection; - - uint8_t req_buf[LSP_MAX_BUFFER_SIZE]; - int req_pos = 0; - bool has_header = false; - bool has_content = false; - int content_length = 0; - Vector res_queue; - int res_sent = 0; - - Error handle_data(); - Error send_data(); - }; - - enum LSPErrorCode { - RequestCancelled = -32800, - ContentModified = -32801, - }; - - static GDScriptLanguageProtocol *singleton; - - HashMap> clients; - Ref server; - int latest_client_id = 0; - int next_client_id = 0; - int next_server_id = 0; - - Ref text_document; - Ref workspace; - - Error on_client_connected(); - void on_client_disconnected(const int &p_client_id); - - String process_message(const String &p_text); - String format_output(const String &p_text); - - bool _initialized = false; - -protected: - static void _bind_methods(); - - Dictionary initialize(const Dictionary &p_params); - void initialized(const Variant &p_params); - -public: - _FORCE_INLINE_ static GDScriptLanguageProtocol *get_singleton() { return singleton; } - _FORCE_INLINE_ Ref get_workspace() { return workspace; } - _FORCE_INLINE_ Ref get_text_document() { return text_document; } - _FORCE_INLINE_ bool is_initialized() const { return _initialized; } - - void poll(); - Error start(int p_port, const IP_Address &p_bind_ip); - void stop(); - - void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1); - void request_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1); - - bool is_smart_resolve_enabled() const; - bool is_goto_native_symbols_enabled() const; - - GDScriptLanguageProtocol(); -}; - -#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 deleted file mode 100644 index eb25525..0000000 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************/ -/* gdscript_language_server.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "gdscript_language_server.h" - -#include "core/os/file_access.h" -#include "core/os/os.h" -#include "editor/editor_log.h" -#include "editor/editor_node.h" -#include "editor/editor_settings.h" - -int GDScriptLanguageServer::port_override = -1; - -GDScriptLanguageServer::GDScriptLanguageServer() { - enabled = false; - thread_running = false; - started = false; - use_thread = false; - host = "127.0.0.1"; - port = 6008; - - _EDITOR_DEF("network/language_server/enabled", enabled, true); - _EDITOR_DEF("network/language_server/remote_host", host); - _EDITOR_DEF("network/language_server/remote_port", port); - _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); -} - -void GDScriptLanguageServer::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: - start(); - break; - case NOTIFICATION_EXIT_TREE: - stop(); - break; - case NOTIFICATION_INTERNAL_PROCESS: { - if (started && !use_thread) { - protocol.poll(); - } - } break; - case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { - if (!enabled) { - return; - } - - String host = String(_EDITOR_GET("network/language_server/remote_host")); - int port = (GDScriptLanguageServer::port_override > -1) ? GDScriptLanguageServer::port_override : (int)_EDITOR_GET("network/language_server/remote_port"); - bool use_thread = (bool)_EDITOR_GET("network/language_server/use_thread"); - if (host != this->host || port != this->port || use_thread != this->use_thread) { - this->stop(); - this->start(); - } - } break; - } -} - -void GDScriptLanguageServer::thread_main(void *p_userdata) { - GDScriptLanguageServer *self = static_cast(p_userdata); - while (self->thread_running) { - // Poll 20 times per second - self->protocol.poll(); - OS::get_singleton()->delay_usec(50000); - } -} - -void GDScriptLanguageServer::start() { - enabled = _EDITOR_GET("network/language_server/enabled"); - 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"); - - if (!enabled) { - return; - } - - if (protocol.start(port, IP_Address(host)) == OK) { - EditorNode::get_log()->add_message("--- GDScript language server started on port " + itos(port) + " ---", EditorLog::MSG_TYPE_EDITOR); - if (use_thread) { - thread_running = true; - thread.start(GDScriptLanguageServer::thread_main, this); - } - set_process_internal(!use_thread); - started = true; - } -} - -void GDScriptLanguageServer::stop() { - if (!enabled) { - return; - } - - if (use_thread) { - ERR_FAIL_COND(!thread.is_started()); - thread_running = false; - thread.wait_to_finish(); - } - protocol.stop(); - started = false; - EditorNode::get_log()->add_message("--- GDScript language server stopped ---", EditorLog::MSG_TYPE_EDITOR); -} - -void register_lsp_types() { - ClassDB::register_class(); - ClassDB::register_class(); - ClassDB::register_class(); -} diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h deleted file mode 100644 index 3d7faa8..0000000 --- a/modules/gdscript/language_server/gdscript_language_server.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************/ -/* gdscript_language_server.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef GDSCRIPT_LANGUAGE_SERVER_H -#define GDSCRIPT_LANGUAGE_SERVER_H - -#include "../gdscript_parser.h" -#include "editor/editor_plugin.h" -#include "gdscript_language_protocol.h" - -class GDScriptLanguageServer : public EditorPlugin { - GDCLASS(GDScriptLanguageServer, EditorPlugin); - - GDScriptLanguageProtocol protocol; - - Thread thread; - bool thread_running; - bool started; - bool use_thread; - String host; - int port; - bool enabled; - - static void thread_main(void *p_userdata); - -private: - void _notification(int p_what); - -public: - static int port_override; - GDScriptLanguageServer(); - void start(); - void stop(); -}; - -void register_lsp_types(); - -#endif // GDSCRIPT_LANGUAGE_SERVER_H diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp deleted file mode 100644 index 44e856e..0000000 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/**************************************************************************/ -/* gdscript_text_document.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "gdscript_text_document.h" - -#include "../gdscript.h" -#include "core/os/os.h" -#include "editor/editor_settings.h" -#include "gdscript_extend_parser.h" -#include "gdscript_language_protocol.h" - -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); - ClassDB::bind_method(D_METHOD("colorPresentation"), &GDScriptTextDocument::colorPresentation); - ClassDB::bind_method(D_METHOD("hover"), &GDScriptTextDocument::hover); - ClassDB::bind_method(D_METHOD("definition"), &GDScriptTextDocument::definition); - ClassDB::bind_method(D_METHOD("declaration"), &GDScriptTextDocument::declaration); - ClassDB::bind_method(D_METHOD("signatureHelp"), &GDScriptTextDocument::signatureHelp); - ClassDB::bind_method(D_METHOD("show_native_symbol_in_editor"), &GDScriptTextDocument::show_native_symbol_in_editor); -} - -void GDScriptTextDocument::didOpen(const Variant &p_param) { - lsp::TextDocumentItem doc = load_document_item(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; - Array contentChanges = dict["contentChanges"]; - for (int i = 0; i < contentChanges.size(); ++i) { - lsp::TextDocumentContentChangeEvent evt; - evt.load(contentChanges[i]); - doc.text = evt.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 doc; - Dictionary params = p_param; - doc.load(params["textDocument"]); - return doc; -} - -void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol *symbol) { - ERR_FAIL_NULL(symbol); - GDScriptLanguageProtocol::get_singleton()->notify_client("gdscript/show_native_symbol", symbol->to_json(true)); -} - -void GDScriptTextDocument::initialize() { - if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - const HashMap &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members; - - const StringName *class_ptr = native_members.next(nullptr); - while (class_ptr) { - const ClassMembers &members = native_members.get(*class_ptr); - - const String *name = members.next(nullptr); - while (name) { - const lsp::DocumentSymbol *symbol = members.get(*name); - lsp::CompletionItem item = symbol->make_completion_item(); - item.data = JOIN_SYMBOLS(String(*class_ptr), *name); - native_member_completions.push_back(item.to_json()); - - name = members.next(name); - } - - class_ptr = native_members.next(class_ptr); - } - } -} - -Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) { - Variant ret; - - lsp::NativeSymbolInspectParams params; - params.load(p_params); - - if (const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_native_symbol(params)) { - ret = symbol->to_json(true); - notify_client_show_symbol(symbol); - } - - return ret; -} - -Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) { - Dictionary params = p_params["textDocument"]; - String uri = params["uri"]; - String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(uri); - Array arr; - if (const RBMap::Element *parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) { - Vector list; - parser->get()->get_symbols().symbol_tree_as_list(uri, list); - for (int i = 0; i < list.size(); i++) { - arr.push_back(list[i].to_json()); - } - } - return arr; -} - -Array GDScriptTextDocument::completion(const Dictionary &p_params) { - Array arr; - - lsp::CompletionParams params; - params.load(p_params); - Dictionary request_data = params.to_json(); - - List options; - GDScriptLanguageProtocol::get_singleton()->get_workspace()->completion(params, &options); - - if (!options.empty()) { - int i = 0; - arr.resize(options.size()); - - for (const List::Element *E = options.front(); E; E = E->next()) { - const ScriptCodeCompletionOption &option = E->get(); - lsp::CompletionItem item; - item.label = option.display; - item.data = request_data; - item.insertText = option.insert_text; - - switch (option.kind) { - case ScriptCodeCompletionOption::KIND_ENUM: - item.kind = lsp::CompletionItemKind::Enum; - break; - case ScriptCodeCompletionOption::KIND_CLASS: - item.kind = lsp::CompletionItemKind::Class; - break; - case ScriptCodeCompletionOption::KIND_MEMBER: - item.kind = lsp::CompletionItemKind::Property; - break; - case ScriptCodeCompletionOption::KIND_FUNCTION: - item.kind = lsp::CompletionItemKind::Method; - break; - case ScriptCodeCompletionOption::KIND_SIGNAL: - item.kind = lsp::CompletionItemKind::Event; - break; - case ScriptCodeCompletionOption::KIND_CONSTANT: - item.kind = lsp::CompletionItemKind::Constant; - break; - case ScriptCodeCompletionOption::KIND_VARIABLE: - item.kind = lsp::CompletionItemKind::Variable; - break; - case ScriptCodeCompletionOption::KIND_FILE_PATH: - item.kind = lsp::CompletionItemKind::File; - break; - case ScriptCodeCompletionOption::KIND_NODE_PATH: - item.kind = lsp::CompletionItemKind::Snippet; - break; - case ScriptCodeCompletionOption::KIND_PLAIN_TEXT: - item.kind = lsp::CompletionItemKind::Text; - break; - } - - arr[i] = item.to_json(); - i++; - } - } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - arr = native_member_completions.duplicate(); - - for (RBMap::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.front(); E; E = E->next()) { - ExtendGDScriptParser *script = E->get(); - const Array &items = script->get_member_completions(); - - const int start_size = arr.size(); - arr.resize(start_size + items.size()); - for (int i = start_size; i < arr.size(); i++) { - arr[i] = items[i - start_size]; - } - } - } - 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); - - lsp::CompletionParams params; - Variant data = p_params["data"]; - - const lsp::DocumentSymbol *symbol = nullptr; - - if (data.get_type() == Variant::DICTIONARY) { - params.load(p_params["data"]); - symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params, item.label, item.kind == lsp::CompletionItemKind::Method || item.kind == lsp::CompletionItemKind::Function); - - } else if (data.get_type() == Variant::STRING) { - String query = data; - - Vector 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]; - String inner_class_name; - if (param_symbols.size() >= 3) { - inner_class_name = param_symbols[1]; - } - - if (const ClassMembers *members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members.getptr(class_name)) { - if (const lsp::DocumentSymbol *const *member = members->getptr(member_name)) { - symbol = *member; - } - } - - if (!symbol) { - if (const RBMap::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(class_name)) { - symbol = E->get()->get_member_symbol(member_name, inner_class_name); - } - } - } - } - - if (symbol) { - item.documentation = symbol->render(); - } - - if (item.kind == lsp::CompletionItemKind::Event) { - if (params.context.triggerKind == lsp::CompletionTriggerKind::TriggerCharacter && (params.context.triggerCharacter == "(")) { - const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; - item.insertText = quote_style + item.label + quote_style; - } - } - - return item.to_json(true); -} - -Array GDScriptTextDocument::foldingRange(const Dictionary &p_params) { - Array arr; - return arr; -} - -Array GDScriptTextDocument::codeLens(const Dictionary &p_params) { - Array arr; - return arr; -} - -Array GDScriptTextDocument::documentLink(const Dictionary &p_params) { - Array ret; - - lsp::DocumentLinkParams params; - params.load(p_params); - - List links; - GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links); - for (const List::Element *E = links.front(); E; E = E->next()) { - ret.push_back(E->get().to_json()); - } - return ret; -} - -Array GDScriptTextDocument::colorPresentation(const Dictionary &p_params) { - Array arr; - return arr; -} - -Variant GDScriptTextDocument::hover(const Dictionary &p_params) { - lsp::TextDocumentPositionParams params; - params.load(p_params); - - const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params); - if (symbol) { - lsp::Hover hover; - hover.contents = symbol->render(); - hover.range.start = params.position; - hover.range.end = params.position; - return hover.to_json(); - - } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - Dictionary ret; - Array contents; - List list; - GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(params, list); - for (List::Element *E = list.front(); E; E = E->next()) { - if (const lsp::DocumentSymbol *s = E->get()) { - contents.push_back(s->render().value); - } - } - ret["contents"] = contents; - return ret; - } - - return Variant(); -} - -Array GDScriptTextDocument::definition(const Dictionary &p_params) { - lsp::TextDocumentPositionParams params; - params.load(p_params); - List symbols; - Array arr = this->find_symbols(params, symbols); - return arr; -} - -Variant GDScriptTextDocument::declaration(const Dictionary &p_params) { - lsp::TextDocumentPositionParams params; - params.load(p_params); - List symbols; - Array arr = this->find_symbols(params, symbols); - if (arr.empty() && !symbols.empty() && !symbols.front()->get()->native_class.empty()) { // Find a native symbol - const lsp::DocumentSymbol *symbol = symbols.front()->get(); - if (GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) { - String id; - switch (symbol->kind) { - case lsp::SymbolKind::Class: - id = "class_name:" + symbol->name; - break; - case lsp::SymbolKind::Constant: - id = "class_constant:" + symbol->native_class + ":" + symbol->name; - break; - case lsp::SymbolKind::Property: - case lsp::SymbolKind::Variable: - id = "class_property:" + symbol->native_class + ":" + symbol->name; - break; - case lsp::SymbolKind::Enum: - id = "class_enum:" + symbol->native_class + ":" + symbol->name; - break; - case lsp::SymbolKind::Method: - case lsp::SymbolKind::Function: - id = "class_method:" + symbol->native_class + ":" + symbol->name; - break; - default: - id = "class_global:" + symbol->native_class + ":" + symbol->name; - break; - } - call_deferred("show_native_symbol_in_editor", id); - } else { - notify_client_show_symbol(symbol); - } - } - return arr; -} - -Variant GDScriptTextDocument::signatureHelp(const Dictionary &p_params) { - Variant ret; - - lsp::TextDocumentPositionParams params; - params.load(p_params); - - lsp::SignatureHelp s; - if (OK == GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_signature(params, s)) { - ret = s.to_json(); - } - - return ret; -} - -GDScriptTextDocument::GDScriptTextDocument() { - file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES); -} - -GDScriptTextDocument::~GDScriptTextDocument() { - memdelete(file_checker); -} - -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 script = ResourceLoader::load(path, "", false, &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) { - OS::get_singleton()->move_window_to_foreground(); -} - -Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &p_location, List &r_list) { - Array arr; - const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(p_location); - if (symbol) { - lsp::Location location; - location.uri = symbol->uri; - location.range = symbol->range; - const String &path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(symbol->uri); - if (file_checker->file_exists(path)) { - arr.push_back(location.to_json()); - } - r_list.push_back(symbol); - } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) { - List list; - GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(p_location, list); - for (List::Element *E = list.front(); E; E = E->next()) { - if (const lsp::DocumentSymbol *s = E->get()) { - if (!s->uri.empty()) { - lsp::Location location; - location.uri = s->uri; - location.range = s->range; - arr.push_back(location.to_json()); - r_list.push_back(s); - } - } - } - } - return arr; -} diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h deleted file mode 100644 index 9e77e11..0000000 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************/ -/* gdscript_text_document.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#ifndef GDSCRIPT_TEXT_DOCUMENT_H -#define GDSCRIPT_TEXT_DOCUMENT_H - -#include "core/os/file_access.h" -#include "core/object/reference.h" -#include "lsp.hpp" - -class GDScriptTextDocument : public Reference { - GDCLASS(GDScriptTextDocument, Reference) -protected: - static void _bind_methods(); - - 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); - - Array native_member_completions; - -private: - Array find_symbols(const lsp::TextDocumentPositionParams &p_location, List &r_list); - lsp::TextDocumentItem load_document_item(const Variant &p_param); - void notify_client_show_symbol(const lsp::DocumentSymbol *symbol); - -public: - Variant nativeSymbol(const Dictionary &p_params); - 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); - Array colorPresentation(const Dictionary &p_params); - Variant hover(const Dictionary &p_params); - Array definition(const Dictionary &p_params); - Variant declaration(const Dictionary &p_params); - Variant signatureHelp(const Dictionary &p_params); - - void initialize(); - - GDScriptTextDocument(); - virtual ~GDScriptTextDocument(); -}; - -#endif // GDSCRIPT_TEXT_DOCUMENT_H diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp deleted file mode 100644 index 54c1e14..0000000 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ /dev/null @@ -1,804 +0,0 @@ -/**************************************************************************/ -/* gdscript_workspace.cpp */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#include "gdscript_workspace.h" - -#include "../gdscript.h" -#include "../gdscript_parser.h" -#include "core/config/project_settings.h" -#include "core/object/script_language.h" -#include "editor/editor_file_system.h" -#include "editor/editor_help.h" -#include "editor/editor_node.h" -#include "editor/editor_settings.h" -#include "gdscript_language_protocol.h" -#include "scene/resources/packed_scene.h" - -void GDScriptWorkspace::_bind_methods() { - ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::did_delete_files); - ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol); - ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script); - ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_local_script); - ClassDB::bind_method(D_METHOD("get_file_path", "uri"), &GDScriptWorkspace::get_file_path); - ClassDB::bind_method(D_METHOD("get_file_uri", "path"), &GDScriptWorkspace::get_file_uri); - ClassDB::bind_method(D_METHOD("publish_diagnostics", "path"), &GDScriptWorkspace::publish_diagnostics); - ClassDB::bind_method(D_METHOD("generate_script_api", "path"), &GDScriptWorkspace::generate_script_api); - ClassDB::bind_method(D_METHOD("apply_new_signal", "obj", "function", "args"), &GDScriptWorkspace::apply_new_signal); -} - -void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PoolStringArray args) { - Ref