aboutsummaryrefslogtreecommitdiff
path: root/code/common.ts
diff options
context:
space:
mode:
Diffstat (limited to 'code/common.ts')
-rw-r--r--code/common.ts278
1 files changed, 0 insertions, 278 deletions
diff --git a/code/common.ts b/code/common.ts
deleted file mode 100644
index dfd49833d..000000000
--- a/code/common.ts
+++ /dev/null
@@ -1,278 +0,0 @@
1import * as vscode from 'vscode'
2import { log } from 'util'
3
4export function createPlugin(
5 backend,
6 fileExtension: string,
7 disposables: vscode.Disposable[],
8 doHighlighting: boolean = false,
9 diganosticCollection: vscode.DiagnosticCollection | null = null
10) {
11 let uris = {
12 syntaxTree: vscode.Uri.parse(`fall-${fileExtension}://syntaxtree`),
13 metrics: vscode.Uri.parse(`fall-${fileExtension}://metrics`)
14 }
15
16 function updateActiveEditor() {
17 let editor = vscode.window.activeTextEditor
18 if (editor == null) return
19 let file = currentFile()
20 if (file == null) return
21 if (doHighlighting) {
22 setHighlights(editor, file.highlight())
23 }
24 if (diganosticCollection != null) {
25 diganosticCollection.clear()
26 diganosticCollection.set(
27 editor.document.uri,
28 file.diagnostics()
29 )
30 }
31 }
32
33
34 function currentFile(): EditorFile | null {
35 let editor = vscode.window.activeTextEditor
36 if (editor == null) return
37 let doc = editor.document
38 return getFile(doc)
39 }
40
41 vscode.window.onDidChangeActiveTextEditor(updateActiveEditor)
42 let cmd = vscode.commands.registerCommand(`fall-${fileExtension}.applyContextAction`, (range, id) => {
43 let file = currentFile()
44 if (file == null) return
45 return file.applyContextAction(range, id)
46 })
47 disposables.push(cmd)
48
49 return {
50 getFile: getFile,
51 showSyntaxTree: () => {
52 let file = currentFile()
53 if (file == null) return
54 return openDoc(uris.syntaxTree)
55 },
56 metrics: () => {
57 let file = currentFile()
58 if (file == null) return
59 return openDoc(uris.metrics)
60 },
61 extendSelection: () => {
62 let editor = vscode.window.activeTextEditor
63 let file = currentFile()
64 if (editor == null || file == null) return
65 editor.selections = editor.selections.map((s) => {
66 let range = file.extendSelection(s)
67 return new vscode.Selection(range.start, range.end)
68 })
69 },
70 documentSymbolsProvider: new DocumentSymbolProvider(getFile),
71 documentFormattingEditProvider: new DocumentFormattingEditProvider(getFile),
72 codeActionProvider: new CodeActionProvider(getFile, fileExtension)
73 }
74}
75
76
77export interface FileStructureNode {
78 name: string
79 range: [number, number]
80 children: [FileStructureNode]
81}
82
83export interface FallDiagnostic {
84 range: [number, number]
85 severity: string
86 message: string
87}
88
89export class EditorFile {
90 backend;
91 imp;
92 doc: vscode.TextDocument;
93
94 constructor(backend, imp, doc: vscode.TextDocument) {
95 this.backend = backend
96 this.imp = imp
97 this.doc = doc
98 }
99
100 metrics(): string { return this.call("metrics") }
101 syntaxTree(): string { return this.call("syntaxTree") }
102 extendSelection(range_: vscode.Range): vscode.Range | null {
103 let range = fromVsRange(this.doc, range_)
104 let exp = this.call("extendSelection", range)
105 if (exp == null) return null
106 return toVsRange(this.doc, exp)
107 }
108
109 structure(): Array<FileStructureNode> { return this.call("structure") }
110 reformat(): Array<vscode.TextEdit> {
111 let edits = this.call("reformat")
112 return toVsEdits(this.doc, edits)
113 }
114
115 highlight(): Array<[[number, number], string]> { return this.call("highlight") }
116 diagnostics(): Array<vscode.Diagnostic> {
117 return this.call("diagnostics").map((d) => {
118 let range = toVsRange(this.doc, d.range)
119 let severity = d.severity == "Error"
120 ? vscode.DiagnosticSeverity.Error
121 : vscode.DiagnosticSeverity.Warning
122
123 return new vscode.Diagnostic(range, d.message, severity)
124 })
125 }
126
127 contextActions(range_: vscode.Range): Array<string> {
128 let range = fromVsRange(this.doc, range_)
129 let result = this.call("contextActions", range)
130 return result
131 }
132
133 applyContextAction(range_: vscode.Range, id: string) {
134 let range = fromVsRange(this.doc, range_)
135 let edits = this.call("applyContextAction", range, id)
136 let editor = vscode.window.activeTextEditor
137 return editor.edit((builder) => {
138 for (let op of edits) {
139 builder.replace(toVsRange(this.doc, op.delete), op.insert)
140 }
141 })
142 }
143
144 call(method: string, ...args) {
145 let result = this.backend[method](this.imp, ...args)
146 return result
147 }
148}
149
150function documentToFile(backend, fileExtension: string, disposables: vscode.Disposable[], onChange) {
151 let docs = {}
152 function update(doc: vscode.TextDocument, file) {
153 let key = doc.uri.toString()
154 if (file == null) {
155 delete docs[key]
156 } else {
157 docs[key] = file
158 }
159 onChange(doc)
160 }
161 function get(doc: vscode.TextDocument) {
162 return docs[doc.uri.toString()]
163 }
164
165 function isKnownDoc(doc: vscode.TextDocument) {
166 return doc.fileName.endsWith(`.${fileExtension}`)
167 }
168
169 vscode.workspace.onDidChangeTextDocument((event: vscode.TextDocumentChangeEvent) => {
170 let doc = event.document
171 if (!isKnownDoc(event.document)) return
172 let tree = get(doc)
173 if (event.contentChanges.length == 1 && tree) {
174 let edits = event.contentChanges.map((change) => {
175 let start = doc.offsetAt(change.range.start)
176 return {
177 "delete": [start, start + change.rangeLength],
178 "insert": change.text
179 }
180 })
181 update(doc, backend.edit(tree, edits))
182 return
183 }
184 update(doc, null)
185 }, null, disposables)
186
187 vscode.workspace.onDidOpenTextDocument((doc: vscode.TextDocument) => {
188 if (!isKnownDoc(doc)) return
189 update(doc, backend.parse(doc.getText()))
190 }, null, disposables)
191
192 vscode.workspace.onDidCloseTextDocument((doc: vscode.TextDocument) => {
193 update(doc, null)
194 }, null, disposables)
195
196 return (doc: vscode.TextDocument) => {
197 if (!isKnownDoc(doc)) return null
198
199 if (!get(doc)) {
200 update(doc, backend.parse(doc.getText()))
201 }
202 let imp = get(doc)
203 return new EditorFile(backend, imp, doc)
204 }
205}
206
207export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
208 getFile: (doc: vscode.TextDocument) => EditorFile | null;
209 constructor(getFile) {
210 this.getFile = getFile
211 }
212
213 provideDocumentSymbols(document: vscode.TextDocument, token: vscode.CancellationToken) {
214 let file = this.getFile(document)
215 if (file == null) return null
216 return file.structure().map((node) => {
217 return new vscode.SymbolInformation(
218 node.name,
219 vscode.SymbolKind.Function,
220 toVsRange(document, node.range),
221 null,
222 null
223 )
224 })
225 }
226}
227
228export class DocumentFormattingEditProvider implements vscode.DocumentFormattingEditProvider {
229 getFile: (doc: vscode.TextDocument) => EditorFile | null;
230 constructor(getFile) { this.getFile = getFile }
231
232 provideDocumentFormattingEdits(
233 document: vscode.TextDocument,
234 options: vscode.FormattingOptions,
235 token: vscode.CancellationToken
236 ): vscode.TextEdit[] {
237 let file = this.getFile(document)
238 if (file == null) return []
239 return file.reformat()
240 }
241}
242
243export class CodeActionProvider implements vscode.CodeActionProvider {
244 fileExtension: string
245 getFile: (doc: vscode.TextDocument) => EditorFile | null;
246 constructor(getFile, fileExtension) {
247 this.getFile = getFile
248 this.fileExtension = fileExtension
249 }
250
251 provideCodeActions(
252 document: vscode.TextDocument,
253 range: vscode.Range,
254 context: vscode.CodeActionContext,
255 token: vscode.CancellationToken
256 ): vscode.Command[] {
257 let file = this.getFile(document)
258 if (file == null) return
259 let actions = file.contextActions(range)
260 return actions.map((id) => {
261 return {
262 title: id,
263 command: `fall-${this.fileExtension}.applyContextAction`,
264 arguments: [range, id]
265 }
266 })
267 }
268}
269
270
271export function toVsEdits(doc: vscode.TextDocument, edits): Array<vscode.TextEdit> {
272 return edits.map((op) => vscode.TextEdit.replace(toVsRange(doc, op.delete), op.insert))
273}
274
275async function openDoc(uri: vscode.Uri) {
276 let document = await vscode.workspace.openTextDocument(uri)
277 vscode.window.showTextDocument(document, vscode.ViewColumn.Two, true)
278}