diff options
Diffstat (limited to 'editors/code')
-rw-r--r-- | editors/code/package.json | 14 | ||||
-rw-r--r-- | editors/code/src/client.ts | 12 | ||||
-rw-r--r-- | editors/code/src/config.ts | 2 | ||||
-rw-r--r-- | editors/code/src/ctx.ts | 13 | ||||
-rw-r--r-- | editors/code/src/main.ts | 84 | ||||
-rw-r--r-- | editors/code/src/run.ts | 4 | ||||
-rw-r--r-- | editors/code/src/snippets.ts | 5 | ||||
-rw-r--r-- | editors/code/src/tasks.ts | 27 |
8 files changed, 102 insertions, 59 deletions
diff --git a/editors/code/package.json b/editors/code/package.json index 17d9281ff..42a06e137 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -572,6 +572,11 @@ | |||
572 | "default": true, | 572 | "default": true, |
573 | "type": "boolean" | 573 | "type": "boolean" |
574 | }, | 574 | }, |
575 | "rust-analyzer.completion.autoself.enable": { | ||
576 | "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses\nwith `self` prefixed to them when inside a method.", | ||
577 | "default": true, | ||
578 | "type": "boolean" | ||
579 | }, | ||
575 | "rust-analyzer.diagnostics.enable": { | 580 | "rust-analyzer.diagnostics.enable": { |
576 | "markdownDescription": "Whether to show native rust-analyzer diagnostics.", | 581 | "markdownDescription": "Whether to show native rust-analyzer diagnostics.", |
577 | "default": true, | 582 | "default": true, |
@@ -597,7 +602,7 @@ | |||
597 | "type": "object" | 602 | "type": "object" |
598 | }, | 603 | }, |
599 | "rust-analyzer.diagnostics.warningsAsHint": { | 604 | "rust-analyzer.diagnostics.warningsAsHint": { |
600 | "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.", | 605 | "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.", |
601 | "default": [], | 606 | "default": [], |
602 | "type": "array", | 607 | "type": "array", |
603 | "items": { | 608 | "items": { |
@@ -605,7 +610,7 @@ | |||
605 | } | 610 | } |
606 | }, | 611 | }, |
607 | "rust-analyzer.diagnostics.warningsAsInfo": { | 612 | "rust-analyzer.diagnostics.warningsAsInfo": { |
608 | "markdownDescription": "List of warnings that should be displayed with hint severity.\n\nThe warnings will be indicated by faded text or three dots in code\nand will not show up in the `Problems Panel`.", | 613 | "markdownDescription": "List of warnings that should be displayed with info severity.\n\nThe warnings will be indicated by a blue squiggly underline in code\nand a blue icon in the `Problems Panel`.", |
609 | "default": [], | 614 | "default": [], |
610 | "type": "array", | 615 | "type": "array", |
611 | "items": { | 616 | "items": { |
@@ -795,6 +800,11 @@ | |||
795 | "type": "string" | 800 | "type": "string" |
796 | } | 801 | } |
797 | }, | 802 | }, |
803 | "rust-analyzer.rustfmt.enableRangeFormatting": { | ||
804 | "markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.", | ||
805 | "default": false, | ||
806 | "type": "boolean" | ||
807 | }, | ||
798 | "rust-analyzer.workspace.symbol.search.scope": { | 808 | "rust-analyzer.workspace.symbol.search.scope": { |
799 | "markdownDescription": "Workspace symbol search scope.", | 809 | "markdownDescription": "Workspace symbol search scope.", |
800 | "default": "workspace", | 810 | "default": "workspace", |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 116f41df6..f13ae07e1 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -4,6 +4,7 @@ import * as ra from '../src/lsp_ext'; | |||
4 | import * as Is from 'vscode-languageclient/lib/common/utils/is'; | 4 | import * as Is from 'vscode-languageclient/lib/common/utils/is'; |
5 | import { assert } from './util'; | 5 | import { assert } from './util'; |
6 | import { WorkspaceEdit } from 'vscode'; | 6 | import { WorkspaceEdit } from 'vscode'; |
7 | import { Workspace } from './ctx'; | ||
7 | 8 | ||
8 | export interface Env { | 9 | export interface Env { |
9 | [name: string]: string; | 10 | [name: string]: string; |
@@ -23,7 +24,7 @@ function renderHoverActions(actions: ra.CommandLinkGroup[]): vscode.MarkdownStri | |||
23 | return result; | 24 | return result; |
24 | } | 25 | } |
25 | 26 | ||
26 | export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc.LanguageClient { | 27 | export function createClient(serverPath: string, workspace: Workspace, extraEnv: Env): lc.LanguageClient { |
27 | // '.' Is the fallback if no folder is open | 28 | // '.' Is the fallback if no folder is open |
28 | // TODO?: Workspace folders support Uri's (eg: file://test.txt). | 29 | // TODO?: Workspace folders support Uri's (eg: file://test.txt). |
29 | // It might be a good idea to test if the uri points to a file. | 30 | // It might be a good idea to test if the uri points to a file. |
@@ -33,7 +34,7 @@ export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc | |||
33 | 34 | ||
34 | const run: lc.Executable = { | 35 | const run: lc.Executable = { |
35 | command: serverPath, | 36 | command: serverPath, |
36 | options: { cwd, env: newEnv }, | 37 | options: { env: newEnv }, |
37 | }; | 38 | }; |
38 | const serverOptions: lc.ServerOptions = { | 39 | const serverOptions: lc.ServerOptions = { |
39 | run, | 40 | run, |
@@ -43,9 +44,14 @@ export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc | |||
43 | 'Rust Analyzer Language Server Trace', | 44 | 'Rust Analyzer Language Server Trace', |
44 | ); | 45 | ); |
45 | 46 | ||
47 | let initializationOptions = vscode.workspace.getConfiguration("rust-analyzer"); | ||
48 | if (workspace.kind === "Detached Files") { | ||
49 | initializationOptions = { "detachedFiles": workspace.files.map(file => file.uri.fsPath), ...initializationOptions }; | ||
50 | } | ||
51 | |||
46 | const clientOptions: lc.LanguageClientOptions = { | 52 | const clientOptions: lc.LanguageClientOptions = { |
47 | documentSelector: [{ scheme: 'file', language: 'rust' }], | 53 | documentSelector: [{ scheme: 'file', language: 'rust' }], |
48 | initializationOptions: vscode.workspace.getConfiguration("rust-analyzer"), | 54 | initializationOptions, |
49 | diagnosticCollectionName: "rustc", | 55 | diagnosticCollectionName: "rustc", |
50 | traceOutputChannel, | 56 | traceOutputChannel, |
51 | middleware: { | 57 | middleware: { |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index fbb7a556a..d3d6e631a 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -34,7 +34,7 @@ export class Config { | |||
34 | readonly globalStoragePath: string; | 34 | readonly globalStoragePath: string; |
35 | 35 | ||
36 | constructor(ctx: vscode.ExtensionContext) { | 36 | constructor(ctx: vscode.ExtensionContext) { |
37 | this.globalStoragePath = ctx.globalStorageUri.path; | 37 | this.globalStoragePath = ctx.globalStorageUri.fsPath; |
38 | vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); | 38 | vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); |
39 | this.refreshLogging(); | 39 | this.refreshLogging(); |
40 | } | 40 | } |
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index bd023f803..cf67dd8cf 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts | |||
@@ -7,6 +7,15 @@ import { createClient } from './client'; | |||
7 | import { isRustEditor, RustEditor } from './util'; | 7 | import { isRustEditor, RustEditor } from './util'; |
8 | import { ServerStatusParams } from './lsp_ext'; | 8 | import { ServerStatusParams } from './lsp_ext'; |
9 | 9 | ||
10 | export type Workspace = | ||
11 | { | ||
12 | kind: 'Workspace Folder'; | ||
13 | } | ||
14 | | { | ||
15 | kind: 'Detached Files'; | ||
16 | files: vscode.TextDocument[]; | ||
17 | }; | ||
18 | |||
10 | export class Ctx { | 19 | export class Ctx { |
11 | private constructor( | 20 | private constructor( |
12 | readonly config: Config, | 21 | readonly config: Config, |
@@ -22,9 +31,9 @@ export class Ctx { | |||
22 | config: Config, | 31 | config: Config, |
23 | extCtx: vscode.ExtensionContext, | 32 | extCtx: vscode.ExtensionContext, |
24 | serverPath: string, | 33 | serverPath: string, |
25 | cwd: string, | 34 | workspace: Workspace, |
26 | ): Promise<Ctx> { | 35 | ): Promise<Ctx> { |
27 | const client = createClient(serverPath, cwd, config.serverExtraEnv); | 36 | const client = createClient(serverPath, workspace, config.serverExtraEnv); |
28 | 37 | ||
29 | const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); | 38 | const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); |
30 | extCtx.subscriptions.push(statusBar); | 39 | extCtx.subscriptions.push(statusBar); |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index aaedc2431..d26273246 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -7,7 +7,7 @@ import * as commands from './commands'; | |||
7 | import { activateInlayHints } from './inlay_hints'; | 7 | import { activateInlayHints } from './inlay_hints'; |
8 | import { Ctx } from './ctx'; | 8 | import { Ctx } from './ctx'; |
9 | import { Config } from './config'; | 9 | import { Config } from './config'; |
10 | import { log, assert, isValidExecutable } from './util'; | 10 | import { log, assert, isValidExecutable, isRustDocument } from './util'; |
11 | import { PersistentState } from './persistent_state'; | 11 | import { PersistentState } from './persistent_state'; |
12 | import { fetchRelease, download } from './net'; | 12 | import { fetchRelease, download } from './net'; |
13 | import { activateTaskProvider } from './tasks'; | 13 | import { activateTaskProvider } from './tasks'; |
@@ -28,26 +28,6 @@ export async function activate(context: vscode.ExtensionContext) { | |||
28 | } | 28 | } |
29 | 29 | ||
30 | async function tryActivate(context: vscode.ExtensionContext) { | 30 | async function tryActivate(context: vscode.ExtensionContext) { |
31 | // Register a "dumb" onEnter command for the case where server fails to | ||
32 | // start. | ||
33 | // | ||
34 | // FIXME: refactor command registration code such that commands are | ||
35 | // **always** registered, even if the server does not start. Use API like | ||
36 | // this perhaps? | ||
37 | // | ||
38 | // ```TypeScript | ||
39 | // registerCommand( | ||
40 | // factory: (Ctx) => ((Ctx) => any), | ||
41 | // fallback: () => any = () => vscode.window.showErrorMessage( | ||
42 | // "rust-analyzer is not available" | ||
43 | // ), | ||
44 | // ) | ||
45 | const defaultOnEnter = vscode.commands.registerCommand( | ||
46 | 'rust-analyzer.onEnter', | ||
47 | () => vscode.commands.executeCommand('default:type', { text: '\n' }), | ||
48 | ); | ||
49 | context.subscriptions.push(defaultOnEnter); | ||
50 | |||
51 | const config = new Config(context); | 31 | const config = new Config(context); |
52 | const state = new PersistentState(context.globalState); | 32 | const state = new PersistentState(context.globalState); |
53 | const serverPath = await bootstrap(config, state).catch(err => { | 33 | const serverPath = await bootstrap(config, state).catch(err => { |
@@ -65,16 +45,53 @@ async function tryActivate(context: vscode.ExtensionContext) { | |||
65 | throw new Error(message); | 45 | throw new Error(message); |
66 | }); | 46 | }); |
67 | 47 | ||
68 | const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; | 48 | if (vscode.workspace.workspaceFolders?.length === 0) { |
69 | if (workspaceFolder === undefined) { | 49 | const rustDocuments = vscode.workspace.textDocuments.filter(document => isRustDocument(document)); |
70 | throw new Error("no folder is opened"); | 50 | if (rustDocuments.length > 0) { |
51 | ctx = await Ctx.create(config, context, serverPath, { kind: 'Detached Files', files: rustDocuments }); | ||
52 | } else { | ||
53 | throw new Error("no rust files are opened"); | ||
54 | } | ||
55 | } else { | ||
56 | // Note: we try to start the server before we activate type hints so that it | ||
57 | // registers its `onDidChangeDocument` handler before us. | ||
58 | // | ||
59 | // This a horribly, horribly wrong way to deal with this problem. | ||
60 | ctx = await Ctx.create(config, context, serverPath, { kind: "Workspace Folder" }); | ||
61 | ctx.pushCleanup(activateTaskProvider(ctx.config)); | ||
71 | } | 62 | } |
63 | await initCommonContext(context, ctx); | ||
64 | |||
65 | activateInlayHints(ctx); | ||
66 | warnAboutExtensionConflicts(); | ||
67 | |||
68 | vscode.workspace.onDidChangeConfiguration( | ||
69 | _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), | ||
70 | null, | ||
71 | ctx.subscriptions, | ||
72 | ); | ||
73 | } | ||
72 | 74 | ||
73 | // Note: we try to start the server before we activate type hints so that it | 75 | async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) { |
74 | // registers its `onDidChangeDocument` handler before us. | 76 | // Register a "dumb" onEnter command for the case where server fails to |
77 | // start. | ||
78 | // | ||
79 | // FIXME: refactor command registration code such that commands are | ||
80 | // **always** registered, even if the server does not start. Use API like | ||
81 | // this perhaps? | ||
75 | // | 82 | // |
76 | // This a horribly, horribly wrong way to deal with this problem. | 83 | // ```TypeScript |
77 | ctx = await Ctx.create(config, context, serverPath, workspaceFolder.uri.fsPath); | 84 | // registerCommand( |
85 | // factory: (Ctx) => ((Ctx) => any), | ||
86 | // fallback: () => any = () => vscode.window.showErrorMessage( | ||
87 | // "rust-analyzer is not available" | ||
88 | // ), | ||
89 | // ) | ||
90 | const defaultOnEnter = vscode.commands.registerCommand( | ||
91 | 'rust-analyzer.onEnter', | ||
92 | () => vscode.commands.executeCommand('default:type', { text: '\n' }), | ||
93 | ); | ||
94 | context.subscriptions.push(defaultOnEnter); | ||
78 | 95 | ||
79 | await setContextValue(RUST_PROJECT_CONTEXT_NAME, true); | 96 | await setContextValue(RUST_PROJECT_CONTEXT_NAME, true); |
80 | 97 | ||
@@ -134,17 +151,6 @@ async function tryActivate(context: vscode.ExtensionContext) { | |||
134 | ctx.registerCommand('resolveCodeAction', commands.resolveCodeAction); | 151 | ctx.registerCommand('resolveCodeAction', commands.resolveCodeAction); |
135 | ctx.registerCommand('applyActionGroup', commands.applyActionGroup); | 152 | ctx.registerCommand('applyActionGroup', commands.applyActionGroup); |
136 | ctx.registerCommand('gotoLocation', commands.gotoLocation); | 153 | ctx.registerCommand('gotoLocation', commands.gotoLocation); |
137 | |||
138 | ctx.pushCleanup(activateTaskProvider(workspaceFolder, ctx.config)); | ||
139 | |||
140 | activateInlayHints(ctx); | ||
141 | warnAboutExtensionConflicts(); | ||
142 | |||
143 | vscode.workspace.onDidChangeConfiguration( | ||
144 | _ => ctx?.client?.sendNotification('workspace/didChangeConfiguration', { settings: "" }), | ||
145 | null, | ||
146 | ctx.subscriptions, | ||
147 | ); | ||
148 | } | 154 | } |
149 | 155 | ||
150 | export async function deactivate() { | 156 | export async function deactivate() { |
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts index 138e3f686..d0be84068 100644 --- a/editors/code/src/run.ts +++ b/editors/code/src/run.ts | |||
@@ -142,7 +142,11 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise | |||
142 | // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion | 142 | // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion |
143 | const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() | 143 | const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate() |
144 | const cargoTask = await tasks.buildCargoTask(target, definition, runnable.label, args, config.cargoRunner, true); | 144 | const cargoTask = await tasks.buildCargoTask(target, definition, runnable.label, args, config.cargoRunner, true); |
145 | |||
145 | cargoTask.presentationOptions.clear = true; | 146 | cargoTask.presentationOptions.clear = true; |
147 | // Sadly, this doesn't prevent focus stealing if the terminal is currently | ||
148 | // hidden, and will become revealed due to task exucution. | ||
149 | cargoTask.presentationOptions.focus = false; | ||
146 | 150 | ||
147 | return cargoTask; | 151 | return cargoTask; |
148 | } | 152 | } |
diff --git a/editors/code/src/snippets.ts b/editors/code/src/snippets.ts index 9561aa345..a409e5296 100644 --- a/editors/code/src/snippets.ts +++ b/editors/code/src/snippets.ts | |||
@@ -52,10 +52,13 @@ export async function applySnippetTextEdits(editor: vscode.TextEditor, edits: vs | |||
52 | } else { | 52 | } else { |
53 | builder.replace(indel.range, indel.newText); | 53 | builder.replace(indel.range, indel.newText); |
54 | } | 54 | } |
55 | lineDelta = countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); | 55 | lineDelta += countLines(indel.newText) - (indel.range.end.line - indel.range.start.line); |
56 | } | 56 | } |
57 | }); | 57 | }); |
58 | if (selections.length > 0) editor.selections = selections; | 58 | if (selections.length > 0) editor.selections = selections; |
59 | if (selections.length === 1) { | ||
60 | editor.revealRange(selections[0], vscode.TextEditorRevealType.InCenterIfOutsideViewport); | ||
61 | } | ||
59 | } | 62 | } |
60 | 63 | ||
61 | function parseSnippet(snip: string): [string, [number, number]] | undefined { | 64 | function parseSnippet(snip: string): [string, [number, number]] | undefined { |
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts index a3ff15102..694ee1e41 100644 --- a/editors/code/src/tasks.ts +++ b/editors/code/src/tasks.ts | |||
@@ -17,11 +17,9 @@ export interface CargoTaskDefinition extends vscode.TaskDefinition { | |||
17 | } | 17 | } |
18 | 18 | ||
19 | class CargoTaskProvider implements vscode.TaskProvider { | 19 | class CargoTaskProvider implements vscode.TaskProvider { |
20 | private readonly target: vscode.WorkspaceFolder; | ||
21 | private readonly config: Config; | 20 | private readonly config: Config; |
22 | 21 | ||
23 | constructor(target: vscode.WorkspaceFolder, config: Config) { | 22 | constructor(config: Config) { |
24 | this.target = target; | ||
25 | this.config = config; | 23 | this.config = config; |
26 | } | 24 | } |
27 | 25 | ||
@@ -40,10 +38,12 @@ class CargoTaskProvider implements vscode.TaskProvider { | |||
40 | ]; | 38 | ]; |
41 | 39 | ||
42 | const tasks: vscode.Task[] = []; | 40 | const tasks: vscode.Task[] = []; |
43 | for (const def of defs) { | 41 | for (const workspaceTarget of vscode.workspace.workspaceFolders || []) { |
44 | const vscodeTask = await buildCargoTask(this.target, { type: TASK_TYPE, command: def.command }, `cargo ${def.command}`, [def.command], this.config.cargoRunner); | 42 | for (const def of defs) { |
45 | vscodeTask.group = def.group; | 43 | const vscodeTask = await buildCargoTask(workspaceTarget, { type: TASK_TYPE, command: def.command }, `cargo ${def.command}`, [def.command], this.config.cargoRunner); |
46 | tasks.push(vscodeTask); | 44 | vscodeTask.group = def.group; |
45 | tasks.push(vscodeTask); | ||
46 | } | ||
47 | } | 47 | } |
48 | 48 | ||
49 | return tasks; | 49 | return tasks; |
@@ -58,14 +58,19 @@ class CargoTaskProvider implements vscode.TaskProvider { | |||
58 | 58 | ||
59 | if (definition.type === TASK_TYPE && definition.command) { | 59 | if (definition.type === TASK_TYPE && definition.command) { |
60 | const args = [definition.command].concat(definition.args ?? []); | 60 | const args = [definition.command].concat(definition.args ?? []); |
61 | 61 | if (isWorkspaceFolder(task.scope)) { | |
62 | return await buildCargoTask(this.target, definition, task.name, args, this.config.cargoRunner); | 62 | return await buildCargoTask(task.scope, definition, task.name, args, this.config.cargoRunner); |
63 | } | ||
63 | } | 64 | } |
64 | 65 | ||
65 | return undefined; | 66 | return undefined; |
66 | } | 67 | } |
67 | } | 68 | } |
68 | 69 | ||
70 | function isWorkspaceFolder(scope?: any): scope is vscode.WorkspaceFolder { | ||
71 | return (scope as vscode.WorkspaceFolder).name !== undefined; | ||
72 | } | ||
73 | |||
69 | export async function buildCargoTask( | 74 | export async function buildCargoTask( |
70 | target: vscode.WorkspaceFolder, | 75 | target: vscode.WorkspaceFolder, |
71 | definition: CargoTaskDefinition, | 76 | definition: CargoTaskDefinition, |
@@ -119,7 +124,7 @@ export async function buildCargoTask( | |||
119 | ); | 124 | ); |
120 | } | 125 | } |
121 | 126 | ||
122 | export function activateTaskProvider(target: vscode.WorkspaceFolder, config: Config): vscode.Disposable { | 127 | export function activateTaskProvider(config: Config): vscode.Disposable { |
123 | const provider = new CargoTaskProvider(target, config); | 128 | const provider = new CargoTaskProvider(config); |
124 | return vscode.tasks.registerTaskProvider(TASK_TYPE, provider); | 129 | return vscode.tasks.registerTaskProvider(TASK_TYPE, provider); |
125 | } | 130 | } |