Merge pull request #32517 from GodotExplorer/gdscript-lsp

GDScript LSP server improvement
This commit is contained in:
Rémi Verschelde 2019-10-03 13:40:09 +02:00 committed by GitHub
commit d66cce0215
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 6 deletions

View file

@ -105,6 +105,40 @@ void ExtendGDScriptParser::update_symbols() {
}
}
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) {
if (tokenizer.get_token() == GDScriptTokenizer::TK_EOF) {
break;
} else if (tokenizer.get_token() == GDScriptTokenizer::TK_CONSTANT) {
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();
@ -345,13 +379,13 @@ String ExtendGDScriptParser::marked_documentation(const String &p_bbcode) {
if (block_start != -1) {
code_block_indent = block_start;
in_code_block = true;
line = "'''gdscript\n";
line = "\n";
} else if (in_code_block) {
line = "\t" + line.substr(code_block_indent, line.length());
}
if (in_code_block && line.find("[/codeblock]") != -1) {
line = "'''\n\n";
line = "\n";
in_code_block = false;
}
@ -572,6 +606,10 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String
return NULL;
}
const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const {
return document_links;
}
const Array &ExtendGDScriptParser::get_member_completions() {
if (member_completions.empty()) {
@ -755,5 +793,6 @@ Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) {
Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, NULL, false);
update_diagnostics();
update_symbols();
update_document_links(p_code);
return err;
}

View file

@ -56,12 +56,14 @@ class ExtendGDScriptParser : public GDScriptParser {
lsp::DocumentSymbol class_symbol;
Vector<lsp::Diagnostic> diagnostics;
List<lsp::DocumentLink> document_links;
ClassMembers members;
HashMap<String, ClassMembers> 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);
@ -93,6 +95,7 @@ public:
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<lsp::DocumentLink> &get_document_links() const;
const Array &get_member_completions();
Dictionary generate_api() const;

View file

@ -271,8 +271,17 @@ Array GDScriptTextDocument::codeLens(const Dictionary &p_params) {
return arr;
}
Variant GDScriptTextDocument::documentLink(const Dictionary &p_params) {
Variant ret;
Array GDScriptTextDocument::documentLink(const Dictionary &p_params) {
Array ret;
lsp::DocumentLinkParams params;
params.load(p_params);
List<lsp::DocumentLink> links;
GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links);
for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) {
ret.push_back(E->get().to_json());
}
return ret;
}

View file

@ -59,7 +59,7 @@ public:
Dictionary resolve(const Dictionary &p_params);
Array foldingRange(const Dictionary &p_params);
Array codeLens(const Dictionary &p_params);
Variant documentLink(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);

View file

@ -475,6 +475,15 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
}
}
void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) {
if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) {
const List<lsp::DocumentLink> &links = parser->get_document_links();
for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) {
r_list.push_back(E->get());
}
}
}
Dictionary GDScriptWorkspace::generate_script_api(const String &p_path) {
Dictionary api;
if (const ExtendGDScriptParser *parser = get_parse_successed_script(p_path)) {

View file

@ -53,7 +53,6 @@ protected:
ExtendGDScriptParser *get_parse_successed_script(const String &p_path);
ExtendGDScriptParser *get_parse_result(const String &p_path);
void strip_flat_symbols(const String &p_branch);
void list_script_files(const String &p_root_dir, List<String> &r_files);
public:
@ -82,6 +81,7 @@ public:
const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_requred = false);
void resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list);
void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
Dictionary generate_script_api(const String &p_path);
GDScriptWorkspace();

View file

@ -199,6 +199,41 @@ struct TextDocumentPositionParams {
}
};
struct DocumentLinkParams {
/**
* The document to provide document links for.
*/
TextDocumentIdentifier textDocument;
_FORCE_INLINE_ void load(const Dictionary &p_params) {
textDocument.load(p_params["textDocument"]);
}
};
/**
* A document link is a range in a text document that links to an internal or external resource, like another
* text document or a web site.
*/
struct DocumentLink {
/**
* The range this link applies to.
*/
Range range;
/**
* The uri this link points to. If missing a resolve request is sent later.
*/
DocumentUri target;
Dictionary to_json() const {
Dictionary dict;
dict["range"] = range.to_json();
dict["target"] = target;
return dict;
}
};
/**
* A textual edit applicable to a text document.
*/