aboutsummaryrefslogtreecommitdiff
path: root/code/src/extension.ts
diff options
context:
space:
mode:
Diffstat (limited to 'code/src/extension.ts')
-rw-r--r--code/src/extension.ts402
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';
2import * as vscode from 'vscode';
3import * as lc from 'vscode-languageclient'
4import { DH_UNABLE_TO_CHECK_GENERATOR } from 'constants';
5
6
7let client: lc.LanguageClient;
8
9let uris = {
10 syntaxTree: vscode.Uri.parse('libsyntax-rust://syntaxtree')
11}
12
13
14export 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.
139function afterLs(f: () => any) {
140 setTimeout(f, 10)
141}
142
143export function deactivate(): Thenable<void> {
144 if (!client) {
145 return Promise.resolve();
146 }
147 return client.stop();
148}
149
150function 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
190async 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
195class 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
214const 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
234function 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
260interface SyntaxTreeParams {
261 textDocument: lc.TextDocumentIdentifier;
262}
263
264type SyntaxTreeResult = string
265
266interface ExtendSelectionParams {
267 textDocument: lc.TextDocumentIdentifier;
268 selections: lc.Range[];
269}
270
271interface ExtendSelectionResult {
272 selections: lc.Range[];
273}
274
275interface FindMatchingBraceParams {
276 textDocument: lc.TextDocumentIdentifier;
277 offsets: lc.Position[];
278}
279
280interface JoinLinesParams {
281 textDocument: lc.TextDocumentIdentifier;
282 range: lc.Range;
283}
284
285interface PublishDecorationsParams {
286 uri: string,
287 decorations: Decoration[],
288}
289
290interface RunnablesParams {
291 textDocument: lc.TextDocumentIdentifier,
292 position?: lc.Position,
293}
294
295interface Runnable {
296 range: lc.Range;
297 label: string;
298 bin: string;
299 args: string[];
300 env: { [index: string]: string },
301}
302
303class 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
314interface Decoration {
315 range: lc.Range,
316 tag: string,
317}
318
319
320interface CargoTaskDefinition extends vscode.TaskDefinition {
321 type: 'cargo';
322 label: string;
323 command: string;
324 args: Array<string>;
325 env?: { [key: string]: string };
326}
327
328function 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
350interface FileSystemEdit {
351 type: string;
352 uri?: string;
353 src?: string;
354 dst?: string;
355}
356
357interface SourceChange {
358 label: string,
359 sourceFileEdits: lc.TextDocumentEdit[],
360 fileSystemEdits: FileSystemEdit[],
361 cursorPosition?: lc.TextDocumentPositionParams,
362}
363
364async 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}