@herb-tools/language-server 0.8.10 → 0.9.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/dist/action_view_helpers.js +19 -0
- package/dist/action_view_helpers.js.map +1 -0
- package/dist/autofix_service.js +1 -1
- package/dist/autofix_service.js.map +1 -1
- package/dist/code_action_service.js +3 -6
- package/dist/code_action_service.js.map +1 -1
- package/dist/comment_ast_utils.js +206 -0
- package/dist/comment_ast_utils.js.map +1 -0
- package/dist/comment_service.js +175 -0
- package/dist/comment_service.js.map +1 -0
- package/dist/diagnostics.js +15 -27
- package/dist/diagnostics.js.map +1 -1
- package/dist/document_highlight_service.js +196 -0
- package/dist/document_highlight_service.js.map +1 -0
- package/dist/document_save_service.js +16 -6
- package/dist/document_save_service.js.map +1 -1
- package/dist/folding_range_service.js +209 -0
- package/dist/folding_range_service.js.map +1 -0
- package/dist/formatting_service.js +4 -4
- package/dist/formatting_service.js.map +1 -1
- package/dist/herb-language-server.js +150189 -41260
- package/dist/herb-language-server.js.map +1 -1
- package/dist/hover_service.js +70 -0
- package/dist/hover_service.js.map +1 -0
- package/dist/index.cjs +1227 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/line_context_collector.js +73 -0
- package/dist/line_context_collector.js.map +1 -0
- package/dist/linter_service.js +20 -4
- package/dist/linter_service.js.map +1 -1
- package/dist/parser_service.js +6 -5
- package/dist/parser_service.js.map +1 -1
- package/dist/range_utils.js +65 -0
- package/dist/range_utils.js.map +1 -0
- package/dist/rewrite_code_action_service.js +135 -0
- package/dist/rewrite_code_action_service.js.map +1 -0
- package/dist/server.js +36 -2
- package/dist/server.js.map +1 -1
- package/dist/service.js +10 -0
- package/dist/service.js.map +1 -1
- package/dist/types/action_view_helpers.d.ts +5 -0
- package/dist/types/comment_ast_utils.d.ts +20 -0
- package/dist/types/comment_service.d.ts +14 -0
- package/dist/types/diagnostics.d.ts +0 -1
- package/dist/types/document_highlight_service.d.ts +28 -0
- package/dist/types/document_save_service.d.ts +8 -0
- package/dist/types/folding_range_service.d.ts +35 -0
- package/dist/types/formatting_service.d.ts +1 -1
- package/dist/types/hover_service.d.ts +8 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/line_context_collector.d.ts +19 -0
- package/dist/types/linter_service.d.ts +1 -0
- package/dist/types/parser_service.d.ts +2 -1
- package/dist/types/range_utils.d.ts +16 -0
- package/dist/types/rewrite_code_action_service.d.ts +11 -0
- package/dist/types/service.d.ts +10 -0
- package/dist/types/utils.d.ts +0 -6
- package/dist/utils.js +0 -16
- package/dist/utils.js.map +1 -1
- package/package.json +10 -5
- package/src/action_view_helpers.ts +23 -0
- package/src/autofix_service.ts +1 -1
- package/src/code_action_service.ts +3 -6
- package/src/comment_ast_utils.ts +282 -0
- package/src/comment_service.ts +228 -0
- package/src/diagnostics.ts +24 -38
- package/src/document_highlight_service.ts +267 -0
- package/src/document_save_service.ts +19 -7
- package/src/folding_range_service.ts +287 -0
- package/src/formatting_service.ts +4 -4
- package/src/hover_service.ts +90 -0
- package/src/index.ts +4 -0
- package/src/line_context_collector.ts +97 -0
- package/src/linter_service.ts +25 -7
- package/src/parser_service.ts +9 -10
- package/src/range_utils.ts +90 -0
- package/src/rewrite_code_action_service.ts +165 -0
- package/src/server.ts +51 -2
- package/src/service.ts +15 -0
- package/src/utils.ts +0 -22
package/src/diagnostics.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Visitor } from "@herb-tools/core"
|
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
Node,
|
|
7
|
+
SerializedLocation,
|
|
7
8
|
ERBCaseNode,
|
|
8
9
|
ERBCaseMatchNode,
|
|
9
10
|
ERBIfNode,
|
|
@@ -20,12 +21,13 @@ import type {
|
|
|
20
21
|
ERBInNode,
|
|
21
22
|
} from "@herb-tools/core"
|
|
22
23
|
|
|
23
|
-
import { isHTMLTextNode } from "@herb-tools/core"
|
|
24
|
+
import { isHTMLTextNode, isERBIfNode, isERBElseNode } from "@herb-tools/core"
|
|
24
25
|
|
|
25
26
|
import { ParserService } from "./parser_service"
|
|
26
27
|
import { LinterService } from "./linter_service"
|
|
27
28
|
import { DocumentService } from "./document_service"
|
|
28
29
|
import { ConfigService } from "./config_service"
|
|
30
|
+
import { lspRangeFromLocation } from "./range_utils"
|
|
29
31
|
|
|
30
32
|
export class Diagnostics {
|
|
31
33
|
private readonly connection: Connection
|
|
@@ -253,18 +255,9 @@ export class UnreachableCodeCollector extends Visitor {
|
|
|
253
255
|
)
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
private addDiagnostic(location:
|
|
258
|
+
private addDiagnostic(location: SerializedLocation, message: string): void {
|
|
257
259
|
const diagnostic: Diagnostic = {
|
|
258
|
-
range:
|
|
259
|
-
start: {
|
|
260
|
-
line: this.toZeroBased(location.start.line),
|
|
261
|
-
character: location.start.column
|
|
262
|
-
},
|
|
263
|
-
end: {
|
|
264
|
-
line: this.toZeroBased(location.end.line),
|
|
265
|
-
character: location.end.column
|
|
266
|
-
}
|
|
267
|
-
},
|
|
260
|
+
range: lspRangeFromLocation(location),
|
|
268
261
|
message,
|
|
269
262
|
severity: DiagnosticSeverity.Hint,
|
|
270
263
|
tags: [DiagnosticTag.Unnecessary],
|
|
@@ -298,27 +291,29 @@ export class UnreachableCodeCollector extends Visitor {
|
|
|
298
291
|
private markIfChainAsProcessed(node: ERBIfNode): void {
|
|
299
292
|
this.processedIfNodes.add(node)
|
|
300
293
|
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
301
|
-
if (current
|
|
302
|
-
this.processedIfNodes.add(current
|
|
294
|
+
if (isERBIfNode(current)) {
|
|
295
|
+
this.processedIfNodes.add(current)
|
|
303
296
|
}
|
|
304
297
|
})
|
|
305
298
|
}
|
|
306
299
|
|
|
307
300
|
private markElseNodesInIfChain(node: ERBIfNode): void {
|
|
308
301
|
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
309
|
-
if (current
|
|
310
|
-
this.processedElseNodes.add(current
|
|
302
|
+
if (isERBElseNode(current)) {
|
|
303
|
+
this.processedElseNodes.add(current)
|
|
311
304
|
}
|
|
312
305
|
})
|
|
313
306
|
}
|
|
314
307
|
|
|
315
|
-
private traverseSubsequentNodes(startNode: Node | null, callback: (node:
|
|
316
|
-
let current = startNode
|
|
308
|
+
private traverseSubsequentNodes(startNode: Node | null, callback: (node: ERBIfNode | ERBElseNode) => void): void {
|
|
309
|
+
let current: Node | null = startNode
|
|
317
310
|
while (current) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
311
|
+
if (isERBIfNode(current)) {
|
|
312
|
+
callback(current)
|
|
313
|
+
current = current.subsequent
|
|
314
|
+
} else if (isERBElseNode(current)) {
|
|
315
|
+
callback(current)
|
|
316
|
+
break
|
|
322
317
|
} else {
|
|
323
318
|
break
|
|
324
319
|
}
|
|
@@ -331,21 +326,17 @@ export class UnreachableCodeCollector extends Visitor {
|
|
|
331
326
|
}
|
|
332
327
|
|
|
333
328
|
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
334
|
-
if (
|
|
335
|
-
return
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
if (this.statementsHaveContent((current as any).statements)) {
|
|
329
|
+
if (this.statementsHaveContent(current.statements)) {
|
|
339
330
|
return
|
|
340
331
|
}
|
|
341
332
|
|
|
342
|
-
const blockType = current
|
|
343
|
-
const nextSubsequent =
|
|
333
|
+
const blockType = isERBIfNode(current) ? 'elsif' : 'else'
|
|
334
|
+
const nextSubsequent = isERBIfNode(current) ? current.subsequent : null
|
|
344
335
|
|
|
345
336
|
if (nextSubsequent) {
|
|
346
|
-
this.checkEmptyStatementsWithEndLocation(current,
|
|
337
|
+
this.checkEmptyStatementsWithEndLocation(current, current.statements, blockType, nextSubsequent)
|
|
347
338
|
} else {
|
|
348
|
-
this.checkEmptyStatements(current,
|
|
339
|
+
this.checkEmptyStatements(current, current.statements, blockType)
|
|
349
340
|
}
|
|
350
341
|
})
|
|
351
342
|
}
|
|
@@ -357,17 +348,12 @@ export class UnreachableCodeCollector extends Visitor {
|
|
|
357
348
|
|
|
358
349
|
let hasContent = false
|
|
359
350
|
this.traverseSubsequentNodes(node.subsequent, (current) => {
|
|
360
|
-
if (
|
|
361
|
-
|
|
362
|
-
hasContent = true
|
|
363
|
-
}
|
|
351
|
+
if (this.statementsHaveContent(current.statements)) {
|
|
352
|
+
hasContent = true
|
|
364
353
|
}
|
|
365
354
|
})
|
|
366
355
|
|
|
367
356
|
return !hasContent
|
|
368
357
|
}
|
|
369
358
|
|
|
370
|
-
private toZeroBased(line: number): number {
|
|
371
|
-
return line - 1
|
|
372
|
-
}
|
|
373
359
|
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { DocumentHighlight, DocumentHighlightKind, Range, Position } from "vscode-languageserver/node"
|
|
2
|
+
import { TextDocument } from "vscode-languageserver-textdocument"
|
|
3
|
+
|
|
4
|
+
import { Visitor } from "@herb-tools/core"
|
|
5
|
+
import { ParserService } from "./parser_service"
|
|
6
|
+
|
|
7
|
+
import { isERBIfNode, isERBElseNode, isHTMLOpenTagNode } from "@herb-tools/core"
|
|
8
|
+
import { erbTagToRange, tokenToRange, nodeToRange, openTagRanges, isPositionInRange, rangeSize } from "./range_utils"
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
Node,
|
|
12
|
+
ERBNode,
|
|
13
|
+
ERBContentNode,
|
|
14
|
+
HTMLElementNode,
|
|
15
|
+
HTMLConditionalElementNode,
|
|
16
|
+
HTMLAttributeNode,
|
|
17
|
+
HTMLCommentNode,
|
|
18
|
+
ERBIfNode,
|
|
19
|
+
ERBUnlessNode,
|
|
20
|
+
ERBCaseNode,
|
|
21
|
+
ERBCaseMatchNode,
|
|
22
|
+
ERBBeginNode,
|
|
23
|
+
ERBRescueNode,
|
|
24
|
+
} from "@herb-tools/core"
|
|
25
|
+
|
|
26
|
+
export class DocumentHighlightCollector extends Visitor {
|
|
27
|
+
public groups: Range[][] = []
|
|
28
|
+
private processedIfNodes: Set<ERBIfNode> = new Set()
|
|
29
|
+
|
|
30
|
+
visitERBNode(node: ERBNode): void {
|
|
31
|
+
if ('end_node' in node && node.end_node) {
|
|
32
|
+
this.addGroup([erbTagToRange(node), erbTagToRange(node.end_node)])
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
visitERBContentNode(node: ERBContentNode): void {
|
|
37
|
+
this.addGroup([tokenToRange(node.tag_opening), tokenToRange(node.tag_closing)])
|
|
38
|
+
this.visitChildNodes(node)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
visitHTMLCommentNode(node: HTMLCommentNode): void {
|
|
42
|
+
this.addGroup([tokenToRange(node.comment_start), tokenToRange(node.comment_end)])
|
|
43
|
+
this.visitChildNodes(node)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
visitHTMLElementNode(node: HTMLElementNode): void {
|
|
47
|
+
const ranges: (Range | null)[] = []
|
|
48
|
+
|
|
49
|
+
if (node.open_tag && isHTMLOpenTagNode(node.open_tag)) {
|
|
50
|
+
ranges.push(...openTagRanges(node.open_tag))
|
|
51
|
+
} else if (node.open_tag) {
|
|
52
|
+
ranges.push(nodeToRange(node.open_tag))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (node.close_tag) {
|
|
56
|
+
ranges.push(nodeToRange(node.close_tag))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.addGroup(ranges)
|
|
60
|
+
this.visitChildNodes(node)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
visitHTMLAttributeNode(node: HTMLAttributeNode): void {
|
|
64
|
+
const ranges: (Range | null)[] = []
|
|
65
|
+
|
|
66
|
+
if (node.name) {
|
|
67
|
+
ranges.push(nodeToRange(node.name))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (node.equals) {
|
|
71
|
+
ranges.push(tokenToRange(node.equals))
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (node.value) {
|
|
75
|
+
ranges.push(nodeToRange(node.value))
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.addGroup(ranges)
|
|
79
|
+
this.visitChildNodes(node)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
visitHTMLConditionalElementNode(node: HTMLConditionalElementNode): void {
|
|
83
|
+
const ranges: (Range | null)[] = []
|
|
84
|
+
|
|
85
|
+
if (node.open_conditional) {
|
|
86
|
+
ranges.push(erbTagToRange(node.open_conditional))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (node.open_tag) {
|
|
90
|
+
ranges.push(...openTagRanges(node.open_tag))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (node.close_tag) {
|
|
94
|
+
ranges.push(nodeToRange(node.close_tag))
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (node.close_conditional) {
|
|
98
|
+
ranges.push(erbTagToRange(node.close_conditional))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.addGroup(ranges)
|
|
102
|
+
this.visitChildNodes(node)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
visitERBIfNode(node: ERBIfNode): void {
|
|
106
|
+
if (this.processedIfNodes.has(node)) {
|
|
107
|
+
this.visitChildNodes(node)
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.markIfChainAsProcessed(node)
|
|
112
|
+
|
|
113
|
+
const ranges: (Range | null)[] = []
|
|
114
|
+
ranges.push(erbTagToRange(node))
|
|
115
|
+
|
|
116
|
+
let current: Node | null = node.subsequent
|
|
117
|
+
|
|
118
|
+
while (current) {
|
|
119
|
+
if (isERBIfNode(current)) {
|
|
120
|
+
ranges.push(erbTagToRange(current))
|
|
121
|
+
current = current.subsequent
|
|
122
|
+
} else if (isERBElseNode(current)) {
|
|
123
|
+
ranges.push(erbTagToRange(current))
|
|
124
|
+
break
|
|
125
|
+
} else {
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (node.end_node) {
|
|
131
|
+
ranges.push(erbTagToRange(node.end_node))
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
this.addGroup(ranges)
|
|
135
|
+
this.visitChildNodes(node)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
visitERBUnlessNode(node: ERBUnlessNode): void {
|
|
139
|
+
const ranges: (Range | null)[] = []
|
|
140
|
+
ranges.push(erbTagToRange(node))
|
|
141
|
+
|
|
142
|
+
if (node.else_clause) {
|
|
143
|
+
ranges.push(erbTagToRange(node.else_clause))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (node.end_node) {
|
|
147
|
+
ranges.push(erbTagToRange(node.end_node))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
this.addGroup(ranges)
|
|
151
|
+
this.visitChildNodes(node)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
visitERBCaseNode(node: ERBCaseNode): void {
|
|
155
|
+
this.visitERBAnyCaseNode(node)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
visitERBCaseMatchNode(node: ERBCaseMatchNode): void {
|
|
159
|
+
this.visitERBAnyCaseNode(node)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
visitERBAnyCaseNode(node: ERBCaseNode | ERBCaseMatchNode): void {
|
|
163
|
+
const ranges: (Range | null)[] = []
|
|
164
|
+
ranges.push(erbTagToRange(node))
|
|
165
|
+
|
|
166
|
+
for (const condition of node.conditions) {
|
|
167
|
+
ranges.push(erbTagToRange(condition as ERBNode))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (node.else_clause) {
|
|
171
|
+
ranges.push(erbTagToRange(node.else_clause))
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (node.end_node) {
|
|
175
|
+
ranges.push(erbTagToRange(node.end_node))
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.addGroup(ranges)
|
|
179
|
+
this.visitChildNodes(node)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
visitERBBeginNode(node: ERBBeginNode): void {
|
|
183
|
+
const ranges: (Range | null)[] = []
|
|
184
|
+
ranges.push(erbTagToRange(node))
|
|
185
|
+
|
|
186
|
+
let rescue: ERBRescueNode | null = node.rescue_clause
|
|
187
|
+
|
|
188
|
+
while (rescue) {
|
|
189
|
+
ranges.push(erbTagToRange(rescue))
|
|
190
|
+
rescue = rescue.subsequent
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (node.else_clause) {
|
|
194
|
+
ranges.push(erbTagToRange(node.else_clause))
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (node.ensure_clause) {
|
|
198
|
+
ranges.push(erbTagToRange(node.ensure_clause))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (node.end_node) {
|
|
202
|
+
ranges.push(erbTagToRange(node.end_node))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this.addGroup(ranges)
|
|
206
|
+
this.visitChildNodes(node)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private markIfChainAsProcessed(node: ERBIfNode): void {
|
|
210
|
+
this.processedIfNodes.add(node)
|
|
211
|
+
|
|
212
|
+
let current: Node | null = node.subsequent
|
|
213
|
+
|
|
214
|
+
while (current) {
|
|
215
|
+
if (isERBIfNode(current)) {
|
|
216
|
+
this.processedIfNodes.add(current)
|
|
217
|
+
current = current.subsequent
|
|
218
|
+
} else {
|
|
219
|
+
break
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private addGroup(ranges: (Range | null)[]): void {
|
|
225
|
+
const filtered = ranges.filter((r): r is Range => r !== null)
|
|
226
|
+
if (filtered.length >= 2) {
|
|
227
|
+
this.groups.push(filtered)
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export class DocumentHighlightService {
|
|
233
|
+
private parserService: ParserService
|
|
234
|
+
|
|
235
|
+
constructor(parserService: ParserService) {
|
|
236
|
+
this.parserService = parserService
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
getDocumentHighlights(textDocument: TextDocument, position: Position): DocumentHighlight[] {
|
|
240
|
+
const parseResult = this.parserService.parseDocument(textDocument)
|
|
241
|
+
const collector = new DocumentHighlightCollector()
|
|
242
|
+
collector.visit(parseResult.document)
|
|
243
|
+
|
|
244
|
+
let bestGroup: Range[] | null = null
|
|
245
|
+
let bestSize = Infinity
|
|
246
|
+
|
|
247
|
+
for (const group of collector.groups) {
|
|
248
|
+
const matchingRange = group.find(range => isPositionInRange(position, range))
|
|
249
|
+
|
|
250
|
+
if (matchingRange) {
|
|
251
|
+
const size = rangeSize(matchingRange)
|
|
252
|
+
|
|
253
|
+
if (size < bestSize) {
|
|
254
|
+
bestSize = size
|
|
255
|
+
bestGroup = group
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (bestGroup) {
|
|
261
|
+
return bestGroup.map(range => DocumentHighlight.create(range, DocumentHighlightKind.Text))
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return []
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
}
|
|
@@ -11,6 +11,15 @@ export class DocumentSaveService {
|
|
|
11
11
|
private autofixService: AutofixService
|
|
12
12
|
private formattingService: FormattingService
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Tracks documents that were recently autofixed via applyFixesAndFormatting
|
|
16
|
+
* (triggered by onDocumentFormatting). When editor.formatOnSave is enabled,
|
|
17
|
+
* onDocumentFormatting fires BEFORE willSaveWaitUntil. If applyFixesAndFormatting
|
|
18
|
+
* already applied autofix, applyFixes must skip to avoid conflicting edits
|
|
19
|
+
* (since this.documents hasn't been updated between the two events).
|
|
20
|
+
*/
|
|
21
|
+
private recentlyAutofixedViaFormatting = new Set<string>()
|
|
22
|
+
|
|
14
23
|
constructor(connection: Connection, settings: Settings, autofixService: AutofixService, formattingService: FormattingService) {
|
|
15
24
|
this.connection = connection
|
|
16
25
|
this.settings = settings
|
|
@@ -30,6 +39,11 @@ export class DocumentSaveService {
|
|
|
30
39
|
|
|
31
40
|
if (!fixOnSave) return []
|
|
32
41
|
|
|
42
|
+
if (this.recentlyAutofixedViaFormatting.delete(document.uri)) {
|
|
43
|
+
this.connection.console.log(`[DocumentSave] applyFixes skipping: already autofixed via formatting`)
|
|
44
|
+
return []
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
return this.autofixService.autofix(document)
|
|
34
48
|
}
|
|
35
49
|
|
|
@@ -48,6 +62,10 @@ export class DocumentSaveService {
|
|
|
48
62
|
|
|
49
63
|
if (fixOnSave) {
|
|
50
64
|
autofixEdits = await this.autofixService.autofix(document)
|
|
65
|
+
|
|
66
|
+
if (autofixEdits.length > 0) {
|
|
67
|
+
this.recentlyAutofixedViaFormatting.add(document.uri)
|
|
68
|
+
}
|
|
51
69
|
}
|
|
52
70
|
|
|
53
71
|
if (!formatterEnabled) return autofixEdits
|
|
@@ -56,12 +74,6 @@ export class DocumentSaveService {
|
|
|
56
74
|
return this.formattingService.formatOnSave(document, reason)
|
|
57
75
|
}
|
|
58
76
|
|
|
59
|
-
|
|
60
|
-
...document,
|
|
61
|
-
uri: document.uri,
|
|
62
|
-
getText: () => autofixEdits[0].newText,
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return this.formattingService.formatOnSave(autofixedDocument, reason)
|
|
77
|
+
return this.formattingService.formatOnSave(document, reason, autofixEdits[0].newText)
|
|
66
78
|
}
|
|
67
79
|
}
|