about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/editors/code
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2025-01-28 16:04:21 +0000
committerGitHub <noreply@github.com>2025-01-28 16:04:21 +0000
commit8ecb754eeae4828aaba9c0c321044c62d12ae1d2 (patch)
tree4445a9c3d840cf380715876ac64cf93801b49d41 /src/tools/rust-analyzer/editors/code
parentf70ac259667acb4f03a11bc6fc9795a2e3339399 (diff)
parent7268b3d81fd49cceb7c5f58dffb2a4d866528ec7 (diff)
downloadrust-8ecb754eeae4828aaba9c0c321044c62d12ae1d2.tar.gz
rust-8ecb754eeae4828aaba9c0c321044c62d12ae1d2.zip
Merge pull request #19056 from Giga-Bowser/fix-syntax-tree-crlf
fix: Properly handle CRLF line endings in the syntax tree view
Diffstat (limited to 'src/tools/rust-analyzer/editors/code')
-rw-r--r--src/tools/rust-analyzer/editors/code/src/commands.ts14
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts4
-rw-r--r--src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts140
3 files changed, 116 insertions, 42 deletions
diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts
index b3aa04af7ed..eee623ecae9 100644
--- a/src/tools/rust-analyzer/editors/code/src/commands.ts
+++ b/src/tools/rust-analyzer/editors/code/src/commands.ts
@@ -361,10 +361,7 @@ export function syntaxTreeReveal(): Cmd {
         const activeEditor = vscode.window.activeTextEditor;
 
         if (activeEditor !== undefined) {
-            const start = activeEditor.document.positionAt(element.start);
-            const end = activeEditor.document.positionAt(element.end);
-
-            const newSelection = new vscode.Selection(start, end);
+            const newSelection = new vscode.Selection(element.range.start, element.range.end);
 
             activeEditor.selection = newSelection;
             activeEditor.revealRange(newSelection);
@@ -378,15 +375,12 @@ function elementToString(
     depth: number = 0,
 ): string {
     let result = "  ".repeat(depth);
-    const start = element.istart ?? element.start;
-    const end = element.iend ?? element.end;
+    const offsets = element.inner?.offsets ?? element.offsets;
 
-    result += `${element.kind}@${start}..${end}`;
+    result += `${element.kind}@${offsets.start}..${offsets.end}`;
 
     if (element.type === "Token") {
-        const startPosition = activeDocument.positionAt(element.start);
-        const endPosition = activeDocument.positionAt(element.end);
-        const text = activeDocument.getText(new vscode.Range(startPosition, endPosition));
+        const text = activeDocument.getText(element.range).replaceAll("\r\n", "\n");
         // JSON.stringify quotes and escapes the string for us.
         result += ` ${JSON.stringify(text)}\n`;
     } else {
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 96dc4f19b82..4248305d5cc 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -384,9 +384,7 @@ export class Ctx implements RustAnalyzerExtensionApi {
                 return;
             }
 
-            const start = e.textEditor.document.offsetAt(selection.start);
-            const end = e.textEditor.document.offsetAt(selection.end);
-            const result = this.syntaxTreeProvider?.getElementByRange(start, end);
+            const result = this.syntaxTreeProvider?.getElementByRange(selection);
             if (result !== undefined) {
                 await this.syntaxTreeView?.reveal(result);
             }
diff --git a/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts b/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts
index c7e8007e838..3f7e30f13a3 100644
--- a/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts
+++ b/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts
@@ -37,11 +37,7 @@ export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement
         const editor = vscode.window.activeTextEditor;
 
         if (editor !== undefined) {
-            const start = editor.document.positionAt(element.start);
-            const end = editor.document.positionAt(element.end);
-            const range = new vscode.Range(start, end);
-
-            const text = editor.document.getText(range);
+            const text = editor.document.getText(element.range);
             item.tooltip = new vscode.MarkdownString().appendCodeblock(text, "rust");
         }
 
@@ -74,14 +70,61 @@ export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement
         if (editor && isRustEditor(editor)) {
             const params = { textDocument: { uri: editor.document.uri.toString() }, range: null };
             const fileText = await this.ctx.client.sendRequest(ra.viewSyntaxTree, params);
-            this.root = JSON.parse(fileText, (_key, value: SyntaxElement) => {
+            this.root = JSON.parse(fileText, (_key, value: RawElement): SyntaxElement => {
+                if (value.type !== "Node" && value.type !== "Token") {
+                    // This is something other than a RawElement.
+                    return value;
+                }
+                const [startOffset, startLine, startCol] = value.start;
+                const [endOffset, endLine, endCol] = value.end;
+                const range = new vscode.Range(startLine, startCol, endLine, endCol);
+                const offsets = {
+                    start: startOffset,
+                    end: endOffset,
+                };
+
+                let inner;
+                if (value.istart && value.iend) {
+                    const [istartOffset, istartLine, istartCol] = value.istart;
+                    const [iendOffset, iendLine, iendCol] = value.iend;
+
+                    inner = {
+                        offsets: {
+                            start: istartOffset,
+                            end: iendOffset,
+                        },
+                        range: new vscode.Range(istartLine, istartCol, iendLine, iendCol),
+                    };
+                }
+
                 if (value.type === "Node") {
-                    for (const child of value.children) {
-                        child.parent = value;
+                    const result = {
+                        type: value.type,
+                        kind: value.kind,
+                        offsets,
+                        range,
+                        inner,
+                        children: value.children,
+                        parent: undefined,
+                        document: editor.document,
+                    };
+
+                    for (const child of result.children) {
+                        child.parent = result;
                     }
-                }
 
-                return value;
+                    return result;
+                } else {
+                    return {
+                        type: value.type,
+                        kind: value.kind,
+                        offsets,
+                        range,
+                        inner,
+                        parent: undefined,
+                        document: editor.document,
+                    };
+                }
             });
         } else {
             this.root = undefined;
@@ -90,14 +133,14 @@ export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement
         this._onDidChangeTreeData.fire();
     }
 
-    getElementByRange(start: number, end: number): SyntaxElement | undefined {
+    getElementByRange(target: vscode.Range): SyntaxElement | undefined {
         if (this.root === undefined) {
             return undefined;
         }
 
         let result: SyntaxElement = this.root;
 
-        if (this.root.start === start && this.root.end === end) {
+        if (this.root.range.isEqual(target)) {
             return result;
         }
 
@@ -105,9 +148,9 @@ export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement
 
         outer: while (true) {
             for (const child of children) {
-                if (child.start <= start && child.end >= end) {
+                if (child.range.contains(target)) {
                     result = child;
-                    if (start === end && start === child.end) {
+                    if (target.isEmpty && target.start === child.range.end) {
                         // When the cursor is on the very end of a token,
                         // we assume the user wants the next token instead.
                         continue;
@@ -136,31 +179,72 @@ export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement
 export type SyntaxNode = {
     type: "Node";
     kind: string;
-    start: number;
-    end: number;
-    istart?: number;
-    iend?: number;
+    range: vscode.Range;
+    offsets: {
+        start: number;
+        end: number;
+    };
+    /** This element's position within a Rust string literal, if it's inside of one. */
+    inner?: {
+        range: vscode.Range;
+        offsets: {
+            start: number;
+            end: number;
+        };
+    };
     children: SyntaxElement[];
     parent?: SyntaxElement;
+    document: vscode.TextDocument;
 };
 
 type SyntaxToken = {
     type: "Token";
     kind: string;
-    start: number;
-    end: number;
-    istart?: number;
-    iend?: number;
+    range: vscode.Range;
+    offsets: {
+        start: number;
+        end: number;
+    };
+    /** This element's position within a Rust string literal, if it's inside of one. */
+    inner?: {
+        range: vscode.Range;
+        offsets: {
+            start: number;
+            end: number;
+        };
+    };
     parent?: SyntaxElement;
+    document: vscode.TextDocument;
 };
 
 export type SyntaxElement = SyntaxNode | SyntaxToken;
 
+type RawNode = {
+    type: "Node";
+    kind: string;
+    start: [number, number, number];
+    end: [number, number, number];
+    istart?: [number, number, number];
+    iend?: [number, number, number];
+    children: SyntaxElement[];
+};
+
+type RawToken = {
+    type: "Token";
+    kind: string;
+    start: [number, number, number];
+    end: [number, number, number];
+    istart?: [number, number, number];
+    iend?: [number, number, number];
+};
+
+type RawElement = RawNode | RawToken;
+
 export class SyntaxTreeItem extends vscode.TreeItem {
     constructor(private readonly element: SyntaxElement) {
         super(element.kind);
-        const icon = getIcon(element.kind);
-        if (element.type === "Node") {
+        const icon = getIcon(this.element.kind);
+        if (this.element.type === "Node") {
             this.contextValue = "syntaxNode";
             this.iconPath = icon ?? new vscode.ThemeIcon("list-tree");
             this.collapsibleState = vscode.TreeItemCollapsibleState.Expanded;
@@ -170,11 +254,9 @@ export class SyntaxTreeItem extends vscode.TreeItem {
             this.collapsibleState = vscode.TreeItemCollapsibleState.None;
         }
 
-        if (element.istart !== undefined && element.iend !== undefined) {
-            this.description = `${this.element.istart}..${this.element.iend}`;
-        } else {
-            this.description = `${this.element.start}..${this.element.end}`;
-        }
+        const offsets = this.element.inner?.offsets ?? this.element.offsets;
+
+        this.description = `${offsets.start}..${offsets.end}`;
     }
 }