@tsuzuri-lab/sed-language-server 0.1.2 → 0.3.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 +50 -39
- package/package.json +8 -4
- package/src/definition.js +30 -32
- package/src/diagnostics.js +83 -1829
- package/src/formatting.js +97 -0
- package/src/server.js +56 -46
- package/src/syntax.js +124 -0
- 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/document-structure.js +0 -774
- package/src/sed-syntax.js +0 -2321
- package/src/syntax-profile.js +0 -95
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,60 @@ 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
|
|
25
|
+
- document formatting for command lists and nested blocks
|
|
34
26
|
|
|
35
|
-
|
|
36
|
-
accessing referenced files.
|
|
37
|
-
|
|
38
|
-
## Syntax profiles
|
|
27
|
+
Scripts are analyzed without executing them or accessing referenced files.
|
|
39
28
|
|
|
40
|
-
|
|
29
|
+
## Configuration
|
|
41
30
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Clients can select a profile during initialization:
|
|
31
|
+
The default dialect is `posix`. To use GNU syntax, pass the following LSP
|
|
32
|
+
initialization options:
|
|
46
33
|
|
|
47
34
|
```json
|
|
48
35
|
{
|
|
49
|
-
"
|
|
50
|
-
"dialect": "gnu",
|
|
51
|
-
"regexpMode": "bre"
|
|
52
|
-
}
|
|
36
|
+
"dialect": "gnu"
|
|
53
37
|
}
|
|
54
38
|
```
|
|
55
39
|
|
|
56
|
-
|
|
57
|
-
`workspace/didChangeConfiguration`:
|
|
40
|
+
The supported dialects are `posix` and `gnu`.
|
|
58
41
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
42
|
+
## Editor setup
|
|
43
|
+
|
|
44
|
+
Configure the LSP client to use:
|
|
45
|
+
|
|
46
|
+
- command: `sed-language-server --stdio`
|
|
47
|
+
- language ID or filetype: `sed`
|
|
48
|
+
- initialization options: `{"dialect":"gnu"}` when using GNU syntax
|
|
49
|
+
|
|
50
|
+
For example, with Emacs and Eglot:
|
|
51
|
+
|
|
52
|
+
```elisp
|
|
53
|
+
(require 'eglot)
|
|
54
|
+
|
|
55
|
+
(add-to-list 'eglot-server-programs
|
|
56
|
+
'((sed-ts-mode sed-mode) .
|
|
57
|
+
("sed-language-server" "--stdio"
|
|
58
|
+
:initializationOptions (:dialect "gnu"))))
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Run `M-x eglot` in a `sed-ts-mode` or `sed-mode` buffer. Omit
|
|
62
|
+
`:initializationOptions` to use the default POSIX dialect.
|
|
63
|
+
|
|
64
|
+
For Neovim 0.11 or later:
|
|
65
|
+
|
|
66
|
+
```lua
|
|
67
|
+
vim.lsp.config("sed_language_server", {
|
|
68
|
+
cmd = { "sed-language-server", "--stdio" },
|
|
69
|
+
filetypes = { "sed" },
|
|
70
|
+
init_options = { dialect = "gnu" },
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
vim.lsp.enable("sed_language_server")
|
|
68
74
|
```
|
|
69
75
|
|
|
70
|
-
|
|
71
|
-
from document contents.
|
|
76
|
+
Omit `init_options` to use the default POSIX dialect.
|
|
72
77
|
|
|
73
78
|
## Development
|
|
74
79
|
|
|
@@ -76,7 +81,13 @@ from document contents.
|
|
|
76
81
|
npm ci
|
|
77
82
|
npm run check
|
|
78
83
|
npm test
|
|
79
|
-
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The published package includes prebuilt POSIX and GNU grammar Wasm files.
|
|
87
|
+
Rebuild them from the pinned `tree-sitter-sed` revision with:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
npm run build:grammar -- /path/to/tree-sitter-sed
|
|
80
91
|
```
|
|
81
92
|
|
|
82
93
|
## 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.3.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/definition.js
CHANGED
|
@@ -1,46 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { defaultSyntaxProfile } from "./syntax-profile.js";
|
|
1
|
+
import { rangeForNode, syntaxTreeFor } from "./syntax.js";
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
function collectLabels(rootNode, offset) {
|
|
4
|
+
const definitions = [];
|
|
5
|
+
let reference;
|
|
6
|
+
const stack = [rootNode];
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
while (stack.length > 0) {
|
|
9
|
+
const node = stack.pop();
|
|
10
|
+
if (node.type === "label_definition") {
|
|
11
|
+
definitions.push(node);
|
|
12
|
+
} else if (
|
|
13
|
+
node.type === "label_reference" &&
|
|
14
|
+
node.startIndex <= offset &&
|
|
15
|
+
offset < node.endIndex
|
|
16
|
+
) {
|
|
17
|
+
reference = node;
|
|
18
|
+
}
|
|
19
|
+
stack.push(...node.children.toReversed());
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { definitions, reference };
|
|
8
23
|
}
|
|
9
24
|
|
|
10
|
-
export function createDefinitionLocations(
|
|
11
|
-
document,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
)
|
|
15
|
-
const structure = getDocumentStructure(document, syntaxProfile);
|
|
16
|
-
const offset = document.offsetAt(position);
|
|
17
|
-
const reference = structure.labelReferences.find(({ range }) =>
|
|
18
|
-
containsCursor(range, offset),
|
|
25
|
+
export function createDefinitionLocations(document, position, dialect) {
|
|
26
|
+
const tree = syntaxTreeFor(document, dialect);
|
|
27
|
+
const { definitions, reference } = collectLabels(
|
|
28
|
+
tree.rootNode,
|
|
29
|
+
document.offsetAt(position),
|
|
19
30
|
);
|
|
20
31
|
|
|
21
32
|
if (reference === undefined) {
|
|
22
|
-
return
|
|
33
|
+
return null;
|
|
23
34
|
}
|
|
24
35
|
|
|
25
|
-
|
|
26
|
-
.filter((definition) => definition.
|
|
36
|
+
const locations = definitions
|
|
37
|
+
.filter((definition) => definition.text === reference.text)
|
|
27
38
|
.map((definition) => ({
|
|
28
39
|
uri: document.uri,
|
|
29
|
-
range:
|
|
30
|
-
start: document.positionAt(definition.range.startOffset),
|
|
31
|
-
end: document.positionAt(definition.range.endOffset),
|
|
32
|
-
},
|
|
40
|
+
range: rangeForNode(document, definition),
|
|
33
41
|
}));
|
|
34
|
-
}
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
documents,
|
|
38
|
-
getSyntaxProfile = () => defaultSyntaxProfile,
|
|
39
|
-
) {
|
|
40
|
-
return ({ textDocument, position }) => {
|
|
41
|
-
const document = documents.get(textDocument.uri);
|
|
42
|
-
return document === undefined
|
|
43
|
-
? null
|
|
44
|
-
: createDefinitionLocations(document, position, getSyntaxProfile());
|
|
45
|
-
};
|
|
43
|
+
return locations.length === 0 ? null : locations;
|
|
46
44
|
}
|