From d453281bb2b5608c5655f116b7722a2514063555 Mon Sep 17 00:00:00 2001 From: veetaha Date: Thu, 2 Apr 2020 03:24:30 +0300 Subject: vscode: add goto definition from rust file to syntax tree editor --- editors/code/src/commands/syntax_tree.ts | 88 ++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 5 deletions(-) (limited to 'editors/code/src') diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index 8d71cb39e..c1af7122f 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -83,7 +83,7 @@ class TextDocumentContentProvider implements vscode.TextDocumentContentProvider // FIXME: consider implementing this via the Tree View API? // https://code.visualstudio.com/api/extension-guides/tree-view class AstInspector implements vscode.HoverProvider, Disposable { - private static readonly astDecorationType = vscode.window.createTextEditorDecorationType({ + private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'), borderStyle: "solid", borderWidth: "2px", @@ -91,9 +91,35 @@ class AstInspector implements vscode.HoverProvider, Disposable { }); private rustEditor: undefined | RustEditor; + // Lazy rust token range -> syntax tree file range. + private readonly rust2Ast = new Lazy(() => { + const astEditor = this.findAstTextEditor(); + if (!this.rustEditor || !astEditor) return undefined; + + console.time("Build goto def index"); + let buf: [vscode.Range, vscode.Range][] = []; + for (let i = 0; i < astEditor.document.lineCount; ++i) { + const astLine = astEditor.document.lineAt(i); + + // Heuristically look for nodes with quoted text (which are token nodes) + const isTokenNode = astLine.text.lastIndexOf('"') >= 0; + if (!isTokenNode) continue; + + const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text); + if (!rustRange) continue; + + buf.push([rustRange, this.findAstRange(astLine)]); + } + + console.timeEnd("Build goto def index"); + return buf; + }); + constructor(ctx: Ctx) { ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: AST_FILE_SCHEME }, this)); + ctx.pushCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); vscode.workspace.onDidCloseTextDocument(this.onDidCloseTextDocument, this, ctx.subscriptions); + vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); vscode.window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, ctx.subscriptions); ctx.pushCleanup(this); @@ -102,6 +128,12 @@ class AstInspector implements vscode.HoverProvider, Disposable { this.setRustEditor(undefined); } + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (this.rustEditor && event.document.uri.toString() === this.rustEditor.document.uri.toString()) { + this.rust2Ast.reset(); + } + } + private onDidCloseTextDocument(doc: vscode.TextDocument) { if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) { this.setRustEditor(undefined); @@ -109,20 +141,51 @@ class AstInspector implements vscode.HoverProvider, Disposable { } private onDidChangeVisibleTextEditors(editors: vscode.TextEditor[]) { - if (editors.every(suspect => suspect.document.uri.scheme !== AST_FILE_SCHEME)) { + if (!this.findAstTextEditor()) { this.setRustEditor(undefined); return; } this.setRustEditor(editors.find(isRustEditor)); } + private findAstTextEditor(): undefined | vscode.TextEditor { + return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === AST_FILE_SCHEME); + } + private setRustEditor(newRustEditor: undefined | RustEditor) { - if (newRustEditor !== this.rustEditor) { - this.rustEditor?.setDecorations(AstInspector.astDecorationType, []); + if (this.rustEditor && this.rustEditor !== newRustEditor) { + this.rustEditor.setDecorations(this.astDecorationType, []); + this.rust2Ast.reset(); } this.rustEditor = newRustEditor; } + // additional positional params are omitted + provideDefinition(doc: vscode.TextDocument, pos: vscode.Position): vscode.ProviderResult { + if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) return; + + const astEditor = this.findAstTextEditor(); + if (!astEditor) return; + + console.time("Goto def"); + const rust2AstRanges = this.rust2Ast.get()?.find(([rustRange, _]) => rustRange.contains(pos)); + console.timeEnd("Goto def"); + if (!rust2AstRanges) return; + + const [rustFileRange, astFileRange] = rust2AstRanges; + + astEditor.revealRange(astFileRange); + astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end); + + return [{ + targetRange: astFileRange, + targetUri: astEditor.document.uri, + originSelectionRange: rustFileRange, + targetSelectionRange: astFileRange, + }]; + } + + // additional positional params are omitted provideHover(doc: vscode.TextDocument, hoverPosition: vscode.Position): vscode.ProviderResult { if (!this.rustEditor) return; @@ -131,7 +194,7 @@ class AstInspector implements vscode.HoverProvider, Disposable { const rustTextRange = this.parseRustTextRange(this.rustEditor.document, astTextLine.text); if (!rustTextRange) return; - this.rustEditor.setDecorations(AstInspector.astDecorationType, [rustTextRange]); + this.rustEditor.setDecorations(this.astDecorationType, [rustTextRange]); this.rustEditor.revealRange(rustTextRange); const rustSourceCode = this.rustEditor.document.getText(rustTextRange); @@ -156,3 +219,18 @@ class AstInspector implements vscode.HoverProvider, Disposable { return new vscode.Range(begin, end); } } + +class Lazy { + val: undefined | T; + + constructor(private readonly compute: () => undefined | T) {} + + get() { + return this.val ?? (this.val = this.compute()); + } + + reset() { + this.val = undefined; + } + +} -- cgit v1.2.3 From e763b279a887cfc518e46b52af9c0ef0572068fc Mon Sep 17 00:00:00 2001 From: veetaha Date: Thu, 2 Apr 2020 03:24:45 +0300 Subject: vscode: postrefactor variable names --- editors/code/src/commands/syntax_tree.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'editors/code/src') diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index c1af7122f..7b58cf788 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -189,18 +189,18 @@ class AstInspector implements vscode.HoverProvider, Disposable { provideHover(doc: vscode.TextDocument, hoverPosition: vscode.Position): vscode.ProviderResult { if (!this.rustEditor) return; - const astTextLine = doc.lineAt(hoverPosition.line); + const astFileLine = doc.lineAt(hoverPosition.line); - const rustTextRange = this.parseRustTextRange(this.rustEditor.document, astTextLine.text); - if (!rustTextRange) return; + const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text); + if (!rustFileRange) return; - this.rustEditor.setDecorations(this.astDecorationType, [rustTextRange]); - this.rustEditor.revealRange(rustTextRange); + this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]); + this.rustEditor.revealRange(rustFileRange); - const rustSourceCode = this.rustEditor.document.getText(rustTextRange); - const astTextRange = this.findAstRange(astTextLine); + const rustSourceCode = this.rustEditor.document.getText(rustFileRange); + const astFileRange = this.findAstRange(astFileLine); - return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astTextRange); + return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange); } private findAstRange(astLine: vscode.TextLine) { -- cgit v1.2.3 From 036a8aee2af960428218cecd68ea2ea1813ab7f6 Mon Sep 17 00:00:00 2001 From: veetaha Date: Thu, 2 Apr 2020 03:35:58 +0300 Subject: vscode: postrefactor --- editors/code/src/commands/syntax_tree.ts | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'editors/code/src') diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index 7b58cf788..b7a397414 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts @@ -82,7 +82,7 @@ class TextDocumentContentProvider implements vscode.TextDocumentContentProvider // FIXME: consider implementing this via the Tree View API? // https://code.visualstudio.com/api/extension-guides/tree-view -class AstInspector implements vscode.HoverProvider, Disposable { +class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'), borderStyle: "solid", @@ -96,8 +96,7 @@ class AstInspector implements vscode.HoverProvider, Disposable { const astEditor = this.findAstTextEditor(); if (!this.rustEditor || !astEditor) return undefined; - console.time("Build goto def index"); - let buf: [vscode.Range, vscode.Range][] = []; + const buf: [vscode.Range, vscode.Range][] = []; for (let i = 0; i < astEditor.document.lineCount; ++i) { const astLine = astEditor.document.lineAt(i); @@ -108,10 +107,8 @@ class AstInspector implements vscode.HoverProvider, Disposable { const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text); if (!rustRange) continue; - buf.push([rustRange, this.findAstRange(astLine)]); + buf.push([rustRange, this.findAstNodeRange(astLine)]); } - - console.timeEnd("Build goto def index"); return buf; }); @@ -167,9 +164,7 @@ class AstInspector implements vscode.HoverProvider, Disposable { const astEditor = this.findAstTextEditor(); if (!astEditor) return; - console.time("Goto def"); const rust2AstRanges = this.rust2Ast.get()?.find(([rustRange, _]) => rustRange.contains(pos)); - console.timeEnd("Goto def"); if (!rust2AstRanges) return; const [rustFileRange, astFileRange] = rust2AstRanges; @@ -198,12 +193,12 @@ class AstInspector implements vscode.HoverProvider, Disposable { this.rustEditor.revealRange(rustFileRange); const rustSourceCode = this.rustEditor.document.getText(rustFileRange); - const astFileRange = this.findAstRange(astFileLine); + const astFileRange = this.findAstNodeRange(astFileLine); return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange); } - private findAstRange(astLine: vscode.TextLine) { + private findAstNodeRange(astLine: vscode.TextLine) { const lineOffset = astLine.range.start; const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex); const end = lineOffset.translate(undefined, astLine.text.trimEnd().length); @@ -223,7 +218,7 @@ class AstInspector implements vscode.HoverProvider, Disposable { class Lazy { val: undefined | T; - constructor(private readonly compute: () => undefined | T) {} + constructor(private readonly compute: () => undefined | T) { } get() { return this.val ?? (this.val = this.compute()); @@ -232,5 +227,4 @@ class Lazy { reset() { this.val = undefined; } - } -- cgit v1.2.3