@tsuzuri-lab/sed-language-server 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -39
- package/package.json +8 -4
- package/src/analysis.js +275 -0
- package/src/server.js +49 -46
- package/vendor/tree-sitter-sed-gnu.wasm +0 -0
- package/vendor/tree-sitter-sed-posix.wasm +0 -0
- package/src/completion.js +0 -148
- package/src/definition.js +0 -46
- package/src/diagnostics.js +0 -1865
- package/src/document-structure.js +0 -774
- package/src/sed-syntax.js +0 -2321
- package/src/syntax-profile.js +0 -99
package/README.md
CHANGED
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/tsuzuri-lab/sed-language-server/actions/workflows/ci.yml)
|
|
4
4
|
|
|
5
|
-
A
|
|
6
|
-
implementation for
|
|
7
|
-
[POSIX `sed`](https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/utilities/sed.html)
|
|
8
|
-
with opt-in GNU sed 4.10 syntax support.
|
|
9
|
-
|
|
10
|
-
The default profile is POSIX with basic regular expressions. BSD and
|
|
11
|
-
other implementation-specific extensions are outside the current scope.
|
|
5
|
+
A Language Server Protocol implementation for POSIX and GNU `sed`.
|
|
12
6
|
|
|
13
7
|
## Installation
|
|
14
8
|
|
|
@@ -18,7 +12,7 @@ Requires Node.js 22 or later.
|
|
|
18
12
|
npm install --global @tsuzuri-lab/sed-language-server
|
|
19
13
|
```
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
Start the server with:
|
|
22
16
|
|
|
23
17
|
```sh
|
|
24
18
|
sed-language-server --stdio
|
|
@@ -26,49 +20,59 @@ sed-language-server --stdio
|
|
|
26
20
|
|
|
27
21
|
## Features
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- profile-aware diagnostics for supported POSIX and GNU sed syntax
|
|
32
|
-
- profile-aware command, substitute-flag, and branch-label completion
|
|
23
|
+
- Tree-sitter-based diagnostics
|
|
33
24
|
- go to definition from `b`, `t`, and GNU `T` label references
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
accessing referenced files.
|
|
37
|
-
|
|
38
|
-
## Syntax profiles
|
|
26
|
+
Scripts are analyzed without executing them or accessing referenced files.
|
|
39
27
|
|
|
40
|
-
|
|
28
|
+
## Configuration
|
|
41
29
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Clients can select a profile during initialization:
|
|
30
|
+
The default dialect is `posix`. To use GNU syntax, pass the following LSP
|
|
31
|
+
initialization options:
|
|
46
32
|
|
|
47
33
|
```json
|
|
48
34
|
{
|
|
49
|
-
"
|
|
50
|
-
"dialect": "gnu",
|
|
51
|
-
"regexpMode": "bre"
|
|
52
|
-
}
|
|
35
|
+
"dialect": "gnu"
|
|
53
36
|
}
|
|
54
37
|
```
|
|
55
38
|
|
|
56
|
-
|
|
57
|
-
`workspace/didChangeConfiguration`:
|
|
39
|
+
The supported dialects are `posix` and `gnu`.
|
|
58
40
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
41
|
+
## Editor setup
|
|
42
|
+
|
|
43
|
+
Configure the LSP client to use:
|
|
44
|
+
|
|
45
|
+
- command: `sed-language-server --stdio`
|
|
46
|
+
- language ID or filetype: `sed`
|
|
47
|
+
- initialization options: `{"dialect":"gnu"}` when using GNU syntax
|
|
48
|
+
|
|
49
|
+
For example, with Emacs and Eglot:
|
|
50
|
+
|
|
51
|
+
```elisp
|
|
52
|
+
(require 'eglot)
|
|
53
|
+
|
|
54
|
+
(add-to-list 'eglot-server-programs
|
|
55
|
+
'((sed-ts-mode sed-mode) .
|
|
56
|
+
("sed-language-server" "--stdio"
|
|
57
|
+
:initializationOptions (:dialect "gnu"))))
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Run `M-x eglot` in a `sed-ts-mode` or `sed-mode` buffer. Omit
|
|
61
|
+
`:initializationOptions` to use the default POSIX dialect.
|
|
62
|
+
|
|
63
|
+
For Neovim 0.11 or later:
|
|
64
|
+
|
|
65
|
+
```lua
|
|
66
|
+
vim.lsp.config("sed_language_server", {
|
|
67
|
+
cmd = { "sed-language-server", "--stdio" },
|
|
68
|
+
filetypes = { "sed" },
|
|
69
|
+
init_options = { dialect = "gnu" },
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
vim.lsp.enable("sed_language_server")
|
|
68
73
|
```
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
from document contents.
|
|
75
|
+
Omit `init_options` to use the default POSIX dialect.
|
|
72
76
|
|
|
73
77
|
## Development
|
|
74
78
|
|
|
@@ -76,7 +80,13 @@ from document contents.
|
|
|
76
80
|
npm ci
|
|
77
81
|
npm run check
|
|
78
82
|
npm test
|
|
79
|
-
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The published package includes prebuilt POSIX and GNU grammar Wasm files.
|
|
86
|
+
Rebuild them from the pinned `tree-sitter-sed` revision with:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
npm run build:grammar -- /path/to/tree-sitter-sed
|
|
80
90
|
```
|
|
81
91
|
|
|
82
92
|
## License
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tsuzuri-lab/sed-language-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Language server for POSIX sed with opt-in GNU syntax support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sed",
|
|
@@ -9,12 +9,14 @@
|
|
|
9
9
|
],
|
|
10
10
|
"type": "module",
|
|
11
11
|
"files": [
|
|
12
|
-
"src"
|
|
12
|
+
"src",
|
|
13
|
+
"vendor"
|
|
13
14
|
],
|
|
14
15
|
"bin": {
|
|
15
16
|
"sed-language-server": "src/server.js"
|
|
16
17
|
},
|
|
17
18
|
"scripts": {
|
|
19
|
+
"build:grammar": "node scripts/build-tree-sitter-sed-wasm.js",
|
|
18
20
|
"check": "biome check .",
|
|
19
21
|
"check:write": "biome check --write .",
|
|
20
22
|
"prepublishOnly": "npm run check && npm test",
|
|
@@ -38,9 +40,11 @@
|
|
|
38
40
|
},
|
|
39
41
|
"dependencies": {
|
|
40
42
|
"vscode-languageserver": "10.1.0",
|
|
41
|
-
"vscode-languageserver-textdocument": "1.0.12"
|
|
43
|
+
"vscode-languageserver-textdocument": "1.0.12",
|
|
44
|
+
"web-tree-sitter": "0.26.11"
|
|
42
45
|
},
|
|
43
46
|
"devDependencies": {
|
|
44
|
-
"@biomejs/biome": "2.5.5"
|
|
47
|
+
"@biomejs/biome": "2.5.5",
|
|
48
|
+
"tree-sitter-cli": "0.26.11"
|
|
45
49
|
}
|
|
46
50
|
}
|
package/src/analysis.js
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { DiagnosticSeverity } from "vscode-languageserver/node";
|
|
3
|
+
import { Language, Parser } from "web-tree-sitter";
|
|
4
|
+
|
|
5
|
+
await Parser.init();
|
|
6
|
+
|
|
7
|
+
async function createParser(dialect) {
|
|
8
|
+
const path = fileURLToPath(
|
|
9
|
+
new URL(`../vendor/tree-sitter-sed-${dialect}.wasm`, import.meta.url),
|
|
10
|
+
);
|
|
11
|
+
return new Parser().setLanguage(await Language.load(path));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const parsers = {
|
|
15
|
+
posix: await createParser("posix"),
|
|
16
|
+
gnu: await createParser("gnu"),
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const documentTrees = new Map();
|
|
20
|
+
|
|
21
|
+
function parseDocument(document, dialect) {
|
|
22
|
+
const source = document.getText();
|
|
23
|
+
let trees = documentTrees.get(document.uri);
|
|
24
|
+
|
|
25
|
+
if (trees === undefined) {
|
|
26
|
+
trees = new Map();
|
|
27
|
+
documentTrees.set(document.uri, trees);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const cached = trees.get(dialect);
|
|
31
|
+
if (
|
|
32
|
+
cached !== undefined &&
|
|
33
|
+
cached.version === document.version &&
|
|
34
|
+
cached.source === source
|
|
35
|
+
) {
|
|
36
|
+
return cached.tree;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
cached?.tree.delete();
|
|
40
|
+
const tree = parsers[dialect].parse(source);
|
|
41
|
+
if (tree === null) {
|
|
42
|
+
throw new Error(`Failed to parse ${dialect} sed source.`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
trees.set(dialect, {
|
|
46
|
+
source,
|
|
47
|
+
tree,
|
|
48
|
+
version: document.version,
|
|
49
|
+
});
|
|
50
|
+
return tree;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function invalidateSyntaxTreeCache(document) {
|
|
54
|
+
const trees = documentTrees.get(document.uri);
|
|
55
|
+
if (trees !== undefined) {
|
|
56
|
+
for (const { tree } of trees.values()) {
|
|
57
|
+
tree.delete();
|
|
58
|
+
}
|
|
59
|
+
documentTrees.delete(document.uri);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const diagnosticSource = "sed-language-server";
|
|
64
|
+
|
|
65
|
+
const issueDescriptions = {
|
|
66
|
+
incomplete_escape: {
|
|
67
|
+
code: "incomplete-escape",
|
|
68
|
+
message: "This escape sequence is incomplete.",
|
|
69
|
+
},
|
|
70
|
+
incomplete_regex: {
|
|
71
|
+
code: "unterminated-regular-expression",
|
|
72
|
+
message: "This regular expression is not terminated.",
|
|
73
|
+
},
|
|
74
|
+
incomplete_replacement: {
|
|
75
|
+
code: "unterminated-replacement",
|
|
76
|
+
message: "This replacement is not terminated.",
|
|
77
|
+
},
|
|
78
|
+
incomplete_translate: {
|
|
79
|
+
code: "unterminated-translation",
|
|
80
|
+
message: "This translation is not terminated.",
|
|
81
|
+
},
|
|
82
|
+
invalid_control_escape: {
|
|
83
|
+
code: "invalid-control-escape",
|
|
84
|
+
message: "This GNU sed control escape is invalid.",
|
|
85
|
+
},
|
|
86
|
+
unclosed_bracket: {
|
|
87
|
+
code: "unclosed-bracket-expression",
|
|
88
|
+
message: "This bracket expression is not terminated.",
|
|
89
|
+
},
|
|
90
|
+
invalid_command: (node, dialect) => ({
|
|
91
|
+
code: "invalid-command",
|
|
92
|
+
message: `Unknown ${dialectName(dialect)} sed command: \`${node.text}\`.`,
|
|
93
|
+
}),
|
|
94
|
+
invalid_flag: (node, dialect) => ({
|
|
95
|
+
code: "invalid-substitution-flag",
|
|
96
|
+
message: `Unknown ${dialectName(dialect)} sed substitution flag: \`${node.text}\`.`,
|
|
97
|
+
}),
|
|
98
|
+
unexpected_text: (_node, dialect) => ({
|
|
99
|
+
code: "unexpected-text",
|
|
100
|
+
message: `Unexpected text after this ${dialectName(dialect)} sed command.`,
|
|
101
|
+
}),
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
function dialectName(dialect) {
|
|
105
|
+
return dialect === "gnu" ? "GNU" : "POSIX";
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function descriptionFor(node, dialect) {
|
|
109
|
+
const description = issueDescriptions[node.type];
|
|
110
|
+
if (typeof description === "function") {
|
|
111
|
+
return description(node, dialect);
|
|
112
|
+
}
|
|
113
|
+
if (description !== undefined) {
|
|
114
|
+
return description;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const displayName = dialectName(dialect);
|
|
118
|
+
if (node.isMissing) {
|
|
119
|
+
return {
|
|
120
|
+
code: "missing-syntax",
|
|
121
|
+
message: `Expected ${node.type.replaceAll("_", " ")}.`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
code: "syntax-error",
|
|
127
|
+
message: `Invalid ${displayName} sed syntax.`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isSpecificIssue(node) {
|
|
132
|
+
return node.isMissing || Object.hasOwn(issueDescriptions, node.type);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function collectIssueNodes(rootNode) {
|
|
136
|
+
const issues = [];
|
|
137
|
+
const stack = [
|
|
138
|
+
{
|
|
139
|
+
node: rootNode,
|
|
140
|
+
children: rootNode.children,
|
|
141
|
+
childIndex: 0,
|
|
142
|
+
hasDescendantIssue: false,
|
|
143
|
+
issueStartIndex: 0,
|
|
144
|
+
},
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
while (stack.length > 0) {
|
|
148
|
+
const frame = stack.at(-1);
|
|
149
|
+
if (frame.childIndex < frame.children.length) {
|
|
150
|
+
const child = frame.children[frame.childIndex];
|
|
151
|
+
frame.childIndex += 1;
|
|
152
|
+
stack.push({
|
|
153
|
+
node: child,
|
|
154
|
+
children: child.children,
|
|
155
|
+
childIndex: 0,
|
|
156
|
+
hasDescendantIssue: false,
|
|
157
|
+
issueStartIndex: issues.length,
|
|
158
|
+
});
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const specific = isSpecificIssue(frame.node);
|
|
163
|
+
const selected =
|
|
164
|
+
specific || (frame.node.isError && !frame.hasDescendantIssue);
|
|
165
|
+
if (specific) {
|
|
166
|
+
issues.length = frame.issueStartIndex;
|
|
167
|
+
}
|
|
168
|
+
if (selected) {
|
|
169
|
+
issues.push(frame.node);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
stack.pop();
|
|
173
|
+
const parent = stack.at(-1);
|
|
174
|
+
if (parent !== undefined) {
|
|
175
|
+
parent.hasDescendantIssue ||= frame.hasDescendantIssue || selected;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return issues;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function issuePriority(node) {
|
|
183
|
+
if (node.isError) {
|
|
184
|
+
return 0;
|
|
185
|
+
}
|
|
186
|
+
if (node.isMissing) {
|
|
187
|
+
return 1;
|
|
188
|
+
}
|
|
189
|
+
return 2;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function preferSpecificIssues(nodes) {
|
|
193
|
+
const issuesByRange = new Map();
|
|
194
|
+
|
|
195
|
+
for (const node of nodes) {
|
|
196
|
+
const key = `${node.startIndex}:${node.endIndex}`;
|
|
197
|
+
const existing = issuesByRange.get(key);
|
|
198
|
+
if (
|
|
199
|
+
existing === undefined ||
|
|
200
|
+
issuePriority(node) > issuePriority(existing)
|
|
201
|
+
) {
|
|
202
|
+
issuesByRange.set(key, node);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return [...issuesByRange.values()].sort(
|
|
207
|
+
(left, right) =>
|
|
208
|
+
left.startIndex - right.startIndex || left.endIndex - right.endIndex,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function rangeForNode(document, node) {
|
|
213
|
+
return {
|
|
214
|
+
start: document.positionAt(node.startIndex),
|
|
215
|
+
end: document.positionAt(node.endIndex),
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function collectLabels(rootNode, offset) {
|
|
220
|
+
const definitions = [];
|
|
221
|
+
let reference;
|
|
222
|
+
const stack = [rootNode];
|
|
223
|
+
|
|
224
|
+
while (stack.length > 0) {
|
|
225
|
+
const node = stack.pop();
|
|
226
|
+
if (node.type === "label_definition") {
|
|
227
|
+
definitions.push(node);
|
|
228
|
+
} else if (
|
|
229
|
+
node.type === "label_reference" &&
|
|
230
|
+
node.startIndex <= offset &&
|
|
231
|
+
offset < node.endIndex
|
|
232
|
+
) {
|
|
233
|
+
reference = node;
|
|
234
|
+
}
|
|
235
|
+
stack.push(...node.children.toReversed());
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return { definitions, reference };
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function createDiagnostics(document, dialect) {
|
|
242
|
+
const tree = parseDocument(document, dialect);
|
|
243
|
+
|
|
244
|
+
return preferSpecificIssues(collectIssueNodes(tree.rootNode)).map((node) => {
|
|
245
|
+
const { code, message } = descriptionFor(node, dialect);
|
|
246
|
+
return {
|
|
247
|
+
severity: DiagnosticSeverity.Error,
|
|
248
|
+
range: rangeForNode(document, node),
|
|
249
|
+
message,
|
|
250
|
+
code,
|
|
251
|
+
source: diagnosticSource,
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function createDefinitionLocations(document, position, dialect) {
|
|
257
|
+
const tree = parseDocument(document, dialect);
|
|
258
|
+
const { definitions, reference } = collectLabels(
|
|
259
|
+
tree.rootNode,
|
|
260
|
+
document.offsetAt(position),
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
if (reference === undefined) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const locations = definitions
|
|
268
|
+
.filter((definition) => definition.text === reference.text)
|
|
269
|
+
.map((definition) => ({
|
|
270
|
+
uri: document.uri,
|
|
271
|
+
range: rangeForNode(document, definition),
|
|
272
|
+
}));
|
|
273
|
+
|
|
274
|
+
return locations.length === 0 ? null : locations;
|
|
275
|
+
}
|
package/src/server.js
CHANGED
|
@@ -12,16 +12,10 @@ import {
|
|
|
12
12
|
} from "vscode-languageserver/node";
|
|
13
13
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import { createDiagnostics } from "./diagnostics.js";
|
|
20
|
-
import { invalidateDocumentStructureCache } from "./document-structure.js";
|
|
21
|
-
import {
|
|
22
|
-
defaultSyntaxProfile,
|
|
23
|
-
resolveSyntaxProfile,
|
|
24
|
-
} from "./syntax-profile.js";
|
|
15
|
+
createDefinitionLocations,
|
|
16
|
+
createDiagnostics,
|
|
17
|
+
invalidateSyntaxTreeCache,
|
|
18
|
+
} from "./analysis.js";
|
|
25
19
|
|
|
26
20
|
if (process.argv.length === 2) {
|
|
27
21
|
process.argv.push("--stdio");
|
|
@@ -29,19 +23,31 @@ if (process.argv.length === 2) {
|
|
|
29
23
|
|
|
30
24
|
const connection = createConnection(ProposedFeatures.all);
|
|
31
25
|
const documents = new TextDocuments(TextDocument);
|
|
32
|
-
|
|
26
|
+
const defaultDialect = "posix";
|
|
27
|
+
let activeDialect = defaultDialect;
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
29
|
+
function resolveDialect(options) {
|
|
30
|
+
if (options === undefined || options === null) {
|
|
31
|
+
return { dialect: defaultDialect };
|
|
32
|
+
}
|
|
33
|
+
if (typeof options !== "object" || Array.isArray(options)) {
|
|
34
|
+
return {
|
|
35
|
+
error: "Syntax options must be provided as an object or null.",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const dialect =
|
|
40
|
+
options.dialect === undefined ? defaultDialect : options.dialect;
|
|
41
|
+
if (dialect !== "posix" && dialect !== "gnu") {
|
|
42
|
+
return {
|
|
43
|
+
error: 'The syntax dialect must be either "posix" or "gnu".',
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return { dialect };
|
|
42
48
|
}
|
|
43
49
|
|
|
44
|
-
function
|
|
50
|
+
function configurationOptions(settings) {
|
|
45
51
|
if (
|
|
46
52
|
settings !== null &&
|
|
47
53
|
typeof settings === "object" &&
|
|
@@ -54,63 +60,60 @@ function configurationProfileOptions(settings) {
|
|
|
54
60
|
return settings;
|
|
55
61
|
}
|
|
56
62
|
|
|
57
|
-
function publishDiagnostics(document
|
|
63
|
+
function publishDiagnostics(document) {
|
|
58
64
|
return connection.sendDiagnostics({
|
|
59
65
|
uri: document.uri,
|
|
60
66
|
version: document.version,
|
|
61
|
-
diagnostics: createDiagnostics(document,
|
|
67
|
+
diagnostics: createDiagnostics(document, activeDialect),
|
|
62
68
|
});
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
connection.onInitialize(({ initializationOptions }) => {
|
|
66
|
-
const result =
|
|
67
|
-
if (
|
|
68
|
-
return new ResponseError(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
{ retry: false },
|
|
72
|
-
);
|
|
72
|
+
const result = resolveDialect(initializationOptions);
|
|
73
|
+
if (result.error !== undefined) {
|
|
74
|
+
return new ResponseError(ErrorCodes.InvalidParams, result.error, {
|
|
75
|
+
retry: false,
|
|
76
|
+
});
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
activeDialect = result.dialect;
|
|
76
80
|
return {
|
|
77
|
-
capabilities:
|
|
81
|
+
capabilities: {
|
|
82
|
+
textDocumentSync: TextDocumentSyncKind.Incremental,
|
|
83
|
+
definitionProvider: true,
|
|
84
|
+
},
|
|
78
85
|
};
|
|
79
86
|
});
|
|
80
87
|
|
|
81
88
|
connection.onDidChangeConfiguration(async ({ settings }) => {
|
|
82
|
-
const result =
|
|
83
|
-
if (
|
|
89
|
+
const result = resolveDialect(configurationOptions(settings));
|
|
90
|
+
if (result.error !== undefined) {
|
|
84
91
|
connection.sendNotification(ShowMessageNotification.type, {
|
|
85
92
|
type: MessageType.Error,
|
|
86
|
-
message:
|
|
93
|
+
message: result.error,
|
|
87
94
|
});
|
|
88
95
|
return;
|
|
89
96
|
}
|
|
90
97
|
|
|
91
|
-
|
|
92
|
-
activeSyntaxProfile = nextSyntaxProfile;
|
|
93
|
-
invalidateDocumentStructureCache();
|
|
98
|
+
activeDialect = result.dialect;
|
|
94
99
|
await Promise.all(
|
|
95
|
-
documents
|
|
96
|
-
.all()
|
|
97
|
-
.map((document) => publishDiagnostics(document, nextSyntaxProfile)),
|
|
100
|
+
documents.all().map((document) => publishDiagnostics(document)),
|
|
98
101
|
);
|
|
99
102
|
});
|
|
100
103
|
|
|
101
|
-
connection.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
);
|
|
104
|
+
connection.onDefinition(({ textDocument, position }) => {
|
|
105
|
+
const document = documents.get(textDocument.uri);
|
|
106
|
+
return document === undefined
|
|
107
|
+
? null
|
|
108
|
+
: createDefinitionLocations(document, position, activeDialect);
|
|
109
|
+
});
|
|
107
110
|
|
|
108
111
|
documents.onDidChangeContent(({ document }) => {
|
|
109
112
|
publishDiagnostics(document);
|
|
110
113
|
});
|
|
111
114
|
|
|
112
115
|
documents.onDidClose(({ document }) => {
|
|
113
|
-
|
|
116
|
+
invalidateSyntaxTreeCache(document);
|
|
114
117
|
connection.sendDiagnostics({ uri: document.uri, diagnostics: [] });
|
|
115
118
|
});
|
|
116
119
|
|
|
Binary file
|
|
Binary file
|