-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathview.ts
108 lines (100 loc) · 3.31 KB
/
view.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/**
* (c) 2022, Micro:bit Educational Foundation and contributors
*
* SPDX-License-Identifier: MIT
*/
import type { PluginValue, ViewUpdate } from "@codemirror/view";
import { EditorView, ViewPlugin } from "@codemirror/view";
import { IntlShape } from "react-intl";
import * as LSP from "vscode-languageserver-protocol";
import { ApiReferenceMap } from "../../../documentation/mapping/content";
import { LanguageServerClient } from "../../../language-server/client";
import { Logging } from "../../../logging/logging";
import { setDiagnostics } from "../lint/lint";
import { autocompletion } from "./autocompletion";
import { BaseLanguageServerView, clientFacet, uriFacet } from "./common";
import { diagnosticsMapping } from "./diagnostics";
import { signatureHelp } from "./signatureHelp";
/**
* The main extension. This synchronises the diagnostics between the client
* and the active editor (based on the given uri) and dispatches changes to
* the language server when the document changes.
*/
class LanguageServerView extends BaseLanguageServerView implements PluginValue {
private diagnosticsListener = (params: LSP.PublishDiagnosticsParams) => {
if (params.uri === this.uri) {
const diagnostics = diagnosticsMapping(
this.view.state.doc,
params.diagnostics
);
this.view.dispatch(setDiagnostics(this.view.state, diagnostics));
}
};
private destroyed = false;
constructor(view: EditorView) {
super(view);
this.client.on("diagnostics", this.diagnosticsListener);
// Is there a better way to do this? We can 't dispatch at this point.
// It would be best to do this with initial state and avoid the dispatch.
setTimeout(() => {
if (!this.destroyed) {
const diagnostics = diagnosticsMapping(
view.state.doc,
this.client.currentDiagnostics(this.uri)
);
view.dispatch(setDiagnostics(view.state, diagnostics));
}
}, 0);
}
update({ docChanged }: ViewUpdate) {
if (docChanged) {
// We should do incremental updates here
// See https://github.com/microbit-foundation/python-editor-v3/issues/256
this.client.didChangeTextDocument(this.uri, [
{ text: this.view.state.doc.toString() },
]);
}
}
destroy() {
this.destroyed = true;
this.client.removeListener("diagnostics", this.diagnosticsListener);
// We don't own the client/connection which might outlive us, just our notifications.
}
}
interface Options {
signatureHelp: {
automatic: boolean;
};
}
export type ShowLinkToBuiltins = (id: string) => boolean;
/**
* Extensions that make use of a language server client.
*
* The client should generally outlive any given editor.
*
* @param client The client.
* @param uri The uri of the open document.
* @returns Extensions.
*/
export function languageServer(
client: LanguageServerClient,
uri: string,
intl: IntlShape,
logging: Logging,
apiReferenceMap: ApiReferenceMap,
options: Options,
showLinkToBuiltins: ShowLinkToBuiltins
) {
return [
uriFacet.of(uri),
clientFacet.of(client),
ViewPlugin.define((view) => new LanguageServerView(view)),
signatureHelp(
intl,
options.signatureHelp.automatic,
apiReferenceMap,
showLinkToBuiltins
),
autocompletion(intl, logging, apiReferenceMap, showLinkToBuiltins),
];
}