LSP: Rework management of client owned files

This commit is contained in:
HolonProduction
2025-06-25 14:43:48 +02:00
parent ccf414ecb4
commit 4cc88e5175
11 changed files with 346 additions and 259 deletions

View File

@@ -45,13 +45,16 @@
void GDScriptWorkspace::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_new_signal"), &GDScriptWorkspace::apply_new_signal);
ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::didDeleteFiles);
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);
#ifndef DISABLE_DEPRECATED
ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::didDeleteFiles);
ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script);
ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_script);
#endif
}
void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStringArray args) {
@@ -106,37 +109,6 @@ void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStr
GDScriptLanguageProtocol::get_singleton()->request_client("workspace/applyEdit", params.to_json());
}
void GDScriptWorkspace::didDeleteFiles(const Dictionary &p_params) {
Array files = p_params["files"];
for (int i = 0; i < files.size(); ++i) {
Dictionary file = files[i];
String uri = file["uri"];
String path = get_file_path(uri);
parse_script(path, "");
}
}
void GDScriptWorkspace::remove_cache_parser(const String &p_path) {
HashMap<String, ExtendGDScriptParser *>::Iterator parser = parse_results.find(p_path);
HashMap<String, ExtendGDScriptParser *>::Iterator scr = scripts.find(p_path);
if (parser && scr) {
if (scr->value && scr->value == parser->value) {
memdelete(scr->value);
} else {
memdelete(scr->value);
memdelete(parser->value);
}
parse_results.erase(p_path);
scripts.erase(p_path);
} else if (parser) {
memdelete(parser->value);
parse_results.erase(p_path);
} else if (scr) {
memdelete(scr->value);
scripts.erase(p_path);
}
}
const LSP::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_class, const String &p_member) const {
StringName class_name = p_class;
StringName empty;
@@ -168,9 +140,9 @@ const LSP::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_
}
const LSP::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_path) const {
HashMap<String, ExtendGDScriptParser *>::ConstIterator S = scripts.find(p_path);
if (S) {
return &(S->value->get_symbols());
ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(p_path);
if (parser) {
return &(parser->get_symbols());
}
return nullptr;
}
@@ -219,18 +191,13 @@ void GDScriptWorkspace::reload_all_workspace_scripts() {
List<String> paths;
list_script_files("res://", paths);
for (const String &path : paths) {
Error err;
String content = FileAccess::get_file_as_string(path, &err);
ERR_CONTINUE(err != OK);
err = parse_script(path, content);
if (err != OK) {
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().front()->get().message;
ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
if (parser == nullptr || parser->parse_result != OK) {
String err_msg = "LSP: Failed to parse script: " + path;
if (parser) {
err_msg += "\n" + parser->get_errors().front()->get().message;
}
ERR_CONTINUE_MSG(err != OK, err_msg);
ERR_PRINT(err_msg);
}
}
}
@@ -260,30 +227,6 @@ void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String>
}
}
ExtendGDScriptParser *GDScriptWorkspace::get_parse_successed_script(const String &p_path) {
HashMap<String, ExtendGDScriptParser *>::Iterator S = scripts.find(p_path);
if (!S) {
parse_local_script(p_path);
S = scripts.find(p_path);
}
if (S) {
return S->value;
}
return nullptr;
}
ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path) {
HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(p_path);
if (!S) {
parse_local_script(p_path);
S = parse_results.find(p_path);
}
if (S) {
return S->value;
}
return nullptr;
}
#define HANDLE_DOC(m_string) ((is_native ? DTR(m_string) : (m_string)).strip_edges())
Error GDScriptWorkspace::initialize() {
@@ -427,11 +370,6 @@ Error GDScriptWorkspace::initialize() {
}
native_members.insert(E.key, members);
}
// Cache member completions.
for (const KeyValue<String, ExtendGDScriptParser *> &S : scripts) {
S.value->get_member_completions();
}
}
EditorNode *editor_node = EditorNode::get_singleton();
@@ -440,29 +378,6 @@ Error GDScriptWorkspace::initialize() {
return OK;
}
Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_content) {
ExtendGDScriptParser *parser = memnew(ExtendGDScriptParser);
Error err = parser->parse(p_content, p_path);
HashMap<String, ExtendGDScriptParser *>::Iterator last_parser = parse_results.find(p_path);
HashMap<String, ExtendGDScriptParser *>::Iterator last_script = scripts.find(p_path);
if (err == OK) {
remove_cache_parser(p_path);
parse_results[p_path] = parser;
scripts[p_path] = parser;
} else {
if (last_parser && last_script && last_parser->value != last_script->value) {
memdelete(last_parser->value);
}
parse_results[p_path] = parser;
}
publish_diagnostics(p_path);
return err;
}
static bool is_valid_rename_target(const LSP::DocumentSymbol *p_symbol) {
// Must be valid symbol.
if (!p_symbol) {
@@ -505,8 +420,8 @@ bool GDScriptWorkspace::can_rename(const LSP::TextDocumentPositionParams &p_doc_
}
String path = get_file_path(p_doc_pos.textDocument.uri);
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
// We only care about the range.
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
if (parser) {
_ALLOW_DISCARD_ parser->get_identifier_under_position(p_doc_pos.position, r_range);
r_symbol = *reference_symbol;
return true;
@@ -519,7 +434,8 @@ Vector<LSP::Location> GDScriptWorkspace::find_usages_in_file(const LSP::Document
Vector<LSP::Location> usages;
String identifier = p_symbol.name;
if (const ExtendGDScriptParser *parser = get_parse_result(p_file_path)) {
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(p_file_path);
if (parser) {
const PackedStringArray &content = parser->get_lines();
for (int i = 0; i < content.size(); ++i) {
String line = content[i];
@@ -570,15 +486,6 @@ Vector<LSP::Location> GDScriptWorkspace::find_all_usages(const LSP::DocumentSymb
return usages;
}
Error GDScriptWorkspace::parse_local_script(const String &p_path) {
Error err;
String content = FileAccess::get_file_as_string(p_path, &err);
if (err == OK) {
err = parse_script(p_path, content);
}
return err;
}
String GDScriptWorkspace::get_file_path(const String &p_uri) {
int port;
String scheme;
@@ -671,9 +578,10 @@ String GDScriptWorkspace::get_file_uri(const String &p_path) const {
void GDScriptWorkspace::publish_diagnostics(const String &p_path) {
Dictionary params;
Array errors;
HashMap<String, ExtendGDScriptParser *>::ConstIterator ele = parse_results.find(p_path);
if (ele) {
const Vector<LSP::Diagnostic> &list = ele->value->get_diagnostics();
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(p_path);
if (parser) {
const Vector<LSP::Diagnostic> &list = parser->get_diagnostics();
errors.resize(list.size());
for (int i = 0; i < list.size(); ++i) {
errors[i] = list[i].to_json();
@@ -734,7 +642,8 @@ void GDScriptWorkspace::completion(const LSP::CompletionParams &p_params, List<S
String call_hint;
bool forced = false;
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
if (parser) {
Node *owner_scene_node = _get_owner_scene_node(path);
Array stack;
@@ -771,7 +680,9 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const LSP::TextDocu
const LSP::DocumentSymbol *symbol = nullptr;
String path = get_file_path(p_doc_pos.textDocument.uri);
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(path);
if (parser) {
String symbol_identifier = p_symbol_name;
if (symbol_identifier.get_slice_count("(") > 0) {
symbol_identifier = symbol_identifier.get_slicec('(', 0);
@@ -803,7 +714,8 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const LSP::TextDocu
target_script_path = ret.script_path;
}
if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) {
const ExtendGDScriptParser *target_parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(target_script_path);
if (target_parser) {
symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location), symbol_identifier);
if (symbol) {
@@ -836,37 +748,6 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const LSP::TextDocu
return symbol;
}
void GDScriptWorkspace::resolve_related_symbols(const LSP::TextDocumentPositionParams &p_doc_pos, List<const LSP::DocumentSymbol *> &r_list) {
String path = get_file_path(p_doc_pos.textDocument.uri);
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
String symbol_identifier;
LSP::Range range;
symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, range);
for (const KeyValue<StringName, ClassMembers> &E : native_members) {
const ClassMembers &members = native_members.get(E.key);
if (const LSP::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
}
for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
const ExtendGDScriptParser *scr = E.value;
const ClassMembers &members = scr->get_members();
if (const LSP::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
for (const KeyValue<String, ClassMembers> &F : scr->get_inner_classes()) {
const ClassMembers *inner_class = &F.value;
if (const LSP::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
}
}
}
}
const LSP::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const LSP::NativeSymbolInspectParams &p_params) {
if (HashMap<StringName, LSP::DocumentSymbol>::Iterator E = native_symbols.find(p_params.native_class)) {
const LSP::DocumentSymbol &symbol = E->value;
@@ -885,7 +766,8 @@ const LSP::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const LSP::N
}
void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<LSP::DocumentLink> &r_list) {
if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) {
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(get_file_path(p_uri));
if (parser && parser->parse_result == Error::OK) {
const List<LSP::DocumentLink> &links = parser->get_document_links();
for (const LSP::DocumentLink &E : links) {
r_list.push_back(E);
@@ -895,14 +777,17 @@ void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<LSP::Do
Dictionary GDScriptWorkspace::generate_script_api(const String &p_path) {
Dictionary api;
if (const ExtendGDScriptParser *parser = get_parse_successed_script(p_path)) {
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(p_path);
if (parser) {
api = parser->generate_api();
}
return api;
}
Error GDScriptWorkspace::resolve_signature(const LSP::TextDocumentPositionParams &p_doc_pos, LSP::SignatureHelp &r_signature) {
if (const ExtendGDScriptParser *parser = get_parse_result(get_file_path(p_doc_pos.textDocument.uri))) {
const ExtendGDScriptParser *parser = GDScriptLanguageProtocol::get_singleton()->get_parse_result(get_file_path(p_doc_pos.textDocument.uri));
if (parser) {
LSP::TextDocumentPositionParams text_pos;
text_pos.textDocument = p_doc_pos.textDocument;
@@ -912,7 +797,7 @@ Error GDScriptWorkspace::resolve_signature(const LSP::TextDocumentPositionParams
if (const LSP::DocumentSymbol *symbol = resolve_symbol(text_pos)) {
symbols.push_back(symbol);
} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_related_symbols(text_pos, symbols);
GDScriptLanguageProtocol::get_singleton()->resolve_related_symbols(text_pos, symbols);
}
for (const LSP::DocumentSymbol *const &symbol : symbols) {
@@ -942,18 +827,4 @@ Error GDScriptWorkspace::resolve_signature(const LSP::TextDocumentPositionParams
GDScriptWorkspace::GDScriptWorkspace() {}
GDScriptWorkspace::~GDScriptWorkspace() {
HashSet<String> cached_parsers;
for (const KeyValue<String, ExtendGDScriptParser *> &E : parse_results) {
cached_parsers.insert(E.key);
}
for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
cached_parsers.insert(E.key);
}
for (const String &E : cached_parsers) {
remove_cache_parser(E);
}
}
GDScriptWorkspace::~GDScriptWorkspace() {}