diff options
Diffstat (limited to 'code/src/extension.ts')
-rw-r--r-- | code/src/extension.ts | 402 |
1 files changed, 0 insertions, 402 deletions
diff --git a/code/src/extension.ts b/code/src/extension.ts deleted file mode 100644 index 53ef83aab..000000000 --- a/code/src/extension.ts +++ /dev/null | |||
@@ -1,402 +0,0 @@ | |||
1 | 'use strict'; | ||
2 | import * as vscode from 'vscode'; | ||
3 | import * as lc from 'vscode-languageclient' | ||
4 | import { DH_UNABLE_TO_CHECK_GENERATOR } from 'constants'; | ||
5 | |||
6 | |||
7 | let client: lc.LanguageClient; | ||
8 | |||
9 | let uris = { | ||
10 | syntaxTree: vscode.Uri.parse('libsyntax-rust://syntaxtree') | ||
11 | } | ||
12 | |||
13 | |||
14 | export function activate(context: vscode.ExtensionContext) { | ||
15 | let textDocumentContentProvider = new TextDocumentContentProvider() | ||
16 | let dispose = (disposable: vscode.Disposable) => { | ||
17 | context.subscriptions.push(disposable); | ||
18 | } | ||
19 | let registerCommand = (name: string, f: any) => { | ||
20 | dispose(vscode.commands.registerCommand(name, f)) | ||
21 | } | ||
22 | |||
23 | registerCommand('libsyntax-rust.syntaxTree', () => openDoc(uris.syntaxTree)) | ||
24 | registerCommand('libsyntax-rust.extendSelection', async () => { | ||
25 | let editor = vscode.window.activeTextEditor | ||
26 | if (editor == null || editor.document.languageId != "rust") return | ||
27 | let request: ExtendSelectionParams = { | ||
28 | textDocument: { uri: editor.document.uri.toString() }, | ||
29 | selections: editor.selections.map((s) => { | ||
30 | return client.code2ProtocolConverter.asRange(s) | ||
31 | }) | ||
32 | } | ||
33 | let response = await client.sendRequest<ExtendSelectionResult>("m/extendSelection", request) | ||
34 | editor.selections = response.selections.map((range) => { | ||
35 | let r = client.protocol2CodeConverter.asRange(range) | ||
36 | return new vscode.Selection(r.start, r.end) | ||
37 | }) | ||
38 | }) | ||
39 | registerCommand('libsyntax-rust.matchingBrace', async () => { | ||
40 | let editor = vscode.window.activeTextEditor | ||
41 | if (editor == null || editor.document.languageId != "rust") return | ||
42 | let request: FindMatchingBraceParams = { | ||
43 | textDocument: { uri: editor.document.uri.toString() }, | ||
44 | offsets: editor.selections.map((s) => { | ||
45 | return client.code2ProtocolConverter.asPosition(s.active) | ||
46 | }) | ||
47 | } | ||
48 | let response = await client.sendRequest<lc.Position[]>("m/findMatchingBrace", request) | ||
49 | editor.selections = editor.selections.map((sel, idx) => { | ||
50 | let active = client.protocol2CodeConverter.asPosition(response[idx]) | ||
51 | let anchor = sel.isEmpty ? active : sel.anchor | ||
52 | return new vscode.Selection(anchor, active) | ||
53 | }) | ||
54 | editor.revealRange(editor.selection) | ||
55 | }) | ||
56 | registerCommand('libsyntax-rust.joinLines', async () => { | ||
57 | let editor = vscode.window.activeTextEditor | ||
58 | if (editor == null || editor.document.languageId != "rust") return | ||
59 | let request: JoinLinesParams = { | ||
60 | textDocument: { uri: editor.document.uri.toString() }, | ||
61 | range: client.code2ProtocolConverter.asRange(editor.selection), | ||
62 | } | ||
63 | let change = await client.sendRequest<SourceChange>("m/joinLines", request) | ||
64 | await applySourceChange(change) | ||
65 | }) | ||
66 | registerCommand('libsyntax-rust.parentModule', async () => { | ||
67 | let editor = vscode.window.activeTextEditor | ||
68 | if (editor == null || editor.document.languageId != "rust") return | ||
69 | let request: lc.TextDocumentIdentifier = { | ||
70 | uri: editor.document.uri.toString() | ||
71 | } | ||
72 | let response = await client.sendRequest<lc.Location[]>("m/parentModule", request) | ||
73 | let loc = response[0] | ||
74 | if (loc == null) return | ||
75 | let uri = client.protocol2CodeConverter.asUri(loc.uri) | ||
76 | let range = client.protocol2CodeConverter.asRange(loc.range) | ||
77 | |||
78 | let doc = await vscode.workspace.openTextDocument(uri) | ||
79 | let e = await vscode.window.showTextDocument(doc) | ||
80 | e.revealRange(range, vscode.TextEditorRevealType.InCenter) | ||
81 | }) | ||
82 | |||
83 | let prevRunnable: RunnableQuickPick | undefined = undefined | ||
84 | registerCommand('libsyntax-rust.run', async () => { | ||
85 | let editor = vscode.window.activeTextEditor | ||
86 | if (editor == null || editor.document.languageId != "rust") return | ||
87 | let textDocument: lc.TextDocumentIdentifier = { | ||
88 | uri: editor.document.uri.toString() | ||
89 | } | ||
90 | let params: RunnablesParams = { | ||
91 | textDocument, | ||
92 | position: client.code2ProtocolConverter.asPosition(editor.selection.active) | ||
93 | } | ||
94 | let runnables = await client.sendRequest<Runnable[]>('m/runnables', params) | ||
95 | let items: RunnableQuickPick[] = [] | ||
96 | if (prevRunnable) { | ||
97 | items.push(prevRunnable) | ||
98 | } | ||
99 | for (let r of runnables) { | ||
100 | if (prevRunnable && JSON.stringify(prevRunnable.runnable) == JSON.stringify(r)) { | ||
101 | continue | ||
102 | } | ||
103 | items.push(new RunnableQuickPick(r)) | ||
104 | } | ||
105 | let item = await vscode.window.showQuickPick(items) | ||
106 | if (item) { | ||
107 | item.detail = "rerun" | ||
108 | prevRunnable = item | ||
109 | let task = createTask(item.runnable) | ||
110 | return await vscode.tasks.executeTask(task) | ||
111 | } | ||
112 | }) | ||
113 | registerCommand('libsyntax-rust.applySourceChange', applySourceChange) | ||
114 | |||
115 | dispose(vscode.workspace.registerTextDocumentContentProvider( | ||
116 | 'libsyntax-rust', | ||
117 | textDocumentContentProvider | ||
118 | )) | ||
119 | startServer() | ||
120 | vscode.workspace.onDidChangeTextDocument((event: vscode.TextDocumentChangeEvent) => { | ||
121 | let doc = event.document | ||
122 | if (doc.languageId != "rust") return | ||
123 | afterLs(() => { | ||
124 | textDocumentContentProvider.eventEmitter.fire(uris.syntaxTree) | ||
125 | }) | ||
126 | }, null, context.subscriptions) | ||
127 | vscode.window.onDidChangeActiveTextEditor(async (editor) => { | ||
128 | if (!editor || editor.document.languageId != 'rust') return | ||
129 | let params: lc.TextDocumentIdentifier = { | ||
130 | uri: editor.document.uri.toString() | ||
131 | } | ||
132 | let decorations = await client.sendRequest<Decoration[]>("m/decorationsRequest", params) | ||
133 | setHighlights(editor, decorations) | ||
134 | }) | ||
135 | } | ||
136 | |||
137 | // We need to order this after LS updates, but there's no API for that. | ||
138 | // Hence, good old setTimeout. | ||
139 | function afterLs(f: () => any) { | ||
140 | setTimeout(f, 10) | ||
141 | } | ||
142 | |||
143 | export function deactivate(): Thenable<void> { | ||
144 | if (!client) { | ||
145 | return Promise.resolve(); | ||
146 | } | ||
147 | return client.stop(); | ||
148 | } | ||
149 | |||
150 | function startServer() { | ||
151 | let run: lc.Executable = { | ||
152 | // command: "cargo", | ||
153 | // args: ["run", "--package", "m"], | ||
154 | command: "m", | ||
155 | options: { cwd: "." } | ||
156 | } | ||
157 | let serverOptions: lc.ServerOptions = { | ||
158 | run, | ||
159 | debug: run | ||
160 | }; | ||
161 | |||
162 | let clientOptions: lc.LanguageClientOptions = { | ||
163 | documentSelector: [{ scheme: 'file', language: 'rust' }], | ||
164 | }; | ||
165 | |||
166 | client = new lc.LanguageClient( | ||
167 | 'm', | ||
168 | 'm languge server', | ||
169 | serverOptions, | ||
170 | clientOptions, | ||
171 | ); | ||
172 | client.onReady().then(() => { | ||
173 | client.onNotification( | ||
174 | "m/publishDecorations", | ||
175 | (params: PublishDecorationsParams) => { | ||
176 | let editor = vscode.window.visibleTextEditors.find( | ||
177 | (editor) => editor.document.uri.toString() == params.uri | ||
178 | ) | ||
179 | if (editor == null) return; | ||
180 | setHighlights( | ||
181 | editor, | ||
182 | params.decorations, | ||
183 | ) | ||
184 | } | ||
185 | ) | ||
186 | }) | ||
187 | client.start(); | ||
188 | } | ||
189 | |||
190 | async function openDoc(uri: vscode.Uri) { | ||
191 | let document = await vscode.workspace.openTextDocument(uri) | ||
192 | return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true) | ||
193 | } | ||
194 | |||
195 | class TextDocumentContentProvider implements vscode.TextDocumentContentProvider { | ||
196 | public eventEmitter = new vscode.EventEmitter<vscode.Uri>() | ||
197 | public syntaxTree: string = "Not available" | ||
198 | |||
199 | public provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult<string> { | ||
200 | let editor = vscode.window.activeTextEditor; | ||
201 | if (editor == null) return "" | ||
202 | let request: SyntaxTreeParams = { | ||
203 | textDocument: { uri: editor.document.uri.toString() } | ||
204 | }; | ||
205 | return client.sendRequest<SyntaxTreeResult>("m/syntaxTree", request); | ||
206 | } | ||
207 | |||
208 | get onDidChange(): vscode.Event<vscode.Uri> { | ||
209 | return this.eventEmitter.event | ||
210 | } | ||
211 | } | ||
212 | |||
213 | |||
214 | const decorations: { [index: string]: vscode.TextEditorDecorationType } = (() => { | ||
215 | const decor = (obj: any) => vscode.window.createTextEditorDecorationType({ color: obj }) | ||
216 | return { | ||
217 | background: decor("#3F3F3F"), | ||
218 | error: vscode.window.createTextEditorDecorationType({ | ||
219 | borderColor: "red", | ||
220 | borderStyle: "none none dashed none", | ||
221 | }), | ||
222 | comment: decor("#7F9F7F"), | ||
223 | string: decor("#CC9393"), | ||
224 | keyword: decor("#F0DFAF"), | ||
225 | function: decor("#93E0E3"), | ||
226 | parameter: decor("#94BFF3"), | ||
227 | builtin: decor("#DD6718"), | ||
228 | text: decor("#DCDCCC"), | ||
229 | attribute: decor("#BFEBBF"), | ||
230 | literal: decor("#DFAF8F"), | ||
231 | } | ||
232 | })() | ||
233 | |||
234 | function setHighlights( | ||
235 | editor: vscode.TextEditor, | ||
236 | highlihgs: Array<Decoration> | ||
237 | ) { | ||
238 | let byTag: Map<string, vscode.Range[]> = new Map() | ||
239 | for (let tag in decorations) { | ||
240 | byTag.set(tag, []) | ||
241 | } | ||
242 | |||
243 | for (let d of highlihgs) { | ||
244 | if (!byTag.get(d.tag)) { | ||
245 | console.log(`unknown tag ${d.tag}`) | ||
246 | continue | ||
247 | } | ||
248 | byTag.get(d.tag)!.push( | ||
249 | client.protocol2CodeConverter.asRange(d.range) | ||
250 | ) | ||
251 | } | ||
252 | |||
253 | for (let tag of byTag.keys()) { | ||
254 | let dec: vscode.TextEditorDecorationType = decorations[tag] | ||
255 | let ranges = byTag.get(tag)! | ||
256 | editor.setDecorations(dec, ranges) | ||
257 | } | ||
258 | } | ||
259 | |||
260 | interface SyntaxTreeParams { | ||
261 | textDocument: lc.TextDocumentIdentifier; | ||
262 | } | ||
263 | |||
264 | type SyntaxTreeResult = string | ||
265 | |||
266 | interface ExtendSelectionParams { | ||
267 | textDocument: lc.TextDocumentIdentifier; | ||
268 | selections: lc.Range[]; | ||
269 | } | ||
270 | |||
271 | interface ExtendSelectionResult { | ||
272 | selections: lc.Range[]; | ||
273 | } | ||
274 | |||
275 | interface FindMatchingBraceParams { | ||
276 | textDocument: lc.TextDocumentIdentifier; | ||
277 | offsets: lc.Position[]; | ||
278 | } | ||
279 | |||
280 | interface JoinLinesParams { | ||
281 | textDocument: lc.TextDocumentIdentifier; | ||
282 | range: lc.Range; | ||
283 | } | ||
284 | |||
285 | interface PublishDecorationsParams { | ||
286 | uri: string, | ||
287 | decorations: Decoration[], | ||
288 | } | ||
289 | |||
290 | interface RunnablesParams { | ||
291 | textDocument: lc.TextDocumentIdentifier, | ||
292 | position?: lc.Position, | ||
293 | } | ||
294 | |||
295 | interface Runnable { | ||
296 | range: lc.Range; | ||
297 | label: string; | ||
298 | bin: string; | ||
299 | args: string[]; | ||
300 | env: { [index: string]: string }, | ||
301 | } | ||
302 | |||
303 | class RunnableQuickPick implements vscode.QuickPickItem { | ||
304 | label: string; | ||
305 | description?: string | undefined; | ||
306 | detail?: string | undefined; | ||
307 | picked?: boolean | undefined; | ||
308 | |||
309 | constructor(public runnable: Runnable) { | ||
310 | this.label = runnable.label | ||
311 | } | ||
312 | } | ||
313 | |||
314 | interface Decoration { | ||
315 | range: lc.Range, | ||
316 | tag: string, | ||
317 | } | ||
318 | |||
319 | |||
320 | interface CargoTaskDefinition extends vscode.TaskDefinition { | ||
321 | type: 'cargo'; | ||
322 | label: string; | ||
323 | command: string; | ||
324 | args: Array<string>; | ||
325 | env?: { [key: string]: string }; | ||
326 | } | ||
327 | |||
328 | function createTask(spec: Runnable): vscode.Task { | ||
329 | const TASK_SOURCE = 'Rust'; | ||
330 | let definition: CargoTaskDefinition = { | ||
331 | type: 'cargo', | ||
332 | label: 'cargo', | ||
333 | command: spec.bin, | ||
334 | args: spec.args, | ||
335 | env: spec.env | ||
336 | } | ||
337 | |||
338 | let execCmd = `${definition.command} ${definition.args.join(' ')}`; | ||
339 | let execOption: vscode.ShellExecutionOptions = { | ||
340 | cwd: '.', | ||
341 | env: definition.env, | ||
342 | }; | ||
343 | let exec = new vscode.ShellExecution(`clear; ${execCmd}`, execOption); | ||
344 | |||
345 | let f = vscode.workspace.workspaceFolders![0] | ||
346 | let t = new vscode.Task(definition, f, definition.label, TASK_SOURCE, exec, ['$rustc']); | ||
347 | return t; | ||
348 | } | ||
349 | |||
350 | interface FileSystemEdit { | ||
351 | type: string; | ||
352 | uri?: string; | ||
353 | src?: string; | ||
354 | dst?: string; | ||
355 | } | ||
356 | |||
357 | interface SourceChange { | ||
358 | label: string, | ||
359 | sourceFileEdits: lc.TextDocumentEdit[], | ||
360 | fileSystemEdits: FileSystemEdit[], | ||
361 | cursorPosition?: lc.TextDocumentPositionParams, | ||
362 | } | ||
363 | |||
364 | async function applySourceChange(change: SourceChange) { | ||
365 | console.log(`applySOurceChange ${JSON.stringify(change)}`) | ||
366 | let wsEdit = new vscode.WorkspaceEdit() | ||
367 | for (let sourceEdit of change.sourceFileEdits) { | ||
368 | let uri = client.protocol2CodeConverter.asUri(sourceEdit.textDocument.uri) | ||
369 | let edits = client.protocol2CodeConverter.asTextEdits(sourceEdit.edits) | ||
370 | wsEdit.set(uri, edits) | ||
371 | } | ||
372 | let created; | ||
373 | let moved; | ||
374 | for (let fsEdit of change.fileSystemEdits) { | ||
375 | if (fsEdit.type == "createFile") { | ||
376 | let uri = vscode.Uri.parse(fsEdit.uri!) | ||
377 | wsEdit.createFile(uri) | ||
378 | created = uri | ||
379 | } else if (fsEdit.type == "moveFile") { | ||
380 | let src = vscode.Uri.parse(fsEdit.src!) | ||
381 | let dst = vscode.Uri.parse(fsEdit.dst!) | ||
382 | wsEdit.renameFile(src, dst) | ||
383 | moved = dst | ||
384 | } else { | ||
385 | console.error(`unknown op: ${JSON.stringify(fsEdit)}`) | ||
386 | } | ||
387 | } | ||
388 | let toOpen = created || moved | ||
389 | let toReveal = change.cursorPosition | ||
390 | await vscode.workspace.applyEdit(wsEdit) | ||
391 | if (toOpen) { | ||
392 | let doc = await vscode.workspace.openTextDocument(toOpen) | ||
393 | await vscode.window.showTextDocument(doc) | ||
394 | } else if (toReveal) { | ||
395 | let uri = client.protocol2CodeConverter.asUri(toReveal.textDocument.uri) | ||
396 | let position = client.protocol2CodeConverter.asPosition(toReveal.position) | ||
397 | let editor = vscode.window.activeTextEditor; | ||
398 | if (!editor || editor.document.uri.toString() != uri.toString()) return | ||
399 | if (!editor.selection.isEmpty) return | ||
400 | editor!.selection = new vscode.Selection(position, position) | ||
401 | } | ||
402 | } | ||