@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,216 @@
1
+ //#region src/fuzzyMatch.ts
2
+ var MAX_PATTERN_LENGTH = 64;
3
+ var MAX_CANDIDATE_LENGTH = 128;
4
+ /** How many leading pattern characters a loose match may give up before it stops trying. */
5
+ var MAX_LOOSE_ATTEMPTS = 13;
6
+ var NO_MATCH = Number.MIN_SAFE_INTEGER;
7
+ /** A character where the user's typing meets the candidate's own structure. */
8
+ var POSITION_PREFIX = 0;
9
+ var POSITION_CAMEL = 1;
10
+ var POSITION_SEPARATOR = 2;
11
+ var POSITION_AFTER_SEPARATOR = 3;
12
+ var POSITION_INSIDE_WORD = 4;
13
+ var STEP_MATCH = 1;
14
+ var STEP_SKIP_ONE = 2;
15
+ var STEP_SKIP_TWO = 3;
16
+ var TABLE_COLUMNS = 129;
17
+ var TABLE_CELLS = 8385;
18
+ var cellScores = new Int32Array(TABLE_CELLS);
19
+ var cellRunLengths = new Int32Array(TABLE_CELLS);
20
+ var cellSteps = new Uint8Array(TABLE_CELLS);
21
+ var earliestPositions = new Int32Array(MAX_PATTERN_LENGTH);
22
+ var latestPositions = new Int32Array(MAX_PATTERN_LENGTH);
23
+ /** Where a candidate visibly breaks, and so where a match may resume without reading as scattered. */
24
+ var SEPARATORS = /* @__PURE__ */ new Set("_-. /\\'\":$<>()[]{}#@");
25
+ /**
26
+ * The match of the whole pattern, or null when there is none.
27
+ *
28
+ * The first character has to land somewhere the candidate begins something — its start, a camel-case
29
+ * hump, the far side of a separator. A pattern that only turns up in the middle of a word is a
30
+ * coincidence rather than what the user was reaching for.
31
+ */
32
+ function fuzzyMatch(pattern, candidate) {
33
+ return matchFrom(pattern, pattern.toLowerCase(), 0, candidate, candidate.toLowerCase(), false);
34
+ }
35
+ /**
36
+ * The match of the pattern, or of what is left of it after dropping leading characters, at any
37
+ * alignment at all.
38
+ *
39
+ * For a string the pattern was never ranked against there is no reason for all of it to be present,
40
+ * and marking the part that is beats marking nothing.
41
+ */
42
+ function looseFuzzyMatch(pattern, candidate) {
43
+ const patternLow = pattern.toLowerCase();
44
+ const candidateLow = candidate.toLowerCase();
45
+ const attempts = Math.min(pattern.length, MAX_LOOSE_ATTEMPTS);
46
+ for (let start = 0; start < attempts; start += 1) {
47
+ const match = matchFrom(pattern, patternLow, start, candidate, candidateLow, true);
48
+ if (match) return match;
49
+ }
50
+ return null;
51
+ }
52
+ function matchFrom(pattern, patternLow, patternStart, candidate, candidateLow, allowWeakStart) {
53
+ const patternEnd = Math.min(pattern.length, MAX_PATTERN_LENGTH);
54
+ const candidateEnd = Math.min(candidate.length, MAX_CANDIDATE_LENGTH);
55
+ const patternLength = patternEnd - patternStart;
56
+ if (patternLength <= 0 || patternLength > candidateEnd) return null;
57
+ if (!fillEarliestPositions(patternLow, patternStart, patternEnd, candidateLow, candidateEnd)) return null;
58
+ fillLatestPositions(patternLow, patternStart, patternEnd, candidateLow, candidateEnd);
59
+ let startsAtBoundary = false;
60
+ for (let patternPos = patternStart, row = 1; patternPos < patternEnd; patternPos += 1, row += 1) {
61
+ const earliest = earliestPositions[patternPos] ?? 0;
62
+ const latest = latestPositions[patternPos] ?? 0;
63
+ const rowEnd = patternPos + 1 < patternEnd ? latestPositions[patternPos + 1] ?? 0 : candidateEnd;
64
+ const isFirst = patternPos === patternStart;
65
+ for (let position = earliest; position < rowEnd; position += 1) {
66
+ const cell = row * TABLE_COLUMNS + position + 1;
67
+ const diagonal = cell - TABLE_COLUMNS - 1;
68
+ let matched = NO_MATCH;
69
+ if (position <= latest && patternLow[patternPos] === candidateLow[position]) {
70
+ const kind = positionKind(candidate, candidateLow, position, patternPos - patternStart);
71
+ matched = characterScore(kind, isGapPosition(kind, candidate, candidateLow, position), pattern[patternPos] === candidate[position], isFirst, position, candidateEnd, (cellRunLengths[diagonal] ?? 0) === 0);
72
+ if (isFirst && kind !== POSITION_INSIDE_WORD) startsAtBoundary = true;
73
+ }
74
+ const matchScore = matched === NO_MATCH ? 0 : matched + (cellScores[diagonal] ?? 0);
75
+ const canSkipOne = position > earliest;
76
+ const skipOneScore = canSkipOne ? (cellScores[cell - 1] ?? 0) - gapStartPenalty(cell - 1) : 0;
77
+ const canSkipTwo = position > earliest + 1 && (cellRunLengths[cell - 1] ?? 0) > 0;
78
+ const skipTwoScore = canSkipTwo ? (cellScores[cell - 2] ?? 0) - gapStartPenalty(cell - 2) : 0;
79
+ if (canSkipTwo && skipTwoScore >= skipOneScore && (matched === NO_MATCH || skipTwoScore >= matchScore)) {
80
+ cellScores[cell] = skipTwoScore;
81
+ cellSteps[cell] = STEP_SKIP_TWO;
82
+ cellRunLengths[cell] = 0;
83
+ } else if (canSkipOne && (matched === NO_MATCH || skipOneScore >= matchScore)) {
84
+ cellScores[cell] = skipOneScore;
85
+ cellSteps[cell] = STEP_SKIP_ONE;
86
+ cellRunLengths[cell] = 0;
87
+ } else {
88
+ cellScores[cell] = matchScore;
89
+ cellSteps[cell] = STEP_MATCH;
90
+ cellRunLengths[cell] = (cellRunLengths[diagonal] ?? 0) + 1;
91
+ }
92
+ }
93
+ }
94
+ if (!startsAtBoundary && !allowWeakStart) return null;
95
+ return traceMatch(patternLow, patternStart, patternEnd, candidate, candidateLow, candidateEnd);
96
+ }
97
+ /**
98
+ * A score cannot say where a match landed, so the positions are recovered by walking the filled table
99
+ * back from its last cell — and the score is settled here too, where the reach of the match is
100
+ * finally known.
101
+ */
102
+ function traceMatch(patternLow, patternStart, patternEnd, candidate, candidateLow, candidateEnd) {
103
+ const positions = [];
104
+ let row = patternEnd - patternStart;
105
+ let column = candidateEnd;
106
+ let score = cellScores[row * TABLE_COLUMNS + column] ?? 0;
107
+ let runLength = 0;
108
+ let lastMatchColumn = 0;
109
+ while (row >= 1) {
110
+ let matchColumn = column;
111
+ while (matchColumn >= 1) {
112
+ const step = cellSteps[row * TABLE_COLUMNS + matchColumn];
113
+ if (step === STEP_SKIP_TWO) matchColumn -= 2;
114
+ else if (step === STEP_SKIP_ONE) matchColumn -= 1;
115
+ else break;
116
+ }
117
+ if (runLength > 1 && patternLow[patternStart + row - 1] === candidateLow[column - 1] && !isUpperCaseAt(candidate, candidateLow, matchColumn - 1) && runLength + 1 > (cellRunLengths[row * TABLE_COLUMNS + matchColumn] ?? 0)) matchColumn = column;
118
+ runLength = matchColumn === column ? runLength + 1 : 1;
119
+ if (lastMatchColumn === 0) lastMatchColumn = matchColumn;
120
+ row -= 1;
121
+ column = matchColumn - 1;
122
+ positions.push(column);
123
+ }
124
+ positions.reverse();
125
+ const patternLength = patternEnd - patternStart;
126
+ if (candidateEnd === patternLength) score += 2;
127
+ score -= lastMatchColumn - patternLength;
128
+ return {
129
+ positions,
130
+ score
131
+ };
132
+ }
133
+ /**
134
+ * Records, per pattern character, the earliest candidate position it can match at, and reports
135
+ * whether the pattern occurs in the candidate at all.
136
+ *
137
+ * A candidate the pattern is not a subsequence of cannot match however it is scored, and this is a
138
+ * linear scan against a table walk.
139
+ */
140
+ function fillEarliestPositions(patternLow, patternStart, patternEnd, candidateLow, candidateEnd) {
141
+ let patternPos = patternStart;
142
+ let position = 0;
143
+ while (patternPos < patternEnd && position < candidateEnd) {
144
+ if (patternLow[patternPos] === candidateLow[position]) {
145
+ earliestPositions[patternPos] = position;
146
+ patternPos += 1;
147
+ }
148
+ position += 1;
149
+ }
150
+ return patternPos === patternEnd;
151
+ }
152
+ /** Records, per pattern character, the latest candidate position it can match at. */
153
+ function fillLatestPositions(patternLow, patternStart, patternEnd, candidateLow, candidateEnd) {
154
+ let patternPos = patternEnd - 1;
155
+ let position = candidateEnd - 1;
156
+ while (patternPos >= patternStart && position >= 0) {
157
+ if (patternLow[patternPos] === candidateLow[position]) {
158
+ latestPositions[patternPos] = position;
159
+ patternPos -= 1;
160
+ }
161
+ position -= 1;
162
+ }
163
+ }
164
+ function positionKind(candidate, candidateLow, position, prefixPosition) {
165
+ if (position === prefixPosition) return POSITION_PREFIX;
166
+ if (isUpperCaseAt(candidate, candidateLow, position) && !isUpperCaseAt(candidate, candidateLow, position - 1)) return POSITION_CAMEL;
167
+ if (isSeparatorAt(candidateLow, position) && !isSeparatorAt(candidateLow, position - 1)) return POSITION_SEPARATOR;
168
+ if (isSeparatorAt(candidateLow, position - 1) || isWhitespaceAt(candidateLow, position - 1)) return POSITION_AFTER_SEPARATOR;
169
+ return POSITION_INSIDE_WORD;
170
+ }
171
+ /**
172
+ * Whether a gap would be forgivable at this position: the reader's eye already breaks the candidate
173
+ * here, so a match that resumes here does not read as scattered.
174
+ */
175
+ function isGapPosition(kind, candidate, candidateLow, position) {
176
+ if (kind === POSITION_CAMEL || kind === POSITION_AFTER_SEPARATOR) return true;
177
+ return isUpperCaseAt(candidate, candidateLow, position) || isSeparatorAt(candidateLow, position - 1) || isWhitespaceAt(candidateLow, position - 1);
178
+ }
179
+ /**
180
+ * What one matched character is worth, which is most of the signal in a score.
181
+ *
182
+ * A character matched where the candidate begins something counts for several times one matched in
183
+ * the middle of a word, and matching the case it is written in counts for more again: both are
184
+ * things the user could only have typed deliberately.
185
+ */
186
+ function characterScore(kind, isGap, sameCase, isFirst, position, candidateEnd, startsRun) {
187
+ let score = 1;
188
+ if (kind === POSITION_PREFIX || kind === POSITION_CAMEL) score = sameCase ? 7 : 5;
189
+ else if (kind === POSITION_SEPARATOR || kind === POSITION_AFTER_SEPARATOR) score = 5;
190
+ if (isFirst) {
191
+ if (position > 0) score -= isGap ? 3 : 5;
192
+ } else if (startsRun) score += isGap ? 2 : 0;
193
+ else score += isGap ? 0 : 1;
194
+ if (position + 1 === candidateEnd) score -= isGap ? 3 : 5;
195
+ return score;
196
+ }
197
+ function gapStartPenalty(cell) {
198
+ return (cellRunLengths[cell] ?? 0) > 0 ? 5 : 0;
199
+ }
200
+ function isUpperCaseAt(candidate, candidateLow, position) {
201
+ if (position < 0 || position >= candidate.length) return false;
202
+ return candidate[position] !== candidateLow[position];
203
+ }
204
+ function isSeparatorAt(candidateLow, position) {
205
+ if (position < 0 || position >= candidateLow.length) return false;
206
+ return SEPARATORS.has(candidateLow[position] ?? "");
207
+ }
208
+ function isWhitespaceAt(candidateLow, position) {
209
+ if (position < 0 || position >= candidateLow.length) return false;
210
+ const character = candidateLow[position];
211
+ return character === " " || character === " ";
212
+ }
213
+ //#endregion
214
+ export { fuzzyMatch, looseFuzzyMatch };
215
+
216
+ //# sourceMappingURL=fuzzyMatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzzyMatch.js","names":[],"sources":["../src/fuzzyMatch.ts"],"sourcesContent":["/*\n * Fuzzy matching of the word being typed against one candidate string.\n *\n * Two things come back from a match rather than one: how well it matched, and where. The positions\n * are what lets a list mark the characters an entry owes its place to, so the ranking can be read off\n * the screen instead of taken on trust.\n *\n * Scoring is a table walk, and its cost is bounded on both axes. Strings are matched up to a fixed\n * length, so a minified bundle arriving as one enormous label costs what any other label costs. And\n * each row only visits the positions its character could possibly match at — no earlier than a\n * forward subsequence scan reaches it, no later than a backward one does — which on a long candidate\n * is a narrow band rather than the whole string.\n */\n\nexport type FuzzyMatch = {\n readonly score: number\n /** Indices into the candidate that the pattern matched, ascending. */\n readonly positions: readonly number[]\n}\n\nconst MAX_PATTERN_LENGTH = 64\nconst MAX_CANDIDATE_LENGTH = 128\n/** How many leading pattern characters a loose match may give up before it stops trying. */\nconst MAX_LOOSE_ATTEMPTS = 13\n\nconst NO_MATCH = Number.MIN_SAFE_INTEGER\n\n/** A character where the user's typing meets the candidate's own structure. */\nconst POSITION_PREFIX = 0\nconst POSITION_CAMEL = 1\nconst POSITION_SEPARATOR = 2\nconst POSITION_AFTER_SEPARATOR = 3\nconst POSITION_INSIDE_WORD = 4\n\nconst STEP_MATCH = 1\nconst STEP_SKIP_ONE = 2\nconst STEP_SKIP_TWO = 3\n\nconst TABLE_COLUMNS = MAX_CANDIDATE_LENGTH + 1\nconst TABLE_CELLS = (MAX_PATTERN_LENGTH + 1) * TABLE_COLUMNS\n\n/*\n * Every item of a list is scored on every keystroke, so the tables are reused across calls instead of\n * allocated per candidate. Row zero is never written, and every read of it is a boundary read that\n * wants the zero it was created with.\n */\nconst cellScores = new Int32Array(TABLE_CELLS)\nconst cellRunLengths = new Int32Array(TABLE_CELLS)\nconst cellSteps = new Uint8Array(TABLE_CELLS)\nconst earliestPositions = new Int32Array(MAX_PATTERN_LENGTH)\nconst latestPositions = new Int32Array(MAX_PATTERN_LENGTH)\n\n/** Where a candidate visibly breaks, and so where a match may resume without reading as scattered. */\nconst SEPARATORS = new Set('_-. /\\\\\\'\":$<>()[]{}#@')\n\n/**\n * The match of the whole pattern, or null when there is none.\n *\n * The first character has to land somewhere the candidate begins something — its start, a camel-case\n * hump, the far side of a separator. A pattern that only turns up in the middle of a word is a\n * coincidence rather than what the user was reaching for.\n */\nexport function fuzzyMatch(pattern: string, candidate: string): FuzzyMatch | null {\n return matchFrom(pattern, pattern.toLowerCase(), 0, candidate, candidate.toLowerCase(), false)\n}\n\n/**\n * The match of the pattern, or of what is left of it after dropping leading characters, at any\n * alignment at all.\n *\n * For a string the pattern was never ranked against there is no reason for all of it to be present,\n * and marking the part that is beats marking nothing.\n */\nexport function looseFuzzyMatch(pattern: string, candidate: string): FuzzyMatch | null {\n const patternLow = pattern.toLowerCase()\n const candidateLow = candidate.toLowerCase()\n const attempts = Math.min(pattern.length, MAX_LOOSE_ATTEMPTS)\n for (let start = 0; start < attempts; start += 1) {\n const match = matchFrom(pattern, patternLow, start, candidate, candidateLow, true)\n if (match) return match\n }\n\n return null\n}\n\nfunction matchFrom(\n pattern: string,\n patternLow: string,\n patternStart: number,\n candidate: string,\n candidateLow: string,\n allowWeakStart: boolean,\n): FuzzyMatch | null {\n const patternEnd = Math.min(pattern.length, MAX_PATTERN_LENGTH)\n const candidateEnd = Math.min(candidate.length, MAX_CANDIDATE_LENGTH)\n const patternLength = patternEnd - patternStart\n if (patternLength <= 0 || patternLength > candidateEnd) return null\n if (!fillEarliestPositions(patternLow, patternStart, patternEnd, candidateLow, candidateEnd)) {\n return null\n }\n\n fillLatestPositions(patternLow, patternStart, patternEnd, candidateLow, candidateEnd)\n\n let startsAtBoundary = false\n for (let patternPos = patternStart, row = 1; patternPos < patternEnd; patternPos += 1, row += 1) {\n const earliest = earliestPositions[patternPos] ?? 0\n const latest = latestPositions[patternPos] ?? 0\n // A row runs past its own last matchable position up to the next character's, because that is the\n // cell the next row reads to its left.\n const rowEnd =\n patternPos + 1 < patternEnd ? (latestPositions[patternPos + 1] ?? 0) : candidateEnd\n const isFirst = patternPos === patternStart\n\n for (let position = earliest; position < rowEnd; position += 1) {\n const cell = row * TABLE_COLUMNS + position + 1\n const diagonal = cell - TABLE_COLUMNS - 1\n\n let matched = NO_MATCH\n if (position <= latest && patternLow[patternPos] === candidateLow[position]) {\n const kind = positionKind(candidate, candidateLow, position, patternPos - patternStart)\n matched = characterScore(\n kind,\n isGapPosition(kind, candidate, candidateLow, position),\n pattern[patternPos] === candidate[position],\n isFirst,\n position,\n candidateEnd,\n (cellRunLengths[diagonal] ?? 0) === 0,\n )\n if (isFirst && kind !== POSITION_INSIDE_WORD) startsAtBoundary = true\n }\n\n const matchScore = matched === NO_MATCH ? 0 : matched + (cellScores[diagonal] ?? 0)\n const canSkipOne = position > earliest\n const skipOneScore = canSkipOne ? (cellScores[cell - 1] ?? 0) - gapStartPenalty(cell - 1) : 0\n const canSkipTwo = position > earliest + 1 && (cellRunLengths[cell - 1] ?? 0) > 0\n const skipTwoScore = canSkipTwo ? (cellScores[cell - 2] ?? 0) - gapStartPenalty(cell - 2) : 0\n\n // Skipping is preferred on a tie because it leaves the match earlier in the candidate, and\n // skipping over a run of matches is preferred over skipping one character for the same reason.\n if (\n canSkipTwo &&\n skipTwoScore >= skipOneScore &&\n (matched === NO_MATCH || skipTwoScore >= matchScore)\n ) {\n cellScores[cell] = skipTwoScore\n cellSteps[cell] = STEP_SKIP_TWO\n cellRunLengths[cell] = 0\n } else if (canSkipOne && (matched === NO_MATCH || skipOneScore >= matchScore)) {\n cellScores[cell] = skipOneScore\n cellSteps[cell] = STEP_SKIP_ONE\n cellRunLengths[cell] = 0\n } else {\n // The earliest position of a row is a match by construction, so a row always has a diagonal\n // to fall back on here.\n cellScores[cell] = matchScore\n cellSteps[cell] = STEP_MATCH\n cellRunLengths[cell] = (cellRunLengths[diagonal] ?? 0) + 1\n }\n }\n }\n\n if (!startsAtBoundary && !allowWeakStart) return null\n\n return traceMatch(patternLow, patternStart, patternEnd, candidate, candidateLow, candidateEnd)\n}\n\n/**\n * A score cannot say where a match landed, so the positions are recovered by walking the filled table\n * back from its last cell — and the score is settled here too, where the reach of the match is\n * finally known.\n */\nfunction traceMatch(\n patternLow: string,\n patternStart: number,\n patternEnd: number,\n candidate: string,\n candidateLow: string,\n candidateEnd: number,\n): FuzzyMatch {\n const positions: number[] = []\n let row = patternEnd - patternStart\n let column = candidateEnd\n let score = cellScores[row * TABLE_COLUMNS + column] ?? 0\n let runLength = 0\n let lastMatchColumn = 0\n\n while (row >= 1) {\n let matchColumn = column\n while (matchColumn >= 1) {\n const step = cellSteps[row * TABLE_COLUMNS + matchColumn]\n if (step === STEP_SKIP_TWO) matchColumn -= 2\n else if (step === STEP_SKIP_ONE) matchColumn -= 1\n else break\n }\n\n // The table was filled left to right and is being read right to left; where the two disagree, the\n // longer unbroken run of matched characters is the one a reader of the list will see.\n if (\n runLength > 1 &&\n patternLow[patternStart + row - 1] === candidateLow[column - 1] &&\n !isUpperCaseAt(candidate, candidateLow, matchColumn - 1) &&\n runLength + 1 > (cellRunLengths[row * TABLE_COLUMNS + matchColumn] ?? 0)\n ) {\n matchColumn = column\n }\n\n runLength = matchColumn === column ? runLength + 1 : 1\n if (lastMatchColumn === 0) lastMatchColumn = matchColumn\n row -= 1\n column = matchColumn - 1\n positions.push(column)\n }\n\n positions.reverse()\n const patternLength = patternEnd - patternStart\n // A candidate the pattern covers entirely is what the user typed, so it comes ahead of anything the\n // pattern is only part of; every candidate character the match stepped over costs it a point.\n if (candidateEnd === patternLength) score += 2\n score -= lastMatchColumn - patternLength\n return { positions, score }\n}\n\n/**\n * Records, per pattern character, the earliest candidate position it can match at, and reports\n * whether the pattern occurs in the candidate at all.\n *\n * A candidate the pattern is not a subsequence of cannot match however it is scored, and this is a\n * linear scan against a table walk.\n */\nfunction fillEarliestPositions(\n patternLow: string,\n patternStart: number,\n patternEnd: number,\n candidateLow: string,\n candidateEnd: number,\n): boolean {\n let patternPos = patternStart\n let position = 0\n while (patternPos < patternEnd && position < candidateEnd) {\n if (patternLow[patternPos] === candidateLow[position]) {\n earliestPositions[patternPos] = position\n patternPos += 1\n }\n position += 1\n }\n\n return patternPos === patternEnd\n}\n\n/** Records, per pattern character, the latest candidate position it can match at. */\nfunction fillLatestPositions(\n patternLow: string,\n patternStart: number,\n patternEnd: number,\n candidateLow: string,\n candidateEnd: number,\n): void {\n let patternPos = patternEnd - 1\n let position = candidateEnd - 1\n while (patternPos >= patternStart && position >= 0) {\n if (patternLow[patternPos] === candidateLow[position]) {\n latestPositions[patternPos] = position\n patternPos -= 1\n }\n position -= 1\n }\n}\n\nfunction positionKind(\n candidate: string,\n candidateLow: string,\n position: number,\n prefixPosition: number,\n): number {\n if (position === prefixPosition) return POSITION_PREFIX\n if (\n isUpperCaseAt(candidate, candidateLow, position) &&\n !isUpperCaseAt(candidate, candidateLow, position - 1)\n ) {\n return POSITION_CAMEL\n }\n if (isSeparatorAt(candidateLow, position) && !isSeparatorAt(candidateLow, position - 1)) {\n return POSITION_SEPARATOR\n }\n if (isSeparatorAt(candidateLow, position - 1) || isWhitespaceAt(candidateLow, position - 1)) {\n return POSITION_AFTER_SEPARATOR\n }\n\n return POSITION_INSIDE_WORD\n}\n\n/**\n * Whether a gap would be forgivable at this position: the reader's eye already breaks the candidate\n * here, so a match that resumes here does not read as scattered.\n */\nfunction isGapPosition(\n kind: number,\n candidate: string,\n candidateLow: string,\n position: number,\n): boolean {\n if (kind === POSITION_CAMEL || kind === POSITION_AFTER_SEPARATOR) return true\n\n return (\n isUpperCaseAt(candidate, candidateLow, position) ||\n isSeparatorAt(candidateLow, position - 1) ||\n isWhitespaceAt(candidateLow, position - 1)\n )\n}\n\n/**\n * What one matched character is worth, which is most of the signal in a score.\n *\n * A character matched where the candidate begins something counts for several times one matched in\n * the middle of a word, and matching the case it is written in counts for more again: both are\n * things the user could only have typed deliberately.\n */\nfunction characterScore(\n kind: number,\n isGap: boolean,\n sameCase: boolean,\n isFirst: boolean,\n position: number,\n candidateEnd: number,\n startsRun: boolean,\n): number {\n let score = 1\n if (kind === POSITION_PREFIX || kind === POSITION_CAMEL) score = sameCase ? 7 : 5\n else if (kind === POSITION_SEPARATOR || kind === POSITION_AFTER_SEPARATOR) score = 5\n\n if (isFirst) {\n // What sits between the start of the candidate and the first matched character is the distance\n // between what was typed and what is being offered.\n if (position > 0) score -= isGap ? 3 : 5\n } else if (startsRun) {\n score += isGap ? 2 : 0\n } else {\n score += isGap ? 0 : 1\n }\n // Gaps are penalized everywhere, which would otherwise hand a free advantage to a match that runs\n // to the end of the candidate and has no room left to leave one.\n if (position + 1 === candidateEnd) score -= isGap ? 3 : 5\n\n return score\n}\n\nfunction gapStartPenalty(cell: number): number {\n return (cellRunLengths[cell] ?? 0) > 0 ? 5 : 0\n}\n\nfunction isUpperCaseAt(candidate: string, candidateLow: string, position: number): boolean {\n if (position < 0 || position >= candidate.length) return false\n\n return candidate[position] !== candidateLow[position]\n}\n\nfunction isSeparatorAt(candidateLow: string, position: number): boolean {\n if (position < 0 || position >= candidateLow.length) return false\n\n return SEPARATORS.has(candidateLow[position] ?? '')\n}\n\nfunction isWhitespaceAt(candidateLow: string, position: number): boolean {\n if (position < 0 || position >= candidateLow.length) return false\n\n const character = candidateLow[position]\n return character === ' ' || character === '\\t'\n}\n"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { LanguageServerDiagnosticActions } from './types';
2
+ import { type LspRequestOptions } from '@singapore-editor/lsp';
3
+ import type { EditorHoverParticipant } from '@singapore-editor/plugin-ui/hover-participant';
4
+ import type * as lsp from 'vscode-languageserver-protocol';
5
+ import { type OpenLocation } from './diagnosticNotes';
6
+ import type { ActiveDocument } from './pluginTypes';
7
+ import type { LanguageServerFeatureRouter, LanguageServerHoverUpdate } from './serverSet';
8
+ export type LanguageServerHoverParticipantOptions = {
9
+ readonly router: LanguageServerFeatureRouter;
10
+ requestHover(params: lsp.TextDocumentPositionParams, options: LspRequestOptions, onUpdate: (update: LanguageServerHoverUpdate) => void): Promise<lsp.Hover | null>;
11
+ getActiveDocument(): ActiveDocument | null;
12
+ getDiagnostics(): readonly lsp.Diagnostic[];
13
+ readonly getDiagnosticActions?: LanguageServerDiagnosticActions;
14
+ /** Follows a diagnostic's related-information link. */
15
+ openLocation?: OpenLocation;
16
+ onRequestSuccess?(): void;
17
+ onRequestError(error: unknown): void;
18
+ };
19
+ /**
20
+ * What the language server has to say at a position: its hover answer, progressively as each lane
21
+ * replies, and the diagnostics published for that offset.
22
+ */
23
+ export declare function createLanguageServerHoverParticipant(options: LanguageServerHoverParticipantOptions): EditorHoverParticipant;
24
+ //# sourceMappingURL=hoverParticipant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hoverParticipant.d.ts","sourceRoot":"","sources":["../src/hoverParticipant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,SAAS,CAAA;AAE9D,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,+CAA+C,CAAA;AACtD,OAAO,KAAK,KAAK,GAAG,MAAM,gCAAgC,CAAA;AAE1D,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAMtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAE,2BAA2B,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAMzF,MAAM,MAAM,qCAAqC,GAAG;IAClD,QAAQ,CAAC,MAAM,EAAE,2BAA2B,CAAA;IAC5C,YAAY,CACV,MAAM,EAAE,GAAG,CAAC,0BAA0B,EACtC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,CAAC,MAAM,EAAE,yBAAyB,KAAK,IAAI,GACpD,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAA;IAC5B,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAAA;IAC1C,cAAc,IAAI,SAAS,GAAG,CAAC,UAAU,EAAE,CAAA;IAC3C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,+BAA+B,CAAA;IAC/D,uDAAuD;IACvD,YAAY,CAAC,EAAE,YAAY,CAAA;IAC3B,gBAAgB,CAAC,IAAI,IAAI,CAAA;IACzB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;CACrC,CAAA;AAED;;;GAGG;AACH,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,qCAAqC,GAC7C,sBAAsB,CAkExB"}
@@ -0,0 +1,156 @@
1
+ import { diagnosticsAtOffset, indexDiagnosticOffsets } from "./diagnosticProjection.js";
2
+ import { diagnosticNotes } from "./diagnosticNotes.js";
3
+ import { lspPositionToOffsetInSnapshot, offsetToLspPositionInSnapshot } from "@singapore-editor/lsp";
4
+ //#region src/hoverParticipant.ts
5
+ /** Diagnostics above the server's prose, the way VS Code orders its marker and Markdown hovers. */
6
+ var DIAGNOSTIC_ORDINAL = 1;
7
+ var HOVER_TEXT_ORDINAL = 3;
8
+ /**
9
+ * What the language server has to say at a position: its hover answer, progressively as each lane
10
+ * replies, and the diagnostics published for that offset.
11
+ */
12
+ function createLanguageServerHoverParticipant(options) {
13
+ let diagnosticIndex = null;
14
+ const runningActions = /* @__PURE__ */ new Map();
15
+ const diagnosticIndexFor = (active) => {
16
+ const diagnostics = options.getDiagnostics();
17
+ const cached = diagnosticIndex;
18
+ if (cached && cached.index.diagnostics === diagnostics && cached.textVersion === active.textVersion) return cached.index;
19
+ const index = indexDiagnosticOffsets(active, diagnostics);
20
+ diagnosticIndex = {
21
+ index,
22
+ textVersion: active.textVersion
23
+ };
24
+ return index;
25
+ };
26
+ return {
27
+ computeSync: (request) => {
28
+ const active = options.getActiveDocument();
29
+ if (!active) return [];
30
+ const diagnostics = diagnosticsAtOffset(diagnosticIndexFor(active), request.anchor.offset);
31
+ if (diagnostics.length === 0) return [];
32
+ return [{
33
+ ordinal: DIAGNOSTIC_ORDINAL,
34
+ range: request.anchor.range,
35
+ notes: diagnosticNotes(diagnostics, options.openLocation ?? (() => void 0), (diagnostic) => diagnosticActions(options, runningActions, active, diagnostic))
36
+ }];
37
+ },
38
+ computeAsync: async (request, emit) => {
39
+ const active = options.getActiveDocument();
40
+ if (!active || !options.router.hasReady("hover", "textDocument/hover")) return;
41
+ const publish = (hovers) => emit(hovers.flatMap((hover) => hoverParts(active, request, hover)));
42
+ try {
43
+ const hover = await options.requestHover({
44
+ textDocument: { uri: active.uri },
45
+ position: offsetToLspPositionInSnapshot(active, request.anchor.offset)
46
+ }, { signal: request.signal }, (update) => publish(update.hovers));
47
+ if (request.signal.aborted) return;
48
+ options.onRequestSuccess?.();
49
+ if (hover) publish([hover]);
50
+ } catch (error) {
51
+ if (!isAbortError(error)) options.onRequestError(error);
52
+ }
53
+ }
54
+ };
55
+ }
56
+ function diagnosticActions(options, runningActions, active, diagnostic) {
57
+ try {
58
+ return (options.getDiagnosticActions?.({
59
+ documentUri: active.uri,
60
+ textVersion: active.textVersion,
61
+ diagnostic
62
+ }) ?? []).map((action) => ({
63
+ ...action,
64
+ run: () => runDiagnosticAction(options, runningActions, active, diagnostic, action)
65
+ }));
66
+ } catch (error) {
67
+ options.onRequestError(error);
68
+ return [];
69
+ }
70
+ }
71
+ function runDiagnosticAction(options, runningActions, active, diagnostic, action) {
72
+ const key = diagnosticKey(diagnostic);
73
+ const current = options.getActiveDocument();
74
+ if (!current || current.uri !== active.uri || current.textVersion !== active.textVersion || !options.getDiagnostics().some((candidate) => diagnosticKey(candidate) === key)) throw new Error("The diagnostic changed. Reopen its hover.");
75
+ const runKey = JSON.stringify([
76
+ active.uri,
77
+ active.textVersion,
78
+ key,
79
+ action.label
80
+ ]);
81
+ const running = runningActions.get(runKey);
82
+ if (running) return running;
83
+ const result = reportActionFailure(options, action);
84
+ if (!result) return;
85
+ const run = result.finally(() => runningActions.delete(runKey));
86
+ runningActions.set(runKey, run);
87
+ return run;
88
+ }
89
+ function reportActionFailure(options, action) {
90
+ const report = (error) => {
91
+ options.onRequestError(error);
92
+ throw error;
93
+ };
94
+ let result;
95
+ try {
96
+ result = action.run();
97
+ } catch (error) {
98
+ return report(error);
99
+ }
100
+ return result ? result.catch(report) : void 0;
101
+ }
102
+ function diagnosticKey(diagnostic) {
103
+ const { range, severity, code, source, message } = diagnostic;
104
+ return JSON.stringify([
105
+ range.start.line,
106
+ range.start.character,
107
+ range.end.line,
108
+ range.end.character,
109
+ severity,
110
+ code,
111
+ source,
112
+ typeof message === "string" ? message : message.value
113
+ ]);
114
+ }
115
+ function hoverParts(active, request, hover) {
116
+ const markdown = hoverContentsText(hover.contents).trim();
117
+ if (!markdown) return [];
118
+ return [{
119
+ ordinal: HOVER_TEXT_ORDINAL,
120
+ range: hoverRangeOffsets(active, hover) ?? request.anchor.range,
121
+ markdown
122
+ }];
123
+ }
124
+ function hoverContentsText(contents) {
125
+ if (typeof contents === "string") return contents;
126
+ if (Array.isArray(contents)) return contents.map(markedStringText).join("\n\n");
127
+ if ("kind" in contents) return contents.value;
128
+ return markedStringText(contents);
129
+ }
130
+ function markedStringText(value) {
131
+ if (typeof value === "string") return value;
132
+ return [
133
+ "```" + value.language,
134
+ value.value,
135
+ "```"
136
+ ].join("\n");
137
+ }
138
+ function hoverRangeOffsets(active, hover) {
139
+ if (!hover.range) return null;
140
+ const start = lspPositionToOffsetInSnapshot(active, hover.range.start);
141
+ const end = lspPositionToOffsetInSnapshot(active, hover.range.end);
142
+ if (end > start) return {
143
+ start,
144
+ end
145
+ };
146
+ return null;
147
+ }
148
+ function isAbortError(error) {
149
+ if (error instanceof DOMException && error.name === "AbortError") return true;
150
+ if (typeof error !== "object" || error === null) return false;
151
+ return "name" in error && error.name === "LspRequestCancelledError";
152
+ }
153
+ //#endregion
154
+ export { createLanguageServerHoverParticipant };
155
+
156
+ //# sourceMappingURL=hoverParticipant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hoverParticipant.js","names":[],"sources":["../src/hoverParticipant.ts"],"sourcesContent":["import type { LanguageServerDiagnosticActions } from './types'\nimport type { TooltipAction } from '@singapore-editor/plugin-ui/tooltip'\nimport {\n lspPositionToOffsetInSnapshot,\n offsetToLspPositionInSnapshot,\n type LspRequestOptions,\n} from '@singapore-editor/lsp'\nimport type {\n EditorHoverParticipant,\n HoverPart,\n HoverRequest,\n} from '@singapore-editor/plugin-ui/hover-participant'\nimport type * as lsp from 'vscode-languageserver-protocol'\n\nimport { diagnosticNotes, type OpenLocation } from './diagnosticNotes'\nimport {\n diagnosticsAtOffset,\n indexDiagnosticOffsets,\n type DiagnosticOffsetIndex,\n} from './diagnosticProjection'\nimport type { ActiveDocument } from './pluginTypes'\nimport type { LanguageServerFeatureRouter, LanguageServerHoverUpdate } from './serverSet'\n\n/** Diagnostics above the server's prose, the way VS Code orders its marker and Markdown hovers. */\nconst DIAGNOSTIC_ORDINAL = 1\nconst HOVER_TEXT_ORDINAL = 3\n\nexport type LanguageServerHoverParticipantOptions = {\n readonly router: LanguageServerFeatureRouter\n requestHover(\n params: lsp.TextDocumentPositionParams,\n options: LspRequestOptions,\n onUpdate: (update: LanguageServerHoverUpdate) => void,\n ): Promise<lsp.Hover | null>\n getActiveDocument(): ActiveDocument | null\n getDiagnostics(): readonly lsp.Diagnostic[]\n readonly getDiagnosticActions?: LanguageServerDiagnosticActions\n /** Follows a diagnostic's related-information link. */\n openLocation?: OpenLocation\n onRequestSuccess?(): void\n onRequestError(error: unknown): void\n}\n\n/**\n * What the language server has to say at a position: its hover answer, progressively as each lane\n * replies, and the diagnostics published for that offset.\n */\nexport function createLanguageServerHoverParticipant(\n options: LanguageServerHoverParticipantOptions,\n): EditorHoverParticipant {\n let diagnosticIndex: { index: DiagnosticOffsetIndex; textVersion: number } | null = null\n // Outlives the tooltip, so reopening a hover joins a run instead of starting a second one.\n const runningActions = new Map<string, Promise<void>>()\n\n // Keyed on the published array and the text it was projected onto, so a pointer move pays for\n // the index only when either changes.\n const diagnosticIndexFor = (active: ActiveDocument): DiagnosticOffsetIndex => {\n const diagnostics = options.getDiagnostics()\n const cached = diagnosticIndex\n if (\n cached &&\n cached.index.diagnostics === diagnostics &&\n cached.textVersion === active.textVersion\n ) {\n return cached.index\n }\n\n const index = indexDiagnosticOffsets(active, diagnostics)\n diagnosticIndex = { index, textVersion: active.textVersion }\n return index\n }\n\n return {\n computeSync: (request) => {\n const active = options.getActiveDocument()\n if (!active) return []\n\n const diagnostics = diagnosticsAtOffset(diagnosticIndexFor(active), request.anchor.offset)\n if (diagnostics.length === 0) return []\n\n return [\n {\n ordinal: DIAGNOSTIC_ORDINAL,\n range: request.anchor.range,\n notes: diagnosticNotes(\n diagnostics,\n options.openLocation ?? (() => undefined),\n (diagnostic) => diagnosticActions(options, runningActions, active, diagnostic),\n ),\n },\n ]\n },\n computeAsync: async (request, emit) => {\n const active = options.getActiveDocument()\n if (!active || !options.router.hasReady('hover', 'textDocument/hover')) return\n\n const publish = (hovers: readonly lsp.Hover[]): void =>\n emit(hovers.flatMap((hover) => hoverParts(active, request, hover)))\n try {\n const hover = await options.requestHover(\n {\n textDocument: { uri: active.uri },\n position: offsetToLspPositionInSnapshot(active, request.anchor.offset),\n },\n { signal: request.signal },\n (update) => publish(update.hovers),\n )\n if (request.signal.aborted) return\n options.onRequestSuccess?.()\n if (hover) publish([hover])\n } catch (error) {\n if (!isAbortError(error)) options.onRequestError(error)\n }\n },\n }\n}\n\nfunction diagnosticActions(\n options: LanguageServerHoverParticipantOptions,\n runningActions: Map<string, Promise<void>>,\n active: ActiveDocument,\n diagnostic: lsp.Diagnostic,\n): readonly TooltipAction[] {\n try {\n const actions =\n options.getDiagnosticActions?.({\n documentUri: active.uri,\n textVersion: active.textVersion,\n diagnostic,\n }) ?? []\n return actions.map((action) => ({\n ...action,\n run: () => runDiagnosticAction(options, runningActions, active, diagnostic, action),\n }))\n } catch (error) {\n options.onRequestError(error)\n return []\n }\n}\n\nfunction runDiagnosticAction(\n options: LanguageServerHoverParticipantOptions,\n runningActions: Map<string, Promise<void>>,\n active: ActiveDocument,\n diagnostic: lsp.Diagnostic,\n action: TooltipAction,\n): void | Promise<void> {\n const key = diagnosticKey(diagnostic)\n const current = options.getActiveDocument()\n if (\n !current ||\n current.uri !== active.uri ||\n current.textVersion !== active.textVersion ||\n !options.getDiagnostics().some((candidate) => diagnosticKey(candidate) === key)\n )\n throw new Error('The diagnostic changed. Reopen its hover.')\n\n const runKey = JSON.stringify([active.uri, active.textVersion, key, action.label])\n const running = runningActions.get(runKey)\n if (running) return running\n\n const result = reportActionFailure(options, action)\n if (!result) return\n const run = result.finally(() => runningActions.delete(runKey))\n runningActions.set(runKey, run)\n return run\n}\n\n// The tooltip may be gone by the time a slow action fails, so the host always hears about it.\nfunction reportActionFailure(\n options: LanguageServerHoverParticipantOptions,\n action: TooltipAction,\n): void | Promise<void> {\n const report = (error: unknown): never => {\n options.onRequestError(error)\n throw error\n }\n let result: void | Promise<void>\n try {\n result = action.run()\n } catch (error) {\n return report(error)\n }\n return result ? result.catch(report) : undefined\n}\n\n// A republish replaces the diagnostic objects, so staleness compares what the user was shown.\nfunction diagnosticKey(diagnostic: lsp.Diagnostic): string {\n const { range, severity, code, source, message } = diagnostic\n return JSON.stringify([\n range.start.line,\n range.start.character,\n range.end.line,\n range.end.character,\n severity,\n code,\n source,\n typeof message === 'string' ? message : message.value,\n ])\n}\n\nfunction hoverParts(\n active: ActiveDocument,\n request: HoverRequest,\n hover: lsp.Hover,\n): readonly HoverPart[] {\n const markdown = hoverContentsText(hover.contents).trim()\n if (!markdown) return []\n\n return [\n {\n ordinal: HOVER_TEXT_ORDINAL,\n range: hoverRangeOffsets(active, hover) ?? request.anchor.range,\n markdown,\n },\n ]\n}\n\nfunction hoverContentsText(contents: lsp.Hover['contents']): string {\n if (typeof contents === 'string') return contents\n if (Array.isArray(contents)) return contents.map(markedStringText).join('\\n\\n')\n if ('kind' in contents) return contents.value\n return markedStringText(contents)\n}\n\nfunction markedStringText(value: lsp.MarkedString): string {\n if (typeof value === 'string') return value\n return ['```' + value.language, value.value, '```'].join('\\n')\n}\n\nfunction hoverRangeOffsets(\n active: ActiveDocument,\n hover: lsp.Hover,\n): { readonly start: number; readonly end: number } | null {\n if (!hover.range) return null\n\n const start = lspPositionToOffsetInSnapshot(active, hover.range.start)\n const end = lspPositionToOffsetInSnapshot(active, hover.range.end)\n if (end > start) return { start, end }\n return null\n}\n\nfunction isAbortError(error: unknown): boolean {\n if (error instanceof DOMException && error.name === 'AbortError') return true\n if (typeof error !== 'object' || error === null) return false\n return 'name' in error && error.name === 'LspRequestCancelledError'\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export { synchronizeLanguageServerBuffer } from './bufferSync';
2
+ export { createLanguageServerDocument, LanguageServerDocument, type LanguageServerDocumentOptions, } from './document';
3
+ export type { LanguageServerDocumentPluginOptions, LanguageServerDocumentSnapshot } from './types';
4
+ export { createLanguageServerAdapterPlugin, createLanguageServerPlugin, createLanguageServerSetPlugin, type LanguageServerCommandSpec, type LanguageServerCommandTarget, type LanguageServerConnectionContext, type LanguageServerAdapterPluginOptions, type LanguageServerResolvedOptions, } from './plugin';
5
+ export { acquireLanguageServerLane, type AcquiredLanguageServerLane, type LanguageServerLaneCallbacks, } from './lane';
6
+ export { allLanguageServerFeatures, LanguageServerSet, laneSupports, rankedLanguageServerLanes, type LanguageServerFeatureRouter, type LanguageServerCodeActionProvenance, type LanguageServerCodeActionRouter, type LanguageServerLaneResult, type LanguageServerSetLane, } from './serverSet';
7
+ export { LspConnectionPool, type LspConnectionPoolEvent, type LspConnectionPoolOptions, } from './lspConnectionPool';
8
+ export { createWebSocketLspTransportFactory, createWorkerLspTransportFactory, LspConnection, type LspConnectionCallbacks, type LspConnectionLease, type LspConnectionOptions, type LspConnectionProvider, type LspReconnectOptions, type LspConnectionTransportFactory, } from './lspConnection';
9
+ export { LanguageServerDocumentSyncController, type LanguageServerDocumentSyncControllerRegistration, type LanguageServerDocumentUriTransition, } from './documentSyncController';
10
+ export { combineDiagnosticsFreshness, diagnosticHighlightGroups, summarizeDiagnostics, type LanguageServerDiagnosticHighlightGroups, type LanguageServerDiagnosticHighlightLayer, type LanguageServerDiagnosticSeverity, } from './diagnostics';
11
+ export { viewDocumentSnapshot } from './viewDocumentSnapshot';
12
+ export { SemanticTokenLayerOwner, type LanguageServerSemanticTokensFactory, type LanguageServerSemanticTokensDocument, type LanguageServerSemanticTokensOwner, type LanguageServerSemanticTokensOwnerOptions, type LanguageServerSemanticTokensOptions, } from './semanticTokens';
13
+ export { decodeSemanticTokens, type SemanticTokenDecodeDocument, type SemanticTokenDecodeDrops, type SemanticTokenDecodeResult, } from './semanticTokenDecoder';
14
+ export { documentUriToFileName, fileNameToDocumentUri, pathOrUriToDocumentUri, sourcePathToFileName, } from './paths';
15
+ export type { ApplyWorkspaceEditRequest, ApplyWorkspaceEditResult, LanguageServerDiagnosticCounts, LanguageServerDiagnosticActionContext, LanguageServerDiagnosticActions, LanguageServerDiagnosticMarkerClaim, LanguageServerDiagnosticMarkerEvent, LanguageServerDefinitionTarget, LanguageServerDiagnosticSummary, LanguageServerDiagnosticsFreshness, LanguageServerDocumentSyncOptions, LanguageServerNavigationKind, LanguageServerNavigationOpenMode, LanguageServerNavigationOptions, LanguageServerPlugin, LanguageServerFeatureId, LanguageServerFeatureRanks, LanguageServerLaneHostOptions, LanguageServerLaneOptions, LanguageServerPluginOptions, LanguageServerRenamePrompt, LanguageServerReadyNotification, LanguageServerReferencesResult, LanguageServerSetPluginOptions, LanguageServerStatus, OnApplyWorkspaceEdit, WorkspaceEditOriginGuard, } from './types';
16
+ export { LANGUAGE_SERVER_FEATURE_IDS } from './types';
17
+ export * from './workspaceEdit';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,cAAc,CAAA;AAC9D,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,iCAAiC,EACjC,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,+BAA+B,EACpC,KAAK,kCAAkC,EACvC,KAAK,6BAA6B,GACnC,MAAM,UAAU,CAAA;AACjB,OAAO,EACL,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,GACjC,MAAM,QAAQ,CAAA;AACf,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,YAAY,EACZ,yBAAyB,EACzB,KAAK,2BAA2B,EAChC,KAAK,kCAAkC,EACvC,KAAK,8BAA8B,EACnC,KAAK,wBAAwB,EAC7B,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,iBAAiB,EACjB,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,GAC9B,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,kCAAkC,EAClC,+BAA+B,EAC/B,aAAa,EACb,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,6BAA6B,GACnC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,oCAAoC,EACpC,KAAK,gDAAgD,EACrD,KAAK,mCAAmC,GACzC,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,2BAA2B,EAC3B,yBAAyB,EACzB,oBAAoB,EACpB,KAAK,uCAAuC,EAC5C,KAAK,sCAAsC,EAC3C,KAAK,gCAAgC,GACtC,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EACL,uBAAuB,EACvB,KAAK,mCAAmC,EACxC,KAAK,oCAAoC,EACzC,KAAK,iCAAiC,EACtC,KAAK,wCAAwC,EAC7C,KAAK,mCAAmC,GACzC,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,GAC/B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,SAAS,CAAA;AAChB,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,qCAAqC,EACrC,+BAA+B,EAC/B,mCAAmC,EACnC,mCAAmC,EACnC,8BAA8B,EAC9B,+BAA+B,EAC/B,kCAAkC,EAClC,iCAAiC,EACjC,4BAA4B,EAC5B,gCAAgC,EAChC,+BAA+B,EAC/B,oBAAoB,EACpB,uBAAuB,EACvB,0BAA0B,EAC1B,6BAA6B,EAC7B,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,+BAA+B,EAC/B,8BAA8B,EAC9B,8BAA8B,EAC9B,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,2BAA2B,EAAE,MAAM,SAAS,CAAA;AACrD,cAAc,iBAAiB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ import { documentUriToFileName, fileNameToDocumentUri, pathOrUriToDocumentUri, sourcePathToFileName } from "./paths.js";
2
+ import { viewDocumentSnapshot } from "./viewDocumentSnapshot.js";
3
+ import { LspConnection, createWebSocketLspTransportFactory, createWorkerLspTransportFactory } from "./lspConnection.js";
4
+ import { acquireLanguageServerLane } from "./lane.js";
5
+ import { synchronizeLanguageServerBuffer } from "./bufferSync.js";
6
+ import { combineDiagnosticsFreshness, diagnosticHighlightGroups, summarizeDiagnostics } from "./diagnostics.js";
7
+ import { LanguageServerDocument, createLanguageServerDocument } from "./document.js";
8
+ import { LANGUAGE_SERVER_FEATURE_IDS } from "./types.js";
9
+ import { LanguageServerSet, allLanguageServerFeatures, laneSupports, rankedLanguageServerLanes } from "./serverSet.js";
10
+ import { prepareWorkspaceTextReplay } from "./workspaceTextEdits.js";
11
+ import { parseWorkspaceEdit } from "./workspaceEdit.js";
12
+ import { SemanticTokenLayerOwner } from "./semanticTokens.js";
13
+ import { createLanguageServerAdapterPlugin, createLanguageServerPlugin, createLanguageServerSetPlugin } from "./plugin.js";
14
+ import { LspConnectionPool } from "./lspConnectionPool.js";
15
+ import { LanguageServerDocumentSyncController } from "./documentSyncController.js";
16
+ import { decodeSemanticTokens } from "./semanticTokenDecoder.js";
17
+ export { LANGUAGE_SERVER_FEATURE_IDS, LanguageServerDocument, LanguageServerDocumentSyncController, LanguageServerSet, LspConnection, LspConnectionPool, SemanticTokenLayerOwner, acquireLanguageServerLane, allLanguageServerFeatures, combineDiagnosticsFreshness, createLanguageServerAdapterPlugin, createLanguageServerDocument, createLanguageServerPlugin, createLanguageServerSetPlugin, createWebSocketLspTransportFactory, createWorkerLspTransportFactory, decodeSemanticTokens, diagnosticHighlightGroups, documentUriToFileName, fileNameToDocumentUri, laneSupports, parseWorkspaceEdit, pathOrUriToDocumentUri, prepareWorkspaceTextReplay, rankedLanguageServerLanes, sourcePathToFileName, summarizeDiagnostics, synchronizeLanguageServerBuffer, viewDocumentSnapshot };
@@ -0,0 +1,19 @@
1
+ export type CompletionKeyCommand = 'trigger' | 'next' | 'previous' | 'nextPage' | 'previousPage' | 'accept' | 'hide';
2
+ export type SignatureHelpKeyCommand = 'close' | 'next' | 'previous';
3
+ /** The editor commands the keymap binds to the completion list; see the core's suggest pack. */
4
+ export declare const COMPLETION_KEY_COMMANDS: {
5
+ readonly trigger: "editor.action.triggerSuggest";
6
+ readonly next: "selectNextSuggestion";
7
+ readonly previous: "selectPrevSuggestion";
8
+ readonly nextPage: "selectNextPageSuggestion";
9
+ readonly previousPage: "selectPrevPageSuggestion";
10
+ readonly accept: "acceptSelectedSuggestion";
11
+ readonly hide: "hideSuggestWidget";
12
+ };
13
+ /** Kept apart from the controller, which loads on the first `(`, so naming them costs nothing. */
14
+ export declare const SIGNATURE_HELP_KEY_COMMANDS: {
15
+ readonly close: "closeParameterHints";
16
+ readonly next: "showNextParameterHint";
17
+ readonly previous: "showPrevParameterHint";
18
+ };
19
+ //# sourceMappingURL=keyCommands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyCommands.d.ts","sourceRoot":"","sources":["../src/keyCommands.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,MAAM,GACN,UAAU,GACV,UAAU,GACV,cAAc,GACd,QAAQ,GACR,MAAM,CAAA;AAEV,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAA;AAEnE,gGAAgG;AAChG,eAAO,MAAM,uBAAuB;;;;;;;;CAQ8B,CAAA;AAElE,kGAAkG;AAClG,eAAO,MAAM,2BAA2B;;;;CAI6B,CAAA"}
@@ -0,0 +1,21 @@
1
+ //#region src/keyCommands.ts
2
+ /** The editor commands the keymap binds to the completion list; see the core's suggest pack. */
3
+ var COMPLETION_KEY_COMMANDS = {
4
+ trigger: "editor.action.triggerSuggest",
5
+ next: "selectNextSuggestion",
6
+ previous: "selectPrevSuggestion",
7
+ nextPage: "selectNextPageSuggestion",
8
+ previousPage: "selectPrevPageSuggestion",
9
+ accept: "acceptSelectedSuggestion",
10
+ hide: "hideSuggestWidget"
11
+ };
12
+ /** Kept apart from the controller, which loads on the first `(`, so naming them costs nothing. */
13
+ var SIGNATURE_HELP_KEY_COMMANDS = {
14
+ close: "closeParameterHints",
15
+ next: "showNextParameterHint",
16
+ previous: "showPrevParameterHint"
17
+ };
18
+ //#endregion
19
+ export { COMPLETION_KEY_COMMANDS, SIGNATURE_HELP_KEY_COMMANDS };
20
+
21
+ //# sourceMappingURL=keyCommands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyCommands.js","names":[],"sources":["../src/keyCommands.ts"],"sourcesContent":["import type { EditorCommandId } from '@singapore-editor/core/editor'\n\nexport type CompletionKeyCommand =\n | 'trigger'\n | 'next'\n | 'previous'\n | 'nextPage'\n | 'previousPage'\n | 'accept'\n | 'hide'\n\nexport type SignatureHelpKeyCommand = 'close' | 'next' | 'previous'\n\n/** The editor commands the keymap binds to the completion list; see the core's suggest pack. */\nexport const COMPLETION_KEY_COMMANDS = {\n trigger: 'editor.action.triggerSuggest',\n next: 'selectNextSuggestion',\n previous: 'selectPrevSuggestion',\n nextPage: 'selectNextPageSuggestion',\n previousPage: 'selectPrevPageSuggestion',\n accept: 'acceptSelectedSuggestion',\n hide: 'hideSuggestWidget',\n} as const satisfies Record<CompletionKeyCommand, EditorCommandId>\n\n/** Kept apart from the controller, which loads on the first `(`, so naming them costs nothing. */\nexport const SIGNATURE_HELP_KEY_COMMANDS = {\n close: 'closeParameterHints',\n next: 'showNextParameterHint',\n previous: 'showPrevParameterHint',\n} as const satisfies Record<SignatureHelpKeyCommand, EditorCommandId>\n"],"mappings":";;AAcA,IAAa,0BAA0B;CACrC,SAAS;CACT,MAAM;CACN,UAAU;CACV,UAAU;CACV,cAAc;CACd,QAAQ;CACR,MAAM;AACR;;AAGA,IAAa,8BAA8B;CACzC,OAAO;CACP,MAAM;CACN,UAAU;AACZ"}
package/dist/lane.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ import { type DocumentLogicalRevisionScope } from '@singapore-editor/core/document';
2
+ import { type LspClient, type LspWorkspace } from '@singapore-editor/lsp';
3
+ import { type LspConnectionTransportFactory } from './lspConnection';
4
+ import type { LanguageServerConnectionContext, LanguageServerLaneOptions } from './types';
5
+ export type AcquiredLanguageServerLane = {
6
+ readonly id: string;
7
+ readonly client: LspClient;
8
+ readonly logicalRevisionScope: DocumentLogicalRevisionScope;
9
+ readonly workspace: LspWorkspace;
10
+ readonly ready: Promise<LanguageServerConnectionContext>;
11
+ isReady(): boolean;
12
+ release(): void;
13
+ };
14
+ export type LanguageServerLaneCallbacks = {
15
+ onDiagnosticRefresh?(): void;
16
+ onReconnecting?(): void;
17
+ onPublishDiagnostics?(params: unknown): void;
18
+ onReady?(): void;
19
+ onUnavailable?(): void;
20
+ };
21
+ export type LanguageServerResolvedLaneOptions = Omit<LanguageServerLaneOptions, 'webSocketRoute' | 'webSocketTransportOptions'> & {
22
+ createTransport: LspConnectionTransportFactory;
23
+ };
24
+ export declare function acquireLanguageServerLane(options: LanguageServerLaneOptions, callbacks?: LanguageServerLaneCallbacks): AcquiredLanguageServerLane;
25
+ export declare function acquireResolvedLanguageServerLane(options: LanguageServerResolvedLaneOptions, callbacks?: LanguageServerLaneCallbacks): AcquiredLanguageServerLane;
26
+ export declare function resolveLanguageServerLaneOptions(options: LanguageServerLaneOptions): LanguageServerResolvedLaneOptions;
27
+ export declare function logicalRevisionScopeFor(workspace: LspWorkspace): DocumentLogicalRevisionScope;
28
+ //# sourceMappingURL=lane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lane.d.ts","sourceRoot":"","sources":["../src/lane.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,iCAAiC,CAAA;AACxC,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAA;AAE9B,OAAO,EAML,KAAK,6BAA6B,EACnC,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EACV,+BAA+B,EAC/B,yBAAyB,EAE1B,MAAM,SAAS,CAAA;AAKhB,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;IAC1B,QAAQ,CAAC,oBAAoB,EAAE,4BAA4B,CAAA;IAC3D,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAA;IAChC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,+BAA+B,CAAC,CAAA;IACxD,OAAO,IAAI,OAAO,CAAA;IAClB,OAAO,IAAI,IAAI,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,mBAAmB,CAAC,IAAI,IAAI,CAAA;IAC5B,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,oBAAoB,CAAC,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAA;IAC5C,OAAO,CAAC,IAAI,IAAI,CAAA;IAChB,aAAa,CAAC,IAAI,IAAI,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,iCAAiC,GAAG,IAAI,CAClD,yBAAyB,EACzB,gBAAgB,GAAG,2BAA2B,CAC/C,GAAG;IACF,eAAe,EAAE,6BAA6B,CAAA;CAC/C,CAAA;AAQD,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,yBAAyB,EAClC,SAAS,GAAE,2BAAgC,GAC1C,0BAA0B,CAE5B;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,iCAAiC,EAC1C,SAAS,GAAE,2BAAgC,GAC1C,0BAA0B,CAkF5B;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,yBAAyB,GACjC,iCAAiC,CAcnC;AAqBD,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,YAAY,GAAG,4BAA4B,CAO7F"}