diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-02-25 09:55:56 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2020-02-25 09:55:56 +0000 |
commit | 5e6f4ca6905e02a5fa34ef292fa2abefcd982222 (patch) | |
tree | 413691f3aab076538aac3c49bef015fb945d5320 /editors/code/src | |
parent | 558d263a0c602ef12914cbb10c263a9e2bb96bf2 (diff) | |
parent | 18b97d9d367d5fc1533c48157ebca7bb18b62e3c (diff) |
Merge #3299
3299: vscode: migrate to request type api r=matklad a=Veetaha
More type-safety to the god of type-safety.
Co-authored-by: Veetaha <[email protected]>
Diffstat (limited to 'editors/code/src')
-rw-r--r-- | editors/code/src/commands/analyzer_status.ts | 6 | ||||
-rw-r--r-- | editors/code/src/commands/expand_macro.ts | 18 | ||||
-rw-r--r-- | editors/code/src/commands/index.ts | 9 | ||||
-rw-r--r-- | editors/code/src/commands/join_lines.ts | 17 | ||||
-rw-r--r-- | editors/code/src/commands/matching_brace.ts | 15 | ||||
-rw-r--r-- | editors/code/src/commands/on_enter.ts | 21 | ||||
-rw-r--r-- | editors/code/src/commands/parent_module.ts | 10 | ||||
-rw-r--r-- | editors/code/src/commands/runnables.ts | 29 | ||||
-rw-r--r-- | editors/code/src/commands/ssr.ts | 16 | ||||
-rw-r--r-- | editors/code/src/commands/syntax_tree.ts | 27 | ||||
-rw-r--r-- | editors/code/src/highlighting.ts | 60 | ||||
-rw-r--r-- | editors/code/src/inlay_hints.ts | 31 | ||||
-rw-r--r-- | editors/code/src/rust-analyzer-api.ts | 117 | ||||
-rw-r--r-- | editors/code/src/source_change.ts | 9 | ||||
-rw-r--r-- | editors/code/src/util.ts | 16 |
15 files changed, 203 insertions, 198 deletions
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts index 6631e8db7..1c6ea399b 100644 --- a/editors/code/src/commands/analyzer_status.ts +++ b/editors/code/src/commands/analyzer_status.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | 2 | ||
3 | import * as ra from '../rust-analyzer-api'; | ||
3 | import { Ctx, Cmd } from '../ctx'; | 4 | import { Ctx, Cmd } from '../ctx'; |
4 | 5 | ||
5 | // Shows status of rust-analyzer (for debugging) | 6 | // Shows status of rust-analyzer (for debugging) |
@@ -50,10 +51,7 @@ class TextDocumentContentProvider | |||
50 | const client = this.ctx.client; | 51 | const client = this.ctx.client; |
51 | if (!editor || !client) return ''; | 52 | if (!editor || !client) return ''; |
52 | 53 | ||
53 | return client.sendRequest<string>( | 54 | return client.sendRequest(ra.analyzerStatus, null); |
54 | 'rust-analyzer/analyzerStatus', | ||
55 | null, | ||
56 | ); | ||
57 | } | 55 | } |
58 | 56 | ||
59 | get onDidChange(): vscode.Event<vscode.Uri> { | 57 | get onDidChange(): vscode.Event<vscode.Uri> { |
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts index edec9bbc1..23f2ef1d5 100644 --- a/editors/code/src/commands/expand_macro.ts +++ b/editors/code/src/commands/expand_macro.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from '../rust-analyzer-api'; |
3 | 3 | ||
4 | import { Ctx, Cmd } from '../ctx'; | 4 | import { Ctx, Cmd } from '../ctx'; |
5 | 5 | ||
@@ -26,12 +26,7 @@ export function expandMacro(ctx: Ctx): Cmd { | |||
26 | }; | 26 | }; |
27 | } | 27 | } |
28 | 28 | ||
29 | interface ExpandedMacro { | 29 | function codeFormat(expanded: ra.ExpandedMacro): string { |
30 | name: string; | ||
31 | expansion: string; | ||
32 | } | ||
33 | |||
34 | function codeFormat(expanded: ExpandedMacro): string { | ||
35 | let result = `// Recursive expansion of ${expanded.name}! macro\n`; | 30 | let result = `// Recursive expansion of ${expanded.name}! macro\n`; |
36 | result += '// ' + '='.repeat(result.length - 3); | 31 | result += '// ' + '='.repeat(result.length - 3); |
37 | result += '\n\n'; | 32 | result += '\n\n'; |
@@ -54,14 +49,11 @@ class TextDocumentContentProvider | |||
54 | if (!editor || !client) return ''; | 49 | if (!editor || !client) return ''; |
55 | 50 | ||
56 | const position = editor.selection.active; | 51 | const position = editor.selection.active; |
57 | const request: lc.TextDocumentPositionParams = { | 52 | |
53 | const expanded = await client.sendRequest(ra.expandMacro, { | ||
58 | textDocument: { uri: editor.document.uri.toString() }, | 54 | textDocument: { uri: editor.document.uri.toString() }, |
59 | position, | 55 | position, |
60 | }; | 56 | }); |
61 | const expanded = await client.sendRequest<ExpandedMacro>( | ||
62 | 'rust-analyzer/expandMacro', | ||
63 | request, | ||
64 | ); | ||
65 | 57 | ||
66 | if (expanded == null) return 'Not available'; | 58 | if (expanded == null) return 'Not available'; |
67 | 59 | ||
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts index 839245f48..bdb7fc3b0 100644 --- a/editors/code/src/commands/index.ts +++ b/editors/code/src/commands/index.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import * as ra from '../rust-analyzer-api'; | ||
3 | 4 | ||
4 | import { Ctx, Cmd } from '../ctx'; | 5 | import { Ctx, Cmd } from '../ctx'; |
5 | import * as sourceChange from '../source_change'; | 6 | import * as sourceChange from '../source_change'; |
@@ -16,9 +17,7 @@ export * from './ssr'; | |||
16 | export * from './server_version'; | 17 | export * from './server_version'; |
17 | 18 | ||
18 | export function collectGarbage(ctx: Ctx): Cmd { | 19 | export function collectGarbage(ctx: Ctx): Cmd { |
19 | return async () => { | 20 | return async () => ctx.client.sendRequest(ra.collectGarbage, null); |
20 | await ctx.client?.sendRequest<null>('rust-analyzer/collectGarbage', null); | ||
21 | }; | ||
22 | } | 21 | } |
23 | 22 | ||
24 | export function showReferences(ctx: Ctx): Cmd { | 23 | export function showReferences(ctx: Ctx): Cmd { |
@@ -36,13 +35,13 @@ export function showReferences(ctx: Ctx): Cmd { | |||
36 | } | 35 | } |
37 | 36 | ||
38 | export function applySourceChange(ctx: Ctx): Cmd { | 37 | export function applySourceChange(ctx: Ctx): Cmd { |
39 | return async (change: sourceChange.SourceChange) => { | 38 | return async (change: ra.SourceChange) => { |
40 | await sourceChange.applySourceChange(ctx, change); | 39 | await sourceChange.applySourceChange(ctx, change); |
41 | }; | 40 | }; |
42 | } | 41 | } |
43 | 42 | ||
44 | export function selectAndApplySourceChange(ctx: Ctx): Cmd { | 43 | export function selectAndApplySourceChange(ctx: Ctx): Cmd { |
45 | return async (changes: sourceChange.SourceChange[]) => { | 44 | return async (changes: ra.SourceChange[]) => { |
46 | if (changes.length === 1) { | 45 | if (changes.length === 1) { |
47 | await sourceChange.applySourceChange(ctx, changes[0]); | 46 | await sourceChange.applySourceChange(ctx, changes[0]); |
48 | } else if (changes.length > 0) { | 47 | } else if (changes.length > 0) { |
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts index 7b08c3255..de0614653 100644 --- a/editors/code/src/commands/join_lines.ts +++ b/editors/code/src/commands/join_lines.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as lc from 'vscode-languageclient'; | 1 | import * as ra from '../rust-analyzer-api'; |
2 | 2 | ||
3 | import { Ctx, Cmd } from '../ctx'; | 3 | import { Ctx, Cmd } from '../ctx'; |
4 | import { applySourceChange, SourceChange } from '../source_change'; | 4 | import { applySourceChange } from '../source_change'; |
5 | 5 | ||
6 | export function joinLines(ctx: Ctx): Cmd { | 6 | export function joinLines(ctx: Ctx): Cmd { |
7 | return async () => { | 7 | return async () => { |
@@ -9,19 +9,10 @@ export function joinLines(ctx: Ctx): Cmd { | |||
9 | const client = ctx.client; | 9 | const client = ctx.client; |
10 | if (!editor || !client) return; | 10 | if (!editor || !client) return; |
11 | 11 | ||
12 | const request: JoinLinesParams = { | 12 | const change = await client.sendRequest(ra.joinLines, { |
13 | range: client.code2ProtocolConverter.asRange(editor.selection), | 13 | range: client.code2ProtocolConverter.asRange(editor.selection), |
14 | textDocument: { uri: editor.document.uri.toString() }, | 14 | textDocument: { uri: editor.document.uri.toString() }, |
15 | }; | 15 | }); |
16 | const change = await client.sendRequest<SourceChange>( | ||
17 | 'rust-analyzer/joinLines', | ||
18 | request, | ||
19 | ); | ||
20 | await applySourceChange(ctx, change); | 16 | await applySourceChange(ctx, change); |
21 | }; | 17 | }; |
22 | } | 18 | } |
23 | |||
24 | interface JoinLinesParams { | ||
25 | textDocument: lc.TextDocumentIdentifier; | ||
26 | range: lc.Range; | ||
27 | } | ||
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts index 7c58bb7e7..a60776e2d 100644 --- a/editors/code/src/commands/matching_brace.ts +++ b/editors/code/src/commands/matching_brace.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from '../rust-analyzer-api'; |
3 | 3 | ||
4 | import { Ctx, Cmd } from '../ctx'; | 4 | import { Ctx, Cmd } from '../ctx'; |
5 | 5 | ||
@@ -9,16 +9,12 @@ export function matchingBrace(ctx: Ctx): Cmd { | |||
9 | const client = ctx.client; | 9 | const client = ctx.client; |
10 | if (!editor || !client) return; | 10 | if (!editor || !client) return; |
11 | 11 | ||
12 | const request: FindMatchingBraceParams = { | 12 | const response = await client.sendRequest(ra.findMatchingBrace, { |
13 | textDocument: { uri: editor.document.uri.toString() }, | 13 | textDocument: { uri: editor.document.uri.toString() }, |
14 | offsets: editor.selections.map(s => | 14 | offsets: editor.selections.map(s => |
15 | client.code2ProtocolConverter.asPosition(s.active), | 15 | client.code2ProtocolConverter.asPosition(s.active), |
16 | ), | 16 | ), |
17 | }; | 17 | }); |
18 | const response = await client.sendRequest<lc.Position[]>( | ||
19 | 'rust-analyzer/findMatchingBrace', | ||
20 | request, | ||
21 | ); | ||
22 | editor.selections = editor.selections.map((sel, idx) => { | 18 | editor.selections = editor.selections.map((sel, idx) => { |
23 | const active = client.protocol2CodeConverter.asPosition( | 19 | const active = client.protocol2CodeConverter.asPosition( |
24 | response[idx], | 20 | response[idx], |
@@ -29,8 +25,3 @@ export function matchingBrace(ctx: Ctx): Cmd { | |||
29 | editor.revealRange(editor.selection); | 25 | editor.revealRange(editor.selection); |
30 | }; | 26 | }; |
31 | } | 27 | } |
32 | |||
33 | interface FindMatchingBraceParams { | ||
34 | textDocument: lc.TextDocumentIdentifier; | ||
35 | offsets: lc.Position[]; | ||
36 | } | ||
diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts index 27ae8ec23..285849db7 100644 --- a/editors/code/src/commands/on_enter.ts +++ b/editors/code/src/commands/on_enter.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from '../rust-analyzer-api'; |
3 | 3 | ||
4 | import { applySourceChange, SourceChange } from '../source_change'; | 4 | import { applySourceChange } from '../source_change'; |
5 | import { Cmd, Ctx } from '../ctx'; | 5 | import { Cmd, Ctx } from '../ctx'; |
6 | 6 | ||
7 | async function handleKeypress(ctx: Ctx) { | 7 | async function handleKeypress(ctx: Ctx) { |
@@ -10,22 +10,15 @@ async function handleKeypress(ctx: Ctx) { | |||
10 | 10 | ||
11 | if (!editor || !client) return false; | 11 | if (!editor || !client) return false; |
12 | 12 | ||
13 | const request: lc.TextDocumentPositionParams = { | 13 | const change = await client.sendRequest(ra.onEnter, { |
14 | textDocument: { uri: editor.document.uri.toString() }, | 14 | textDocument: { uri: editor.document.uri.toString() }, |
15 | position: client.code2ProtocolConverter.asPosition( | 15 | position: client.code2ProtocolConverter.asPosition( |
16 | editor.selection.active, | 16 | editor.selection.active, |
17 | ), | 17 | ), |
18 | }; | 18 | }).catch(_error => { |
19 | const change = await client.sendRequest<undefined | SourceChange>( | 19 | // client.logFailedRequest(OnEnterRequest.type, error); |
20 | 'rust-analyzer/onEnter', | 20 | return null; |
21 | request, | 21 | }); |
22 | ).catch( | ||
23 | (_error: any) => { | ||
24 | // FIXME: switch to the more modern (?) typed request infrastructure | ||
25 | // client.logFailedRequest(OnEnterRequest.type, error); | ||
26 | return Promise.resolve(null); | ||
27 | } | ||
28 | ); | ||
29 | if (!change) return false; | 22 | if (!change) return false; |
30 | 23 | ||
31 | await applySourceChange(ctx, change); | 24 | await applySourceChange(ctx, change); |
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts index bf40b4021..8f78ddd71 100644 --- a/editors/code/src/commands/parent_module.ts +++ b/editors/code/src/commands/parent_module.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from '../rust-analyzer-api'; |
3 | 3 | ||
4 | import { Ctx, Cmd } from '../ctx'; | 4 | import { Ctx, Cmd } from '../ctx'; |
5 | 5 | ||
@@ -9,16 +9,12 @@ export function parentModule(ctx: Ctx): Cmd { | |||
9 | const client = ctx.client; | 9 | const client = ctx.client; |
10 | if (!editor || !client) return; | 10 | if (!editor || !client) return; |
11 | 11 | ||
12 | const request: lc.TextDocumentPositionParams = { | 12 | const response = await client.sendRequest(ra.parentModule, { |
13 | textDocument: { uri: editor.document.uri.toString() }, | 13 | textDocument: { uri: editor.document.uri.toString() }, |
14 | position: client.code2ProtocolConverter.asPosition( | 14 | position: client.code2ProtocolConverter.asPosition( |
15 | editor.selection.active, | 15 | editor.selection.active, |
16 | ), | 16 | ), |
17 | }; | 17 | }); |
18 | const response = await client.sendRequest<lc.Location[]>( | ||
19 | 'rust-analyzer/parentModule', | ||
20 | request, | ||
21 | ); | ||
22 | const loc = response[0]; | 18 | const loc = response[0]; |
23 | if (loc == null) return; | 19 | if (loc == null) return; |
24 | 20 | ||
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 7919997ce..06b513466 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import * as ra from '../rust-analyzer-api'; | ||
3 | 4 | ||
4 | import { Ctx, Cmd } from '../ctx'; | 5 | import { Ctx, Cmd } from '../ctx'; |
5 | 6 | ||
@@ -14,16 +15,13 @@ export function run(ctx: Ctx): Cmd { | |||
14 | const textDocument: lc.TextDocumentIdentifier = { | 15 | const textDocument: lc.TextDocumentIdentifier = { |
15 | uri: editor.document.uri.toString(), | 16 | uri: editor.document.uri.toString(), |
16 | }; | 17 | }; |
17 | const params: RunnablesParams = { | 18 | |
19 | const runnables = await client.sendRequest(ra.runnables, { | ||
18 | textDocument, | 20 | textDocument, |
19 | position: client.code2ProtocolConverter.asPosition( | 21 | position: client.code2ProtocolConverter.asPosition( |
20 | editor.selection.active, | 22 | editor.selection.active, |
21 | ), | 23 | ), |
22 | }; | 24 | }); |
23 | const runnables = await client.sendRequest<Runnable[]>( | ||
24 | 'rust-analyzer/runnables', | ||
25 | params, | ||
26 | ); | ||
27 | const items: RunnableQuickPick[] = []; | 25 | const items: RunnableQuickPick[] = []; |
28 | if (prevRunnable) { | 26 | if (prevRunnable) { |
29 | items.push(prevRunnable); | 27 | items.push(prevRunnable); |
@@ -48,7 +46,7 @@ export function run(ctx: Ctx): Cmd { | |||
48 | } | 46 | } |
49 | 47 | ||
50 | export function runSingle(ctx: Ctx): Cmd { | 48 | export function runSingle(ctx: Ctx): Cmd { |
51 | return async (runnable: Runnable) => { | 49 | return async (runnable: ra.Runnable) => { |
52 | const editor = ctx.activeRustEditor; | 50 | const editor = ctx.activeRustEditor; |
53 | if (!editor) return; | 51 | if (!editor) return; |
54 | 52 | ||
@@ -64,26 +62,13 @@ export function runSingle(ctx: Ctx): Cmd { | |||
64 | }; | 62 | }; |
65 | } | 63 | } |
66 | 64 | ||
67 | interface RunnablesParams { | ||
68 | textDocument: lc.TextDocumentIdentifier; | ||
69 | position?: lc.Position; | ||
70 | } | ||
71 | |||
72 | interface Runnable { | ||
73 | label: string; | ||
74 | bin: string; | ||
75 | args: string[]; | ||
76 | env: { [index: string]: string }; | ||
77 | cwd?: string; | ||
78 | } | ||
79 | |||
80 | class RunnableQuickPick implements vscode.QuickPickItem { | 65 | class RunnableQuickPick implements vscode.QuickPickItem { |
81 | public label: string; | 66 | public label: string; |
82 | public description?: string | undefined; | 67 | public description?: string | undefined; |
83 | public detail?: string | undefined; | 68 | public detail?: string | undefined; |
84 | public picked?: boolean | undefined; | 69 | public picked?: boolean | undefined; |
85 | 70 | ||
86 | constructor(public runnable: Runnable) { | 71 | constructor(public runnable: ra.Runnable) { |
87 | this.label = runnable.label; | 72 | this.label = runnable.label; |
88 | } | 73 | } |
89 | } | 74 | } |
@@ -96,7 +81,7 @@ interface CargoTaskDefinition extends vscode.TaskDefinition { | |||
96 | env?: { [key: string]: string }; | 81 | env?: { [key: string]: string }; |
97 | } | 82 | } |
98 | 83 | ||
99 | function createTask(spec: Runnable): vscode.Task { | 84 | function createTask(spec: ra.Runnable): vscode.Task { |
100 | const TASK_SOURCE = 'Rust'; | 85 | const TASK_SOURCE = 'Rust'; |
101 | const definition: CargoTaskDefinition = { | 86 | const definition: CargoTaskDefinition = { |
102 | type: 'cargo', | 87 | type: 'cargo', |
diff --git a/editors/code/src/commands/ssr.ts b/editors/code/src/commands/ssr.ts index 9b814612a..eee48c693 100644 --- a/editors/code/src/commands/ssr.ts +++ b/editors/code/src/commands/ssr.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | import { Ctx, Cmd } from '../ctx'; | ||
2 | import { applySourceChange, SourceChange } from '../source_change'; | ||
3 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as ra from "../rust-analyzer-api"; | ||
3 | |||
4 | import { Ctx, Cmd } from '../ctx'; | ||
5 | import { applySourceChange } from '../source_change'; | ||
4 | 6 | ||
5 | export function ssr(ctx: Ctx): Cmd { | 7 | export function ssr(ctx: Ctx): Cmd { |
6 | return async () => { | 8 | return async () => { |
@@ -21,16 +23,8 @@ export function ssr(ctx: Ctx): Cmd { | |||
21 | 23 | ||
22 | if (!request) return; | 24 | if (!request) return; |
23 | 25 | ||
24 | const ssrRequest: SsrRequest = { arg: request }; | 26 | const change = await client.sendRequest(ra.ssr, { arg: request }); |
25 | const change = await client.sendRequest<SourceChange>( | ||
26 | 'rust-analyzer/ssr', | ||
27 | ssrRequest, | ||
28 | ); | ||
29 | 27 | ||
30 | await applySourceChange(ctx, change); | 28 | await applySourceChange(ctx, change); |
31 | }; | 29 | }; |
32 | } | 30 | } |
33 | |||
34 | interface SsrRequest { | ||
35 | arg: string; | ||
36 | } | ||
diff --git a/editors/code/src/commands/syntax_tree.ts b/editors/code/src/commands/syntax_tree.ts index 2887c96c8..7218bfb90 100644 --- a/editors/code/src/commands/syntax_tree.ts +++ b/editors/code/src/commands/syntax_tree.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from '../rust-analyzer-api'; |
3 | 3 | ||
4 | import { Ctx, Cmd } from '../ctx'; | 4 | import { Ctx, Cmd } from '../ctx'; |
5 | 5 | ||
@@ -61,13 +61,8 @@ function afterLs(f: () => void) { | |||
61 | setTimeout(f, 10); | 61 | setTimeout(f, 10); |
62 | } | 62 | } |
63 | 63 | ||
64 | interface SyntaxTreeParams { | ||
65 | textDocument: lc.TextDocumentIdentifier; | ||
66 | range?: lc.Range; | ||
67 | } | ||
68 | 64 | ||
69 | class TextDocumentContentProvider | 65 | class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { |
70 | implements vscode.TextDocumentContentProvider { | ||
71 | uri = vscode.Uri.parse('rust-analyzer://syntaxtree'); | 66 | uri = vscode.Uri.parse('rust-analyzer://syntaxtree'); |
72 | eventEmitter = new vscode.EventEmitter<vscode.Uri>(); | 67 | eventEmitter = new vscode.EventEmitter<vscode.Uri>(); |
73 | 68 | ||
@@ -79,23 +74,15 @@ class TextDocumentContentProvider | |||
79 | const client = this.ctx.client; | 74 | const client = this.ctx.client; |
80 | if (!editor || !client) return ''; | 75 | if (!editor || !client) return ''; |
81 | 76 | ||
82 | let range: lc.Range | undefined; | ||
83 | |||
84 | // When the range based query is enabled we take the range of the selection | 77 | // When the range based query is enabled we take the range of the selection |
85 | if (uri.query === 'range=true') { | 78 | const range = uri.query === 'range=true' && !editor.selection.isEmpty |
86 | range = editor.selection.isEmpty | 79 | ? client.code2ProtocolConverter.asRange(editor.selection) |
87 | ? undefined | 80 | : null; |
88 | : client.code2ProtocolConverter.asRange(editor.selection); | ||
89 | } | ||
90 | 81 | ||
91 | const request: SyntaxTreeParams = { | 82 | return client.sendRequest(ra.syntaxTree, { |
92 | textDocument: { uri: editor.document.uri.toString() }, | 83 | textDocument: { uri: editor.document.uri.toString() }, |
93 | range, | 84 | range, |
94 | }; | 85 | }); |
95 | return client.sendRequest<string>( | ||
96 | 'rust-analyzer/syntaxTree', | ||
97 | request, | ||
98 | ); | ||
99 | } | 86 | } |
100 | 87 | ||
101 | get onDidChange(): vscode.Event<vscode.Uri> { | 88 | get onDidChange(): vscode.Event<vscode.Uri> { |
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts index 77b4a1a68..3e0cbdc56 100644 --- a/editors/code/src/highlighting.ts +++ b/editors/code/src/highlighting.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from './rust-analyzer-api'; |
3 | 3 | ||
4 | import { ColorTheme, TextMateRuleSettings } from './color_theme'; | 4 | import { ColorTheme, TextMateRuleSettings } from './color_theme'; |
5 | 5 | ||
@@ -8,29 +8,25 @@ import { sendRequestWithRetry } from './util'; | |||
8 | 8 | ||
9 | export function activateHighlighting(ctx: Ctx) { | 9 | export function activateHighlighting(ctx: Ctx) { |
10 | const highlighter = new Highlighter(ctx); | 10 | const highlighter = new Highlighter(ctx); |
11 | const client = ctx.client; | ||
12 | if (client != null) { | ||
13 | client.onNotification( | ||
14 | 'rust-analyzer/publishDecorations', | ||
15 | (params: PublishDecorationsParams) => { | ||
16 | if (!ctx.config.highlightingOn) return; | ||
17 | |||
18 | const targetEditor = vscode.window.visibleTextEditors.find( | ||
19 | editor => { | ||
20 | const unescapedUri = unescape( | ||
21 | editor.document.uri.toString(), | ||
22 | ); | ||
23 | // Unescaped URI looks like: | ||
24 | // file:///c:/Workspace/ra-test/src/main.rs | ||
25 | return unescapedUri === params.uri; | ||
26 | }, | ||
27 | ); | ||
28 | if (!targetEditor) return; | ||
29 | 11 | ||
30 | highlighter.setHighlights(targetEditor, params.decorations); | 12 | ctx.client.onNotification(ra.publishDecorations, params => { |
13 | if (!ctx.config.highlightingOn) return; | ||
14 | |||
15 | const targetEditor = vscode.window.visibleTextEditors.find( | ||
16 | editor => { | ||
17 | const unescapedUri = unescape( | ||
18 | editor.document.uri.toString(), | ||
19 | ); | ||
20 | // Unescaped URI looks like: | ||
21 | // file:///c:/Workspace/ra-test/src/main.rs | ||
22 | return unescapedUri === params.uri; | ||
31 | }, | 23 | }, |
32 | ); | 24 | ); |
33 | } | 25 | if (!targetEditor) return; |
26 | |||
27 | highlighter.setHighlights(targetEditor, params.decorations); | ||
28 | }); | ||
29 | |||
34 | 30 | ||
35 | vscode.workspace.onDidChangeConfiguration( | 31 | vscode.workspace.onDidChangeConfiguration( |
36 | _ => highlighter.removeHighlights(), | 32 | _ => highlighter.removeHighlights(), |
@@ -45,13 +41,10 @@ export function activateHighlighting(ctx: Ctx) { | |||
45 | const client = ctx.client; | 41 | const client = ctx.client; |
46 | if (!client) return; | 42 | if (!client) return; |
47 | 43 | ||
48 | const params: lc.TextDocumentIdentifier = { | 44 | const decorations = await sendRequestWithRetry( |
49 | uri: editor.document.uri.toString(), | ||
50 | }; | ||
51 | const decorations = await sendRequestWithRetry<Decoration[]>( | ||
52 | client, | 45 | client, |
53 | 'rust-analyzer/decorationsRequest', | 46 | ra.decorationsRequest, |
54 | params, | 47 | { uri: editor.document.uri.toString() }, |
55 | ); | 48 | ); |
56 | highlighter.setHighlights(editor, decorations); | 49 | highlighter.setHighlights(editor, decorations); |
57 | }, | 50 | }, |
@@ -60,17 +53,6 @@ export function activateHighlighting(ctx: Ctx) { | |||
60 | ); | 53 | ); |
61 | } | 54 | } |
62 | 55 | ||
63 | interface PublishDecorationsParams { | ||
64 | uri: string; | ||
65 | decorations: Decoration[]; | ||
66 | } | ||
67 | |||
68 | interface Decoration { | ||
69 | range: lc.Range; | ||
70 | tag: string; | ||
71 | bindingHash?: string; | ||
72 | } | ||
73 | |||
74 | // Based on this HSL-based color generator: https://gist.github.com/bendc/76c48ce53299e6078a76 | 56 | // Based on this HSL-based color generator: https://gist.github.com/bendc/76c48ce53299e6078a76 |
75 | function fancify(seed: string, shade: 'light' | 'dark') { | 57 | function fancify(seed: string, shade: 'light' | 'dark') { |
76 | const random = randomU32Numbers(hashString(seed)); | 58 | const random = randomU32Numbers(hashString(seed)); |
@@ -108,7 +90,7 @@ class Highlighter { | |||
108 | this.decorations = null; | 90 | this.decorations = null; |
109 | } | 91 | } |
110 | 92 | ||
111 | public setHighlights(editor: vscode.TextEditor, highlights: Decoration[]) { | 93 | public setHighlights(editor: vscode.TextEditor, highlights: ra.Decoration[]) { |
112 | const client = this.ctx.client; | 94 | const client = this.ctx.client; |
113 | if (!client) return; | 95 | if (!client) return; |
114 | // Initialize decorations if necessary | 96 | // Initialize decorations if necessary |
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts index 5f9229efb..5951cf1b4 100644 --- a/editors/code/src/inlay_hints.ts +++ b/editors/code/src/inlay_hints.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as ra from './rust-analyzer-api'; |
3 | 3 | ||
4 | import { Ctx } from './ctx'; | 4 | import { Ctx } from './ctx'; |
5 | import { log, sendRequestWithRetry } from './util'; | 5 | import { log, sendRequestWithRetry } from './util'; |
@@ -39,16 +39,6 @@ export function activateInlayHints(ctx: Ctx) { | |||
39 | void hintsUpdater.setEnabled(ctx.config.displayInlayHints); | 39 | void hintsUpdater.setEnabled(ctx.config.displayInlayHints); |
40 | } | 40 | } |
41 | 41 | ||
42 | interface InlayHintsParams { | ||
43 | textDocument: lc.TextDocumentIdentifier; | ||
44 | } | ||
45 | |||
46 | interface InlayHint { | ||
47 | range: vscode.Range; | ||
48 | kind: "TypeHint" | "ParameterHint"; | ||
49 | label: string; | ||
50 | } | ||
51 | |||
52 | const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ | 42 | const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ |
53 | after: { | 43 | after: { |
54 | color: new vscode.ThemeColor('rust_analyzer.inlayHint'), | 44 | color: new vscode.ThemeColor('rust_analyzer.inlayHint'), |
@@ -107,9 +97,9 @@ class HintsUpdater { | |||
107 | if (newHints == null) return; | 97 | if (newHints == null) return; |
108 | 98 | ||
109 | const newTypeDecorations = newHints | 99 | const newTypeDecorations = newHints |
110 | .filter(hint => hint.kind === 'TypeHint') | 100 | .filter(hint => hint.kind === ra.InlayKind.TypeHint) |
111 | .map(hint => ({ | 101 | .map(hint => ({ |
112 | range: hint.range, | 102 | range: this.ctx.client.protocol2CodeConverter.asRange(hint.range), |
113 | renderOptions: { | 103 | renderOptions: { |
114 | after: { | 104 | after: { |
115 | contentText: `: ${hint.label}`, | 105 | contentText: `: ${hint.label}`, |
@@ -119,9 +109,9 @@ class HintsUpdater { | |||
119 | this.setTypeDecorations(editor, newTypeDecorations); | 109 | this.setTypeDecorations(editor, newTypeDecorations); |
120 | 110 | ||
121 | const newParameterDecorations = newHints | 111 | const newParameterDecorations = newHints |
122 | .filter(hint => hint.kind === 'ParameterHint') | 112 | .filter(hint => hint.kind === ra.InlayKind.ParameterHint) |
123 | .map(hint => ({ | 113 | .map(hint => ({ |
124 | range: hint.range, | 114 | range: this.ctx.client.protocol2CodeConverter.asRange(hint.range), |
125 | renderOptions: { | 115 | renderOptions: { |
126 | before: { | 116 | before: { |
127 | contentText: `${hint.label}: `, | 117 | contentText: `${hint.label}: `, |
@@ -151,20 +141,15 @@ class HintsUpdater { | |||
151 | ); | 141 | ); |
152 | } | 142 | } |
153 | 143 | ||
154 | private async queryHints(documentUri: string): Promise<InlayHint[] | null> { | 144 | private async queryHints(documentUri: string): Promise<ra.InlayHint[] | null> { |
155 | this.pending.get(documentUri)?.cancel(); | 145 | this.pending.get(documentUri)?.cancel(); |
156 | 146 | ||
157 | const tokenSource = new vscode.CancellationTokenSource(); | 147 | const tokenSource = new vscode.CancellationTokenSource(); |
158 | this.pending.set(documentUri, tokenSource); | 148 | this.pending.set(documentUri, tokenSource); |
159 | 149 | ||
160 | const request: InlayHintsParams = { textDocument: { uri: documentUri } }; | 150 | const request = { textDocument: { uri: documentUri } }; |
161 | 151 | ||
162 | return sendRequestWithRetry<InlayHint[]>( | 152 | return sendRequestWithRetry(this.ctx.client, ra.inlayHints, request, tokenSource.token) |
163 | this.ctx.client, | ||
164 | 'rust-analyzer/inlayHints', | ||
165 | request, | ||
166 | tokenSource.token | ||
167 | ) | ||
168 | .catch(_ => null) | 153 | .catch(_ => null) |
169 | .finally(() => { | 154 | .finally(() => { |
170 | if (!tokenSource.token.isCancellationRequested) { | 155 | if (!tokenSource.token.isCancellationRequested) { |
diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts new file mode 100644 index 000000000..c5a010e94 --- /dev/null +++ b/editors/code/src/rust-analyzer-api.ts | |||
@@ -0,0 +1,117 @@ | |||
1 | /** | ||
2 | * This file mirrors `crates/rust-analyzer/src/req.rs` declarations. | ||
3 | */ | ||
4 | |||
5 | import * as lc from "vscode-languageclient"; | ||
6 | |||
7 | type Option<T> = null | T; | ||
8 | type Vec<T> = T[]; | ||
9 | type FxHashMap<K extends PropertyKey, V> = Record<K, V>; | ||
10 | |||
11 | function request<TParams, TResult>(method: string) { | ||
12 | return new lc.RequestType<TParams, TResult, unknown>(`rust-analyzer/${method}`); | ||
13 | } | ||
14 | function notification<TParam>(method: string) { | ||
15 | return new lc.NotificationType<TParam>(method); | ||
16 | } | ||
17 | |||
18 | |||
19 | export const analyzerStatus = request<null, string>("analyzerStatus"); | ||
20 | |||
21 | |||
22 | export const collectGarbage = request<null, null>("collectGarbage"); | ||
23 | |||
24 | |||
25 | export interface SyntaxTreeParams { | ||
26 | textDocument: lc.TextDocumentIdentifier; | ||
27 | range: Option<lc.Range>; | ||
28 | } | ||
29 | export const syntaxTree = request<SyntaxTreeParams, string>("syntaxTree"); | ||
30 | |||
31 | |||
32 | export interface ExpandMacroParams { | ||
33 | textDocument: lc.TextDocumentIdentifier; | ||
34 | position: Option<lc.Position>; | ||
35 | } | ||
36 | export interface ExpandedMacro { | ||
37 | name: string; | ||
38 | expansion: string; | ||
39 | } | ||
40 | export const expandMacro = request<ExpandMacroParams, Option<ExpandedMacro>>("expandMacro"); | ||
41 | |||
42 | |||
43 | export interface FindMatchingBraceParams { | ||
44 | textDocument: lc.TextDocumentIdentifier; | ||
45 | offsets: Vec<lc.Position>; | ||
46 | } | ||
47 | export const findMatchingBrace = request<FindMatchingBraceParams, Vec<lc.Position>>("findMatchingBrace"); | ||
48 | |||
49 | |||
50 | export interface PublishDecorationsParams { | ||
51 | uri: string; | ||
52 | decorations: Vec<Decoration>; | ||
53 | } | ||
54 | export interface Decoration { | ||
55 | range: lc.Range; | ||
56 | tag: string; | ||
57 | bindingHash: Option<string>; | ||
58 | } | ||
59 | export const decorationsRequest = request<lc.TextDocumentIdentifier, Vec<Decoration>>("decorationsRequest"); | ||
60 | |||
61 | |||
62 | export const parentModule = request<lc.TextDocumentPositionParams, Vec<lc.Location>>("parentModule"); | ||
63 | |||
64 | |||
65 | export interface JoinLinesParams { | ||
66 | textDocument: lc.TextDocumentIdentifier; | ||
67 | range: lc.Range; | ||
68 | } | ||
69 | export const joinLines = request<JoinLinesParams, SourceChange>("joinLines"); | ||
70 | |||
71 | |||
72 | export const onEnter = request<lc.TextDocumentPositionParams, Option<SourceChange>>("onEnter"); | ||
73 | |||
74 | export interface RunnablesParams { | ||
75 | textDocument: lc.TextDocumentIdentifier; | ||
76 | position: Option<lc.Position>; | ||
77 | } | ||
78 | export interface Runnable { | ||
79 | range: lc.Range; | ||
80 | label: string; | ||
81 | bin: string; | ||
82 | args: Vec<string>; | ||
83 | env: FxHashMap<string, string>; | ||
84 | cwd: Option<string>; | ||
85 | } | ||
86 | export const runnables = request<RunnablesParams, Vec<Runnable>>("runnables"); | ||
87 | |||
88 | |||
89 | export const enum InlayKind { | ||
90 | TypeHint = "TypeHint", | ||
91 | ParameterHint = "ParameterHint", | ||
92 | } | ||
93 | export interface InlayHint { | ||
94 | range: lc.Range; | ||
95 | kind: InlayKind; | ||
96 | label: string; | ||
97 | } | ||
98 | export interface InlayHintsParams { | ||
99 | textDocument: lc.TextDocumentIdentifier; | ||
100 | } | ||
101 | export const inlayHints = request<InlayHintsParams, Vec<InlayHint>>("inlayHints"); | ||
102 | |||
103 | |||
104 | export interface SsrParams { | ||
105 | arg: string; | ||
106 | } | ||
107 | export const ssr = request<SsrParams, SourceChange>("ssr"); | ||
108 | |||
109 | |||
110 | export const publishDecorations = notification<PublishDecorationsParams>("publishDecorations"); | ||
111 | |||
112 | |||
113 | export interface SourceChange { | ||
114 | label: string; | ||
115 | workspaceEdit: lc.WorkspaceEdit; | ||
116 | cursorPosition: Option<lc.TextDocumentPositionParams>; | ||
117 | } | ||
diff --git a/editors/code/src/source_change.ts b/editors/code/src/source_change.ts index a336269ba..399a150c6 100644 --- a/editors/code/src/source_change.ts +++ b/editors/code/src/source_change.ts | |||
@@ -1,15 +1,10 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import * as ra from './rust-analyzer-api'; | ||
3 | 4 | ||
4 | import { Ctx } from './ctx'; | 5 | import { Ctx } from './ctx'; |
5 | 6 | ||
6 | export interface SourceChange { | 7 | export async function applySourceChange(ctx: Ctx, change: ra.SourceChange) { |
7 | label: string; | ||
8 | workspaceEdit: lc.WorkspaceEdit; | ||
9 | cursorPosition?: lc.TextDocumentPositionParams; | ||
10 | } | ||
11 | |||
12 | export async function applySourceChange(ctx: Ctx, change: SourceChange) { | ||
13 | const client = ctx.client; | 8 | const client = ctx.client; |
14 | if (!client) return; | 9 | if (!client) return; |
15 | 10 | ||
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 2f18f85a3..68c2a94d0 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts | |||
@@ -20,21 +20,21 @@ export const log = { | |||
20 | } | 20 | } |
21 | }; | 21 | }; |
22 | 22 | ||
23 | export async function sendRequestWithRetry<R>( | 23 | export async function sendRequestWithRetry<TParam, TRet>( |
24 | client: lc.LanguageClient, | 24 | client: lc.LanguageClient, |
25 | method: string, | 25 | reqType: lc.RequestType<TParam, TRet, unknown>, |
26 | param: unknown, | 26 | param: TParam, |
27 | token?: vscode.CancellationToken, | 27 | token?: vscode.CancellationToken, |
28 | ): Promise<R> { | 28 | ): Promise<TRet> { |
29 | for (const delay of [2, 4, 6, 8, 10, null]) { | 29 | for (const delay of [2, 4, 6, 8, 10, null]) { |
30 | try { | 30 | try { |
31 | return await (token | 31 | return await (token |
32 | ? client.sendRequest(method, param, token) | 32 | ? client.sendRequest(reqType, param, token) |
33 | : client.sendRequest(method, param) | 33 | : client.sendRequest(reqType, param) |
34 | ); | 34 | ); |
35 | } catch (error) { | 35 | } catch (error) { |
36 | if (delay === null) { | 36 | if (delay === null) { |
37 | log.error("LSP request timed out", { method, param, error }); | 37 | log.error("LSP request timed out", { method: reqType.method, param, error }); |
38 | throw error; | 38 | throw error; |
39 | } | 39 | } |
40 | 40 | ||
@@ -43,7 +43,7 @@ export async function sendRequestWithRetry<R>( | |||
43 | } | 43 | } |
44 | 44 | ||
45 | if (error.code !== lc.ErrorCodes.ContentModified) { | 45 | if (error.code !== lc.ErrorCodes.ContentModified) { |
46 | log.error("LSP request failed", { method, param, error }); | 46 | log.error("LSP request failed", { method: reqType.method, param, error }); |
47 | throw error; | 47 | throw error; |
48 | } | 48 | } |
49 | 49 | ||