@singapore-editor/lsp-plugin 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +103 -0
- package/dist/bufferSync.d.ts +12 -0
- package/dist/bufferSync.d.ts.map +1 -0
- package/dist/bufferSync.js +35 -0
- package/dist/bufferSync.js.map +1 -0
- package/dist/codeActions.d.ts +83 -0
- package/dist/codeActions.d.ts.map +1 -0
- package/dist/codeActions.js +294 -0
- package/dist/codeActions.js.map +1 -0
- package/dist/colorAlpha.d.ts +4 -0
- package/dist/colorAlpha.d.ts.map +1 -0
- package/dist/colorAlpha.js +28 -0
- package/dist/colorAlpha.js.map +1 -0
- package/dist/completion.d.ts +124 -0
- package/dist/completion.d.ts.map +1 -0
- package/dist/completion.js +609 -0
- package/dist/completion.js.map +1 -0
- package/dist/completionCommit.d.ts +19 -0
- package/dist/completionCommit.d.ts.map +1 -0
- package/dist/completionCommit.js +57 -0
- package/dist/completionCommit.js.map +1 -0
- package/dist/completionController.d.ts +89 -0
- package/dist/completionController.d.ts.map +1 -0
- package/dist/completionController.js +376 -0
- package/dist/completionController.js.map +1 -0
- package/dist/completionProviders.d.ts +50 -0
- package/dist/completionProviders.d.ts.map +1 -0
- package/dist/completionProviders.js +64 -0
- package/dist/completionProviders.js.map +1 -0
- package/dist/connectionContext.d.ts +7 -0
- package/dist/connectionContext.d.ts.map +1 -0
- package/dist/definitionLinkController.d.ts +54 -0
- package/dist/definitionLinkController.d.ts.map +1 -0
- package/dist/definitionLinkController.js +221 -0
- package/dist/definitionLinkController.js.map +1 -0
- package/dist/definitionNavigation.d.ts +76 -0
- package/dist/definitionNavigation.d.ts.map +1 -0
- package/dist/definitionNavigation.js +143 -0
- package/dist/definitionNavigation.js.map +1 -0
- package/dist/diagnosticNotes.d.ts +7 -0
- package/dist/diagnosticNotes.d.ts.map +1 -0
- package/dist/diagnosticNotes.js +37 -0
- package/dist/diagnosticNotes.js.map +1 -0
- package/dist/diagnosticProjection.d.ts +31 -0
- package/dist/diagnosticProjection.d.ts.map +1 -0
- package/dist/diagnosticProjection.js +79 -0
- package/dist/diagnosticProjection.js.map +1 -0
- package/dist/diagnostics.d.ts +16 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +94 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/diagnosticsPresenter.d.ts +64 -0
- package/dist/diagnosticsPresenter.d.ts.map +1 -0
- package/dist/diagnosticsPresenter.js +305 -0
- package/dist/diagnosticsPresenter.js.map +1 -0
- package/dist/document.d.ts +69 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +190 -0
- package/dist/document.js.map +1 -0
- package/dist/documentHighlightController.d.ts +34 -0
- package/dist/documentHighlightController.d.ts.map +1 -0
- package/dist/documentHighlightController.js +101 -0
- package/dist/documentHighlightController.js.map +1 -0
- package/dist/documentSnapshot.d.ts +9 -0
- package/dist/documentSnapshot.d.ts.map +1 -0
- package/dist/documentSnapshot.js +31 -0
- package/dist/documentSnapshot.js.map +1 -0
- package/dist/documentSync.d.ts +53 -0
- package/dist/documentSync.d.ts.map +1 -0
- package/dist/documentSync.js +334 -0
- package/dist/documentSync.js.map +1 -0
- package/dist/documentSyncController.d.ts +26 -0
- package/dist/documentSyncController.d.ts.map +1 -0
- package/dist/documentSyncController.js +24 -0
- package/dist/documentSyncController.js.map +1 -0
- package/dist/formatOnType.d.ts +43 -0
- package/dist/formatOnType.d.ts.map +1 -0
- package/dist/formatOnType.js +198 -0
- package/dist/formatOnType.js.map +1 -0
- package/dist/formatting.d.ts +18 -0
- package/dist/formatting.d.ts.map +1 -0
- package/dist/formatting.js +52 -0
- package/dist/formatting.js.map +1 -0
- package/dist/fuzzyMatch.d.ts +22 -0
- package/dist/fuzzyMatch.d.ts.map +1 -0
- package/dist/fuzzyMatch.js +216 -0
- package/dist/fuzzyMatch.js.map +1 -0
- package/dist/hoverParticipant.d.ts +24 -0
- package/dist/hoverParticipant.d.ts.map +1 -0
- package/dist/hoverParticipant.js +156 -0
- package/dist/hoverParticipant.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/keyCommands.d.ts +19 -0
- package/dist/keyCommands.d.ts.map +1 -0
- package/dist/keyCommands.js +21 -0
- package/dist/keyCommands.js.map +1 -0
- package/dist/lane.d.ts +28 -0
- package/dist/lane.d.ts.map +1 -0
- package/dist/lane.js +138 -0
- package/dist/lane.js.map +1 -0
- package/dist/lspConnection.d.ts +94 -0
- package/dist/lspConnection.d.ts.map +1 -0
- package/dist/lspConnection.js +195 -0
- package/dist/lspConnection.js.map +1 -0
- package/dist/lspConnectionPool.d.ts +34 -0
- package/dist/lspConnectionPool.d.ts.map +1 -0
- package/dist/lspConnectionPool.js +255 -0
- package/dist/lspConnectionPool.js.map +1 -0
- package/dist/minimalEdits.d.ts +21 -0
- package/dist/minimalEdits.d.ts.map +1 -0
- package/dist/minimalEdits.js +181 -0
- package/dist/minimalEdits.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +38 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin.d.ts +100 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +837 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.styles.d.ts +31 -0
- package/dist/plugin.styles.d.ts.map +1 -0
- package/dist/plugin.styles.js +102 -0
- package/dist/plugin.styles.js.map +1 -0
- package/dist/pluginTypes.d.ts +41 -0
- package/dist/pluginTypes.d.ts.map +1 -0
- package/dist/pluginTypes.js +0 -0
- package/dist/pullDiagnostics.d.ts +30 -0
- package/dist/pullDiagnostics.d.ts.map +1 -0
- package/dist/pullDiagnostics.js +94 -0
- package/dist/pullDiagnostics.js.map +1 -0
- package/dist/renameWidget.d.ts +30 -0
- package/dist/renameWidget.d.ts.map +1 -0
- package/dist/renameWidget.js +117 -0
- package/dist/renameWidget.js.map +1 -0
- package/dist/semanticTokenDecoder.d.ts +81 -0
- package/dist/semanticTokenDecoder.d.ts.map +1 -0
- package/dist/semanticTokenDecoder.js +132 -0
- package/dist/semanticTokenDecoder.js.map +1 -0
- package/dist/semanticTokens.d.ts +47 -0
- package/dist/semanticTokens.d.ts.map +1 -0
- package/dist/semanticTokens.js +68 -0
- package/dist/semanticTokens.js.map +1 -0
- package/dist/serverSet.d.ts +69 -0
- package/dist/serverSet.d.ts.map +1 -0
- package/dist/serverSet.js +331 -0
- package/dist/serverSet.js.map +1 -0
- package/dist/signatureHelp.d.ts +40 -0
- package/dist/signatureHelp.d.ts.map +1 -0
- package/dist/signatureHelp.js +108 -0
- package/dist/signatureHelp.js.map +1 -0
- package/dist/signatureHelpController.d.ts +52 -0
- package/dist/signatureHelpController.d.ts.map +1 -0
- package/dist/signatureHelpController.js +160 -0
- package/dist/signatureHelpController.js.map +1 -0
- package/dist/sourceText.d.ts +22 -0
- package/dist/sourceText.d.ts.map +1 -0
- package/dist/sourceText.js +70 -0
- package/dist/sourceText.js.map +1 -0
- package/dist/types.d.ts +238 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +17 -0
- package/dist/types.js.map +1 -0
- package/dist/viewDocumentSnapshot.d.ts +5 -0
- package/dist/viewDocumentSnapshot.d.ts.map +1 -0
- package/dist/viewDocumentSnapshot.js +12 -0
- package/dist/viewDocumentSnapshot.js.map +1 -0
- package/dist/websocket.d.ts +6 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +4 -0
- package/dist/workspaceEdit.d.ts +66 -0
- package/dist/workspaceEdit.d.ts.map +1 -0
- package/dist/workspaceEdit.js +276 -0
- package/dist/workspaceEdit.js.map +1 -0
- package/dist/workspaceEditProvenance.d.ts +5 -0
- package/dist/workspaceEditProvenance.d.ts.map +1 -0
- package/dist/workspaceEditProvenance.js +16 -0
- package/dist/workspaceEditProvenance.js.map +1 -0
- package/dist/workspaceTextEdits.d.ts +60 -0
- package/dist/workspaceTextEdits.d.ts.map +1 -0
- package/dist/workspaceTextEdits.js +395 -0
- package/dist/workspaceTextEdits.js.map +1 -0
- package/package.json +118 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { createAnchoredSurface } from "@singapore-editor/plugin-ui/anchored-surface";
|
|
2
|
+
//#region src/renameWidget.ts
|
|
3
|
+
var THEME_VARIABLES = [
|
|
4
|
+
"--editor-background",
|
|
5
|
+
"--editor-popup-background",
|
|
6
|
+
"--editor-foreground",
|
|
7
|
+
"--editor-font-family",
|
|
8
|
+
"--editor-font-size"
|
|
9
|
+
];
|
|
10
|
+
/** Tighter than the tooltips: the input reads as attached to the symbol, not floating near it. */
|
|
11
|
+
var RENAME_GAP_PX = 4;
|
|
12
|
+
/**
|
|
13
|
+
* The editor's own rename input: a small floating field anchored at the symbol.
|
|
14
|
+
*
|
|
15
|
+
* It exists so the engine is usable on its own. A host with its own dialog language passes
|
|
16
|
+
* `onRequestRenameName` instead and this is never built.
|
|
17
|
+
*/
|
|
18
|
+
function createRenameWidgetController(options) {
|
|
19
|
+
const namespace = options.classNamespace ?? "lsp-plugin";
|
|
20
|
+
const element = options.document.createElement("div");
|
|
21
|
+
element.className = `${namespace}-rename`;
|
|
22
|
+
element.style.zIndex = "60";
|
|
23
|
+
element.style.display = "none";
|
|
24
|
+
element.style.background = "var(--editor-popup-background, var(--editor-background, #1e1e1e))";
|
|
25
|
+
const input = options.document.createElement("input");
|
|
26
|
+
input.className = `${namespace}-rename-input`;
|
|
27
|
+
input.type = "text";
|
|
28
|
+
input.spellcheck = false;
|
|
29
|
+
input.autocomplete = "off";
|
|
30
|
+
input.setAttribute("aria-label", "New name");
|
|
31
|
+
element.appendChild(input);
|
|
32
|
+
options.document.body.appendChild(element);
|
|
33
|
+
const surface = createAnchoredSurface({
|
|
34
|
+
element,
|
|
35
|
+
anchorClassName: `${namespace}-rename-anchor`,
|
|
36
|
+
preferredPlacement: "bottom",
|
|
37
|
+
alignment: "start",
|
|
38
|
+
gapPx: RENAME_GAP_PX
|
|
39
|
+
});
|
|
40
|
+
const promptState = {
|
|
41
|
+
removeAbortListener: null,
|
|
42
|
+
settle: null
|
|
43
|
+
};
|
|
44
|
+
function close(value) {
|
|
45
|
+
if (!promptState.settle) return;
|
|
46
|
+
const resolve = promptState.settle;
|
|
47
|
+
promptState.settle = null;
|
|
48
|
+
promptState.removeAbortListener?.();
|
|
49
|
+
promptState.removeAbortListener = null;
|
|
50
|
+
const heldFocus = element.contains(options.document.activeElement);
|
|
51
|
+
element.style.display = "none";
|
|
52
|
+
surface.release();
|
|
53
|
+
if (heldFocus) options.returnFocus?.();
|
|
54
|
+
resolve(value);
|
|
55
|
+
}
|
|
56
|
+
input.addEventListener("keydown", (event) => {
|
|
57
|
+
if (event.key === "Enter") {
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
const next = input.value.trim();
|
|
60
|
+
close(next.length === 0 ? null : next);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (event.key === "Escape") {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
event.stopPropagation();
|
|
66
|
+
close(null);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
input.addEventListener("blur", () => close(null));
|
|
70
|
+
return {
|
|
71
|
+
containsTarget: (target) => target instanceof Node && element.contains(target),
|
|
72
|
+
reanchor(anchor) {
|
|
73
|
+
if (!promptState.settle) return;
|
|
74
|
+
surface.place(anchor);
|
|
75
|
+
},
|
|
76
|
+
dispose() {
|
|
77
|
+
close(null);
|
|
78
|
+
surface.dispose();
|
|
79
|
+
element.remove();
|
|
80
|
+
},
|
|
81
|
+
prompt({ anchor, currentName, signal }) {
|
|
82
|
+
close(null);
|
|
83
|
+
if (signal.aborted) return Promise.resolve(null);
|
|
84
|
+
applyTheme(element, options.themeSource);
|
|
85
|
+
element.style.display = "block";
|
|
86
|
+
surface.place(anchor);
|
|
87
|
+
input.value = currentName;
|
|
88
|
+
input.focus();
|
|
89
|
+
input.select();
|
|
90
|
+
return beginRenamePrompt(promptState, signal, close);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function beginRenamePrompt(state, signal, close) {
|
|
95
|
+
return new Promise((resolve) => {
|
|
96
|
+
state.settle = resolve;
|
|
97
|
+
const handleAbort = () => close(null);
|
|
98
|
+
signal.addEventListener("abort", handleAbort, { once: true });
|
|
99
|
+
state.removeAbortListener = () => signal.removeEventListener("abort", handleAbort);
|
|
100
|
+
if (signal.aborted) close(null);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function applyTheme(element, source) {
|
|
104
|
+
const style = getComputedStyle(source);
|
|
105
|
+
for (const variable of THEME_VARIABLES) {
|
|
106
|
+
const value = style.getPropertyValue(variable);
|
|
107
|
+
if (value) {
|
|
108
|
+
element.style.setProperty(variable, value);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
element.style.removeProperty(variable);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
//#endregion
|
|
115
|
+
export { createRenameWidgetController };
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=renameWidget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renameWidget.js","names":[],"sources":["../src/renameWidget.ts"],"sourcesContent":["import { createAnchoredSurface } from '@singapore-editor/plugin-ui/anchored-surface'\n\nexport type RenameWidgetOptions = {\n readonly document: Document\n /** Element whose computed style carries the editor theme variables. */\n readonly themeSource: HTMLElement\n readonly classNamespace?: string\n /** Called when the prompt closes while it holds focus, which hiding it would otherwise strand. */\n readonly returnFocus?: () => void\n}\n\ntype RenameWidgetPrompt = {\n readonly anchor: DOMRect\n readonly currentName: string\n readonly signal: AbortSignal\n}\n\nexport type RenameWidgetController = {\n /** Shows the input and resolves with the new name, or null when dismissed. */\n prompt(options: RenameWidgetPrompt): Promise<string | null>\n /** Moves an open prompt to where the symbol is drawn now. */\n reanchor(anchor: DOMRect): void\n containsTarget(target: EventTarget | null): boolean\n dispose(): void\n}\n\ntype RenamePromptState = {\n removeAbortListener: (() => void) | null\n settle: ((value: string | null) => void) | null\n}\n\nconst THEME_VARIABLES = [\n '--editor-background',\n '--editor-popup-background',\n '--editor-foreground',\n '--editor-font-family',\n '--editor-font-size',\n] as const\n\n/** Tighter than the tooltips: the input reads as attached to the symbol, not floating near it. */\nconst RENAME_GAP_PX = 4\n\n/**\n * The editor's own rename input: a small floating field anchored at the symbol.\n *\n * It exists so the engine is usable on its own. A host with its own dialog language passes\n * `onRequestRenameName` instead and this is never built.\n */\nexport function createRenameWidgetController(options: RenameWidgetOptions): RenameWidgetController {\n const namespace = options.classNamespace ?? 'lsp-plugin'\n const element = options.document.createElement('div')\n element.className = `${namespace}-rename`\n element.style.zIndex = '60'\n element.style.display = 'none'\n element.style.background = 'var(--editor-popup-background, var(--editor-background, #1e1e1e))'\n\n const input = options.document.createElement('input')\n input.className = `${namespace}-rename-input`\n input.type = 'text'\n input.spellcheck = false\n input.autocomplete = 'off'\n input.setAttribute('aria-label', 'New name')\n element.appendChild(input)\n options.document.body.appendChild(element)\n const surface = createAnchoredSurface({\n element,\n anchorClassName: `${namespace}-rename-anchor`,\n // Below the symbol, so the word being renamed stays readable while the new one is typed.\n preferredPlacement: 'bottom',\n alignment: 'start',\n gapPx: RENAME_GAP_PX,\n })\n\n const promptState: RenamePromptState = {\n removeAbortListener: null,\n settle: null,\n }\n\n function close(value: string | null): void {\n if (!promptState.settle) return\n\n const resolve = promptState.settle\n promptState.settle = null\n promptState.removeAbortListener?.()\n promptState.removeAbortListener = null\n // A close from a click elsewhere has already moved focus; Enter and Escape leave it here.\n const heldFocus = element.contains(options.document.activeElement)\n element.style.display = 'none'\n surface.release()\n if (heldFocus) options.returnFocus?.()\n resolve(value)\n }\n\n input.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n // An unchanged or empty name is a cancel: renaming a symbol to itself is a no-op edit, and to\n // nothing is not a rename at all.\n const next = input.value.trim()\n close(next.length === 0 ? null : next)\n return\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n event.stopPropagation()\n close(null)\n }\n })\n input.addEventListener('blur', () => close(null))\n\n return {\n containsTarget: (target) => target instanceof Node && element.contains(target),\n reanchor(anchor) {\n if (!promptState.settle) return\n\n surface.place(anchor)\n },\n dispose() {\n close(null)\n surface.dispose()\n element.remove()\n },\n prompt({ anchor, currentName, signal }) {\n // A prompt already open is dismissed first, because dismissing it hides the element and takes\n // the anchor out of the page — done afterwards it would undo the showing it comes with.\n close(null)\n if (signal.aborted) return Promise.resolve(null)\n\n applyTheme(element, options.themeSource)\n element.style.display = 'block'\n surface.place(anchor)\n input.value = currentName\n input.focus()\n // Selected, so typing replaces the old name — the common case — while arrow keys still edit it.\n input.select()\n\n return beginRenamePrompt(promptState, signal, close)\n },\n }\n}\n\nfunction beginRenamePrompt(\n state: RenamePromptState,\n signal: AbortSignal,\n close: (value: string | null) => void,\n): Promise<string | null> {\n return new Promise((resolve) => {\n state.settle = resolve\n const handleAbort = () => close(null)\n signal.addEventListener('abort', handleAbort, { once: true })\n state.removeAbortListener = () => signal.removeEventListener('abort', handleAbort)\n if (signal.aborted) close(null)\n })\n}\n\nfunction applyTheme(element: HTMLElement, source: HTMLElement): void {\n const style = getComputedStyle(source)\n for (const variable of THEME_VARIABLES) {\n const value = style.getPropertyValue(variable)\n if (value) {\n element.style.setProperty(variable, value)\n continue\n }\n element.style.removeProperty(variable)\n }\n}\n"],"mappings":";;AA+BA,IAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;AACF;;AAGA,IAAM,gBAAgB;;;;;;;AAQtB,SAAgB,6BAA6B,SAAsD;CACjG,MAAM,YAAY,QAAQ,kBAAkB;CAC5C,MAAM,UAAU,QAAQ,SAAS,cAAc,KAAK;CACpD,QAAQ,YAAY,GAAG,UAAU;CACjC,QAAQ,MAAM,SAAS;CACvB,QAAQ,MAAM,UAAU;CACxB,QAAQ,MAAM,aAAa;CAE3B,MAAM,QAAQ,QAAQ,SAAS,cAAc,OAAO;CACpD,MAAM,YAAY,GAAG,UAAU;CAC/B,MAAM,OAAO;CACb,MAAM,aAAa;CACnB,MAAM,eAAe;CACrB,MAAM,aAAa,cAAc,UAAU;CAC3C,QAAQ,YAAY,KAAK;CACzB,QAAQ,SAAS,KAAK,YAAY,OAAO;CACzC,MAAM,UAAU,sBAAsB;EACpC;EACA,iBAAiB,GAAG,UAAU;EAE9B,oBAAoB;EACpB,WAAW;EACX,OAAO;CACT,CAAC;CAED,MAAM,cAAiC;EACrC,qBAAqB;EACrB,QAAQ;CACV;CAEA,SAAS,MAAM,OAA4B;EACzC,IAAI,CAAC,YAAY,QAAQ;EAEzB,MAAM,UAAU,YAAY;EAC5B,YAAY,SAAS;EACrB,YAAY,sBAAsB;EAClC,YAAY,sBAAsB;EAElC,MAAM,YAAY,QAAQ,SAAS,QAAQ,SAAS,aAAa;EACjE,QAAQ,MAAM,UAAU;EACxB,QAAQ,QAAQ;EAChB,IAAI,WAAW,QAAQ,cAAc;EACrC,QAAQ,KAAK;CACf;CAEA,MAAM,iBAAiB,YAAY,UAAU;EAC3C,IAAI,MAAM,QAAQ,SAAS;GACzB,MAAM,eAAe;GAGrB,MAAM,OAAO,MAAM,MAAM,KAAK;GAC9B,MAAM,KAAK,WAAW,IAAI,OAAO,IAAI;GACrC;EACF;EACA,IAAI,MAAM,QAAQ,UAAU;GAC1B,MAAM,eAAe;GACrB,MAAM,gBAAgB;GACtB,MAAM,IAAI;EACZ;CACF,CAAC;CACD,MAAM,iBAAiB,cAAc,MAAM,IAAI,CAAC;CAEhD,OAAO;EACL,iBAAiB,WAAW,kBAAkB,QAAQ,QAAQ,SAAS,MAAM;EAC7E,SAAS,QAAQ;GACf,IAAI,CAAC,YAAY,QAAQ;GAEzB,QAAQ,MAAM,MAAM;EACtB;EACA,UAAU;GACR,MAAM,IAAI;GACV,QAAQ,QAAQ;GAChB,QAAQ,OAAO;EACjB;EACA,OAAO,EAAE,QAAQ,aAAa,UAAU;GAGtC,MAAM,IAAI;GACV,IAAI,OAAO,SAAS,OAAO,QAAQ,QAAQ,IAAI;GAE/C,WAAW,SAAS,QAAQ,WAAW;GACvC,QAAQ,MAAM,UAAU;GACxB,QAAQ,MAAM,MAAM;GACpB,MAAM,QAAQ;GACd,MAAM,MAAM;GAEZ,MAAM,OAAO;GAEb,OAAO,kBAAkB,aAAa,QAAQ,KAAK;EACrD;CACF;AACF;AAEA,SAAS,kBACP,OACA,QACA,OACwB;CACxB,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,SAAS;EACf,MAAM,oBAAoB,MAAM,IAAI;EACpC,OAAO,iBAAiB,SAAS,aAAa,EAAE,MAAM,KAAK,CAAC;EAC5D,MAAM,4BAA4B,OAAO,oBAAoB,SAAS,WAAW;EACjF,IAAI,OAAO,SAAS,MAAM,IAAI;CAChC,CAAC;AACH;AAEA,SAAS,WAAW,SAAsB,QAA2B;CACnE,MAAM,QAAQ,iBAAiB,MAAM;CACrC,KAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,QAAQ,MAAM,iBAAiB,QAAQ;EAC7C,IAAI,OAAO;GACT,QAAQ,MAAM,YAAY,UAAU,KAAK;GACzC;EACF;EACA,QAAQ,MAAM,eAAe,QAAQ;CACvC;AACF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { SemanticTokenSpan } from '@singapore-editor/core/syntax';
|
|
2
|
+
import type * as lsp from 'vscode-languageserver-protocol';
|
|
3
|
+
/**
|
|
4
|
+
* What the decoder threw away, one count per rejection rule.
|
|
5
|
+
*
|
|
6
|
+
* Counts rather than samples, and all of them zero in the healthy case. They exist because every
|
|
7
|
+
* rule below discards input from an untrusted source, and a silent discard is indistinguishable
|
|
8
|
+
* from a server that simply sent fewer tokens — which is how a legend ends up two thirds on the
|
|
9
|
+
* floor while everything looks like it is working.
|
|
10
|
+
*
|
|
11
|
+
* The decoder neither aggregates nor logs. Whether these are summed per server, reported once per
|
|
12
|
+
* session, or ignored is the host's policy, on the host's side of the seam: this package does not
|
|
13
|
+
* know what a session is, or which server answered.
|
|
14
|
+
*/
|
|
15
|
+
export type SemanticTokenDecodeDrops = {
|
|
16
|
+
/** Rule 2: `tokenTypeIndex` outside the legend. Tuple dropped, cursor still advanced. */
|
|
17
|
+
readonly outOfLegendType: number;
|
|
18
|
+
/** Rule 4: zero-length tuple. */
|
|
19
|
+
readonly zeroLength: number;
|
|
20
|
+
/**
|
|
21
|
+
* Rule 5: the token began past the end of the text it addresses — either because `deltaLine` ran
|
|
22
|
+
* past the last line, or because `character` ran past the end of the line it did reach. Both axes
|
|
23
|
+
* of the same failure, and both usually mean one thing: the response describes a longer document
|
|
24
|
+
* than the `lineStarts` and `textLength` it was decoded against, i.e. the host's own snapshot has
|
|
25
|
+
* moved. Counting that under `zeroLength` would point the host at the server.
|
|
26
|
+
*
|
|
27
|
+
* The character axis is checked against `lineStarts[line + 1]`, not against `textLength`. Clamped
|
|
28
|
+
* to the document alone, a `character` past the end of line 1 of a long file is still a valid
|
|
29
|
+
* offset — one somewhere on line 3 — so the tuple decoded to a plausible span over unrelated text
|
|
30
|
+
* and reported nothing.
|
|
31
|
+
*/
|
|
32
|
+
readonly pastEndOfDocument: number;
|
|
33
|
+
/** Rule 3: modifier bits beyond the legend's length. The SPAN SURVIVES; only the bits are lost. */
|
|
34
|
+
readonly unknownModifierBits: number;
|
|
35
|
+
/**
|
|
36
|
+
* A trailing partial tuple, or a tuple carrying a value that is not a non-negative integer.
|
|
37
|
+
* Neither is one of the five rules — it is input that was never a 5-tuple to begin with — but a
|
|
38
|
+
* truncated frame that decoded to silence would be indistinguishable from a short answer.
|
|
39
|
+
*/
|
|
40
|
+
readonly malformedTuple: number;
|
|
41
|
+
};
|
|
42
|
+
export type SemanticTokenDecodeResult = {
|
|
43
|
+
readonly spans: readonly SemanticTokenSpan[];
|
|
44
|
+
readonly drops: SemanticTokenDecodeDrops;
|
|
45
|
+
};
|
|
46
|
+
export type SemanticTokenDecodeDocument = {
|
|
47
|
+
/** Offset of the first character of every line, ascending. */
|
|
48
|
+
readonly lineStarts: readonly number[];
|
|
49
|
+
/** Length of the document text in UTF-16 code units. Every offset is clamped to it. */
|
|
50
|
+
readonly textLength: number;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Turns an LSP semantic-tokens response into absolute spans with names on them.
|
|
54
|
+
*
|
|
55
|
+
* This is the one decoder. It lives in this package rather than in the editor because it is on the
|
|
56
|
+
* *request* side of the seam — it runs on the host's schedule, against the host's legend, and the
|
|
57
|
+
* editor's paint layer never sees a legend or a 5-tuple. A second implementation anywhere is a
|
|
58
|
+
* defect: the relative cursor below is stateful, and its rejection rules are the kind that produce
|
|
59
|
+
* plausible wrong offsets rather than exceptions. A copy that drops an out-of-legend tuple without
|
|
60
|
+
* advancing the cursor corrupts every span after it and still paints something.
|
|
61
|
+
*
|
|
62
|
+
* Five rules, each of which exists because a real server violates it:
|
|
63
|
+
*
|
|
64
|
+
* 1. **Decode by index. Never invert the legend into a name-to-index map.** Real legends ship the
|
|
65
|
+
* same name at several indices — one server ships `variable` at three and `function` at two — and
|
|
66
|
+
* an inverted map silently mis-decodes every duplicate.
|
|
67
|
+
* 2. **An out-of-legend `tokenTypeIndex` drops the tuple but still advances the cursor.**
|
|
68
|
+
* 3. **Modifier bits beyond the legend's length are ignored, not errors.** The bitset is 32 bits
|
|
69
|
+
* wide and a legend may declare six.
|
|
70
|
+
* 4. **Zero-length tuples are dropped.** They cannot paint and they are common in the wild.
|
|
71
|
+
* 5. **Every offset is clamped to the document length**, and a tuple that begins past the end of
|
|
72
|
+
* the text it addresses — `deltaLine` past the last line, or `character` past the end of the
|
|
73
|
+
* line it reached — is dropped rather than throwing. Only the *start* is held to the line: an
|
|
74
|
+
* `end` beyond it is a multi-line span, which is a thing this decoder emits on purpose.
|
|
75
|
+
*
|
|
76
|
+
* Offsets come out absolute, in UTF-16 code units, which needs no encoding conversion at all: the
|
|
77
|
+
* client declares `general.positionEncodings: ['utf-16']`, UTF-16 code units are JavaScript string
|
|
78
|
+
* indices, and the editor's paint APIs take offsets.
|
|
79
|
+
*/
|
|
80
|
+
export declare function decodeSemanticTokens(data: ArrayLike<number>, legend: lsp.SemanticTokensLegend, document: SemanticTokenDecodeDocument): SemanticTokenDecodeResult;
|
|
81
|
+
//# sourceMappingURL=semanticTokenDecoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticTokenDecoder.d.ts","sourceRoot":"","sources":["../src/semanticTokenDecoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,KAAK,KAAK,GAAG,MAAM,gCAAgC,CAAA;AAE1D;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,yFAAyF;IACzF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,iCAAiC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,mGAAmG;IACnG,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,KAAK,EAAE,SAAS,iBAAiB,EAAE,CAAA;IAC5C,QAAQ,CAAC,KAAK,EAAE,wBAAwB,CAAA;CACzC,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,uFAAuF;IACvF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B,CAAA;AAKD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,EACvB,MAAM,EAAE,GAAG,CAAC,oBAAoB,EAChC,QAAQ,EAAE,2BAA2B,GACpC,yBAAyB,CAoG3B"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
//#region src/semanticTokenDecoder.ts
|
|
2
|
+
var TUPLE_LENGTH = 5;
|
|
3
|
+
var MODIFIER_BITS = 32;
|
|
4
|
+
/**
|
|
5
|
+
* Turns an LSP semantic-tokens response into absolute spans with names on them.
|
|
6
|
+
*
|
|
7
|
+
* This is the one decoder. It lives in this package rather than in the editor because it is on the
|
|
8
|
+
* *request* side of the seam — it runs on the host's schedule, against the host's legend, and the
|
|
9
|
+
* editor's paint layer never sees a legend or a 5-tuple. A second implementation anywhere is a
|
|
10
|
+
* defect: the relative cursor below is stateful, and its rejection rules are the kind that produce
|
|
11
|
+
* plausible wrong offsets rather than exceptions. A copy that drops an out-of-legend tuple without
|
|
12
|
+
* advancing the cursor corrupts every span after it and still paints something.
|
|
13
|
+
*
|
|
14
|
+
* Five rules, each of which exists because a real server violates it:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Decode by index. Never invert the legend into a name-to-index map.** Real legends ship the
|
|
17
|
+
* same name at several indices — one server ships `variable` at three and `function` at two — and
|
|
18
|
+
* an inverted map silently mis-decodes every duplicate.
|
|
19
|
+
* 2. **An out-of-legend `tokenTypeIndex` drops the tuple but still advances the cursor.**
|
|
20
|
+
* 3. **Modifier bits beyond the legend's length are ignored, not errors.** The bitset is 32 bits
|
|
21
|
+
* wide and a legend may declare six.
|
|
22
|
+
* 4. **Zero-length tuples are dropped.** They cannot paint and they are common in the wild.
|
|
23
|
+
* 5. **Every offset is clamped to the document length**, and a tuple that begins past the end of
|
|
24
|
+
* the text it addresses — `deltaLine` past the last line, or `character` past the end of the
|
|
25
|
+
* line it reached — is dropped rather than throwing. Only the *start* is held to the line: an
|
|
26
|
+
* `end` beyond it is a multi-line span, which is a thing this decoder emits on purpose.
|
|
27
|
+
*
|
|
28
|
+
* Offsets come out absolute, in UTF-16 code units, which needs no encoding conversion at all: the
|
|
29
|
+
* client declares `general.positionEncodings: ['utf-16']`, UTF-16 code units are JavaScript string
|
|
30
|
+
* indices, and the editor's paint APIs take offsets.
|
|
31
|
+
*/
|
|
32
|
+
function decodeSemanticTokens(data, legend, document) {
|
|
33
|
+
const spans = [];
|
|
34
|
+
const tokenTypes = legend.tokenTypes;
|
|
35
|
+
const tokenModifiers = legend.tokenModifiers;
|
|
36
|
+
const lineStarts = document.lineStarts;
|
|
37
|
+
const textLength = document.textLength;
|
|
38
|
+
let outOfLegendType = 0;
|
|
39
|
+
let zeroLength = 0;
|
|
40
|
+
let pastEndOfDocument = 0;
|
|
41
|
+
let unknownModifierBits = 0;
|
|
42
|
+
let malformedTuple = 0;
|
|
43
|
+
let line = 0;
|
|
44
|
+
let character = 0;
|
|
45
|
+
let index = 0;
|
|
46
|
+
for (; index + TUPLE_LENGTH <= data.length; index += TUPLE_LENGTH) {
|
|
47
|
+
const deltaLine = data[index];
|
|
48
|
+
const deltaStartChar = data[index + 1];
|
|
49
|
+
const length = data[index + 2];
|
|
50
|
+
const tokenTypeIndex = data[index + 3];
|
|
51
|
+
const modifierBitset = data[index + 4];
|
|
52
|
+
if (!isUnsignedInteger(deltaLine) || !isUnsignedInteger(deltaStartChar) || !isUnsignedInteger(length) || !isUnsignedInteger(tokenTypeIndex) || !isUnsignedInteger(modifierBitset)) {
|
|
53
|
+
malformedTuple += 1;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
line += deltaLine;
|
|
57
|
+
character = deltaLine === 0 ? character + deltaStartChar : deltaStartChar;
|
|
58
|
+
if (line >= lineStarts.length) {
|
|
59
|
+
pastEndOfDocument += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (length === 0) {
|
|
63
|
+
zeroLength += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const tokenType = tokenTypes[tokenTypeIndex];
|
|
67
|
+
if (tokenType === void 0) {
|
|
68
|
+
outOfLegendType += 1;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const lineStart = lineStarts[line];
|
|
72
|
+
const lineEnd = lineStarts[line + 1] ?? textLength;
|
|
73
|
+
const start = clampOffset(lineStart + character, textLength);
|
|
74
|
+
const end = clampOffset(lineStart + character + length, textLength);
|
|
75
|
+
if (end <= start || start >= lineEnd) {
|
|
76
|
+
pastEndOfDocument += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const modifiers = decodeModifiers(modifierBitset, tokenModifiers);
|
|
80
|
+
if (modifiers.unknownBits) unknownModifierBits += 1;
|
|
81
|
+
spans.push(modifiers.names.length > 0 ? {
|
|
82
|
+
end,
|
|
83
|
+
start,
|
|
84
|
+
tokenModifiers: modifiers.names,
|
|
85
|
+
tokenType
|
|
86
|
+
} : {
|
|
87
|
+
end,
|
|
88
|
+
start,
|
|
89
|
+
tokenType
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (index < data.length && malformedTuple === 0) malformedTuple += 1;
|
|
93
|
+
return {
|
|
94
|
+
drops: {
|
|
95
|
+
malformedTuple,
|
|
96
|
+
outOfLegendType,
|
|
97
|
+
pastEndOfDocument,
|
|
98
|
+
unknownModifierBits,
|
|
99
|
+
zeroLength
|
|
100
|
+
},
|
|
101
|
+
spans
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function decodeModifiers(bitset, tokenModifiers) {
|
|
105
|
+
if (bitset === 0) return {
|
|
106
|
+
names: [],
|
|
107
|
+
unknownBits: false
|
|
108
|
+
};
|
|
109
|
+
const names = [];
|
|
110
|
+
let unknownBits = false;
|
|
111
|
+
for (let bit = 0; bit < MODIFIER_BITS; bit += 1) {
|
|
112
|
+
if ((bitset & 1 << bit) === 0) continue;
|
|
113
|
+
const name = tokenModifiers[bit];
|
|
114
|
+
if (name === void 0) unknownBits = true;
|
|
115
|
+
else names.push(name);
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
names,
|
|
119
|
+
unknownBits
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function isUnsignedInteger(value) {
|
|
123
|
+
return Number.isInteger(value) && value >= 0;
|
|
124
|
+
}
|
|
125
|
+
function clampOffset(offset, textLength) {
|
|
126
|
+
if (offset < 0) return 0;
|
|
127
|
+
return offset > textLength ? textLength : offset;
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { decodeSemanticTokens };
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=semanticTokenDecoder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticTokenDecoder.js","names":[],"sources":["../src/semanticTokenDecoder.ts"],"sourcesContent":["import type { SemanticTokenSpan } from '@singapore-editor/core/syntax'\nimport type * as lsp from 'vscode-languageserver-protocol'\n\n/**\n * What the decoder threw away, one count per rejection rule.\n *\n * Counts rather than samples, and all of them zero in the healthy case. They exist because every\n * rule below discards input from an untrusted source, and a silent discard is indistinguishable\n * from a server that simply sent fewer tokens — which is how a legend ends up two thirds on the\n * floor while everything looks like it is working.\n *\n * The decoder neither aggregates nor logs. Whether these are summed per server, reported once per\n * session, or ignored is the host's policy, on the host's side of the seam: this package does not\n * know what a session is, or which server answered.\n */\nexport type SemanticTokenDecodeDrops = {\n /** Rule 2: `tokenTypeIndex` outside the legend. Tuple dropped, cursor still advanced. */\n readonly outOfLegendType: number\n /** Rule 4: zero-length tuple. */\n readonly zeroLength: number\n /**\n * Rule 5: the token began past the end of the text it addresses — either because `deltaLine` ran\n * past the last line, or because `character` ran past the end of the line it did reach. Both axes\n * of the same failure, and both usually mean one thing: the response describes a longer document\n * than the `lineStarts` and `textLength` it was decoded against, i.e. the host's own snapshot has\n * moved. Counting that under `zeroLength` would point the host at the server.\n *\n * The character axis is checked against `lineStarts[line + 1]`, not against `textLength`. Clamped\n * to the document alone, a `character` past the end of line 1 of a long file is still a valid\n * offset — one somewhere on line 3 — so the tuple decoded to a plausible span over unrelated text\n * and reported nothing.\n */\n readonly pastEndOfDocument: number\n /** Rule 3: modifier bits beyond the legend's length. The SPAN SURVIVES; only the bits are lost. */\n readonly unknownModifierBits: number\n /**\n * A trailing partial tuple, or a tuple carrying a value that is not a non-negative integer.\n * Neither is one of the five rules — it is input that was never a 5-tuple to begin with — but a\n * truncated frame that decoded to silence would be indistinguishable from a short answer.\n */\n readonly malformedTuple: number\n}\n\nexport type SemanticTokenDecodeResult = {\n readonly spans: readonly SemanticTokenSpan[]\n readonly drops: SemanticTokenDecodeDrops\n}\n\nexport type SemanticTokenDecodeDocument = {\n /** Offset of the first character of every line, ascending. */\n readonly lineStarts: readonly number[]\n /** Length of the document text in UTF-16 code units. Every offset is clamped to it. */\n readonly textLength: number\n}\n\nconst TUPLE_LENGTH = 5\nconst MODIFIER_BITS = 32\n\n/**\n * Turns an LSP semantic-tokens response into absolute spans with names on them.\n *\n * This is the one decoder. It lives in this package rather than in the editor because it is on the\n * *request* side of the seam — it runs on the host's schedule, against the host's legend, and the\n * editor's paint layer never sees a legend or a 5-tuple. A second implementation anywhere is a\n * defect: the relative cursor below is stateful, and its rejection rules are the kind that produce\n * plausible wrong offsets rather than exceptions. A copy that drops an out-of-legend tuple without\n * advancing the cursor corrupts every span after it and still paints something.\n *\n * Five rules, each of which exists because a real server violates it:\n *\n * 1. **Decode by index. Never invert the legend into a name-to-index map.** Real legends ship the\n * same name at several indices — one server ships `variable` at three and `function` at two — and\n * an inverted map silently mis-decodes every duplicate.\n * 2. **An out-of-legend `tokenTypeIndex` drops the tuple but still advances the cursor.**\n * 3. **Modifier bits beyond the legend's length are ignored, not errors.** The bitset is 32 bits\n * wide and a legend may declare six.\n * 4. **Zero-length tuples are dropped.** They cannot paint and they are common in the wild.\n * 5. **Every offset is clamped to the document length**, and a tuple that begins past the end of\n * the text it addresses — `deltaLine` past the last line, or `character` past the end of the\n * line it reached — is dropped rather than throwing. Only the *start* is held to the line: an\n * `end` beyond it is a multi-line span, which is a thing this decoder emits on purpose.\n *\n * Offsets come out absolute, in UTF-16 code units, which needs no encoding conversion at all: the\n * client declares `general.positionEncodings: ['utf-16']`, UTF-16 code units are JavaScript string\n * indices, and the editor's paint APIs take offsets.\n */\nexport function decodeSemanticTokens(\n data: ArrayLike<number>,\n legend: lsp.SemanticTokensLegend,\n document: SemanticTokenDecodeDocument,\n): SemanticTokenDecodeResult {\n const spans: SemanticTokenSpan[] = []\n const tokenTypes = legend.tokenTypes\n const tokenModifiers = legend.tokenModifiers\n const lineStarts = document.lineStarts\n const textLength = document.textLength\n\n let outOfLegendType = 0\n let zeroLength = 0\n let pastEndOfDocument = 0\n let unknownModifierBits = 0\n let malformedTuple = 0\n\n let line = 0\n let character = 0\n let index = 0\n\n for (; index + TUPLE_LENGTH <= data.length; index += TUPLE_LENGTH) {\n const deltaLine = data[index] as number\n const deltaStartChar = data[index + 1] as number\n const length = data[index + 2] as number\n const tokenTypeIndex = data[index + 3] as number\n const modifierBitset = data[index + 4] as number\n\n if (\n !isUnsignedInteger(deltaLine) ||\n !isUnsignedInteger(deltaStartChar) ||\n !isUnsignedInteger(length) ||\n !isUnsignedInteger(tokenTypeIndex) ||\n !isUnsignedInteger(modifierBitset)\n ) {\n // The cursor cannot be advanced by a value that is not a number, and guessing would put every\n // later span at a plausible wrong offset. Stop rather than corrupt the rest.\n malformedTuple += 1\n break\n }\n\n // Advance first, unconditionally: every rule below may reject the tuple, and a rejection that\n // skipped the advance would shift every span after it.\n line += deltaLine\n character = deltaLine === 0 ? character + deltaStartChar : deltaStartChar\n\n if (line >= lineStarts.length) {\n pastEndOfDocument += 1\n continue\n }\n if (length === 0) {\n zeroLength += 1\n continue\n }\n\n // Rule 1: by index. Inverting the legend would collapse the duplicate names real legends carry.\n const tokenType = tokenTypes[tokenTypeIndex]\n if (tokenType === undefined) {\n outOfLegendType += 1\n continue\n }\n\n const lineStart = lineStarts[line] as number\n // Where the line the tuple addresses actually stops. LSP's own `Position` rule says a character\n // past the end of a line means the end of that line, so a `character` beyond it describes text\n // that is not there — and clamping only to `textLength` cannot see that: `lineStart + character`\n // lands on a perfectly valid offset somewhere further down the file. A stale host snapshot after\n // a line was shortened produced exactly that, and the span painted on an unrelated line with\n // every drop counter still reading zero.\n const lineEnd = lineStarts[line + 1] ?? textLength\n const start = clampOffset(lineStart + character, textLength)\n const end = clampOffset(lineStart + character + length, textLength)\n // A tuple that clamped away to nothing is not a zero-length tuple — it arrived with a real\n // length and began past the end of the text it addresses. Same failure as `deltaLine`\n // overrunning, one axis over, so it is counted the same way. `end` is deliberately NOT clamped\n // to the line: a span crossing a newline is a thing this decoder produces on purpose, for a\n // client that declared `multilineTokenSupport`.\n if (end <= start || start >= lineEnd) {\n pastEndOfDocument += 1\n continue\n }\n\n const modifiers = decodeModifiers(modifierBitset, tokenModifiers)\n if (modifiers.unknownBits) unknownModifierBits += 1\n\n spans.push(\n modifiers.names.length > 0\n ? { end, start, tokenModifiers: modifiers.names, tokenType }\n : { end, start, tokenType },\n )\n }\n\n if (index < data.length && malformedTuple === 0) malformedTuple += 1\n\n return {\n drops: {\n malformedTuple,\n outOfLegendType,\n pastEndOfDocument,\n unknownModifierBits,\n zeroLength,\n },\n spans,\n }\n}\n\nfunction decodeModifiers(\n bitset: number,\n tokenModifiers: readonly string[],\n): { readonly names: readonly string[]; readonly unknownBits: boolean } {\n if (bitset === 0) return { names: [], unknownBits: false }\n\n const names: string[] = []\n let unknownBits = false\n for (let bit = 0; bit < MODIFIER_BITS; bit += 1) {\n if ((bitset & (1 << bit)) === 0) continue\n\n const name = tokenModifiers[bit]\n // Rule 3: a bit the legend does not name is ignored rather than fatal, and the span survives it\n // — losing a modifier costs a shade of colour, where dropping the span costs the colour itself.\n if (name === undefined) unknownBits = true\n else names.push(name)\n }\n\n return { names, unknownBits }\n}\n\nfunction isUnsignedInteger(value: number): boolean {\n return Number.isInteger(value) && value >= 0\n}\n\nfunction clampOffset(offset: number, textLength: number): number {\n if (offset < 0) return 0\n return offset > textLength ? textLength : offset\n}\n"],"mappings":";AAuDA,IAAM,eAAe;AACrB,IAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BtB,SAAgB,qBACd,MACA,QACA,UAC2B;CAC3B,MAAM,QAA6B,CAAC;CACpC,MAAM,aAAa,OAAO;CAC1B,MAAM,iBAAiB,OAAO;CAC9B,MAAM,aAAa,SAAS;CAC5B,MAAM,aAAa,SAAS;CAE5B,IAAI,kBAAkB;CACtB,IAAI,aAAa;CACjB,IAAI,oBAAoB;CACxB,IAAI,sBAAsB;CAC1B,IAAI,iBAAiB;CAErB,IAAI,OAAO;CACX,IAAI,YAAY;CAChB,IAAI,QAAQ;CAEZ,OAAO,QAAQ,gBAAgB,KAAK,QAAQ,SAAS,cAAc;EACjE,MAAM,YAAY,KAAK;EACvB,MAAM,iBAAiB,KAAK,QAAQ;EACpC,MAAM,SAAS,KAAK,QAAQ;EAC5B,MAAM,iBAAiB,KAAK,QAAQ;EACpC,MAAM,iBAAiB,KAAK,QAAQ;EAEpC,IACE,CAAC,kBAAkB,SAAS,KAC5B,CAAC,kBAAkB,cAAc,KACjC,CAAC,kBAAkB,MAAM,KACzB,CAAC,kBAAkB,cAAc,KACjC,CAAC,kBAAkB,cAAc,GACjC;GAGA,kBAAkB;GAClB;EACF;EAIA,QAAQ;EACR,YAAY,cAAc,IAAI,YAAY,iBAAiB;EAE3D,IAAI,QAAQ,WAAW,QAAQ;GAC7B,qBAAqB;GACrB;EACF;EACA,IAAI,WAAW,GAAG;GAChB,cAAc;GACd;EACF;EAGA,MAAM,YAAY,WAAW;EAC7B,IAAI,cAAc,KAAA,GAAW;GAC3B,mBAAmB;GACnB;EACF;EAEA,MAAM,YAAY,WAAW;EAO7B,MAAM,UAAU,WAAW,OAAO,MAAM;EACxC,MAAM,QAAQ,YAAY,YAAY,WAAW,UAAU;EAC3D,MAAM,MAAM,YAAY,YAAY,YAAY,QAAQ,UAAU;EAMlE,IAAI,OAAO,SAAS,SAAS,SAAS;GACpC,qBAAqB;GACrB;EACF;EAEA,MAAM,YAAY,gBAAgB,gBAAgB,cAAc;EAChE,IAAI,UAAU,aAAa,uBAAuB;EAElD,MAAM,KACJ,UAAU,MAAM,SAAS,IACrB;GAAE;GAAK;GAAO,gBAAgB,UAAU;GAAO;EAAU,IACzD;GAAE;GAAK;GAAO;EAAU,CAC9B;CACF;CAEA,IAAI,QAAQ,KAAK,UAAU,mBAAmB,GAAG,kBAAkB;CAEnE,OAAO;EACL,OAAO;GACL;GACA;GACA;GACA;GACA;EACF;EACA;CACF;AACF;AAEA,SAAS,gBACP,QACA,gBACsE;CACtE,IAAI,WAAW,GAAG,OAAO;EAAE,OAAO,CAAC;EAAG,aAAa;CAAM;CAEzD,MAAM,QAAkB,CAAC;CACzB,IAAI,cAAc;CAClB,KAAK,IAAI,MAAM,GAAG,MAAM,eAAe,OAAO,GAAG;EAC/C,KAAK,SAAU,KAAK,SAAU,GAAG;EAEjC,MAAM,OAAO,eAAe;EAG5B,IAAI,SAAS,KAAA,GAAW,cAAc;OACjC,MAAM,KAAK,IAAI;CACtB;CAEA,OAAO;EAAE;EAAO;CAAY;AAC9B;AAEA,SAAS,kBAAkB,OAAwB;CACjD,OAAO,OAAO,UAAU,KAAK,KAAK,SAAS;AAC7C;AAEA,SAAS,YAAY,QAAgB,YAA4B;CAC/D,IAAI,SAAS,GAAG,OAAO;CACvB,OAAO,SAAS,aAAa,aAAa;AAC5C"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { EditorDisposable, EditorViewContributionContext, EditorViewContributionUpdateKind, EditorViewSnapshot, SemanticTokenLayer, SemanticTokenLayerOptions } from '@singapore-editor/core/extensions';
|
|
2
|
+
import type { LanguageServerConnectionContext } from './connectionContext';
|
|
3
|
+
/** Which document a layer was created for. A layer never spans two. */
|
|
4
|
+
export type LanguageServerSemanticTokensDocument = {
|
|
5
|
+
readonly documentId: string;
|
|
6
|
+
readonly languageId: string | null;
|
|
7
|
+
};
|
|
8
|
+
export type LanguageServerSemanticTokensOptions = Omit<SemanticTokenLayerOptions, 'name'> & {
|
|
9
|
+
/** Namespaced within the view. Defaults to `semantic`. */
|
|
10
|
+
readonly name?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Receives the layer the view contribution created.
|
|
13
|
+
*
|
|
14
|
+
* A host cannot construct one itself: a layer needs a viewport, a snapshot and a lifecycle, and
|
|
15
|
+
* all three belong to the contribution. Returning a disposable ties the host's own request-side
|
|
16
|
+
* controller to the layer, in the shape `onConnectionCreated` already uses.
|
|
17
|
+
*
|
|
18
|
+
* **A layer never spans two documents or two language ids.** A change to either disposes the one
|
|
19
|
+
* the host is holding and delivers a *new* one through a second call carrying the new identity —
|
|
20
|
+
* so `clear()` across a document change is a call on a dead handle, not a reset.
|
|
21
|
+
*/
|
|
22
|
+
onLayer?(layer: SemanticTokenLayer, document: LanguageServerSemanticTokensDocument): EditorDisposable | void;
|
|
23
|
+
};
|
|
24
|
+
export type LanguageServerSemanticTokensOwner = {
|
|
25
|
+
readonly id: string;
|
|
26
|
+
readonly connection: LanguageServerConnectionContext;
|
|
27
|
+
};
|
|
28
|
+
export type LanguageServerSemanticTokensOwnerOptions = LanguageServerSemanticTokensOptions & {
|
|
29
|
+
dispose?(): void;
|
|
30
|
+
};
|
|
31
|
+
export type LanguageServerSemanticTokensFactory = (owner: LanguageServerSemanticTokensOwner) => LanguageServerSemanticTokensOwnerOptions;
|
|
32
|
+
/**
|
|
33
|
+
* Owns the semantic token layer's lifetime on the contribution's behalf.
|
|
34
|
+
*
|
|
35
|
+
* The contribution itself is per *view* and outlives a document change; the contract says a layer
|
|
36
|
+
* does not. So the identity is watched here, and a document or language change tears the layer down
|
|
37
|
+
* and hands the host a fresh one rather than quietly re-pointing the old one at different text.
|
|
38
|
+
*/
|
|
39
|
+
export declare class SemanticTokenLayerOwner {
|
|
40
|
+
#private;
|
|
41
|
+
private readonly context;
|
|
42
|
+
private readonly options;
|
|
43
|
+
constructor(context: EditorViewContributionContext, options: LanguageServerSemanticTokensOptions);
|
|
44
|
+
update(snapshot: EditorViewSnapshot, kind: EditorViewContributionUpdateKind): void;
|
|
45
|
+
dispose(): void;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=semanticTokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticTokens.d.ts","sourceRoot":"","sources":["../src/semanticTokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,6BAA6B,EAC7B,gCAAgC,EAChC,kBAAkB,EAClB,kBAAkB,EAElB,yBAAyB,EAC1B,MAAM,mCAAmC,CAAA;AAG1C,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAA;AAE1E,uEAAuE;AACvE,MAAM,MAAM,oCAAoC,GAAG;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CACnC,CAAA;AAED,MAAM,MAAM,mCAAmC,GAAG,IAAI,CAAC,yBAAyB,EAAE,MAAM,CAAC,GAAG;IAC1F,0DAA0D;IAC1D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,CACN,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,oCAAoC,GAC7C,gBAAgB,GAAG,IAAI,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,iCAAiC,GAAG;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,UAAU,EAAE,+BAA+B,CAAA;CACrD,CAAA;AAED,MAAM,MAAM,wCAAwC,GAAG,mCAAmC,GAAG;IAC3F,OAAO,CAAC,IAAI,IAAI,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,mCAAmC,GAAG,CAChD,KAAK,EAAE,iCAAiC,KACrC,wCAAwC,CAAA;AAE7C;;;;;;GAMG;AACH,qBAAa,uBAAuB;;IAQhC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,OAAO,EAAE,6BAA6B,EACtC,OAAO,EAAE,mCAAmC;IAGxD,MAAM,CAAC,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,gCAAgC,GAAG,IAAI;IAgBlF,OAAO,IAAI,IAAI;CA6BvB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createSemanticTokenLayer } from "@singapore-editor/core/extensions";
|
|
2
|
+
//#region src/semanticTokens.ts
|
|
3
|
+
/**
|
|
4
|
+
* Owns the semantic token layer's lifetime on the contribution's behalf.
|
|
5
|
+
*
|
|
6
|
+
* The contribution itself is per *view* and outlives a document change; the contract says a layer
|
|
7
|
+
* does not. So the identity is watched here, and a document or language change tears the layer down
|
|
8
|
+
* and hands the host a fresh one rather than quietly re-pointing the old one at different text.
|
|
9
|
+
*/
|
|
10
|
+
var SemanticTokenLayerOwner = class {
|
|
11
|
+
context;
|
|
12
|
+
options;
|
|
13
|
+
#layer = null;
|
|
14
|
+
#registration = null;
|
|
15
|
+
#documentId = null;
|
|
16
|
+
#languageId = null;
|
|
17
|
+
#disposed = false;
|
|
18
|
+
constructor(context, options) {
|
|
19
|
+
this.context = context;
|
|
20
|
+
this.options = options;
|
|
21
|
+
}
|
|
22
|
+
update(snapshot, kind) {
|
|
23
|
+
if (this.#disposed) return;
|
|
24
|
+
const documentId = snapshot.documentId;
|
|
25
|
+
if (documentId === null || kind === "clear") {
|
|
26
|
+
this.#tearDown();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (documentId !== this.#documentId || snapshot.languageId !== this.#languageId) {
|
|
30
|
+
this.#tearDown();
|
|
31
|
+
this.#create(documentId, snapshot.languageId);
|
|
32
|
+
}
|
|
33
|
+
this.#layer?.update(snapshot, kind);
|
|
34
|
+
}
|
|
35
|
+
dispose() {
|
|
36
|
+
if (this.#disposed) return;
|
|
37
|
+
this.#disposed = true;
|
|
38
|
+
this.#tearDown();
|
|
39
|
+
}
|
|
40
|
+
#create(documentId, languageId) {
|
|
41
|
+
const layer = createSemanticTokenLayer(this.context, {
|
|
42
|
+
name: this.options.name ?? "semantic",
|
|
43
|
+
onRangeNeeded: this.options.onRangeNeeded,
|
|
44
|
+
onResyncRequired: this.options.onResyncRequired,
|
|
45
|
+
scopeAliases: this.options.scopeAliases,
|
|
46
|
+
viewportDelayMs: this.options.viewportDelayMs
|
|
47
|
+
});
|
|
48
|
+
this.#layer = layer;
|
|
49
|
+
this.#documentId = documentId;
|
|
50
|
+
this.#languageId = languageId;
|
|
51
|
+
this.#registration = this.options.onLayer?.(layer, {
|
|
52
|
+
documentId,
|
|
53
|
+
languageId
|
|
54
|
+
}) ?? null;
|
|
55
|
+
}
|
|
56
|
+
#tearDown() {
|
|
57
|
+
this.#registration?.dispose();
|
|
58
|
+
this.#registration = null;
|
|
59
|
+
this.#layer?.dispose();
|
|
60
|
+
this.#layer = null;
|
|
61
|
+
this.#documentId = null;
|
|
62
|
+
this.#languageId = null;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
export { SemanticTokenLayerOwner };
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=semanticTokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticTokens.js","names":[],"sources":["../src/semanticTokens.ts"],"sourcesContent":["import type {\n EditorDisposable,\n EditorViewContributionContext,\n EditorViewContributionUpdateKind,\n EditorViewSnapshot,\n SemanticTokenLayer,\n SemanticTokenLayerController,\n SemanticTokenLayerOptions,\n} from '@singapore-editor/core/extensions'\nimport { createSemanticTokenLayer } from '@singapore-editor/core/extensions'\n\nimport type { LanguageServerConnectionContext } from './connectionContext'\n\n/** Which document a layer was created for. A layer never spans two. */\nexport type LanguageServerSemanticTokensDocument = {\n readonly documentId: string\n readonly languageId: string | null\n}\n\nexport type LanguageServerSemanticTokensOptions = Omit<SemanticTokenLayerOptions, 'name'> & {\n /** Namespaced within the view. Defaults to `semantic`. */\n readonly name?: string\n /**\n * Receives the layer the view contribution created.\n *\n * A host cannot construct one itself: a layer needs a viewport, a snapshot and a lifecycle, and\n * all three belong to the contribution. Returning a disposable ties the host's own request-side\n * controller to the layer, in the shape `onConnectionCreated` already uses.\n *\n * **A layer never spans two documents or two language ids.** A change to either disposes the one\n * the host is holding and delivers a *new* one through a second call carrying the new identity —\n * so `clear()` across a document change is a call on a dead handle, not a reset.\n */\n onLayer?(\n layer: SemanticTokenLayer,\n document: LanguageServerSemanticTokensDocument,\n ): EditorDisposable | void\n}\n\nexport type LanguageServerSemanticTokensOwner = {\n readonly id: string\n readonly connection: LanguageServerConnectionContext\n}\n\nexport type LanguageServerSemanticTokensOwnerOptions = LanguageServerSemanticTokensOptions & {\n dispose?(): void\n}\n\nexport type LanguageServerSemanticTokensFactory = (\n owner: LanguageServerSemanticTokensOwner,\n) => LanguageServerSemanticTokensOwnerOptions\n\n/**\n * Owns the semantic token layer's lifetime on the contribution's behalf.\n *\n * The contribution itself is per *view* and outlives a document change; the contract says a layer\n * does not. So the identity is watched here, and a document or language change tears the layer down\n * and hands the host a fresh one rather than quietly re-pointing the old one at different text.\n */\nexport class SemanticTokenLayerOwner {\n #layer: SemanticTokenLayerController | null = null\n #registration: EditorDisposable | null = null\n #documentId: string | null = null\n #languageId: string | null = null\n #disposed = false\n\n public constructor(\n private readonly context: EditorViewContributionContext,\n private readonly options: LanguageServerSemanticTokensOptions,\n ) {}\n\n public update(snapshot: EditorViewSnapshot, kind: EditorViewContributionUpdateKind): void {\n if (this.#disposed) return\n\n const documentId = snapshot.documentId\n if (documentId === null || kind === 'clear') {\n this.#tearDown()\n return\n }\n if (documentId !== this.#documentId || snapshot.languageId !== this.#languageId) {\n this.#tearDown()\n this.#create(documentId, snapshot.languageId)\n }\n\n this.#layer?.update(snapshot, kind)\n }\n\n public dispose(): void {\n if (this.#disposed) return\n\n this.#disposed = true\n this.#tearDown()\n }\n\n #create(documentId: string, languageId: string | null): void {\n const layer = createSemanticTokenLayer(this.context, {\n name: this.options.name ?? 'semantic',\n onRangeNeeded: this.options.onRangeNeeded,\n onResyncRequired: this.options.onResyncRequired,\n scopeAliases: this.options.scopeAliases,\n viewportDelayMs: this.options.viewportDelayMs,\n })\n this.#layer = layer\n this.#documentId = documentId\n this.#languageId = languageId\n this.#registration = this.options.onLayer?.(layer, { documentId, languageId }) ?? null\n }\n\n #tearDown(): void {\n this.#registration?.dispose()\n this.#registration = null\n this.#layer?.dispose()\n this.#layer = null\n this.#documentId = null\n this.#languageId = null\n }\n}\n"],"mappings":";;;;;;;;;AA2DA,IAAa,0BAAb,MAAqC;CAQhB;CACA;CARnB,SAA8C;CAC9C,gBAAyC;CACzC,cAA6B;CAC7B,cAA6B;CAC7B,YAAY;CAEZ,YACE,SACA,SACA;EAFiB,KAAA,UAAA;EACA,KAAA,UAAA;CAChB;CAEH,OAAc,UAA8B,MAA8C;EACxF,IAAI,KAAK,WAAW;EAEpB,MAAM,aAAa,SAAS;EAC5B,IAAI,eAAe,QAAQ,SAAS,SAAS;GAC3C,KAAK,UAAU;GACf;EACF;EACA,IAAI,eAAe,KAAK,eAAe,SAAS,eAAe,KAAK,aAAa;GAC/E,KAAK,UAAU;GACf,KAAK,QAAQ,YAAY,SAAS,UAAU;EAC9C;EAEA,KAAK,QAAQ,OAAO,UAAU,IAAI;CACpC;CAEA,UAAuB;EACrB,IAAI,KAAK,WAAW;EAEpB,KAAK,YAAY;EACjB,KAAK,UAAU;CACjB;CAEA,QAAQ,YAAoB,YAAiC;EAC3D,MAAM,QAAQ,yBAAyB,KAAK,SAAS;GACnD,MAAM,KAAK,QAAQ,QAAQ;GAC3B,eAAe,KAAK,QAAQ;GAC5B,kBAAkB,KAAK,QAAQ;GAC/B,cAAc,KAAK,QAAQ;GAC3B,iBAAiB,KAAK,QAAQ;EAChC,CAAC;EACD,KAAK,SAAS;EACd,KAAK,cAAc;EACnB,KAAK,cAAc;EACnB,KAAK,gBAAgB,KAAK,QAAQ,UAAU,OAAO;GAAE;GAAY;EAAW,CAAC,KAAK;CACpF;CAEA,YAAkB;EAChB,KAAK,eAAe,QAAQ;EAC5B,KAAK,gBAAgB;EACrB,KAAK,QAAQ,QAAQ;EACrB,KAAK,SAAS;EACd,KAAK,cAAc;EACnB,KAAK,cAAc;CACrB;AACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { LspRequestOptions, LspWorkspace } from '@singapore-editor/lsp';
|
|
2
|
+
import type * as lsp from 'vscode-languageserver-protocol';
|
|
3
|
+
import type { AcquiredLanguageServerLane } from './lane';
|
|
4
|
+
import { type LanguageServerFeatureId, type LanguageServerFeatureRanks, type OnApplyWorkspaceEdit, type WorkspaceEditOriginGuard } from './types';
|
|
5
|
+
export type LanguageServerSetLane = {
|
|
6
|
+
readonly id: string;
|
|
7
|
+
readonly features: LanguageServerFeatureRanks;
|
|
8
|
+
readonly connection: AcquiredLanguageServerLane;
|
|
9
|
+
readonly onInteractiveReady?: () => void;
|
|
10
|
+
readonly onApplyWorkspaceEdit?: OnApplyWorkspaceEdit;
|
|
11
|
+
readonly onRequestError?: (method: string, error: unknown) => void;
|
|
12
|
+
};
|
|
13
|
+
export type LanguageServerLaneResult = {
|
|
14
|
+
readonly lane: LanguageServerSetLane;
|
|
15
|
+
readonly provenance?: LanguageServerCodeActionProvenance;
|
|
16
|
+
readonly result: unknown;
|
|
17
|
+
};
|
|
18
|
+
export type LanguageServerHoverUpdate = {
|
|
19
|
+
/** Hover answers in feature-rank order, regardless of the order in which they resolved. */
|
|
20
|
+
readonly hovers: readonly lsp.Hover[];
|
|
21
|
+
/** True until every ready hover lane has either answered or failed. */
|
|
22
|
+
readonly pending: boolean;
|
|
23
|
+
};
|
|
24
|
+
export type LanguageServerFeatureRouter = {
|
|
25
|
+
canResolveCodeActions(): boolean;
|
|
26
|
+
hasReady(feature: LanguageServerFeatureId, method?: string): boolean;
|
|
27
|
+
request<TResult = unknown, TParams = unknown>(method: string, params?: TParams, options?: LspRequestOptions): Promise<TResult>;
|
|
28
|
+
};
|
|
29
|
+
export type LanguageServerCodeActionRouter = LanguageServerFeatureRouter & {
|
|
30
|
+
ownerOf(value: unknown): LanguageServerSetLane | null;
|
|
31
|
+
provenanceOf(value: unknown): LanguageServerCodeActionProvenance | null;
|
|
32
|
+
resolveOwnedCodeAction(action: lsp.CodeAction, options: LspRequestOptions): Promise<LanguageServerOwnedCodeAction | null>;
|
|
33
|
+
};
|
|
34
|
+
export type LanguageServerCodeActionProvenance = {
|
|
35
|
+
readonly guard: WorkspaceEditOriginGuard;
|
|
36
|
+
readonly lane: LanguageServerSetLane;
|
|
37
|
+
};
|
|
38
|
+
export type LanguageServerOwnedCodeAction = LanguageServerCodeActionProvenance & {
|
|
39
|
+
readonly action: lsp.CodeAction;
|
|
40
|
+
};
|
|
41
|
+
export declare class LanguageServerSet {
|
|
42
|
+
#private;
|
|
43
|
+
constructor(lanes: readonly LanguageServerSetLane[]);
|
|
44
|
+
declared(feature: LanguageServerFeatureId): readonly LanguageServerSetLane[];
|
|
45
|
+
ready(feature: LanguageServerFeatureId, method?: string): readonly LanguageServerSetLane[];
|
|
46
|
+
hasReady(feature: LanguageServerFeatureId, method?: string): boolean;
|
|
47
|
+
canResolveCodeActions(): boolean;
|
|
48
|
+
ownerOf(value: unknown): LanguageServerSetLane | null;
|
|
49
|
+
provenanceOf(value: unknown): LanguageServerCodeActionProvenance | null;
|
|
50
|
+
request<TResult = unknown, TParams = unknown>(method: string, params?: TParams, options?: LspRequestOptions): Promise<TResult>;
|
|
51
|
+
requestHover<TParams>(params: TParams | undefined, options?: LspRequestOptions, onUpdate?: (update: LanguageServerHoverUpdate) => void): Promise<lsp.Hover | null>;
|
|
52
|
+
private requestHoverLane;
|
|
53
|
+
mergedArray<TParams>(feature: 'codeActions', method: string, params: TParams | undefined, options: LspRequestOptions): Promise<unknown[]>;
|
|
54
|
+
mergeArrayResults(feature: 'codeActions', results: readonly LanguageServerLaneResult[]): unknown[];
|
|
55
|
+
resolveCodeAction<TParams>(params: TParams | undefined, options: LspRequestOptions): Promise<lsp.CodeAction | NonNullable<TParams> | null>;
|
|
56
|
+
resolveOwnedCodeAction(action: lsp.CodeAction, options: LspRequestOptions): Promise<LanguageServerOwnedCodeAction | null>;
|
|
57
|
+
requestSingle<TParams, TResult = unknown>(lane: LanguageServerSetLane | undefined, method: string, params: TParams | undefined, options: LspRequestOptions, fallback: TResult, transform?: (result: unknown) => TResult): Promise<TResult>;
|
|
58
|
+
requestFirst<TParams, TResult = unknown>(feature: LanguageServerFeatureId, method: string, params: TParams | undefined, options: LspRequestOptions | undefined, fallback: TResult, accepts?: (result: unknown) => boolean): Promise<TResult>;
|
|
59
|
+
requestOwner<TParams, TResult = unknown>(feature: LanguageServerFeatureId, method: string, params: TParams | undefined, options: LspRequestOptions | undefined, fallback: TResult): Promise<TResult>;
|
|
60
|
+
requestAll<TParams>(feature: LanguageServerFeatureId, method: string, params: TParams | undefined, options: LspRequestOptions): Promise<readonly LanguageServerLaneResult[]>;
|
|
61
|
+
private requestLane;
|
|
62
|
+
}
|
|
63
|
+
export declare function rankedLanguageServerLanes<TLane extends {
|
|
64
|
+
readonly features: LanguageServerFeatureRanks;
|
|
65
|
+
}>(lanes: readonly TLane[], feature: LanguageServerFeatureId): readonly TLane[];
|
|
66
|
+
export declare function allLanguageServerFeatures(rank?: number): LanguageServerFeatureRanks;
|
|
67
|
+
export declare function laneSupports(lane: LanguageServerSetLane, feature: LanguageServerFeatureId, method?: string): boolean;
|
|
68
|
+
export declare function captureWorkspaceEditOriginGuard(workspace: LspWorkspace): WorkspaceEditOriginGuard;
|
|
69
|
+
//# sourceMappingURL=serverSet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverSet.d.ts","sourceRoot":"","sources":["../src/serverSet.ts"],"names":[],"mappings":"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"}
|