@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.
Files changed (185) hide show
  1. package/README.md +103 -0
  2. package/dist/bufferSync.d.ts +12 -0
  3. package/dist/bufferSync.d.ts.map +1 -0
  4. package/dist/bufferSync.js +35 -0
  5. package/dist/bufferSync.js.map +1 -0
  6. package/dist/codeActions.d.ts +83 -0
  7. package/dist/codeActions.d.ts.map +1 -0
  8. package/dist/codeActions.js +294 -0
  9. package/dist/codeActions.js.map +1 -0
  10. package/dist/colorAlpha.d.ts +4 -0
  11. package/dist/colorAlpha.d.ts.map +1 -0
  12. package/dist/colorAlpha.js +28 -0
  13. package/dist/colorAlpha.js.map +1 -0
  14. package/dist/completion.d.ts +124 -0
  15. package/dist/completion.d.ts.map +1 -0
  16. package/dist/completion.js +609 -0
  17. package/dist/completion.js.map +1 -0
  18. package/dist/completionCommit.d.ts +19 -0
  19. package/dist/completionCommit.d.ts.map +1 -0
  20. package/dist/completionCommit.js +57 -0
  21. package/dist/completionCommit.js.map +1 -0
  22. package/dist/completionController.d.ts +89 -0
  23. package/dist/completionController.d.ts.map +1 -0
  24. package/dist/completionController.js +376 -0
  25. package/dist/completionController.js.map +1 -0
  26. package/dist/completionProviders.d.ts +50 -0
  27. package/dist/completionProviders.d.ts.map +1 -0
  28. package/dist/completionProviders.js +64 -0
  29. package/dist/completionProviders.js.map +1 -0
  30. package/dist/connectionContext.d.ts +7 -0
  31. package/dist/connectionContext.d.ts.map +1 -0
  32. package/dist/definitionLinkController.d.ts +54 -0
  33. package/dist/definitionLinkController.d.ts.map +1 -0
  34. package/dist/definitionLinkController.js +221 -0
  35. package/dist/definitionLinkController.js.map +1 -0
  36. package/dist/definitionNavigation.d.ts +76 -0
  37. package/dist/definitionNavigation.d.ts.map +1 -0
  38. package/dist/definitionNavigation.js +143 -0
  39. package/dist/definitionNavigation.js.map +1 -0
  40. package/dist/diagnosticNotes.d.ts +7 -0
  41. package/dist/diagnosticNotes.d.ts.map +1 -0
  42. package/dist/diagnosticNotes.js +37 -0
  43. package/dist/diagnosticNotes.js.map +1 -0
  44. package/dist/diagnosticProjection.d.ts +31 -0
  45. package/dist/diagnosticProjection.d.ts.map +1 -0
  46. package/dist/diagnosticProjection.js +79 -0
  47. package/dist/diagnosticProjection.js.map +1 -0
  48. package/dist/diagnostics.d.ts +16 -0
  49. package/dist/diagnostics.d.ts.map +1 -0
  50. package/dist/diagnostics.js +94 -0
  51. package/dist/diagnostics.js.map +1 -0
  52. package/dist/diagnosticsPresenter.d.ts +64 -0
  53. package/dist/diagnosticsPresenter.d.ts.map +1 -0
  54. package/dist/diagnosticsPresenter.js +305 -0
  55. package/dist/diagnosticsPresenter.js.map +1 -0
  56. package/dist/document.d.ts +69 -0
  57. package/dist/document.d.ts.map +1 -0
  58. package/dist/document.js +190 -0
  59. package/dist/document.js.map +1 -0
  60. package/dist/documentHighlightController.d.ts +34 -0
  61. package/dist/documentHighlightController.d.ts.map +1 -0
  62. package/dist/documentHighlightController.js +101 -0
  63. package/dist/documentHighlightController.js.map +1 -0
  64. package/dist/documentSnapshot.d.ts +9 -0
  65. package/dist/documentSnapshot.d.ts.map +1 -0
  66. package/dist/documentSnapshot.js +31 -0
  67. package/dist/documentSnapshot.js.map +1 -0
  68. package/dist/documentSync.d.ts +53 -0
  69. package/dist/documentSync.d.ts.map +1 -0
  70. package/dist/documentSync.js +334 -0
  71. package/dist/documentSync.js.map +1 -0
  72. package/dist/documentSyncController.d.ts +26 -0
  73. package/dist/documentSyncController.d.ts.map +1 -0
  74. package/dist/documentSyncController.js +24 -0
  75. package/dist/documentSyncController.js.map +1 -0
  76. package/dist/formatOnType.d.ts +43 -0
  77. package/dist/formatOnType.d.ts.map +1 -0
  78. package/dist/formatOnType.js +198 -0
  79. package/dist/formatOnType.js.map +1 -0
  80. package/dist/formatting.d.ts +18 -0
  81. package/dist/formatting.d.ts.map +1 -0
  82. package/dist/formatting.js +52 -0
  83. package/dist/formatting.js.map +1 -0
  84. package/dist/fuzzyMatch.d.ts +22 -0
  85. package/dist/fuzzyMatch.d.ts.map +1 -0
  86. package/dist/fuzzyMatch.js +216 -0
  87. package/dist/fuzzyMatch.js.map +1 -0
  88. package/dist/hoverParticipant.d.ts +24 -0
  89. package/dist/hoverParticipant.d.ts.map +1 -0
  90. package/dist/hoverParticipant.js +156 -0
  91. package/dist/hoverParticipant.js.map +1 -0
  92. package/dist/index.d.ts +18 -0
  93. package/dist/index.d.ts.map +1 -0
  94. package/dist/index.js +17 -0
  95. package/dist/keyCommands.d.ts +19 -0
  96. package/dist/keyCommands.d.ts.map +1 -0
  97. package/dist/keyCommands.js +21 -0
  98. package/dist/keyCommands.js.map +1 -0
  99. package/dist/lane.d.ts +28 -0
  100. package/dist/lane.d.ts.map +1 -0
  101. package/dist/lane.js +138 -0
  102. package/dist/lane.js.map +1 -0
  103. package/dist/lspConnection.d.ts +94 -0
  104. package/dist/lspConnection.d.ts.map +1 -0
  105. package/dist/lspConnection.js +195 -0
  106. package/dist/lspConnection.js.map +1 -0
  107. package/dist/lspConnectionPool.d.ts +34 -0
  108. package/dist/lspConnectionPool.d.ts.map +1 -0
  109. package/dist/lspConnectionPool.js +255 -0
  110. package/dist/lspConnectionPool.js.map +1 -0
  111. package/dist/minimalEdits.d.ts +21 -0
  112. package/dist/minimalEdits.d.ts.map +1 -0
  113. package/dist/minimalEdits.js +181 -0
  114. package/dist/minimalEdits.js.map +1 -0
  115. package/dist/paths.d.ts +6 -0
  116. package/dist/paths.d.ts.map +1 -0
  117. package/dist/paths.js +38 -0
  118. package/dist/paths.js.map +1 -0
  119. package/dist/plugin.d.ts +100 -0
  120. package/dist/plugin.d.ts.map +1 -0
  121. package/dist/plugin.js +837 -0
  122. package/dist/plugin.js.map +1 -0
  123. package/dist/plugin.styles.d.ts +31 -0
  124. package/dist/plugin.styles.d.ts.map +1 -0
  125. package/dist/plugin.styles.js +102 -0
  126. package/dist/plugin.styles.js.map +1 -0
  127. package/dist/pluginTypes.d.ts +41 -0
  128. package/dist/pluginTypes.d.ts.map +1 -0
  129. package/dist/pluginTypes.js +0 -0
  130. package/dist/pullDiagnostics.d.ts +30 -0
  131. package/dist/pullDiagnostics.d.ts.map +1 -0
  132. package/dist/pullDiagnostics.js +94 -0
  133. package/dist/pullDiagnostics.js.map +1 -0
  134. package/dist/renameWidget.d.ts +30 -0
  135. package/dist/renameWidget.d.ts.map +1 -0
  136. package/dist/renameWidget.js +117 -0
  137. package/dist/renameWidget.js.map +1 -0
  138. package/dist/semanticTokenDecoder.d.ts +81 -0
  139. package/dist/semanticTokenDecoder.d.ts.map +1 -0
  140. package/dist/semanticTokenDecoder.js +132 -0
  141. package/dist/semanticTokenDecoder.js.map +1 -0
  142. package/dist/semanticTokens.d.ts +47 -0
  143. package/dist/semanticTokens.d.ts.map +1 -0
  144. package/dist/semanticTokens.js +68 -0
  145. package/dist/semanticTokens.js.map +1 -0
  146. package/dist/serverSet.d.ts +69 -0
  147. package/dist/serverSet.d.ts.map +1 -0
  148. package/dist/serverSet.js +331 -0
  149. package/dist/serverSet.js.map +1 -0
  150. package/dist/signatureHelp.d.ts +40 -0
  151. package/dist/signatureHelp.d.ts.map +1 -0
  152. package/dist/signatureHelp.js +108 -0
  153. package/dist/signatureHelp.js.map +1 -0
  154. package/dist/signatureHelpController.d.ts +52 -0
  155. package/dist/signatureHelpController.d.ts.map +1 -0
  156. package/dist/signatureHelpController.js +160 -0
  157. package/dist/signatureHelpController.js.map +1 -0
  158. package/dist/sourceText.d.ts +22 -0
  159. package/dist/sourceText.d.ts.map +1 -0
  160. package/dist/sourceText.js +70 -0
  161. package/dist/sourceText.js.map +1 -0
  162. package/dist/types.d.ts +238 -0
  163. package/dist/types.d.ts.map +1 -0
  164. package/dist/types.js +17 -0
  165. package/dist/types.js.map +1 -0
  166. package/dist/viewDocumentSnapshot.d.ts +5 -0
  167. package/dist/viewDocumentSnapshot.d.ts.map +1 -0
  168. package/dist/viewDocumentSnapshot.js +12 -0
  169. package/dist/viewDocumentSnapshot.js.map +1 -0
  170. package/dist/websocket.d.ts +6 -0
  171. package/dist/websocket.d.ts.map +1 -0
  172. package/dist/websocket.js +4 -0
  173. package/dist/workspaceEdit.d.ts +66 -0
  174. package/dist/workspaceEdit.d.ts.map +1 -0
  175. package/dist/workspaceEdit.js +276 -0
  176. package/dist/workspaceEdit.js.map +1 -0
  177. package/dist/workspaceEditProvenance.d.ts +5 -0
  178. package/dist/workspaceEditProvenance.d.ts.map +1 -0
  179. package/dist/workspaceEditProvenance.js +16 -0
  180. package/dist/workspaceEditProvenance.js.map +1 -0
  181. package/dist/workspaceTextEdits.d.ts +60 -0
  182. package/dist/workspaceTextEdits.d.ts.map +1 -0
  183. package/dist/workspaceTextEdits.js +395 -0
  184. package/dist/workspaceTextEdits.js.map +1 -0
  185. package/package.json +118 -0
@@ -0,0 +1,160 @@
1
+ import { formatSignatureHelp, nextSignatureIndex, signatureHelpTriggerFromTypedText } from "./signatureHelp.js";
2
+ import { offsetToLspPositionInSnapshot } from "@singapore-editor/lsp";
3
+ import { anchoredSurfaceFollowsUpdate } from "@singapore-editor/plugin-ui/anchored-surface";
4
+ import { createTooltipController } from "@singapore-editor/plugin-ui/tooltip";
5
+ //#region src/signatureHelpController.ts
6
+ /**
7
+ * Shows the signature of the call the caret is inside, requested when an argument list opens or the
8
+ * caret moves to the next argument.
9
+ *
10
+ * Reuses the hover tooltip rather than introducing a second floating surface, so signature text
11
+ * inherits the same theming, markdown rendering, and placement behaviour.
12
+ */
13
+ var SignatureHelpController = class {
14
+ options;
15
+ context;
16
+ tooltip;
17
+ abort = null;
18
+ requestId = 0;
19
+ currentTheme = null;
20
+ lastHelp = null;
21
+ display = null;
22
+ disposed = false;
23
+ keymapKeys;
24
+ constructor(options) {
25
+ this.options = options;
26
+ this.context = options.context;
27
+ this.tooltip = createTooltipController({
28
+ classNamespace: options.tooltipClassNamespace ?? "lsp-plugin",
29
+ document: this.context.container.ownerDocument,
30
+ reentryElement: this.context.scrollElement,
31
+ themeSource: this.context.scrollElement
32
+ });
33
+ this.keymapKeys = [this.context.registerKeymapContextKey("parameterHintsVisible", () => this.display !== null), this.context.registerKeymapContextKey("parameterHintsMultipleSignatures", () => (this.display?.signatureCount ?? 0) > 1)];
34
+ }
35
+ update(snapshot, kind) {
36
+ this.currentTheme = snapshot.theme ?? null;
37
+ if (kind === "document" || kind === "clear") {
38
+ this.hide();
39
+ return;
40
+ }
41
+ if (anchoredSurfaceFollowsUpdate(kind)) this.reanchor();
42
+ }
43
+ /** The keystroke, not the edit it caused; see signatureHelpTriggerFromTypedText. */
44
+ handleTypedText(text) {
45
+ const trigger = signatureHelpTriggerFromTypedText(text);
46
+ if (!trigger) return;
47
+ if (trigger.kind === "close") {
48
+ this.hide();
49
+ return;
50
+ }
51
+ this.request(trigger.triggerCharacter);
52
+ }
53
+ hide() {
54
+ this.abort?.abort();
55
+ this.abort = null;
56
+ this.lastHelp = null;
57
+ this.display = null;
58
+ this.tooltip.hide();
59
+ }
60
+ containsTarget(target) {
61
+ return this.tooltip.containsTarget(target);
62
+ }
63
+ dispose() {
64
+ if (this.disposed) return;
65
+ this.disposed = true;
66
+ for (const key of this.keymapKeys) key.dispose();
67
+ this.hide();
68
+ this.tooltip.dispose();
69
+ }
70
+ /** The keymap's commands; false when there is nothing on screen for them to act on. */
71
+ runKeyCommand(command) {
72
+ const display = this.display;
73
+ if (!display) return false;
74
+ if (command === "close") {
75
+ this.hide();
76
+ return true;
77
+ }
78
+ if (display.signatureCount < 2) return false;
79
+ const delta = command === "next" ? 1 : -1;
80
+ this.showSignature(nextSignatureIndex(display.activeSignature, display.signatureCount, delta));
81
+ return true;
82
+ }
83
+ async request(triggerCharacter) {
84
+ const active = this.options.getActiveDocument();
85
+ const selection = this.context.getSnapshot().selections[0];
86
+ if (!active || !selection) {
87
+ this.hide();
88
+ return;
89
+ }
90
+ if (!this.options.router.hasReady("signatureHelp", "textDocument/signatureHelp")) return;
91
+ this.abort?.abort();
92
+ const abort = new AbortController();
93
+ const requestId = this.requestId + 1;
94
+ this.requestId = requestId;
95
+ this.abort = abort;
96
+ try {
97
+ const help = await this.options.router.request("textDocument/signatureHelp", {
98
+ context: {
99
+ isRetrigger: false,
100
+ triggerCharacter,
101
+ triggerKind: 2
102
+ },
103
+ position: offsetToLspPositionInSnapshot(active, selection.headOffset),
104
+ textDocument: { uri: active.uri }
105
+ }, { signal: abort.signal });
106
+ this.options.onRequestSuccess?.();
107
+ if (requestId !== this.requestId) return;
108
+ if (this.disposed) return;
109
+ if (active !== this.options.getActiveDocument()) return;
110
+ this.lastHelp = help ?? null;
111
+ this.showSignature(help?.activeSignature ?? 0);
112
+ } catch (error) {
113
+ this.options.onRequestError(error);
114
+ }
115
+ }
116
+ showSignature(signatureIndex) {
117
+ const display = formatSignatureHelp(this.lastHelp, signatureIndex);
118
+ this.display = display;
119
+ if (!display) {
120
+ this.tooltip.hide();
121
+ return;
122
+ }
123
+ const anchor = this.caretAnchor();
124
+ if (!anchor) {
125
+ this.tooltip.hide();
126
+ return;
127
+ }
128
+ this.tooltip.show({
129
+ anchor,
130
+ hoverText: display.markdown,
131
+ preferredPlacement: "top",
132
+ theme: this.currentTheme
133
+ });
134
+ }
135
+ /**
136
+ * Follows the caret when the view moves under the signature.
137
+ *
138
+ * The call being typed is where the signature belongs, and a caret that has scrolled out of the
139
+ * rendered rows has no rect to belong to any more — leaving the widget parked over unrelated code
140
+ * is worse than losing it, and the next keystroke in the argument list asks for it again.
141
+ */
142
+ reanchor() {
143
+ if (!this.display) return;
144
+ const anchor = this.caretAnchor();
145
+ if (!anchor) {
146
+ this.hide();
147
+ return;
148
+ }
149
+ this.tooltip.reanchor(anchor);
150
+ }
151
+ caretAnchor() {
152
+ const selection = this.context.getSnapshot().selections[0];
153
+ if (!selection) return null;
154
+ return this.context.getRangeClientRect(selection.headOffset, selection.headOffset);
155
+ }
156
+ };
157
+ //#endregion
158
+ export { SignatureHelpController };
159
+
160
+ //# sourceMappingURL=signatureHelpController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signatureHelpController.js","names":[],"sources":["../src/signatureHelpController.ts"],"sourcesContent":["import type * as lsp from 'vscode-languageserver-protocol'\n\nimport type {\n EditorDisposable,\n EditorTheme,\n EditorViewContributionContext,\n EditorViewContributionUpdateKind,\n EditorViewSnapshot,\n} from '@singapore-editor/core'\nimport { offsetToLspPositionInSnapshot } from '@singapore-editor/lsp'\n\nimport type { ActiveDocument } from './pluginTypes'\nimport type { SignatureHelpKeyCommand } from './keyCommands'\nimport type { LanguageServerFeatureRouter } from './serverSet'\nimport {\n formatSignatureHelp,\n nextSignatureIndex,\n signatureHelpTriggerFromTypedText,\n type SignatureHelpDisplay,\n} from './signatureHelp'\nimport { anchoredSurfaceFollowsUpdate } from '@singapore-editor/plugin-ui/anchored-surface'\nimport {\n type TooltipController,\n createTooltipController,\n} from '@singapore-editor/plugin-ui/tooltip'\n\nexport type SignatureHelpControllerOptions = {\n readonly context: EditorViewContributionContext\n readonly router: LanguageServerFeatureRouter\n readonly getActiveDocument: () => ActiveDocument | null\n readonly tooltipClassNamespace?: string\n readonly onRequestSuccess?: () => void\n readonly onRequestError: (error: unknown) => void\n}\n\n/**\n * Shows the signature of the call the caret is inside, requested when an argument list opens or the\n * caret moves to the next argument.\n *\n * Reuses the hover tooltip rather than introducing a second floating surface, so signature text\n * inherits the same theming, markdown rendering, and placement behaviour.\n */\nexport class SignatureHelpController {\n private readonly context: EditorViewContributionContext\n private readonly tooltip: TooltipController\n private abort: AbortController | null = null\n private requestId = 0\n private currentTheme: EditorTheme | null = null\n private lastHelp: lsp.SignatureHelp | null = null\n private display: SignatureHelpDisplay | null = null\n private disposed = false\n private readonly keymapKeys: readonly EditorDisposable[]\n\n public constructor(private readonly options: SignatureHelpControllerOptions) {\n this.context = options.context\n this.tooltip = createTooltipController({\n classNamespace: options.tooltipClassNamespace ?? 'lsp-plugin',\n document: this.context.container.ownerDocument,\n reentryElement: this.context.scrollElement,\n themeSource: this.context.scrollElement,\n })\n this.keymapKeys = [\n this.context.registerKeymapContextKey('parameterHintsVisible', () => this.display !== null),\n this.context.registerKeymapContextKey(\n 'parameterHintsMultipleSignatures',\n () => (this.display?.signatureCount ?? 0) > 1,\n ),\n ]\n }\n\n public update(snapshot: EditorViewSnapshot, kind: EditorViewContributionUpdateKind): void {\n this.currentTheme = snapshot.theme ?? null\n if (kind === 'document' || kind === 'clear') {\n this.hide()\n return\n }\n if (anchoredSurfaceFollowsUpdate(kind)) this.reanchor()\n }\n\n /** The keystroke, not the edit it caused; see signatureHelpTriggerFromTypedText. */\n public handleTypedText(text: string): void {\n const trigger = signatureHelpTriggerFromTypedText(text)\n if (!trigger) return\n if (trigger.kind === 'close') {\n this.hide()\n return\n }\n\n void this.request(trigger.triggerCharacter)\n }\n\n public hide(): void {\n this.abort?.abort()\n this.abort = null\n this.lastHelp = null\n this.display = null\n this.tooltip.hide()\n }\n\n public containsTarget(target: EventTarget | null): boolean {\n return this.tooltip.containsTarget(target)\n }\n\n public dispose(): void {\n if (this.disposed) return\n\n this.disposed = true\n for (const key of this.keymapKeys) key.dispose()\n this.hide()\n this.tooltip.dispose()\n }\n\n /** The keymap's commands; false when there is nothing on screen for them to act on. */\n public runKeyCommand(command: SignatureHelpKeyCommand): boolean {\n const display = this.display\n if (!display) return false\n if (command === 'close') {\n this.hide()\n return true\n }\n if (display.signatureCount < 2) return false\n\n const delta = command === 'next' ? 1 : -1\n this.showSignature(nextSignatureIndex(display.activeSignature, display.signatureCount, delta))\n return true\n }\n\n private async request(triggerCharacter: '(' | ','): Promise<void> {\n const active = this.options.getActiveDocument()\n const selection = this.context.getSnapshot().selections[0]\n if (!active || !selection) {\n this.hide()\n return\n }\n if (!this.options.router.hasReady('signatureHelp', 'textDocument/signatureHelp')) return\n\n this.abort?.abort()\n const abort = new AbortController()\n const requestId = this.requestId + 1\n this.requestId = requestId\n this.abort = abort\n\n try {\n const help = await this.options.router.request<lsp.SignatureHelp | null>(\n 'textDocument/signatureHelp',\n {\n context: { isRetrigger: false, triggerCharacter, triggerKind: 2 },\n position: offsetToLspPositionInSnapshot(active, selection.headOffset),\n textDocument: { uri: active.uri },\n },\n { signal: abort.signal },\n )\n this.options.onRequestSuccess?.()\n // A newer request, a document swap, or a teardown between send and receive all mean this\n // answer describes a call the caret is no longer in.\n if (requestId !== this.requestId) return\n if (this.disposed) return\n if (active !== this.options.getActiveDocument()) return\n\n this.lastHelp = help ?? null\n this.showSignature(help?.activeSignature ?? 0)\n } catch (error) {\n this.options.onRequestError(error)\n }\n }\n\n private showSignature(signatureIndex: number): void {\n const display = formatSignatureHelp(this.lastHelp, signatureIndex)\n this.display = display\n if (!display) {\n this.tooltip.hide()\n return\n }\n\n const anchor = this.caretAnchor()\n if (!anchor) {\n this.tooltip.hide()\n return\n }\n\n this.tooltip.show({\n anchor,\n hoverText: display.markdown,\n // Above the caret: the argument being typed sits below it, and covering that is the one\n // thing the widget must not do.\n preferredPlacement: 'top',\n theme: this.currentTheme,\n })\n }\n\n /**\n * Follows the caret when the view moves under the signature.\n *\n * The call being typed is where the signature belongs, and a caret that has scrolled out of the\n * rendered rows has no rect to belong to any more — leaving the widget parked over unrelated code\n * is worse than losing it, and the next keystroke in the argument list asks for it again.\n */\n private reanchor(): void {\n if (!this.display) return\n\n const anchor = this.caretAnchor()\n if (!anchor) {\n this.hide()\n return\n }\n\n this.tooltip.reanchor(anchor)\n }\n\n private caretAnchor(): DOMRect | null {\n const selection = this.context.getSnapshot().selections[0]\n if (!selection) return null\n\n return this.context.getRangeClientRect(selection.headOffset, selection.headOffset)\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { TextReadSnapshot } from '@singapore-editor/core/document';
2
+ import type { LspTextDocumentSnapshot } from '@singapore-editor/lsp';
3
+ import type { OffsetRange } from '@singapore-editor/plugin-ui/offset-range';
4
+ type RowBounds = {
5
+ readonly start: number;
6
+ /** The row's break, or the document end for the last row. */
7
+ readonly end: number;
8
+ /** The next row's start, or the document end: the row with its break. */
9
+ readonly next: number;
10
+ };
11
+ export declare function rowBounds(document: LspTextDocumentSnapshot, offset: number): RowBounds;
12
+ /** One code unit, or '' outside the document. */
13
+ export declare function characterAt(document: LspTextDocumentSnapshot, offset: number): string;
14
+ /**
15
+ * Runs a line-local finder over a window of the row around `offset`, break included, widening it
16
+ * while the answer reaches a clipped edge. Finding a word never copies a long row whole.
17
+ */
18
+ export declare function rangeAroundOffset<Found extends OffsetRange | null>(document: LspTextDocumentSnapshot, offset: number, find: (text: string, offset: number) => Found): Found;
19
+ /** Line queries over an LSP document, for a core helper that takes a read source. */
20
+ export declare function textReadSnapshotOf(document: LspTextDocumentSnapshot): TextReadSnapshot;
21
+ export {};
22
+ //# sourceMappingURL=sourceText.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceText.d.ts","sourceRoot":"","sources":["../src/sourceText.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAA;AAI3E,KAAK,SAAS,GAAG;IACf,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAOtF;AAED,iDAAiD;AACjD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGrF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,SAAS,WAAW,GAAG,IAAI,EAChE,QAAQ,EAAE,uBAAuB,EACjC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,KAAK,GAC5C,KAAK,CAUP;AAaD,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,gBAAgB,CAkBtF"}
@@ -0,0 +1,70 @@
1
+ //#region src/sourceText.ts
2
+ var INITIAL_RADIUS = 256;
3
+ function rowBounds(document, offset) {
4
+ const length = document.textSnapshot.length;
5
+ const row = document.lineStarts.indexForOffset(Math.max(0, Math.min(offset, length)));
6
+ const start = document.lineStarts.at(row) ?? 0;
7
+ const nextStart = document.lineStarts.at(row + 1);
8
+ if (nextStart === void 0) return {
9
+ start,
10
+ end: length,
11
+ next: length
12
+ };
13
+ return {
14
+ start,
15
+ end: Math.max(start, nextStart - 1),
16
+ next: nextStart
17
+ };
18
+ }
19
+ /** One code unit, or '' outside the document. */
20
+ function characterAt(document, offset) {
21
+ if (offset < 0 || offset >= document.textSnapshot.length) return "";
22
+ return document.textSnapshot.readRange(offset, offset + 1);
23
+ }
24
+ /**
25
+ * Runs a line-local finder over a window of the row around `offset`, break included, widening it
26
+ * while the answer reaches a clipped edge. Finding a word never copies a long row whole.
27
+ */
28
+ function rangeAroundOffset(document, offset, find) {
29
+ const row = rowBounds(document, offset);
30
+ for (let radius = INITIAL_RADIUS;; radius *= 2) {
31
+ const from = Math.max(row.start, offset - radius);
32
+ const to = Math.min(row.next, offset + radius);
33
+ const found = find(document.textSnapshot.readRange(from, to), offset - from);
34
+ const range = found ? {
35
+ start: from + found.start,
36
+ end: from + found.end
37
+ } : found;
38
+ if (!reachesClippedEdge(range, from, to, row)) return range;
39
+ }
40
+ }
41
+ function reachesClippedEdge(range, from, to, row) {
42
+ if (!range) return false;
43
+ if (range.start <= from && from > row.start) return true;
44
+ return range.end >= to && to < row.next;
45
+ }
46
+ /** Line queries over an LSP document, for a core helper that takes a read source. */
47
+ function textReadSnapshotOf(document) {
48
+ const { lineStarts, textSnapshot } = document;
49
+ const lineStart = (lineIndex) => lineStarts.at(Math.max(0, lineIndex)) ?? textSnapshot.length;
50
+ return {
51
+ length: textSnapshot.length,
52
+ lineCount: Math.max(1, lineStarts.length),
53
+ lineStart,
54
+ lineRange: (lineIndex) => {
55
+ const row = Math.max(0, lineIndex);
56
+ const next = lineStarts.at(row + 1);
57
+ return {
58
+ start: lineStart(row),
59
+ end: next === void 0 ? textSnapshot.length : next - 1
60
+ };
61
+ },
62
+ lineAt: (offset) => lineStarts.indexForOffset(Math.max(0, Math.min(offset, textSnapshot.length))),
63
+ readRange: (start, end) => textSnapshot.readRange(start, end),
64
+ forEachTextChunk: (visit) => textSnapshot.forEachTextChunk(visit)
65
+ };
66
+ }
67
+ //#endregion
68
+ export { characterAt, rangeAroundOffset, rowBounds, textReadSnapshotOf };
69
+
70
+ //# sourceMappingURL=sourceText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceText.js","names":[],"sources":["../src/sourceText.ts"],"sourcesContent":["import type { TextReadSnapshot } from '@singapore-editor/core/document'\nimport type { LspTextDocumentSnapshot } from '@singapore-editor/lsp'\nimport type { OffsetRange } from '@singapore-editor/plugin-ui/offset-range'\n\nconst INITIAL_RADIUS = 256\n\ntype RowBounds = {\n readonly start: number\n /** The row's break, or the document end for the last row. */\n readonly end: number\n /** The next row's start, or the document end: the row with its break. */\n readonly next: number\n}\n\nexport function rowBounds(document: LspTextDocumentSnapshot, offset: number): RowBounds {\n const length = document.textSnapshot.length\n const row = document.lineStarts.indexForOffset(Math.max(0, Math.min(offset, length)))\n const start = document.lineStarts.at(row) ?? 0\n const nextStart = document.lineStarts.at(row + 1)\n if (nextStart === undefined) return { start, end: length, next: length }\n return { start, end: Math.max(start, nextStart - 1), next: nextStart }\n}\n\n/** One code unit, or '' outside the document. */\nexport function characterAt(document: LspTextDocumentSnapshot, offset: number): string {\n if (offset < 0 || offset >= document.textSnapshot.length) return ''\n return document.textSnapshot.readRange(offset, offset + 1)\n}\n\n/**\n * Runs a line-local finder over a window of the row around `offset`, break included, widening it\n * while the answer reaches a clipped edge. Finding a word never copies a long row whole.\n */\nexport function rangeAroundOffset<Found extends OffsetRange | null>(\n document: LspTextDocumentSnapshot,\n offset: number,\n find: (text: string, offset: number) => Found,\n): Found {\n const row = rowBounds(document, offset)\n for (let radius = INITIAL_RADIUS; ; radius *= 2) {\n const from = Math.max(row.start, offset - radius)\n const to = Math.min(row.next, offset + radius)\n const found = find(document.textSnapshot.readRange(from, to), offset - from)\n // Shifting keeps the finder's own null-or-range shape, so a finder that always answers stays so.\n const range = (found ? { start: from + found.start, end: from + found.end } : found) as Found\n if (!reachesClippedEdge(range, from, to, row)) return range\n }\n}\n\nfunction reachesClippedEdge(\n range: OffsetRange | null,\n from: number,\n to: number,\n row: RowBounds,\n): boolean {\n if (!range) return false\n if (range.start <= from && from > row.start) return true\n return range.end >= to && to < row.next\n}\n\n/** Line queries over an LSP document, for a core helper that takes a read source. */\nexport function textReadSnapshotOf(document: LspTextDocumentSnapshot): TextReadSnapshot {\n const { lineStarts, textSnapshot } = document\n const lineStart = (lineIndex: number): number =>\n lineStarts.at(Math.max(0, lineIndex)) ?? textSnapshot.length\n return {\n length: textSnapshot.length,\n lineCount: Math.max(1, lineStarts.length),\n lineStart,\n lineRange: (lineIndex) => {\n const row = Math.max(0, lineIndex)\n const next = lineStarts.at(row + 1)\n return { start: lineStart(row), end: next === undefined ? textSnapshot.length : next - 1 }\n },\n lineAt: (offset) =>\n lineStarts.indexForOffset(Math.max(0, Math.min(offset, textSnapshot.length))),\n readRange: (start, end) => textSnapshot.readRange(start, end),\n forEachTextChunk: (visit) => textSnapshot.forEachTextChunk(visit),\n }\n}\n"],"mappings":";AAIA,IAAM,iBAAiB;AAUvB,SAAgB,UAAU,UAAmC,QAA2B;CACtF,MAAM,SAAS,SAAS,aAAa;CACrC,MAAM,MAAM,SAAS,WAAW,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,MAAM,CAAC,CAAC;CACpF,MAAM,QAAQ,SAAS,WAAW,GAAG,GAAG,KAAK;CAC7C,MAAM,YAAY,SAAS,WAAW,GAAG,MAAM,CAAC;CAChD,IAAI,cAAc,KAAA,GAAW,OAAO;EAAE;EAAO,KAAK;EAAQ,MAAM;CAAO;CACvE,OAAO;EAAE;EAAO,KAAK,KAAK,IAAI,OAAO,YAAY,CAAC;EAAG,MAAM;CAAU;AACvE;;AAGA,SAAgB,YAAY,UAAmC,QAAwB;CACrF,IAAI,SAAS,KAAK,UAAU,SAAS,aAAa,QAAQ,OAAO;CACjE,OAAO,SAAS,aAAa,UAAU,QAAQ,SAAS,CAAC;AAC3D;;;;;AAMA,SAAgB,kBACd,UACA,QACA,MACO;CACP,MAAM,MAAM,UAAU,UAAU,MAAM;CACtC,KAAK,IAAI,SAAS,iBAAkB,UAAU,GAAG;EAC/C,MAAM,OAAO,KAAK,IAAI,IAAI,OAAO,SAAS,MAAM;EAChD,MAAM,KAAK,KAAK,IAAI,IAAI,MAAM,SAAS,MAAM;EAC7C,MAAM,QAAQ,KAAK,SAAS,aAAa,UAAU,MAAM,EAAE,GAAG,SAAS,IAAI;EAE3E,MAAM,QAAS,QAAQ;GAAE,OAAO,OAAO,MAAM;GAAO,KAAK,OAAO,MAAM;EAAI,IAAI;EAC9E,IAAI,CAAC,mBAAmB,OAAO,MAAM,IAAI,GAAG,GAAG,OAAO;CACxD;AACF;AAEA,SAAS,mBACP,OACA,MACA,IACA,KACS;CACT,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI,MAAM,SAAS,QAAQ,OAAO,IAAI,OAAO,OAAO;CACpD,OAAO,MAAM,OAAO,MAAM,KAAK,IAAI;AACrC;;AAGA,SAAgB,mBAAmB,UAAqD;CACtF,MAAM,EAAE,YAAY,iBAAiB;CACrC,MAAM,aAAa,cACjB,WAAW,GAAG,KAAK,IAAI,GAAG,SAAS,CAAC,KAAK,aAAa;CACxD,OAAO;EACL,QAAQ,aAAa;EACrB,WAAW,KAAK,IAAI,GAAG,WAAW,MAAM;EACxC;EACA,YAAY,cAAc;GACxB,MAAM,MAAM,KAAK,IAAI,GAAG,SAAS;GACjC,MAAM,OAAO,WAAW,GAAG,MAAM,CAAC;GAClC,OAAO;IAAE,OAAO,UAAU,GAAG;IAAG,KAAK,SAAS,KAAA,IAAY,aAAa,SAAS,OAAO;GAAE;EAC3F;EACA,SAAS,WACP,WAAW,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,QAAQ,aAAa,MAAM,CAAC,CAAC;EAC9E,YAAY,OAAO,QAAQ,aAAa,UAAU,OAAO,GAAG;EAC5D,mBAAmB,UAAU,aAAa,iBAAiB,KAAK;CAClE;AACF"}
@@ -0,0 +1,238 @@
1
+ import type { TooltipAction } from '@singapore-editor/plugin-ui/tooltip';
2
+ import type { LanguageServerDocument } from './document';
3
+ import type { DocumentLogicalRevisionScope } from '@singapore-editor/core/document';
4
+ import type { EditorDisposable, EditorPlugin, EditorTextAnchor, EditorViewSnapshot } from '@singapore-editor/core/extensions';
5
+ import type { LspClient, LspNotificationHandler, LspServerRequestHandler, LspWebSocketTransportOptions } from '@singapore-editor/lsp';
6
+ import type * as lsp from 'vscode-languageserver-protocol';
7
+ import type { LanguageServerConnectionContext } from './connectionContext';
8
+ import type { LanguageServerDocumentSyncController } from './documentSyncController';
9
+ import type { LspConnectionProvider, LspReconnectOptions } from './lspConnection';
10
+ import type { ParsedWorkspaceEdit } from './workspaceEdit';
11
+ import type { WorkspaceTextDocumentProvenance } from './workspaceTextEdits';
12
+ export type { LanguageServerConnectionContext } from './connectionContext';
13
+ import type { LanguageServerSemanticTokensFactory, LanguageServerSemanticTokensOptions } from './semanticTokens';
14
+ export type LanguageServerStatus = 'idle' | 'loading' | 'ready' | 'error';
15
+ export declare const LANGUAGE_SERVER_FEATURE_IDS: readonly ["completion", "hover", "navigation", "signatureHelp", "diagnostics", "codeActions", "formatting", "rename", "documentHighlights", "semanticTokens"];
16
+ export type LanguageServerFeatureId = (typeof LANGUAGE_SERVER_FEATURE_IDS)[number];
17
+ export type LanguageServerFeatureRanks = Partial<Readonly<Record<LanguageServerFeatureId, number>>>;
18
+ export type LanguageServerReadyNotification = {
19
+ readonly method: string;
20
+ readonly params: unknown;
21
+ };
22
+ export type LanguageServerDiagnosticCounts = {
23
+ readonly error: number;
24
+ readonly warning: number;
25
+ readonly information: number;
26
+ readonly hint: number;
27
+ readonly total: number;
28
+ };
29
+ /**
30
+ * How far a summary's diagnostics can be trusted, so an empty list is never mistaken for a clean
31
+ * file. `awaiting`: a first result is being asked for. `refreshing`: a result is shown and a newer
32
+ * one is being asked for. `current`: nothing is pending. `silent`: the server has said nothing and
33
+ * nothing is pending — a push-only server may never publish, so this never waits. `unavailable`:
34
+ * the connection is gone and what was shown was cleared.
35
+ */
36
+ export type LanguageServerDiagnosticsFreshness = 'awaiting' | 'refreshing' | 'current' | 'silent' | 'unavailable';
37
+ export type LanguageServerDiagnosticSummary = {
38
+ readonly uri: lsp.DocumentUri | null;
39
+ readonly version: number | null;
40
+ readonly diagnostics: readonly lsp.Diagnostic[];
41
+ readonly counts: LanguageServerDiagnosticCounts;
42
+ readonly freshness: LanguageServerDiagnosticsFreshness;
43
+ };
44
+ export type LanguageServerDiagnosticMarkerEvent = {
45
+ readonly direction: 'next' | 'previous';
46
+ readonly diagnostic: lsp.Diagnostic;
47
+ readonly documentUri: lsp.DocumentUri;
48
+ readonly textVersion: number;
49
+ readonly anchor: EditorTextAnchor;
50
+ };
51
+ export type LanguageServerDiagnosticMarkerClaim = {
52
+ readonly kind: 'claimed';
53
+ dispose(): void;
54
+ } | {
55
+ readonly kind: 'ignored';
56
+ };
57
+ export type LanguageServerDefinitionTarget = {
58
+ readonly uri: lsp.DocumentUri;
59
+ readonly path: string;
60
+ readonly range: lsp.Range;
61
+ };
62
+ export type LanguageServerNavigationKind = 'definition' | 'references' | 'implementation' | 'typeDefinition';
63
+ export type LanguageServerNavigationOpenMode = 'default' | 'peek' | 'aside';
64
+ export type LanguageServerNavigationOptions = {
65
+ readonly kind: LanguageServerNavigationKind;
66
+ readonly openMode: LanguageServerNavigationOpenMode;
67
+ };
68
+ export type LanguageServerReferencesResult = {
69
+ readonly uri: lsp.DocumentUri;
70
+ readonly targets: readonly LanguageServerDefinitionTarget[];
71
+ };
72
+ export type LanguageServerDocumentSnapshot = Pick<EditorViewSnapshot, 'documentId' | 'languageId' | 'textSnapshot' | 'textVersion' | 'documentSyncPoint' | 'changesSinceDocumentSyncPoint' | 'lineStarts' | 'lineStartsView'>;
73
+ export type LanguageServerDocumentSyncOptions = {
74
+ /** Projects a live path transition before deferred view publication catches up. */
75
+ readonly controller?: LanguageServerDocumentSyncController;
76
+ /** Resolves opaque editor identities to protocol URIs. Returning null disables synchronization. */
77
+ uriForDocument?(snapshot: LanguageServerDocumentSnapshot): lsp.DocumentUri | null;
78
+ /**
79
+ * The language id sent to the server when the editor and protocol use different names.
80
+ * Returning undefined keeps the editor's id.
81
+ */
82
+ languageIdForDocument?(languageId: string, uri: lsp.DocumentUri): string | undefined;
83
+ shouldSyncLanguageId?(languageId: string, snapshot: LanguageServerDocumentSnapshot): boolean;
84
+ shouldSyncUri?(uri: lsp.DocumentUri, snapshot: LanguageServerDocumentSnapshot): boolean;
85
+ };
86
+ export type { WorkspaceTextDocumentProvenance } from './workspaceTextEdits';
87
+ export type WorkspaceEditOriginGuard = {
88
+ readonly documents: readonly WorkspaceTextDocumentProvenance[];
89
+ isCurrent(uri: string): boolean;
90
+ };
91
+ export type ApplyWorkspaceEditRequest = {
92
+ readonly guard: WorkspaceEditOriginGuard;
93
+ readonly label: string;
94
+ readonly logicalRevisionScope: DocumentLogicalRevisionScope;
95
+ readonly originUri: string;
96
+ readonly originVersion: number;
97
+ readonly plan: ParsedWorkspaceEdit;
98
+ readonly serverId: string;
99
+ readonly signal: AbortSignal;
100
+ readonly source: 'code-action' | 'rename';
101
+ };
102
+ export type ApplyWorkspaceEditResult = {
103
+ readonly status: 'applied';
104
+ } | {
105
+ readonly status: 'cancelled';
106
+ } | {
107
+ readonly code: string;
108
+ readonly message: string;
109
+ readonly status: 'failed';
110
+ } | {
111
+ readonly code: string;
112
+ readonly message: string;
113
+ readonly status: 'rolled-back';
114
+ } | {
115
+ readonly affectedPaths: readonly string[];
116
+ readonly code: string;
117
+ readonly message: string;
118
+ readonly status: 'recovery-required';
119
+ };
120
+ export type OnApplyWorkspaceEdit = (request: ApplyWorkspaceEditRequest) => Promise<ApplyWorkspaceEditResult>;
121
+ export type LanguageServerLaneHostOptions = {
122
+ readonly onApplyWorkspaceEdit?: OnApplyWorkspaceEdit;
123
+ };
124
+ export type LanguageServerRenamePrompt = {
125
+ readonly anchor: DOMRect;
126
+ readonly currentName: string;
127
+ readonly signal: AbortSignal;
128
+ };
129
+ export type LanguageServerDiagnosticActionContext = {
130
+ readonly documentUri: lsp.DocumentUri;
131
+ readonly textVersion: number;
132
+ readonly diagnostic: lsp.Diagnostic;
133
+ };
134
+ export type LanguageServerDiagnosticActions = (context: LanguageServerDiagnosticActionContext) => readonly TooltipAction[];
135
+ export type LanguageServerPluginOptions = LanguageServerLaneHostOptions & {
136
+ readonly rootUri?: lsp.DocumentUri | null;
137
+ readonly initializationOptions?: unknown;
138
+ readonly timeoutMs?: number;
139
+ /**
140
+ * Merged over `defaultClientCapabilities()`, so a host declares only what it adds. Build a
141
+ * semantic-tokens block with `semanticTokensClientCapability()` from `@singapore-editor/lsp` rather than
142
+ * by hand: it refuses the flags this editor cannot honour, each of which a real server acts on.
143
+ */
144
+ readonly capabilities?: lsp.ClientCapabilities;
145
+ /** At least one real server branches on this. The value is the host's to pick. */
146
+ readonly clientInfo?: lsp.InitializeParams['clientInfo'];
147
+ /**
148
+ * Merged around the plugin's own handlers. An entry for `textDocument/publishDiagnostics` runs
149
+ * after the plugin's and cannot displace it, because the diagnostics feature hangs off it.
150
+ */
151
+ readonly notificationHandlers?: Readonly<Record<string, LspNotificationHandler<LspClient>>>;
152
+ /**
153
+ * Answers requests the server sends the client, such as a server asking the host for files.
154
+ * A method the plugin answers itself (`workspace/diagnostic/refresh`) stays the plugin's.
155
+ */
156
+ readonly serverRequestHandlers?: Readonly<Record<string, LspServerRequestHandler<LspClient>>>;
157
+ /** Which documents reach the server, and under what language id. */
158
+ readonly documentSync?: LanguageServerDocumentSyncOptions;
159
+ readonly webSocketRoute: string | URL;
160
+ readonly webSocketTransportOptions?: LspWebSocketTransportOptions;
161
+ /**
162
+ * Borrows the connection rather than owning one per view, so a file switch that rebuilds the view
163
+ * does not also rebuild the websocket and re-run `initialize`. The route and options above still
164
+ * describe the connection — the provider is handed them and builds from them the first time it
165
+ * sees a key. See `LspConnectionProvider`.
166
+ */
167
+ readonly connectionProvider?: LspConnectionProvider;
168
+ /**
169
+ * Turns on the semantic token layer, and is how the host gets hold of one: a layer needs a
170
+ * viewport, a snapshot and a lifecycle, so the contribution creates it and hands it over through
171
+ * `onLayer`. Supplying nothing creates no layer and fires no demand signal.
172
+ */
173
+ readonly semanticTokens?: LanguageServerSemanticTokensOptions;
174
+ /**
175
+ * Hands the host the connection the moment it exists, which is the only way to reach the
176
+ * `LspClient` — and therefore the only way to issue a request, override the timeout for one, or
177
+ * cancel one. Returning a disposable ties the host's own controller to the connection's life.
178
+ */
179
+ onConnectionCreated?(context: LanguageServerConnectionContext): EditorDisposable | void;
180
+ /** The same context again, once `initialize` has come back and server capabilities are known. */
181
+ onConnected?(context: LanguageServerConnectionContext): void;
182
+ readonly onStatusChange?: (status: LanguageServerStatus) => void;
183
+ readonly onDiagnostics?: (summary: LanguageServerDiagnosticSummary) => void;
184
+ readonly getDiagnosticActions?: LanguageServerDiagnosticActions;
185
+ readonly onDidNavigateDiagnostic?: (event: LanguageServerDiagnosticMarkerEvent) => LanguageServerDiagnosticMarkerClaim;
186
+ readonly onInteractiveReady?: () => void;
187
+ readonly onRequestError?: (serverId: string, method: string, error: unknown) => void;
188
+ /** Reports the selected destination when Ctrl/Cmd-hover renders a jumpable link. */
189
+ readonly onDefinitionLinkHover?: (target: LanguageServerDefinitionTarget) => void;
190
+ readonly onOpenDefinition?: (target: LanguageServerDefinitionTarget, options?: LanguageServerNavigationOptions) => void | boolean;
191
+ readonly onOpenReferences?: (result: LanguageServerReferencesResult) => void | boolean;
192
+ readonly onError?: (error: unknown) => void;
193
+ };
194
+ export type LanguageServerLaneOptions = LanguageServerLaneHostOptions & {
195
+ readonly id: string;
196
+ readonly features: LanguageServerFeatureRanks;
197
+ readonly rootUri?: lsp.DocumentUri | null;
198
+ readonly initializationOptions?: unknown;
199
+ readonly timeoutMs?: number;
200
+ readonly capabilities?: lsp.ClientCapabilities;
201
+ readonly clientInfo?: lsp.InitializeParams['clientInfo'];
202
+ readonly notificationHandlers?: Readonly<Record<string, LspNotificationHandler<LspClient>>>;
203
+ readonly serverRequestHandlers?: Readonly<Record<string, LspServerRequestHandler<LspClient>>>;
204
+ readonly webSocketRoute: string | URL;
205
+ readonly webSocketTransportOptions?: LspWebSocketTransportOptions;
206
+ readonly connectionProvider?: LspConnectionProvider;
207
+ /** Reconnects after the server goes away on its own; off unless given. */
208
+ readonly reconnect?: LspReconnectOptions;
209
+ readonly readyNotifications?: readonly LanguageServerReadyNotification[];
210
+ onConnectionCreated?(context: LanguageServerConnectionContext): EditorDisposable | void;
211
+ onConnected?(context: LanguageServerConnectionContext): void;
212
+ readonly onStatusChange?: (status: LanguageServerStatus) => void;
213
+ readonly onDiagnostics?: (summary: LanguageServerDiagnosticSummary) => void;
214
+ readonly onInteractiveReady?: () => void;
215
+ readonly onRequestError?: (method: string, error: unknown) => void;
216
+ readonly onError?: (error: unknown) => void;
217
+ };
218
+ export type LanguageServerSetPluginOptions = Pick<LanguageServerPluginOptions, 'onDiagnostics' | 'onDidNavigateDiagnostic' | 'getDiagnosticActions' | 'onInteractiveReady' | 'onRequestError' | 'onDefinitionLinkHover' | 'onOpenDefinition' | 'onOpenReferences' | 'onError'> & {
219
+ readonly semanticTokens?: LanguageServerSemanticTokensFactory;
220
+ } & ({
221
+ readonly lanes: readonly LanguageServerLaneOptions[];
222
+ readonly document?: never;
223
+ readonly documentSync?: LanguageServerDocumentSyncOptions;
224
+ readonly onApplyWorkspaceEdit?: OnApplyWorkspaceEdit;
225
+ } | {
226
+ readonly document: LanguageServerDocument;
227
+ readonly lanes?: never;
228
+ readonly documentSync?: never;
229
+ readonly onApplyWorkspaceEdit?: never;
230
+ });
231
+ export type LanguageServerDocumentPluginOptions = Omit<Extract<LanguageServerSetPluginOptions, {
232
+ readonly document: LanguageServerDocument;
233
+ }>, 'lanes' | 'document'> & {
234
+ readonly document: LanguageServerDocument;
235
+ readonly webSocketRoute?: never;
236
+ };
237
+ export type LanguageServerPlugin = EditorPlugin;
238
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,17 @@
1
+ //#region src/types.ts
2
+ var LANGUAGE_SERVER_FEATURE_IDS = [
3
+ "completion",
4
+ "hover",
5
+ "navigation",
6
+ "signatureHelp",
7
+ "diagnostics",
8
+ "codeActions",
9
+ "formatting",
10
+ "rename",
11
+ "documentHighlights",
12
+ "semanticTokens"
13
+ ];
14
+ //#endregion
15
+ export { LANGUAGE_SERVER_FEATURE_IDS };
16
+
17
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../src/types.ts"],"sourcesContent":["import type { TooltipAction } from '@singapore-editor/plugin-ui/tooltip'\nimport type { LanguageServerDocument } from './document'\nimport type { DocumentLogicalRevisionScope } from '@singapore-editor/core/document'\nimport type {\n EditorDisposable,\n EditorPlugin,\n EditorTextAnchor,\n EditorViewSnapshot,\n} from '@singapore-editor/core/extensions'\nimport type {\n LspClient,\n LspNotificationHandler,\n LspServerRequestHandler,\n LspWebSocketTransportOptions,\n} from '@singapore-editor/lsp'\nimport type * as lsp from 'vscode-languageserver-protocol'\n\nimport type { LanguageServerConnectionContext } from './connectionContext'\nimport type { LanguageServerDocumentSyncController } from './documentSyncController'\nimport type { LspConnectionProvider, LspReconnectOptions } from './lspConnection'\nimport type { ParsedWorkspaceEdit } from './workspaceEdit'\nimport type { WorkspaceTextDocumentProvenance } from './workspaceTextEdits'\nexport type { LanguageServerConnectionContext } from './connectionContext'\nimport type {\n LanguageServerSemanticTokensFactory,\n LanguageServerSemanticTokensOptions,\n} from './semanticTokens'\n\nexport type LanguageServerStatus = 'idle' | 'loading' | 'ready' | 'error'\n\nexport const LANGUAGE_SERVER_FEATURE_IDS = [\n 'completion',\n 'hover',\n 'navigation',\n 'signatureHelp',\n 'diagnostics',\n 'codeActions',\n 'formatting',\n 'rename',\n 'documentHighlights',\n 'semanticTokens',\n] as const\n\nexport type LanguageServerFeatureId = (typeof LANGUAGE_SERVER_FEATURE_IDS)[number]\n\nexport type LanguageServerFeatureRanks = Partial<Readonly<Record<LanguageServerFeatureId, number>>>\n\nexport type LanguageServerReadyNotification = {\n readonly method: string\n readonly params: unknown\n}\n\nexport type LanguageServerDiagnosticCounts = {\n readonly error: number\n readonly warning: number\n readonly information: number\n readonly hint: number\n readonly total: number\n}\n\n/**\n * How far a summary's diagnostics can be trusted, so an empty list is never mistaken for a clean\n * file. `awaiting`: a first result is being asked for. `refreshing`: a result is shown and a newer\n * one is being asked for. `current`: nothing is pending. `silent`: the server has said nothing and\n * nothing is pending — a push-only server may never publish, so this never waits. `unavailable`:\n * the connection is gone and what was shown was cleared.\n */\nexport type LanguageServerDiagnosticsFreshness =\n | 'awaiting'\n | 'refreshing'\n | 'current'\n | 'silent'\n | 'unavailable'\n\nexport type LanguageServerDiagnosticSummary = {\n readonly uri: lsp.DocumentUri | null\n readonly version: number | null\n readonly diagnostics: readonly lsp.Diagnostic[]\n readonly counts: LanguageServerDiagnosticCounts\n readonly freshness: LanguageServerDiagnosticsFreshness\n}\n\nexport type LanguageServerDiagnosticMarkerEvent = {\n readonly direction: 'next' | 'previous'\n readonly diagnostic: lsp.Diagnostic\n readonly documentUri: lsp.DocumentUri\n readonly textVersion: number\n readonly anchor: EditorTextAnchor\n}\n\nexport type LanguageServerDiagnosticMarkerClaim =\n | { readonly kind: 'claimed'; dispose(): void }\n | { readonly kind: 'ignored' }\n\nexport type LanguageServerDefinitionTarget = {\n readonly uri: lsp.DocumentUri\n readonly path: string\n readonly range: lsp.Range\n}\n\nexport type LanguageServerNavigationKind =\n | 'definition'\n | 'references'\n | 'implementation'\n | 'typeDefinition'\n\nexport type LanguageServerNavigationOpenMode = 'default' | 'peek' | 'aside'\n\nexport type LanguageServerNavigationOptions = {\n readonly kind: LanguageServerNavigationKind\n readonly openMode: LanguageServerNavigationOpenMode\n}\n\nexport type LanguageServerReferencesResult = {\n readonly uri: lsp.DocumentUri\n readonly targets: readonly LanguageServerDefinitionTarget[]\n}\n\nexport type LanguageServerDocumentSnapshot = Pick<\n EditorViewSnapshot,\n | 'documentId'\n | 'languageId'\n | 'textSnapshot'\n | 'textVersion'\n | 'documentSyncPoint'\n | 'changesSinceDocumentSyncPoint'\n | 'lineStarts'\n | 'lineStartsView'\n>\n\nexport type LanguageServerDocumentSyncOptions = {\n /** Projects a live path transition before deferred view publication catches up. */\n readonly controller?: LanguageServerDocumentSyncController\n /** Resolves opaque editor identities to protocol URIs. Returning null disables synchronization. */\n uriForDocument?(snapshot: LanguageServerDocumentSnapshot): lsp.DocumentUri | null\n /**\n * The language id sent to the server when the editor and protocol use different names.\n * Returning undefined keeps the editor's id.\n */\n languageIdForDocument?(languageId: string, uri: lsp.DocumentUri): string | undefined\n shouldSyncLanguageId?(languageId: string, snapshot: LanguageServerDocumentSnapshot): boolean\n shouldSyncUri?(uri: lsp.DocumentUri, snapshot: LanguageServerDocumentSnapshot): boolean\n}\n\nexport type { WorkspaceTextDocumentProvenance } from './workspaceTextEdits'\n\nexport type WorkspaceEditOriginGuard = {\n readonly documents: readonly WorkspaceTextDocumentProvenance[]\n isCurrent(uri: string): boolean\n}\n\nexport type ApplyWorkspaceEditRequest = {\n readonly guard: WorkspaceEditOriginGuard\n readonly label: string\n readonly logicalRevisionScope: DocumentLogicalRevisionScope\n readonly originUri: string\n readonly originVersion: number\n readonly plan: ParsedWorkspaceEdit\n readonly serverId: string\n readonly signal: AbortSignal\n readonly source: 'code-action' | 'rename'\n}\n\nexport type ApplyWorkspaceEditResult =\n | { readonly status: 'applied' }\n | { readonly status: 'cancelled' }\n | { readonly code: string; readonly message: string; readonly status: 'failed' }\n | { readonly code: string; readonly message: string; readonly status: 'rolled-back' }\n | {\n readonly affectedPaths: readonly string[]\n readonly code: string\n readonly message: string\n readonly status: 'recovery-required'\n }\n\nexport type OnApplyWorkspaceEdit = (\n request: ApplyWorkspaceEditRequest,\n) => Promise<ApplyWorkspaceEditResult>\n\nexport type LanguageServerLaneHostOptions = {\n readonly onApplyWorkspaceEdit?: OnApplyWorkspaceEdit\n}\n\nexport type LanguageServerRenamePrompt = {\n readonly anchor: DOMRect\n readonly currentName: string\n readonly signal: AbortSignal\n}\n\nexport type LanguageServerDiagnosticActionContext = {\n readonly documentUri: lsp.DocumentUri\n readonly textVersion: number\n readonly diagnostic: lsp.Diagnostic\n}\n\nexport type LanguageServerDiagnosticActions = (\n context: LanguageServerDiagnosticActionContext,\n) => readonly TooltipAction[]\n\nexport type LanguageServerPluginOptions = LanguageServerLaneHostOptions & {\n readonly rootUri?: lsp.DocumentUri | null\n readonly initializationOptions?: unknown\n readonly timeoutMs?: number\n /**\n * Merged over `defaultClientCapabilities()`, so a host declares only what it adds. Build a\n * semantic-tokens block with `semanticTokensClientCapability()` from `@singapore-editor/lsp` rather than\n * by hand: it refuses the flags this editor cannot honour, each of which a real server acts on.\n */\n readonly capabilities?: lsp.ClientCapabilities\n /** At least one real server branches on this. The value is the host's to pick. */\n readonly clientInfo?: lsp.InitializeParams['clientInfo']\n /**\n * Merged around the plugin's own handlers. An entry for `textDocument/publishDiagnostics` runs\n * after the plugin's and cannot displace it, because the diagnostics feature hangs off it.\n */\n readonly notificationHandlers?: Readonly<Record<string, LspNotificationHandler<LspClient>>>\n /**\n * Answers requests the server sends the client, such as a server asking the host for files.\n * A method the plugin answers itself (`workspace/diagnostic/refresh`) stays the plugin's.\n */\n readonly serverRequestHandlers?: Readonly<Record<string, LspServerRequestHandler<LspClient>>>\n /** Which documents reach the server, and under what language id. */\n readonly documentSync?: LanguageServerDocumentSyncOptions\n readonly webSocketRoute: string | URL\n readonly webSocketTransportOptions?: LspWebSocketTransportOptions\n /**\n * Borrows the connection rather than owning one per view, so a file switch that rebuilds the view\n * does not also rebuild the websocket and re-run `initialize`. The route and options above still\n * describe the connection — the provider is handed them and builds from them the first time it\n * sees a key. See `LspConnectionProvider`.\n */\n readonly connectionProvider?: LspConnectionProvider\n /**\n * Turns on the semantic token layer, and is how the host gets hold of one: a layer needs a\n * viewport, a snapshot and a lifecycle, so the contribution creates it and hands it over through\n * `onLayer`. Supplying nothing creates no layer and fires no demand signal.\n */\n readonly semanticTokens?: LanguageServerSemanticTokensOptions\n /**\n * Hands the host the connection the moment it exists, which is the only way to reach the\n * `LspClient` — and therefore the only way to issue a request, override the timeout for one, or\n * cancel one. Returning a disposable ties the host's own controller to the connection's life.\n */\n onConnectionCreated?(context: LanguageServerConnectionContext): EditorDisposable | void\n /** The same context again, once `initialize` has come back and server capabilities are known. */\n onConnected?(context: LanguageServerConnectionContext): void\n readonly onStatusChange?: (status: LanguageServerStatus) => void\n readonly onDiagnostics?: (summary: LanguageServerDiagnosticSummary) => void\n readonly getDiagnosticActions?: LanguageServerDiagnosticActions\n readonly onDidNavigateDiagnostic?: (\n event: LanguageServerDiagnosticMarkerEvent,\n ) => LanguageServerDiagnosticMarkerClaim\n readonly onInteractiveReady?: () => void\n readonly onRequestError?: (serverId: string, method: string, error: unknown) => void\n /** Reports the selected destination when Ctrl/Cmd-hover renders a jumpable link. */\n readonly onDefinitionLinkHover?: (target: LanguageServerDefinitionTarget) => void\n readonly onOpenDefinition?: (\n target: LanguageServerDefinitionTarget,\n options?: LanguageServerNavigationOptions,\n ) => void | boolean\n readonly onOpenReferences?: (result: LanguageServerReferencesResult) => void | boolean\n readonly onError?: (error: unknown) => void\n}\n\nexport type LanguageServerLaneOptions = LanguageServerLaneHostOptions & {\n readonly id: string\n readonly features: LanguageServerFeatureRanks\n readonly rootUri?: lsp.DocumentUri | null\n readonly initializationOptions?: unknown\n readonly timeoutMs?: number\n readonly capabilities?: lsp.ClientCapabilities\n readonly clientInfo?: lsp.InitializeParams['clientInfo']\n readonly notificationHandlers?: Readonly<Record<string, LspNotificationHandler<LspClient>>>\n readonly serverRequestHandlers?: Readonly<Record<string, LspServerRequestHandler<LspClient>>>\n readonly webSocketRoute: string | URL\n readonly webSocketTransportOptions?: LspWebSocketTransportOptions\n readonly connectionProvider?: LspConnectionProvider\n /** Reconnects after the server goes away on its own; off unless given. */\n readonly reconnect?: LspReconnectOptions\n readonly readyNotifications?: readonly LanguageServerReadyNotification[]\n onConnectionCreated?(context: LanguageServerConnectionContext): EditorDisposable | void\n onConnected?(context: LanguageServerConnectionContext): void\n readonly onStatusChange?: (status: LanguageServerStatus) => void\n readonly onDiagnostics?: (summary: LanguageServerDiagnosticSummary) => void\n readonly onInteractiveReady?: () => void\n readonly onRequestError?: (method: string, error: unknown) => void\n readonly onError?: (error: unknown) => void\n}\n\nexport type LanguageServerSetPluginOptions = Pick<\n LanguageServerPluginOptions,\n | 'onDiagnostics'\n | 'onDidNavigateDiagnostic'\n | 'getDiagnosticActions'\n | 'onInteractiveReady'\n | 'onRequestError'\n | 'onDefinitionLinkHover'\n | 'onOpenDefinition'\n | 'onOpenReferences'\n | 'onError'\n> & {\n readonly semanticTokens?: LanguageServerSemanticTokensFactory\n} & (\n | {\n readonly lanes: readonly LanguageServerLaneOptions[]\n readonly document?: never\n readonly documentSync?: LanguageServerDocumentSyncOptions\n readonly onApplyWorkspaceEdit?: OnApplyWorkspaceEdit\n }\n | {\n readonly document: LanguageServerDocument\n readonly lanes?: never\n readonly documentSync?: never\n readonly onApplyWorkspaceEdit?: never\n }\n )\n\nexport type LanguageServerDocumentPluginOptions = Omit<\n Extract<LanguageServerSetPluginOptions, { readonly document: LanguageServerDocument }>,\n 'lanes' | 'document'\n> & {\n readonly document: LanguageServerDocument\n readonly webSocketRoute?: never\n}\n\nexport type LanguageServerPlugin = EditorPlugin\n"],"mappings":";AA8BA,IAAa,8BAA8B;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
@@ -0,0 +1,5 @@
1
+ import type { LanguageServerDocumentSnapshot } from './types';
2
+ import type { LspTextDocumentSnapshot } from '@singapore-editor/lsp';
3
+ /** The view's text and line-start index as an LSP document snapshot, so nothing rescans the text. */
4
+ export declare function viewDocumentSnapshot(snapshot: LanguageServerDocumentSnapshot): LspTextDocumentSnapshot;
5
+ //# sourceMappingURL=viewDocumentSnapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewDocumentSnapshot.d.ts","sourceRoot":"","sources":["../src/viewDocumentSnapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,SAAS,CAAA;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AAEpE,qGAAqG;AACrG,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,8BAA8B,GACvC,uBAAuB,CAKzB"}
@@ -0,0 +1,12 @@
1
+ //#region src/viewDocumentSnapshot.ts
2
+ /** The view's text and line-start index as an LSP document snapshot, so nothing rescans the text. */
3
+ function viewDocumentSnapshot(snapshot) {
4
+ return {
5
+ textSnapshot: snapshot.textSnapshot,
6
+ lineStarts: snapshot.lineStartsView
7
+ };
8
+ }
9
+ //#endregion
10
+ export { viewDocumentSnapshot };
11
+
12
+ //# sourceMappingURL=viewDocumentSnapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewDocumentSnapshot.js","names":[],"sources":["../src/viewDocumentSnapshot.ts"],"sourcesContent":["import type { LanguageServerDocumentSnapshot } from './types'\nimport type { LspTextDocumentSnapshot } from '@singapore-editor/lsp'\n\n/** The view's text and line-start index as an LSP document snapshot, so nothing rescans the text. */\nexport function viewDocumentSnapshot(\n snapshot: LanguageServerDocumentSnapshot,\n): LspTextDocumentSnapshot {\n return {\n textSnapshot: snapshot.textSnapshot,\n lineStarts: snapshot.lineStartsView,\n }\n}\n"],"mappings":";;AAIA,SAAgB,qBACd,UACyB;CACzB,OAAO;EACL,cAAc,SAAS;EACvB,YAAY,SAAS;CACvB;AACF"}
@@ -0,0 +1,6 @@
1
+ export { createLanguageServerDocument, LanguageServerDocument, type LanguageServerDocumentOptions, } from './document';
2
+ export type { LanguageServerDocumentPluginOptions, LanguageServerDocumentSnapshot } from './types';
3
+ export { createLanguageServerPlugin, createLanguageServerSetPlugin, type LanguageServerResolvedOptions, } from './plugin';
4
+ export { acquireLanguageServerLane, type AcquiredLanguageServerLane } from './lane';
5
+ export type { LanguageServerDefinitionTarget, LanguageServerDiagnosticSummary, LanguageServerDiagnosticsFreshness, LanguageServerPlugin, LanguageServerLaneOptions, LanguageServerPluginOptions, LanguageServerSetPluginOptions, LanguageServerStatus, } from './types';
6
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,sBAAsB,EACtB,KAAK,6BAA6B,GACnC,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,mCAAmC,EAAE,8BAA8B,EAAE,MAAM,SAAS,CAAA;AAClG,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,6BAA6B,GACnC,MAAM,UAAU,CAAA;AACjB,OAAO,EAAE,yBAAyB,EAAE,KAAK,0BAA0B,EAAE,MAAM,QAAQ,CAAA;AACnF,YAAY,EACV,8BAA8B,EAC9B,+BAA+B,EAC/B,kCAAkC,EAClC,oBAAoB,EACpB,yBAAyB,EACzB,2BAA2B,EAC3B,8BAA8B,EAC9B,oBAAoB,GACrB,MAAM,SAAS,CAAA"}