diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/ast_inspector.ts similarity index 67% rename from editors/code/src/commands/syntax_tree.ts rename to editors/code/src/ast_inspector.ts index a5446c3272..4fdd167bd5 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/ast_inspector.ts @@ -1,93 +1,15 @@ import * as vscode from 'vscode'; -import * as ra from '../rust-analyzer-api'; - -import { Ctx, Cmd, Disposable } from '../ctx'; -import { isRustDocument, RustEditor, isRustEditor, sleep } from '../util'; - -const AST_FILE_SCHEME = "rust-analyzer"; - -// Opens the virtual file that will show the syntax tree -// -// The contents of the file come from the `TextDocumentContentProvider` -export function syntaxTree(ctx: Ctx): Cmd { - const tdcp = new TextDocumentContentProvider(ctx); - - void new AstInspector(ctx); - - ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider(AST_FILE_SCHEME, tdcp)); - ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", { - brackets: [["[", ")"]], - })); - - return async () => { - const editor = vscode.window.activeTextEditor; - const rangeEnabled = !!editor && !editor.selection.isEmpty; - - const uri = rangeEnabled - ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) - : tdcp.uri; - - const document = await vscode.workspace.openTextDocument(uri); - - tdcp.eventEmitter.fire(uri); - - void await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true - }); - }; -} - -class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast'); - readonly eventEmitter = new vscode.EventEmitter(); - - - constructor(private readonly ctx: Ctx) { - vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); - vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { - // We need to order this after language server updates, but there's no API for that. - // Hence, good old sleep(). - void sleep(10).then(() => this.eventEmitter.fire(this.uri)); - } - } - private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { - this.eventEmitter.fire(this.uri); - } - } - - provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { - const rustEditor = this.ctx.activeRustEditor; - if (!rustEditor) return ''; - - // When the range based query is enabled we take the range of the selection - const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty - ? this.ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) - : null; - - const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, }; - return this.ctx.client.sendRequest(ra.syntaxTree, params, ct); - } - - get onDidChange(): vscode.Event { - return this.eventEmitter.event; - } -} +import { Ctx, Disposable } from './ctx'; +import { RustEditor, isRustEditor } from './util'; // FIXME: consider implementing this via the Tree View API? // https://code.visualstudio.com/api/extension-guides/tree-view -class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { +export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ borderColor: new vscode.ThemeColor('rust_analyzer.syntaxTreeBorder'), borderStyle: "solid", borderWidth: "2px", - }); private rustEditor: undefined | RustEditor; @@ -113,7 +35,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D }); constructor(ctx: Ctx) { - ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: AST_FILE_SCHEME }, this)); + ctx.pushCleanup(vscode.languages.registerHoverProvider({ scheme: 'rust-analyzer' }, 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); @@ -146,7 +68,7 @@ class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, D } private findAstTextEditor(): undefined | vscode.TextEditor { - return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === AST_FILE_SCHEME); + return vscode.window.visibleTextEditors.find(it => it.document.uri.scheme === 'rust-analyzer'); } private setRustEditor(newRustEditor: undefined | RustEditor) { diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands.ts similarity index 72% rename from editors/code/src/commands/index.ts rename to editors/code/src/commands.ts index 1585912a2b..573af5aa58 100644 --- a/editors/code/src/commands/index.ts +++ b/editors/code/src/commands.ts @@ -1,13 +1,16 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; -import * as ra from '../rust-analyzer-api'; +import * as ra from './rust-analyzer-api'; -import { Ctx, Cmd } from '../ctx'; -import { applySnippetWorkspaceEdit } from '../snippets'; +import { Ctx, Cmd } from './ctx'; +import { applySnippetWorkspaceEdit } from './snippets'; import { spawnSync } from 'child_process'; +import { RunnableQuickPick, selectRunnable, createTask } from './run'; +import { AstInspector } from './ast_inspector'; +import { isRustDocument, sleep, isRustEditor } from './util'; -export * from './syntax_tree'; -export * from './runnables'; +export * from './ast_inspector'; +export * from './run'; export function analyzerStatus(ctx: Ctx): Cmd { const tdcp = new class implements vscode.TextDocumentContentProvider { @@ -194,6 +197,90 @@ export function toggleInlayHints(ctx: Ctx): Cmd { }; } +export function run(ctx: Ctx): Cmd { + let prevRunnable: RunnableQuickPick | undefined; + + return async () => { + const item = await selectRunnable(ctx, prevRunnable); + if (!item) return; + + item.detail = 'rerun'; + prevRunnable = item; + const task = createTask(item.runnable); + return await vscode.tasks.executeTask(task); + }; +} + +// Opens the virtual file that will show the syntax tree +// +// The contents of the file come from the `TextDocumentContentProvider` +export function syntaxTree(ctx: Ctx): Cmd { + const tdcp = new class implements vscode.TextDocumentContentProvider { + readonly uri = vscode.Uri.parse('rust-analyzer://syntaxtree/tree.rast'); + readonly eventEmitter = new vscode.EventEmitter(); + constructor() { + vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions); + vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions); + } + + private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { + if (isRustDocument(event.document)) { + // We need to order this after language server updates, but there's no API for that. + // Hence, good old sleep(). + void sleep(10).then(() => this.eventEmitter.fire(this.uri)); + } + } + private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { + if (editor && isRustEditor(editor)) { + this.eventEmitter.fire(this.uri); + } + } + + provideTextDocumentContent(uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult { + const rustEditor = ctx.activeRustEditor; + if (!rustEditor) return ''; + + // When the range based query is enabled we take the range of the selection + const range = uri.query === 'range=true' && !rustEditor.selection.isEmpty + ? ctx.client.code2ProtocolConverter.asRange(rustEditor.selection) + : null; + + const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range, }; + return ctx.client.sendRequest(ra.syntaxTree, params, ct); + } + + get onDidChange(): vscode.Event { + return this.eventEmitter.event; + } + }; + + void new AstInspector(ctx); + + ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp)); + ctx.pushCleanup(vscode.languages.setLanguageConfiguration("ra_syntax_tree", { + brackets: [["[", ")"]], + })); + + return async () => { + const editor = vscode.window.activeTextEditor; + const rangeEnabled = !!editor && !editor.selection.isEmpty; + + const uri = rangeEnabled + ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) + : tdcp.uri; + + const document = await vscode.workspace.openTextDocument(uri); + + tdcp.eventEmitter.fire(uri); + + void await vscode.window.showTextDocument(document, { + viewColumn: vscode.ViewColumn.Two, + preserveFocus: true + }); + }; +} + + // Opens the virtual file that will show the syntax tree // // The contents of the file come from the `TextDocumentContentProvider` diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 0e5a206410..31ac81ee88 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -92,7 +92,6 @@ export async function activate(context: vscode.ExtensionContext) { ctx.registerCommand('runSingle', commands.runSingle); ctx.registerCommand('debugSingle', commands.debugSingle); ctx.registerCommand('showReferences', commands.showReferences); - ctx.registerCommand('applySourceChange', commands.applySourceChange); ctx.registerCommand('applySnippetWorkspaceEdit', commands.applySnippetWorkspaceEditCommand); ctx.registerCommand('applyActionGroup', commands.applyActionGroup); diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/run.ts similarity index 88% rename from editors/code/src/commands/runnables.ts rename to editors/code/src/run.ts index 0bd30fb077..8f0487d74a 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/run.ts @@ -1,13 +1,13 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; -import * as ra from '../rust-analyzer-api'; +import * as ra from './rust-analyzer-api'; -import { Ctx, Cmd } from '../ctx'; -import { startDebugSession, getDebugConfiguration } from '../debug'; +import { Ctx, Cmd } from './ctx'; +import { startDebugSession, getDebugConfiguration } from './debug'; const quickPickButtons = [{ iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configurtation." }]; -async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise { +export async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debuggeeOnly = false, showButtons: boolean = true): Promise { const editor = ctx.activeRustEditor; const client = ctx.client; if (!editor || !client) return; @@ -83,20 +83,6 @@ async function selectRunnable(ctx: Ctx, prevRunnable?: RunnableQuickPick, debugg }); } -export function run(ctx: Ctx): Cmd { - let prevRunnable: RunnableQuickPick | undefined; - - return async () => { - const item = await selectRunnable(ctx, prevRunnable); - if (!item) return; - - item.detail = 'rerun'; - prevRunnable = item; - const task = createTask(item.runnable); - return await vscode.tasks.executeTask(task); - }; -} - export function runSingle(ctx: Ctx): Cmd { return async (runnable: ra.Runnable) => { const editor = ctx.activeRustEditor; @@ -165,7 +151,7 @@ export function newDebugConfig(ctx: Ctx): Cmd { }; } -class RunnableQuickPick implements vscode.QuickPickItem { +export class RunnableQuickPick implements vscode.QuickPickItem { public label: string; public description?: string | undefined; public detail?: string | undefined; @@ -184,7 +170,7 @@ interface CargoTaskDefinition extends vscode.TaskDefinition { env?: { [key: string]: string }; } -function createTask(spec: ra.Runnable): vscode.Task { +export function createTask(spec: ra.Runnable): vscode.Task { const TASK_SOURCE = 'Rust'; const definition: CargoTaskDefinition = { type: 'cargo',