@herb-tools/language-server 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -7
- package/bin/herb-language-server +0 -16
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.js.map +1 -1
- package/dist/diagnostics.js +17 -50
- package/dist/diagnostics.js.map +1 -1
- package/dist/formatting_service.js +124 -0
- package/dist/formatting_service.js.map +1 -0
- package/dist/herb-language-server.js +16118 -6762
- package/dist/herb-language-server.js.map +1 -1
- package/dist/index.cjs +29900 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/linter_service.js +44 -0
- package/dist/linter_service.js.map +1 -0
- package/dist/parser_service.js +47 -0
- package/dist/parser_service.js.map +1 -0
- package/dist/project.js +2 -1
- package/dist/project.js.map +1 -1
- package/dist/server.js +72 -61
- package/dist/server.js.map +1 -1
- package/dist/service.js +16 -4
- package/dist/service.js.map +1 -1
- package/dist/settings.js +11 -1
- package/dist/settings.js.map +1 -1
- package/dist/types/cli.d.ts +4 -0
- package/dist/types/config.d.ts +9 -1
- package/dist/types/diagnostics.d.ts +9 -7
- package/dist/types/formatting_service.d.ts +19 -0
- package/dist/types/herb-language-server.d.ts +2 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/linter_service.d.ts +14 -0
- package/dist/types/parser_service.d.ts +10 -0
- package/dist/types/project.d.ts +2 -0
- package/dist/types/server.d.ts +7 -1
- package/dist/types/service.d.ts +6 -0
- package/dist/types/settings.d.ts +11 -0
- package/package.json +22 -24
- package/src/cli.ts +23 -0
- package/src/config.ts +9 -1
- package/src/diagnostics.ts +22 -79
- package/src/formatting_service.ts +150 -0
- package/src/herb-language-server.ts +6 -0
- package/src/index.ts +10 -0
- package/src/linter_service.ts +63 -0
- package/src/parser_service.ts +59 -0
- package/src/project.ts +4 -2
- package/src/server.ts +83 -65
- package/src/service.ts +21 -6
- package/src/settings.ts +24 -2
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
# Herb Language Server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Package**: [`@herb-tools/language-server`](https://www.npmjs.com/package/@herb-tools/language-server)
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
[Language Server Protocol](https://github.com/Microsoft/language-server-protocol) integration for HTML-aware ERB parsing using the [Herb Parser](
|
|
7
|
+
[Language Server Protocol](https://github.com/Microsoft/language-server-protocol) integration for HTML-aware ERB parsing using the [Herb Parser](/projects/parser).
|
|
8
8
|
|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
### Installation
|
|
12
12
|
|
|
@@ -26,14 +26,48 @@ Read more in the [documentation](https://zed.dev/docs/languages/ruby).
|
|
|
26
26
|
|
|
27
27
|
#### Neovim (using `nvim-lspconfig`)
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
After installing the Herb Language Server (see below), add `herb_ls` to your Neovim config (requires nvim 0.11+):
|
|
30
|
+
|
|
31
|
+
```lua
|
|
32
|
+
require('lspconfig')
|
|
33
|
+
vim.lsp.enable('herb_ls')
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### Sublime Text (using Sublime LSP)
|
|
37
|
+
|
|
38
|
+
After installing the Herb Language Server (see below) and [Sublime LSP](http://lsp.sublimetext.io), update the preferences for the `LSP` package:
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
// LSP.sublime-settings
|
|
42
|
+
{
|
|
43
|
+
"clients": {
|
|
44
|
+
"herb": {
|
|
45
|
+
"enabled": true,
|
|
46
|
+
"command": [
|
|
47
|
+
"herb-language-server",
|
|
48
|
+
"--stdio"
|
|
49
|
+
],
|
|
50
|
+
"selector": "text.html.ruby | text.html.rails",
|
|
51
|
+
"settings": {
|
|
52
|
+
"languageServerHerb.linter": {
|
|
53
|
+
"enabled": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"initializationOptions": {
|
|
57
|
+
"enabledFeatures": {
|
|
58
|
+
"diagnostics": true,
|
|
59
|
+
},
|
|
60
|
+
"experimentalFeaturesEnabled": true
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
```
|
|
30
66
|
|
|
31
67
|
#### Manual Installation
|
|
32
68
|
|
|
33
69
|
You can use the language server in any editor that supports the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/).
|
|
34
70
|
|
|
35
|
-
##### Install
|
|
36
|
-
|
|
37
71
|
###### NPM (Global)
|
|
38
72
|
|
|
39
73
|
```bash
|
|
@@ -52,6 +86,8 @@ yarn global add @herb-tools/language-server
|
|
|
52
86
|
herb-language-server --stdio
|
|
53
87
|
```
|
|
54
88
|
|
|
89
|
+
##### Usage
|
|
90
|
+
|
|
55
91
|
```
|
|
56
92
|
Usage: herb-language-server [options]
|
|
57
93
|
|
|
@@ -69,3 +105,34 @@ Alternatively you can also run the language server directly with `npx` without i
|
|
|
69
105
|
```bash
|
|
70
106
|
npx @herb-tools/language-server --stdio
|
|
71
107
|
```
|
|
108
|
+
|
|
109
|
+
## Configuration
|
|
110
|
+
|
|
111
|
+
The language server can be configured using a `.herb-lsp/config.json` file in your project root. This file is automatically created when the language server starts if it doesn't exist.
|
|
112
|
+
|
|
113
|
+
### Formatter Configuration
|
|
114
|
+
|
|
115
|
+
You can configure formatting behavior by adding a `formatter` section to your config:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"version": "0.3.1",
|
|
120
|
+
"createdAt": "2025-06-29T00:00:00.000Z",
|
|
121
|
+
"updatedAt": "2025-06-29T00:00:00.000Z",
|
|
122
|
+
"options": {
|
|
123
|
+
"formatter": {
|
|
124
|
+
"enabled": true,
|
|
125
|
+
"indentWidth": 2,
|
|
126
|
+
"maxLineLength": 80
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### `formatter` Options
|
|
133
|
+
|
|
134
|
+
- `enabled` (`boolean`): Enable or disable formatting for this project. Defaults to `false`.
|
|
135
|
+
- `indentWidth` (`number`): Number of spaces for each indentation level. Defaults to `2`.
|
|
136
|
+
- `maxLineLength` (`number`): Maximum line length before wrapping. Defaults to `80`.
|
|
137
|
+
|
|
138
|
+
**Note**: VS Code users can also control formatting globally through the `languageServerHerb.formatter.enabled` setting in VS Code preferences. Formatting is currently in **Beta** and disabled by default.
|
package/bin/herb-language-server
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const usage = `
|
|
4
|
-
Usage: herb-language-server [options]
|
|
5
|
-
|
|
6
|
-
Options:
|
|
7
|
-
--stdio use stdio
|
|
8
|
-
--node-ipc use node-ipc
|
|
9
|
-
--socket=<port> use socket
|
|
10
|
-
`
|
|
11
|
-
|
|
12
|
-
if (process.argv.length <= 2) {
|
|
13
|
-
console.error(`Error: Connection input stream is not set. Set command line parameters: '--node-ipc', '--stdio' or '--socket=<port>'`)
|
|
14
|
-
console.error(usage)
|
|
15
|
-
|
|
16
|
-
process.exit(1)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
3
|
import("../dist/herb-language-server.js")
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CLI = void 0;
|
|
4
|
+
const server_1 = require("./server");
|
|
5
|
+
class CLI {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.usage = `
|
|
8
|
+
Usage: herb-language-server [options]
|
|
9
|
+
|
|
10
|
+
Options:
|
|
11
|
+
--stdio use stdio
|
|
12
|
+
--node-ipc use node-ipc
|
|
13
|
+
--socket=<port> use socket
|
|
14
|
+
`;
|
|
15
|
+
}
|
|
16
|
+
run() {
|
|
17
|
+
if (process.argv.length <= 2) {
|
|
18
|
+
console.error(`Error: Connection input stream is not set. Set command line parameters: '--node-ipc', '--stdio' or '--socket=<port>'`);
|
|
19
|
+
console.error(this.usage);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
const server = new server_1.Server();
|
|
23
|
+
server.listen();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.CLI = CLI;
|
|
27
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAAA,qCAAiC;AAEjC,MAAa,GAAG;IAAhB;QACU,UAAK,GAAG;;;;;;;CAOjB,CAAA;IAYD,CAAC;IAVC,GAAG;QACD,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,KAAK,CAAC,sHAAsH,CAAC,CAAA;YACrI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,eAAM,EAAE,CAAA;QAC3B,MAAM,CAAC,MAAM,EAAE,CAAA;IACjB,CAAC;CACF;AApBD,kBAoBC"}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/diagnostics.js
CHANGED
|
@@ -1,63 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Diagnostics = void 0;
|
|
4
|
-
const node_1 = require("vscode-languageserver/node");
|
|
5
|
-
const node_wasm_1 = require("@herb-tools/node-wasm");
|
|
6
|
-
class ErrorVisitor extends node_wasm_1.Visitor {
|
|
7
|
-
constructor(diagnostics, textDocument) {
|
|
8
|
-
super();
|
|
9
|
-
this.diagnostics = diagnostics;
|
|
10
|
-
this.textDocument = textDocument;
|
|
11
|
-
}
|
|
12
|
-
visitChildNodes(node) {
|
|
13
|
-
super.visitChildNodes(node);
|
|
14
|
-
node.errors.forEach(error => this.publishDiagnosticForError(error, node));
|
|
15
|
-
}
|
|
16
|
-
publishDiagnosticForError(error, node) {
|
|
17
|
-
this.diagnostics.pushDiagnostic(error.message, error.type, this.rangeFromHerbError(error), this.textDocument, {
|
|
18
|
-
error: error.toJSON(),
|
|
19
|
-
node: node.toJSON()
|
|
20
|
-
}, node_1.DiagnosticSeverity.Error);
|
|
21
|
-
}
|
|
22
|
-
rangeFromHerbError(error) {
|
|
23
|
-
return node_1.Range.create(node_1.Position.create(error.location.start.line - 1, error.location.start.column), node_1.Position.create(error.location.end.line - 1, error.location.end.column));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
4
|
class Diagnostics {
|
|
27
|
-
constructor(connection, documentService) {
|
|
28
|
-
this.diagnosticsSource = "Herb LSP ";
|
|
5
|
+
constructor(connection, documentService, parserService, linterService) {
|
|
29
6
|
this.diagnostics = new Map();
|
|
30
7
|
this.connection = connection;
|
|
31
8
|
this.documentService = documentService;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
9
|
+
this.parserService = parserService;
|
|
10
|
+
this.linterService = linterService;
|
|
11
|
+
}
|
|
12
|
+
async validate(textDocument) {
|
|
13
|
+
const parseResult = this.parserService.parseDocument(textDocument);
|
|
14
|
+
const lintResult = await this.linterService.lintDocument(parseResult.document, textDocument);
|
|
15
|
+
const allDiagnostics = [
|
|
16
|
+
...parseResult.diagnostics,
|
|
17
|
+
...lintResult.diagnostics,
|
|
18
|
+
];
|
|
19
|
+
this.diagnostics.set(textDocument, allDiagnostics);
|
|
38
20
|
this.sendDiagnosticsFor(textDocument);
|
|
39
21
|
}
|
|
40
|
-
refreshDocument(document) {
|
|
41
|
-
this.validate(document);
|
|
42
|
-
}
|
|
43
|
-
refreshAllDocuments() {
|
|
44
|
-
this.documentService.getAll().forEach((document) => {
|
|
45
|
-
this.refreshDocument(document);
|
|
46
|
-
});
|
|
22
|
+
async refreshDocument(document) {
|
|
23
|
+
await this.validate(document);
|
|
47
24
|
}
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
severity,
|
|
52
|
-
range,
|
|
53
|
-
message,
|
|
54
|
-
code,
|
|
55
|
-
data,
|
|
56
|
-
};
|
|
57
|
-
const diagnostics = this.diagnostics.get(textDocument) || [];
|
|
58
|
-
diagnostics.push(diagnostic);
|
|
59
|
-
this.diagnostics.set(textDocument, diagnostics);
|
|
60
|
-
return diagnostic;
|
|
25
|
+
async refreshAllDocuments() {
|
|
26
|
+
const documents = this.documentService.getAll();
|
|
27
|
+
await Promise.all(documents.map(document => this.refreshDocument(document)));
|
|
61
28
|
}
|
|
62
29
|
sendDiagnosticsFor(textDocument) {
|
|
63
30
|
const diagnostics = this.diagnostics.get(textDocument) || [];
|
package/dist/diagnostics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../src/diagnostics.ts"],"names":[],"mappings":";;;AAOA,MAAa,WAAW;IAOtB,YACE,UAAsB,EACtB,eAAgC,EAChC,aAA4B,EAC5B,aAA4B;QANtB,gBAAW,GAAoC,IAAI,GAAG,EAAE,CAAA;QAQ9D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,eAAe,GAAG,eAAe,CAAA;QACtC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;QAClC,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;IACpC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,YAA0B;QACvC,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;QAClE,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QAE5F,MAAM,cAAc,GAAG;YACrB,GAAG,WAAW,CAAC,WAAW;YAC1B,GAAG,UAAU,CAAC,WAAW;SAC1B,CAAA;QAED,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,EAAE,cAAc,CAAC,CAAA;QAClD,IAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAA;IACvC,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAsB;QAC1C,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC/B,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAA;QAC/C,MAAM,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;IAC9E,CAAC;IAEO,kBAAkB,CAAC,YAA0B;QACnD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAA;QAE5D,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC;YAC9B,GAAG,EAAE,YAAY,CAAC,GAAG;YACrB,WAAW;SACZ,CAAC,CAAA;QAEF,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;IACvC,CAAC;CACF;AAnDD,kCAmDC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FormattingService = void 0;
|
|
4
|
+
const node_1 = require("vscode-languageserver/node");
|
|
5
|
+
const formatter_1 = require("@herb-tools/formatter");
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
const glob_1 = require("glob");
|
|
8
|
+
class FormattingService {
|
|
9
|
+
constructor(connection, documents, project, settings) {
|
|
10
|
+
this.connection = connection;
|
|
11
|
+
this.documents = documents;
|
|
12
|
+
this.project = project;
|
|
13
|
+
this.settings = settings;
|
|
14
|
+
}
|
|
15
|
+
async initialize() {
|
|
16
|
+
try {
|
|
17
|
+
this.config = await config_1.Config.fromPathOrNew(this.project.projectPath);
|
|
18
|
+
this.connection.console.log("Herb formatter initialized successfully");
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
this.connection.console.error(`Failed to initialize Herb formatter: ${error}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async refreshConfig() {
|
|
25
|
+
this.config = await config_1.Config.fromPathOrNew(this.project.projectPath);
|
|
26
|
+
}
|
|
27
|
+
async shouldFormatFile(filePath) {
|
|
28
|
+
var _a;
|
|
29
|
+
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.options.formatter)) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
const formatter = this.config.options.formatter;
|
|
33
|
+
// Check if formatting is disabled in project config
|
|
34
|
+
if (formatter.enabled === false) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
// Check exclude patterns first
|
|
38
|
+
if (formatter.exclude) {
|
|
39
|
+
for (const pattern of formatter.exclude) {
|
|
40
|
+
try {
|
|
41
|
+
const matches = await new Promise((resolve, reject) => {
|
|
42
|
+
(0, glob_1.glob)(pattern, { cwd: this.project.projectPath }).then(resolve).catch(reject);
|
|
43
|
+
});
|
|
44
|
+
if (Array.isArray(matches) && matches.some((match) => filePath.includes(match) || filePath.endsWith(match))) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (formatter.include && formatter.include.length > 0) {
|
|
54
|
+
for (const pattern of formatter.include) {
|
|
55
|
+
try {
|
|
56
|
+
const matches = await new Promise((resolve, reject) => {
|
|
57
|
+
(0, glob_1.glob)(pattern, { cwd: this.project.projectPath }).then(resolve).catch(reject);
|
|
58
|
+
});
|
|
59
|
+
if (Array.isArray(matches) && matches.some((match) => filePath.includes(match) || filePath.endsWith(match))) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
async getFormatterOptions(uri) {
|
|
72
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
73
|
+
const settings = await this.settings.getDocumentSettings(uri);
|
|
74
|
+
const projectFormatter = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.options.formatter) || {};
|
|
75
|
+
return {
|
|
76
|
+
indentWidth: (_d = (_b = projectFormatter.indentWidth) !== null && _b !== void 0 ? _b : (_c = settings.formatter) === null || _c === void 0 ? void 0 : _c.indentWidth) !== null && _d !== void 0 ? _d : formatter_1.defaultFormatOptions.indentWidth,
|
|
77
|
+
maxLineLength: (_g = (_e = projectFormatter.maxLineLength) !== null && _e !== void 0 ? _e : (_f = settings.formatter) === null || _f === void 0 ? void 0 : _f.maxLineLength) !== null && _g !== void 0 ? _g : formatter_1.defaultFormatOptions.maxLineLength
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async performFormatting(params) {
|
|
81
|
+
const document = this.documents.get(params.textDocument.uri);
|
|
82
|
+
if (!document) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
const options = await this.getFormatterOptions(params.textDocument.uri);
|
|
87
|
+
const formatter = new formatter_1.Formatter(this.project.herbBackend, options);
|
|
88
|
+
const text = document.getText();
|
|
89
|
+
let newText = formatter.format(text);
|
|
90
|
+
if (!newText.endsWith('\n')) {
|
|
91
|
+
newText = newText + '\n';
|
|
92
|
+
}
|
|
93
|
+
if (newText === text) {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
const range = {
|
|
97
|
+
start: node_1.Position.create(0, 0),
|
|
98
|
+
end: node_1.Position.create(document.lineCount, 0)
|
|
99
|
+
};
|
|
100
|
+
return [{ range, newText }];
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
this.connection.console.error(`Formatting failed: ${error}`);
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async formatDocument(params) {
|
|
108
|
+
var _a;
|
|
109
|
+
const settings = await this.settings.getDocumentSettings(params.textDocument.uri);
|
|
110
|
+
if (((_a = settings.formatter) === null || _a === void 0 ? void 0 : _a.enabled) === false) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
const filePath = params.textDocument.uri.replace(/^file:\/\//, '');
|
|
114
|
+
if (!(await this.shouldFormatFile(filePath))) {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
return this.performFormatting(params);
|
|
118
|
+
}
|
|
119
|
+
async formatDocumentIgnoreConfig(params) {
|
|
120
|
+
return this.performFormatting(params);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.FormattingService = FormattingService;
|
|
124
|
+
//# sourceMappingURL=formatting_service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatting_service.js","sourceRoot":"","sources":["../src/formatting_service.ts"],"names":[],"mappings":"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"}
|