aboutsummaryrefslogtreecommitdiff
path: root/code/src
diff options
context:
space:
mode:
Diffstat (limited to 'code/src')
-rw-r--r--code/src/extension.ts194
-rw-r--r--code/src/main.ts208
2 files changed, 194 insertions, 208 deletions
diff --git a/code/src/extension.ts b/code/src/extension.ts
new file mode 100644
index 000000000..bdad1568a
--- /dev/null
+++ b/code/src/extension.ts
@@ -0,0 +1,194 @@
1'use strict';
2import * as vscode from 'vscode';
3import * as lc from 'vscode-languageclient'
4
5
6let client: lc.LanguageClient;
7
8let uris = {
9 syntaxTree: vscode.Uri.parse('libsyntax-rust://syntaxtree')
10}
11
12
13export function activate(context: vscode.ExtensionContext) {
14 let textDocumentContentProvider = new TextDocumentContentProvider()
15 let dispose = (disposable) => {
16 context.subscriptions.push(disposable);
17 }
18 let registerCommand = (name, f) => {
19 dispose(vscode.commands.registerCommand(name, f))
20 }
21
22 registerCommand('libsyntax-rust.syntaxTree', () => openDoc(uris.syntaxTree))
23 registerCommand('libsyntax-rust.extendSelection', async () => {
24 let editor = vscode.window.activeTextEditor
25 if (editor == null || editor.document.languageId != "rust") return
26 let request: ExtendSelectionParams = {
27 textDocument: { uri: editor.document.uri.toString() },
28 selections: editor.selections.map((s) => {
29 return { start: s.start, end: s.end };
30 })
31 }
32 let response = await client.sendRequest<ExtendSelectionResult>("m/extendSelection", request)
33 editor.selections = response.selections.map((range) => {
34 return new vscode.Selection(
35 new vscode.Position(range.start.line, range.start.character),
36 new vscode.Position(range.end.line, range.end.character),
37 )
38 })
39 })
40
41 dispose(vscode.workspace.registerTextDocumentContentProvider(
42 'libsyntax-rust',
43 textDocumentContentProvider
44 ))
45 startServer()
46 vscode.workspace.onDidChangeTextDocument((event: vscode.TextDocumentChangeEvent) => {
47 let doc = event.document
48 if (doc.languageId != "rust") return
49 // We need to order this after LS updates, but there's no API for that.
50 // Hence, good old setTimeout.
51 setTimeout(() => {
52 textDocumentContentProvider.eventEmitter.fire(uris.syntaxTree)
53 }, 10)
54 }, null, context.subscriptions)
55}
56
57export function deactivate(): Thenable<void> {
58 if (!client) {
59 return undefined;
60 }
61 return client.stop();
62}
63
64function startServer() {
65 let run: lc.Executable = {
66 command: "m",
67 // args: ["run", "--package", "m"],
68 options: { cwd: "." }
69 }
70 let serverOptions: lc.ServerOptions = {
71 run,
72 debug: run
73 };
74
75 let clientOptions: lc.LanguageClientOptions = {
76 documentSelector: [{ scheme: 'file', language: 'rust' }],
77 };
78
79 client = new lc.LanguageClient(
80 'm',
81 'm languge server',
82 serverOptions,
83 clientOptions,
84 );
85 client.onReady().then(() => {
86 client.onNotification(
87 new lc.NotificationType("m/publishDecorations"),
88 (params: PublishDecorationsParams) => {
89 let editor = vscode.window.visibleTextEditors.find(
90 (editor) => editor.document.uri.toString() == params.uri
91 )
92 if (editor == null) return;
93 setHighlights(
94 editor,
95 params.decorations,
96 )
97 }
98 )
99 })
100 client.start();
101}
102
103async function openDoc(uri: vscode.Uri) {
104 let document = await vscode.workspace.openTextDocument(uri)
105 return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true)
106}
107
108class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
109 public eventEmitter = new vscode.EventEmitter<vscode.Uri>()
110 public syntaxTree: string = "Not available"
111
112 public provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult<string> {
113 let editor = vscode.window.activeTextEditor;
114 if (editor == null) return ""
115 let request: SyntaxTreeParams = {
116 textDocument: { uri: editor.document.uri.toString() }
117 };
118 return client.sendRequest<SyntaxTreeResult>("m/syntaxTree", request);
119 }
120
121 get onDidChange(): vscode.Event<vscode.Uri> {
122 return this.eventEmitter.event
123 }
124}
125
126
127const decorations = (() => {
128 const decor = (obj) => vscode.window.createTextEditorDecorationType({ color: obj })
129 return {
130 background: decor("#3F3F3F"),
131 error: vscode.window.createTextEditorDecorationType({
132 borderColor: "red",
133 borderStyle: "none none dashed none",
134 }),
135 comment: decor("#7F9F7F"),
136 string: decor("#CC9393"),
137 keyword: decor("#F0DFAF"),
138 function: decor("#93E0E3"),
139 parameter: decor("#94BFF3"),
140 builtin: decor("#DD6718"),
141 text: decor("#DCDCCC"),
142 attribute: decor("#BFEBBF"),
143 literal: decor("#DFAF8F"),
144 }
145})()
146
147function setHighlights(
148 editor: vscode.TextEditor,
149 highlihgs: Array<Decoration>
150) {
151 let byTag = {}
152 for (let tag in decorations) {
153 byTag[tag] = []
154 }
155
156 for (let d of highlihgs) {
157 if (!byTag[d.tag]) {
158 console.log(`unknown tag ${d.tag}`)
159 continue
160 }
161 byTag[d.tag].push(d.range)
162 }
163
164 for (let tag in byTag) {
165 let dec = decorations[tag]
166 let ranges = byTag[tag]
167 editor.setDecorations(dec, ranges)
168 }
169}
170
171interface SyntaxTreeParams {
172 textDocument: lc.TextDocumentIdentifier;
173}
174
175type SyntaxTreeResult = string
176
177interface ExtendSelectionParams {
178 textDocument: lc.TextDocumentIdentifier;
179 selections: lc.Range[];
180}
181
182interface ExtendSelectionResult {
183 selections: lc.Range[];
184}
185
186interface PublishDecorationsParams {
187 uri: string,
188 decorations: Decoration[],
189}
190
191interface Decoration {
192 range: lc.Range,
193 tag: string,
194}
diff --git a/code/src/main.ts b/code/src/main.ts
deleted file mode 100644
index 72bef7061..000000000
--- a/code/src/main.ts
+++ /dev/null
@@ -1,208 +0,0 @@
1'use strict'
2import * as vscode from 'vscode'
3
4const backend = require("../../native")
5
6let docToSyntax;
7
8let uris = {
9 syntaxTree: vscode.Uri.parse('libsyntax-rust://syntaxtree')
10}
11
12
13export function activate(context: vscode.ExtensionContext) {
14 let textDocumentContentProvider = new TextDocumentContentProvider()
15 let dispose = (disposable) => {
16 context.subscriptions.push(disposable);
17 }
18
19 let registerCommand = (name, f) => {
20 dispose(vscode.commands.registerCommand(name, f))
21 }
22
23 docToSyntax = documentToFile(context.subscriptions, () => {
24 let emitter = textDocumentContentProvider.eventEmitter
25 emitter.fire(uris.syntaxTree)
26 let syntax = activeSyntax()
27 setHighlights(vscode.window.activeTextEditor, syntax.highlight())
28 })
29
30
31 dispose(vscode.workspace.registerTextDocumentContentProvider(
32 'libsyntax-rust',
33 textDocumentContentProvider
34 ))
35
36 registerCommand('libsyntax-rust.syntaxTree', () => openDoc(uris.syntaxTree))
37 registerCommand('libsyntax-rust.extendSelection', () => {
38 let editor = vscode.window.activeTextEditor
39 let file = activeSyntax()
40 if (editor == null || file == null) return
41 editor.selections = editor.selections.map((s) => {
42 let range = file.extendSelection(s)
43 if (range == null) return null
44 return new vscode.Selection(range.start, range.end)
45 })
46 })
47}
48
49export function deactivate() { }
50
51export class Syntax {
52 imp;
53 doc: vscode.TextDocument;
54
55 constructor(imp, doc: vscode.TextDocument) {
56 this.imp = imp
57 this.doc = doc
58 }
59
60 syntaxTree(): string { return this.imp.syntaxTree() }
61 highlight(): Array<[number, number, string]> { return this.imp.highlight() }
62 extendSelection(range: vscode.Range): vscode.Range {
63 let range_ = fromVsRange(this.doc, range);
64 let extRange = this.imp.extendSelection(range_[0], range_[1]);
65 return toVsRange(this.doc, extRange);
66 }
67}
68
69
70function activeDoc() {
71 return vscode.window.activeTextEditor.document
72}
73
74function activeSyntax(): Syntax {
75 let doc = activeDoc()
76 if (doc == null) return null
77 return docToSyntax(doc)
78}
79
80async function openDoc(uri: vscode.Uri) {
81 let document = await vscode.workspace.openTextDocument(uri)
82 return vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true)
83}
84
85function documentToFile(disposables: vscode.Disposable[], onChange) {
86 let docs = {}
87 function update(doc: vscode.TextDocument, file) {
88 let key = doc.uri.toString()
89 if (file == null) {
90 delete docs[key]
91 } else {
92 docs[key] = file
93 }
94 onChange(doc)
95 }
96 function get(doc: vscode.TextDocument) {
97 return docs[doc.uri.toString()]
98 }
99
100 function isKnownDoc(doc: vscode.TextDocument) {
101 return doc.fileName.endsWith('.rs')
102 }
103
104 function createFile(text: String) {
105 console.time("parsing")
106 let res = new backend.RustFile(text);
107 console.timeEnd("parsing")
108 return res
109 }
110
111 vscode.workspace.onDidChangeTextDocument((event: vscode.TextDocumentChangeEvent) => {
112 let doc = event.document
113 if (!isKnownDoc(event.document)) return
114 update(doc, null)
115 }, null, disposables)
116
117 vscode.workspace.onDidOpenTextDocument((doc: vscode.TextDocument) => {
118 if (!isKnownDoc(doc)) return
119 update(doc, createFile(doc.getText()))
120 }, null, disposables)
121
122 vscode.workspace.onDidCloseTextDocument((doc: vscode.TextDocument) => {
123 update(doc, null)
124 }, null, disposables)
125
126 return (doc: vscode.TextDocument) => {
127 if (!isKnownDoc(doc)) return null
128
129 if (!get(doc)) {
130 update(doc, createFile(doc.getText()))
131 }
132 let imp = get(doc)
133 return new Syntax(imp, doc)
134 }
135}
136
137export class TextDocumentContentProvider implements vscode.TextDocumentContentProvider {
138 public eventEmitter = new vscode.EventEmitter<vscode.Uri>()
139 public syntaxTree: string = "Not available"
140
141 public provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult<string> {
142 let syntax = activeSyntax()
143 if (syntax == null) return
144 if (uri.toString() == uris.syntaxTree.toString()) {
145 return syntax.syntaxTree()
146 }
147 }
148
149 get onDidChange(): vscode.Event<vscode.Uri> {
150 return this.eventEmitter.event
151 }
152}
153
154const decorations = (() => {
155 const decor = (obj) => vscode.window.createTextEditorDecorationType({ color: obj })
156 return {
157 background: decor("#3F3F3F"),
158 error: vscode.window.createTextEditorDecorationType({
159 borderColor: "red",
160 borderStyle: "none none dashed none",
161 }),
162 comment: decor("#7F9F7F"),
163 string: decor("#CC9393"),
164 keyword: decor("#F0DFAF"),
165 function: decor("#93E0E3"),
166 parameter: decor("#94BFF3"),
167 builtin: decor("#DD6718"),
168 text: decor("#DCDCCC"),
169 attribute: decor("#BFEBBF"),
170 literal: decor("#DFAF8F"),
171 }
172})()
173
174function setHighlights(
175 editor: vscode.TextEditor,
176 highlihgs: Array<[number, number, string]>
177) {
178 let byTag = {}
179 for (let tag in decorations) {
180 byTag[tag] = []
181 }
182
183 for (let [start, end, tag] of highlihgs) {
184 if (!byTag[tag]) {
185 console.log(`unknown tag ${tag}`)
186 continue
187 }
188 let range = toVsRange(editor.document, [start, end])
189 byTag[tag].push(range)
190 }
191
192 for (let tag in byTag) {
193 let dec = decorations[tag]
194 let ranges = byTag[tag]
195 editor.setDecorations(dec, ranges)
196 }
197}
198
199export function toVsRange(doc: vscode.TextDocument, range: [number, number]): vscode.Range {
200 return new vscode.Range(
201 doc.positionAt(range[0]),
202 doc.positionAt(range[1]),
203 )
204}
205
206function fromVsRange(doc: vscode.TextDocument, range: vscode.Range): [number, number] {
207 return [doc.offsetAt(range.start), doc.offsetAt(range.end)]
208}