GDScript: Track columns by raw string offsets

This commit is contained in:
HolonProduction
2026-03-02 23:20:25 +01:00
parent 6d6e822c68
commit 612475a680
15 changed files with 107 additions and 279 deletions
@@ -35,95 +35,27 @@
#include "gdscript_language_protocol.h"
#include "gdscript_workspace.h"
#include "editor/settings/editor_settings.h"
int get_indent_size() {
if (EditorSettings::get_singleton()) {
return EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
} else {
return 4;
}
}
LSP::Position GodotPosition::to_lsp(const Vector<String> &p_lines) const {
LSP::Position GodotPosition::to_lsp() const {
LSP::Position res;
// Special case: `line = 0` -> root class (range covers everything).
if (line <= 0) {
return res;
}
// Special case: `line = p_lines.size() + 1` -> root class (range covers everything).
if (line >= p_lines.size() + 1) {
res.line = p_lines.size();
return res;
}
res.line = line - 1;
// Special case: `column = 0` -> Starts at beginning of line.
if (column <= 0) {
return res;
}
// Note: character outside of `pos_line.length()-1` is valid.
res.character = column - 1;
String pos_line = p_lines[res.line];
if (pos_line.contains_char('\t')) {
int tab_size = get_indent_size();
int in_col = 1;
int res_char = 0;
while (res_char < pos_line.size() && in_col < column) {
if (pos_line[res_char] == '\t') {
in_col += tab_size;
res_char++;
} else {
in_col++;
res_char++;
}
}
res.character = res_char;
}
return res;
}
GodotPosition GodotPosition::from_lsp(const LSP::Position p_pos, const Vector<String> &p_lines) {
GodotPosition res(p_pos.line + 1, p_pos.character + 1);
// Line outside of actual text is valid (-> pos/cursor at end of text).
if (res.line > p_lines.size()) {
return res;
}
String line = p_lines[p_pos.line];
int tabs_before_char = 0;
for (int i = 0; i < p_pos.character && i < line.length(); i++) {
if (line[i] == '\t') {
tabs_before_char++;
}
}
if (tabs_before_char > 0) {
int tab_size = get_indent_size();
res.column += tabs_before_char * (tab_size - 1);
}
return res;
GodotPosition GodotPosition::from_lsp(const LSP::Position p_pos) {
return GodotPosition(p_pos.line + 1, p_pos.character + 1);
}
LSP::Range GodotRange::to_lsp(const Vector<String> &p_lines) const {
LSP::Range GodotRange::to_lsp() const {
LSP::Range res;
res.start = start.to_lsp(p_lines);
res.end = end.to_lsp(p_lines);
res.start = start.to_lsp();
res.end = end.to_lsp();
return res;
}
GodotRange GodotRange::from_lsp(const LSP::Range &p_range, const Vector<String> &p_lines) {
GodotPosition start = GodotPosition::from_lsp(p_range.start, p_lines);
GodotPosition end = GodotPosition::from_lsp(p_range.end, p_lines);
GodotRange GodotRange::from_lsp(const LSP::Range &p_range) {
GodotPosition start = GodotPosition::from_lsp(p_range.start);
GodotPosition end = GodotPosition::from_lsp(p_range.end);
return GodotRange(start, end);
}
@@ -141,7 +73,7 @@ void ExtendGDScriptParser::update_diagnostics() {
GodotPosition(error.start_line, error.start_column),
GodotPosition(error.end_line, error.end_column));
diagnostic.range = godot_range.to_lsp(get_lines());
diagnostic.range = godot_range.to_lsp();
diagnostics.push_back(diagnostic);
}
@@ -156,7 +88,7 @@ void ExtendGDScriptParser::update_diagnostics() {
GodotPosition(warning.start_line, warning.start_column),
GodotPosition(warning.end_line, warning.end_column));
diagnostic.range = godot_range.to_lsp(get_lines());
diagnostic.range = godot_range.to_lsp();
diagnostics.push_back(diagnostic);
}
}
@@ -207,7 +139,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
String value = const_val;
LSP::DocumentLink link;
link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(scr_path);
link.range = GodotRange(GodotPosition(token.start_line, token.start_column), GodotPosition(token.end_line, token.end_column)).to_lsp(lines);
link.range = GodotRange(GodotPosition(token.start_line, token.start_column), GodotPosition(token.end_line, token.end_column)).to_lsp();
document_links.push_back(link);
}
}
@@ -218,7 +150,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
LSP::Range ExtendGDScriptParser::range_of_node(const GDScriptParser::Node *p_node) const {
GodotPosition start(p_node->start_line, p_node->start_column);
GodotPosition end(p_node->end_line, p_node->end_column);
return GodotRange(start, end).to_lsp(lines);
return GodotRange(start, end).to_lsp();
}
void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, LSP::DocumentSymbol &r_symbol) {
@@ -394,8 +326,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.name = m.enum_value.identifier->name;
symbol.kind = LSP::SymbolKind::EnumMember;
symbol.deprecated = false;
symbol.range.start = GodotPosition(m.enum_value.line, m.enum_value.start_column).to_lsp(lines);
symbol.range.end = GodotPosition(m.enum_value.line, m.enum_value.end_column).to_lsp(lines);
symbol.range.start = GodotPosition(m.enum_value.line, m.enum_value.start_column).to_lsp();
symbol.range.end = GodotPosition(m.enum_value.line, m.enum_value.end_column).to_lsp();
symbol.selectionRange = range_of_node(m.enum_value.identifier);
symbol.documentation = m.enum_value.doc_data.description;
symbol.uri = uri;
@@ -430,8 +362,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
child.name = value.identifier->name;
child.kind = LSP::SymbolKind::EnumMember;
child.deprecated = false;
child.range.start = GodotPosition(value.line, value.start_column).to_lsp(lines);
child.range.end = GodotPosition(value.line, value.end_column).to_lsp(lines);
child.range.start = GodotPosition(value.line, value.start_column).to_lsp();
child.range.end = GodotPosition(value.line, value.end_column).to_lsp();
child.selectionRange = range_of_node(value.identifier);
child.documentation = value.doc_data.description;
child.uri = uri;
@@ -605,8 +537,8 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
break;
default:
// Fallback.
symbol.range.start = GodotPosition(local.start_line, local.start_column).to_lsp(get_lines());
symbol.range.end = GodotPosition(local.end_line, local.end_column).to_lsp(get_lines());
symbol.range.start = GodotPosition(local.start_line, local.start_column).to_lsp();
symbol.range.end = GodotPosition(local.end_line, local.end_column).to_lsp();
symbol.selectionRange = symbol.range;
break;
}