@likec4/language-server 1.8.1 → 1.10.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/contrib/likec4.tmLanguage.json +1 -1
- package/dist/browser.cjs +21 -0
- package/dist/browser.d.cts +22 -0
- package/dist/browser.d.mts +22 -0
- package/dist/browser.d.ts +22 -0
- package/dist/browser.mjs +19 -0
- package/dist/index.cjs +10 -0
- package/dist/index.d.cts +18 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.mjs +1 -0
- package/dist/likec4lib.cjs +961 -0
- package/dist/likec4lib.d.cts +6 -0
- package/dist/likec4lib.d.mts +6 -0
- package/dist/likec4lib.d.ts +6 -0
- package/dist/likec4lib.mjs +957 -0
- package/dist/model-graph/index.cjs +10 -0
- package/dist/model-graph/index.d.cts +79 -0
- package/dist/model-graph/index.d.mts +79 -0
- package/dist/model-graph/index.d.ts +79 -0
- package/dist/model-graph/index.mjs +1 -0
- package/dist/node.cjs +18 -0
- package/dist/node.d.cts +20 -0
- package/dist/node.d.mts +20 -0
- package/dist/node.d.ts +20 -0
- package/dist/node.mjs +16 -0
- package/dist/protocol.cjs +25 -0
- package/dist/protocol.d.cts +43 -0
- package/dist/protocol.d.mts +43 -0
- package/dist/protocol.d.ts +43 -0
- package/dist/protocol.mjs +17 -0
- package/dist/shared/language-server.CjFzaJwI.d.cts +1223 -0
- package/dist/shared/language-server.CtKHXJDD.d.ts +1223 -0
- package/dist/shared/language-server.D-84I33F.d.mts +1223 -0
- package/dist/shared/language-server.DBJJUUgF.mjs +5737 -0
- package/dist/shared/language-server.DtBRb9os.mjs +1656 -0
- package/dist/shared/language-server.DwyCJvXm.cjs +1669 -0
- package/dist/shared/language-server.JWkqVjGv.cjs +5748 -0
- package/package.json +36 -20
- package/src/ast.ts +48 -36
- package/src/browser.ts +0 -3
- package/src/elementRef.ts +1 -1
- package/src/formatting/LikeC4Formatter.ts +388 -0
- package/src/formatting/utils.ts +26 -0
- package/src/generated/ast.ts +170 -12
- package/src/generated/grammar.ts +1 -1
- package/src/generated-lib/icons.ts +1 -1
- package/src/like-c4.langium +49 -8
- package/src/likec4lib.ts +2 -3
- package/src/logger.ts +9 -1
- package/src/lsp/DocumentLinkProvider.ts +27 -15
- package/src/lsp/RenameProvider.ts +8 -0
- package/src/lsp/SemanticTokenProvider.ts +20 -2
- package/src/lsp/index.ts +1 -0
- package/src/model/fqn-computation.ts +33 -23
- package/src/model/fqn-index.ts +5 -21
- package/src/model/model-builder.ts +180 -112
- package/src/model/model-locator.ts +1 -1
- package/src/model/model-parser-where.ts +3 -2
- package/src/model/model-parser.ts +99 -39
- package/src/model-graph/LikeC4ModelGraph.ts +42 -21
- package/src/model-graph/compute-view/__test__/fixture.ts +16 -14
- package/src/model-graph/compute-view/compute.ts +110 -81
- package/src/model-graph/compute-view/predicates.ts +6 -8
- package/src/model-graph/dynamic-view/__test__/fixture.ts +1 -0
- package/src/model-graph/dynamic-view/compute.ts +98 -61
- package/src/model-graph/utils/buildElementNotations.ts +1 -1
- package/src/model-graph/utils/elementExpressionToPredicate.ts +1 -1
- package/src/model-graph/utils/sortNodes.ts +2 -6
- package/src/module.ts +21 -4
- package/src/protocol.ts +4 -5
- package/src/references/scope-computation.ts +10 -1
- package/src/references/scope-provider.ts +2 -1
- package/src/shared/NodeKindProvider.ts +73 -34
- package/src/test/setup.ts +3 -8
- package/src/test/testServices.ts +27 -7
- package/src/utils/graphlib.ts +11 -0
- package/src/validation/index.ts +2 -1
- package/src/validation/property-checks.ts +13 -1
- package/src/validation/specification.ts +3 -3
- package/src/view-utils/manual-layout.ts +1 -1
- package/src/view-utils/resolve-extended-views.ts +19 -10
- package/src/view-utils/resolve-relative-paths.ts +19 -24
- package/src/view-utils/view-hash.ts +1 -1
- package/src/reset.d.ts +0 -2
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { type AstNode, GrammarUtils } from 'langium'
|
|
2
|
+
import { AbstractFormatter, Formatting, type NodeFormatter } from 'langium/lsp'
|
|
3
|
+
import * as ast from '../generated/ast'
|
|
4
|
+
import * as utils from './utils'
|
|
5
|
+
|
|
6
|
+
const FormattingOptions = {
|
|
7
|
+
newLine: Formatting.newLine({ allowMore: true }),
|
|
8
|
+
oneSpace: Formatting.oneSpace(),
|
|
9
|
+
noSpace: Formatting.noSpace(),
|
|
10
|
+
indent: Formatting.indent({ allowMore: true }),
|
|
11
|
+
noIndent: Formatting.noIndent()
|
|
12
|
+
}
|
|
13
|
+
type Predicate<T extends AstNode> = (x: unknown) => x is T
|
|
14
|
+
|
|
15
|
+
export class LikeC4Formatter extends AbstractFormatter {
|
|
16
|
+
protected format(node: AstNode): void {
|
|
17
|
+
this.removeIndentFromTopLevelStatements(node)
|
|
18
|
+
this.indentContentInBraces(node)
|
|
19
|
+
|
|
20
|
+
this.formatSpecificationRule(node)
|
|
21
|
+
this.formatElementDeclaration(node)
|
|
22
|
+
this.formatRelation(node)
|
|
23
|
+
this.formatView(node)
|
|
24
|
+
this.formatViewRuleStyle(node)
|
|
25
|
+
this.formatIncludeExcludeExpressions(node)
|
|
26
|
+
this.formatWhereExpression(node)
|
|
27
|
+
this.formatWithPredicate(node)
|
|
28
|
+
this.formatLeafProperty(node)
|
|
29
|
+
this.formatMetadataProperty(node)
|
|
30
|
+
this.formatAutolayoutProperty(node)
|
|
31
|
+
this.formatLinkProperty(node)
|
|
32
|
+
this.formatNavigateToProperty(node)
|
|
33
|
+
this.formatTags(node)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected formatTags(node: AstNode) {
|
|
37
|
+
this.on(node, ast.isTags, (n, f) => {
|
|
38
|
+
f.cst(GrammarUtils.findNodesForProperty(n.$cstNode, 'values').slice(1))
|
|
39
|
+
.prepend(FormattingOptions.oneSpace)
|
|
40
|
+
|
|
41
|
+
f.keywords(',')
|
|
42
|
+
.prepend(FormattingOptions.noSpace)
|
|
43
|
+
.append(FormattingOptions.oneSpace)
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
protected formatRelation(node: AstNode) {
|
|
48
|
+
this.on(node, ast.isRelation, (n, f) => {
|
|
49
|
+
f.property('source').append(FormattingOptions.oneSpace)
|
|
50
|
+
f.keywords(']->').prepend(FormattingOptions.noSpace)
|
|
51
|
+
f.keywords('-[').append(FormattingOptions.noSpace)
|
|
52
|
+
|
|
53
|
+
f.properties('target', 'title', 'technology', 'tags').prepend(FormattingOptions.oneSpace)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
this.on(node, ast.isDynamicViewStep, (n, f) => {
|
|
57
|
+
f.properties('source').append(FormattingOptions.oneSpace)
|
|
58
|
+
f.keywords(']->').prepend(FormattingOptions.noSpace)
|
|
59
|
+
f.keywords('-[').append(FormattingOptions.noSpace)
|
|
60
|
+
f.properties('target', 'title').prepend(FormattingOptions.oneSpace)
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
this.on(node, ast.isDirectedRelationExpression)
|
|
64
|
+
?.property('target').prepend(FormattingOptions.oneSpace)
|
|
65
|
+
|
|
66
|
+
this.on(node, ast.isOutgoingRelationExpression, (n, f) => {
|
|
67
|
+
f.property('from').append(FormattingOptions.oneSpace)
|
|
68
|
+
f.keywords(']->').prepend(FormattingOptions.noSpace)
|
|
69
|
+
f.keywords('-[').append(FormattingOptions.noSpace)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
this.on(node, ast.isIncomingRelationExpression)
|
|
73
|
+
?.keywords('->').append(FormattingOptions.oneSpace)
|
|
74
|
+
|
|
75
|
+
this.on(node, ast.isInOutRelationExpression)
|
|
76
|
+
?.property('inout').append(FormattingOptions.oneSpace)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected removeIndentFromTopLevelStatements(node: AstNode) {
|
|
80
|
+
if (
|
|
81
|
+
ast.isModel(node)
|
|
82
|
+
|| ast.isSpecificationRule(node)
|
|
83
|
+
|| ast.isModelViews(node)
|
|
84
|
+
|| ast.isLikeC4Lib(node)
|
|
85
|
+
) {
|
|
86
|
+
const formatter = this.getNodeFormatter(node)
|
|
87
|
+
formatter.keywords('specification', 'model', 'views', 'likec4lib')
|
|
88
|
+
.prepend(FormattingOptions.noIndent)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
protected indentContentInBraces(node: AstNode) {
|
|
93
|
+
if (
|
|
94
|
+
ast.isLikeC4Lib(node)
|
|
95
|
+
|| ast.isSpecificationRule(node)
|
|
96
|
+
|| ast.isSpecificationElementKind(node)
|
|
97
|
+
|| ast.isSpecificationRelationshipKind(node)
|
|
98
|
+
|| ast.isModel(node)
|
|
99
|
+
|| ast.isElementBody(node)
|
|
100
|
+
|| ast.isExtendElementBody(node)
|
|
101
|
+
|| ast.isRelationBody(node)
|
|
102
|
+
|| ast.isRelationStyleProperty(node)
|
|
103
|
+
|| ast.isMetadataBody(node)
|
|
104
|
+
|| ast.isModelViews(node)
|
|
105
|
+
|| ast.isElementViewBody(node)
|
|
106
|
+
|| ast.isDynamicViewBody(node)
|
|
107
|
+
|| ast.isViewRuleStyle(node)
|
|
108
|
+
|| ast.isCustomElementProperties(node)
|
|
109
|
+
|| ast.isCustomRelationProperties(node)
|
|
110
|
+
|| ast.isElementStyleProperty(node)
|
|
111
|
+
) {
|
|
112
|
+
const formatter = this.getNodeFormatter(node)
|
|
113
|
+
const openBrace = formatter.keywords('{')
|
|
114
|
+
const closeBrace = formatter.keywords('}')
|
|
115
|
+
|
|
116
|
+
const interiorNodes = formatter.interior(openBrace, closeBrace)
|
|
117
|
+
|
|
118
|
+
// Workaround for tags as they are parsed as overlapping regions.
|
|
119
|
+
// E.g. '#tag1, #tag2' will be parsed as two nodes: '#tag1' and '#tag1, #tag2'
|
|
120
|
+
let perviousNode = null
|
|
121
|
+
for (const interiorNode of interiorNodes.nodes) {
|
|
122
|
+
if (!perviousNode || !utils.areOverlap(perviousNode, interiorNode)) {
|
|
123
|
+
formatter.cst([interiorNode]).prepend(FormattingOptions.indent)
|
|
124
|
+
}
|
|
125
|
+
perviousNode = interiorNode
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
openBrace
|
|
129
|
+
.prepend(FormattingOptions.noIndent)
|
|
130
|
+
.prepend(FormattingOptions.oneSpace)
|
|
131
|
+
closeBrace
|
|
132
|
+
.prepend(FormattingOptions.noIndent)
|
|
133
|
+
.prepend(Formatting.newLine({ allowMore: true }))
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
protected appendKeywordsWithSpace(node: AstNode) {
|
|
138
|
+
this.on(node, ast.isElementKind)
|
|
139
|
+
?.keywords('element').append(FormattingOptions.oneSpace)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
protected formatView(node: AstNode) {
|
|
143
|
+
this.on(node, ast.isElementView, (n, f) => {
|
|
144
|
+
if (n.extends || n.viewOf || n.name) {
|
|
145
|
+
f.keywords('view').append(FormattingOptions.oneSpace)
|
|
146
|
+
}
|
|
147
|
+
f.keywords('of', 'extends').surround(FormattingOptions.oneSpace)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
this.on(node, ast.isDynamicView)
|
|
151
|
+
?.keywords('dynamic', 'view').append(FormattingOptions.oneSpace)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
protected formatLeafProperty(node: AstNode) {
|
|
155
|
+
if (
|
|
156
|
+
ast.isElementStringProperty(node)
|
|
157
|
+
|| ast.isRelationStringProperty(node)
|
|
158
|
+
|| ast.isViewStringProperty(node)
|
|
159
|
+
|| ast.isNotationProperty(node)
|
|
160
|
+
|| ast.isSpecificationElementStringProperty(node)
|
|
161
|
+
|| ast.isSpecificationRelationshipStringProperty(node)
|
|
162
|
+
|| ast.isColorProperty(node)
|
|
163
|
+
|| ast.isLineProperty(node)
|
|
164
|
+
|| ast.isArrowProperty(node)
|
|
165
|
+
|| ast.isIconProperty(node)
|
|
166
|
+
|| ast.isShapeProperty(node)
|
|
167
|
+
|| ast.isBorderProperty(node)
|
|
168
|
+
|| ast.isOpacityProperty(node)
|
|
169
|
+
) {
|
|
170
|
+
const formatter = this.getNodeFormatter(node)
|
|
171
|
+
formatter.keywords(
|
|
172
|
+
'title',
|
|
173
|
+
'description',
|
|
174
|
+
'technology',
|
|
175
|
+
'notation',
|
|
176
|
+
'color',
|
|
177
|
+
'line',
|
|
178
|
+
'head',
|
|
179
|
+
'tail',
|
|
180
|
+
'icon',
|
|
181
|
+
'shape',
|
|
182
|
+
'border',
|
|
183
|
+
'opacity'
|
|
184
|
+
)
|
|
185
|
+
.append(FormattingOptions.oneSpace)
|
|
186
|
+
|
|
187
|
+
formatter.keyword(':')
|
|
188
|
+
.prepend(FormattingOptions.noSpace)
|
|
189
|
+
.append(FormattingOptions.oneSpace)
|
|
190
|
+
|
|
191
|
+
formatter.keyword(';')
|
|
192
|
+
.prepend(FormattingOptions.noSpace)
|
|
193
|
+
.append(FormattingOptions.newLine)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
protected formatLinkProperty(node: AstNode) {
|
|
198
|
+
this.on(node, ast.isLinkProperty, (n, f) => {
|
|
199
|
+
f.keyword('link').append(FormattingOptions.oneSpace)
|
|
200
|
+
f.property('value').append(FormattingOptions.oneSpace)
|
|
201
|
+
f.keyword(':')
|
|
202
|
+
.prepend(FormattingOptions.noSpace)
|
|
203
|
+
.append(FormattingOptions.oneSpace)
|
|
204
|
+
|
|
205
|
+
f.keyword(';')
|
|
206
|
+
.prepend(FormattingOptions.noSpace)
|
|
207
|
+
.append(FormattingOptions.newLine)
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected formatNavigateToProperty(node: AstNode) {
|
|
212
|
+
this.on(node, ast.isNavigateToProperty)
|
|
213
|
+
?.property('key').append(FormattingOptions.oneSpace)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
protected formatAutolayoutProperty(node: AstNode) {
|
|
217
|
+
this.on(node, ast.isViewRuleAutoLayout)
|
|
218
|
+
?.keyword('autoLayout').append(FormattingOptions.oneSpace)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
protected formatMetadataProperty(node: AstNode) {
|
|
222
|
+
this.on(node, ast.isMetadataAttribute, (n, f) => {
|
|
223
|
+
f.property('key').append(FormattingOptions.oneSpace)
|
|
224
|
+
f.keyword(':')
|
|
225
|
+
.prepend(FormattingOptions.noSpace)
|
|
226
|
+
.append(FormattingOptions.oneSpace)
|
|
227
|
+
f.keyword(';')
|
|
228
|
+
.prepend(FormattingOptions.noSpace)
|
|
229
|
+
.append(FormattingOptions.newLine)
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
protected formatElementDeclaration(node: AstNode) {
|
|
234
|
+
this.on(node, ast.isElement, (n, f) => {
|
|
235
|
+
const kind = GrammarUtils.findNodeForProperty(n.$cstNode, 'kind')
|
|
236
|
+
const name = GrammarUtils.findNodeForProperty(n.$cstNode, 'name')
|
|
237
|
+
|
|
238
|
+
if (name && kind) {
|
|
239
|
+
// system sys1
|
|
240
|
+
if (utils.compareRanges(name, kind) > 0) {
|
|
241
|
+
f.cst([kind]).append(FormattingOptions.oneSpace)
|
|
242
|
+
}
|
|
243
|
+
// sys1 = system
|
|
244
|
+
else {
|
|
245
|
+
f.cst([name]).append(FormattingOptions.oneSpace)
|
|
246
|
+
f.cst([kind]).prepend(FormattingOptions.oneSpace)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
f.properties('props').prepend(FormattingOptions.oneSpace)
|
|
251
|
+
})
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
protected formatSpecificationRule(node: AstNode) {
|
|
255
|
+
if (
|
|
256
|
+
ast.isSpecificationElementKind(node)
|
|
257
|
+
|| ast.isSpecificationRelationshipKind(node)
|
|
258
|
+
|| ast.isSpecificationTag(node)
|
|
259
|
+
) {
|
|
260
|
+
const formatter = this.getNodeFormatter(node)
|
|
261
|
+
|
|
262
|
+
formatter.keywords('element', 'relationship', 'tag')
|
|
263
|
+
.append(FormattingOptions.oneSpace)
|
|
264
|
+
}
|
|
265
|
+
if (
|
|
266
|
+
ast.isSpecificationColor(node)
|
|
267
|
+
) {
|
|
268
|
+
const formatter = this.getNodeFormatter(node)
|
|
269
|
+
formatter.keyword('color').append(FormattingOptions.oneSpace)
|
|
270
|
+
formatter.property('name').append(FormattingOptions.oneSpace)
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
protected formatWithPredicate(node: AstNode) {
|
|
275
|
+
const formatter = this.getNodeFormatter(node)
|
|
276
|
+
if (
|
|
277
|
+
ast.isElementPredicateWith(node)
|
|
278
|
+
|| ast.isRelationPredicateWith(node)
|
|
279
|
+
) {
|
|
280
|
+
formatter.keyword('with').prepend(FormattingOptions.oneSpace)
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
protected formatViewRuleStyle(node: AstNode) {
|
|
285
|
+
this.on(node, ast.isViewRuleStyle)
|
|
286
|
+
?.keyword('style').append(FormattingOptions.oneSpace)
|
|
287
|
+
|
|
288
|
+
this.on(node, ast.isElementExpressionsIterator)
|
|
289
|
+
?.keyword(',')
|
|
290
|
+
.prepend(FormattingOptions.noSpace)
|
|
291
|
+
.append(FormattingOptions.oneSpace)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
protected formatWhereExpression(node: AstNode) {
|
|
295
|
+
if (
|
|
296
|
+
ast.isRelationPredicateOrWhere(node)
|
|
297
|
+
|| ast.isElementPredicateOrWhere(node)
|
|
298
|
+
) {
|
|
299
|
+
const formatter = this.getNodeFormatter(node)
|
|
300
|
+
formatter.keyword('where').append(FormattingOptions.oneSpace)
|
|
301
|
+
}
|
|
302
|
+
if (
|
|
303
|
+
ast.isWhereRelationExpression(node)
|
|
304
|
+
|| ast.isWhereElementExpression(node)
|
|
305
|
+
) {
|
|
306
|
+
const formatter = this.getNodeFormatter(node)
|
|
307
|
+
formatter.property('operator').surround(FormattingOptions.oneSpace)
|
|
308
|
+
}
|
|
309
|
+
if (
|
|
310
|
+
ast.isWhereElementNegation(node)
|
|
311
|
+
|| ast.isWhereRelationNegation(node)
|
|
312
|
+
) {
|
|
313
|
+
const formatter = this.getNodeFormatter(node)
|
|
314
|
+
formatter.keyword('not').append(FormattingOptions.oneSpace)
|
|
315
|
+
}
|
|
316
|
+
if (
|
|
317
|
+
ast.isWhereElement(node)
|
|
318
|
+
|| ast.isWhereElementTag(node)
|
|
319
|
+
|| ast.isWhereElementKind(node)
|
|
320
|
+
|| ast.isWhereRelation(node)
|
|
321
|
+
|| ast.isWhereRelationTag(node)
|
|
322
|
+
|| ast.isWhereRelationKind(node)
|
|
323
|
+
) {
|
|
324
|
+
const formatter = this.getNodeFormatter(node)
|
|
325
|
+
formatter.property('operator').surround(FormattingOptions.oneSpace)
|
|
326
|
+
formatter.property('not').surround(FormattingOptions.oneSpace)
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
protected formatIncludeExcludeExpressions(node: AstNode) {
|
|
331
|
+
if (
|
|
332
|
+
ast.isDynamicViewRule(node)
|
|
333
|
+
|| ast.isIncludePredicate(node)
|
|
334
|
+
|| ast.isExcludePredicate(node)
|
|
335
|
+
) {
|
|
336
|
+
const formatter = this.getNodeFormatter(node)
|
|
337
|
+
|
|
338
|
+
if (!node.$cstNode || !utils.isMultiline(node.$cstNode)) {
|
|
339
|
+
formatter.keywords('include', 'exclude')
|
|
340
|
+
.append(FormattingOptions.oneSpace)
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (
|
|
344
|
+
ast.isDynamicViewPredicateIterator(node)
|
|
345
|
+
|| ast.isPredicates(node)
|
|
346
|
+
|| ast.isPredicates(node)
|
|
347
|
+
) {
|
|
348
|
+
const formatter = this.getNodeFormatter(node)
|
|
349
|
+
const parent = this.findPredicateExpressionRoot(node)
|
|
350
|
+
const isMultiline = parent?.$cstNode && utils.isMultiline(parent?.$cstNode)
|
|
351
|
+
|
|
352
|
+
if (isMultiline) {
|
|
353
|
+
formatter.property('value').prepend(FormattingOptions.indent)
|
|
354
|
+
}
|
|
355
|
+
formatter.keyword(',')
|
|
356
|
+
.prepend(FormattingOptions.noSpace)
|
|
357
|
+
.append(isMultiline ? FormattingOptions.newLine : FormattingOptions.oneSpace)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
private findPredicateExpressionRoot(node: AstNode): AstNode | undefined {
|
|
362
|
+
let parent = node.$container
|
|
363
|
+
while (true) {
|
|
364
|
+
if (
|
|
365
|
+
!parent
|
|
366
|
+
|| ast.isDynamicViewRule(parent)
|
|
367
|
+
|| ast.isIncludePredicate(parent)
|
|
368
|
+
|| ast.isExcludePredicate(parent)
|
|
369
|
+
) {
|
|
370
|
+
return parent
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
parent = parent.$container
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
private on<T extends AstNode>(
|
|
378
|
+
node: AstNode,
|
|
379
|
+
predicate: Predicate<T>,
|
|
380
|
+
format?: (node: T, f: NodeFormatter<T>) => void
|
|
381
|
+
): NodeFormatter<T> | undefined {
|
|
382
|
+
const formatter = predicate(node) ? this.getNodeFormatter(node) : undefined
|
|
383
|
+
|
|
384
|
+
format && formatter && format(node as T, formatter)
|
|
385
|
+
|
|
386
|
+
return formatter
|
|
387
|
+
}
|
|
388
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { CstNode } from "langium"
|
|
2
|
+
import type { Position, Range } from "vscode-languageserver-types"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function areOverlap(a: CstNode, b: CstNode): boolean {
|
|
6
|
+
;[a, b] = compareRanges(a, b) > 0 ? [b, a] : [a, b]
|
|
7
|
+
|
|
8
|
+
return isInRagne(a.range, b.range.start)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function compareRanges(a: CstNode, b: CstNode): number {
|
|
12
|
+
const lineDiff = a.range.start.line - b.range.start.line
|
|
13
|
+
|
|
14
|
+
return lineDiff !== 0 ? lineDiff : a.range.start.character - b.range.start.character
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isInRagne(range: Range, pos: Position): boolean {
|
|
18
|
+
return !(pos.line < range.start.line
|
|
19
|
+
|| pos.line > range.end.line
|
|
20
|
+
|| pos.line == range.start.line && pos.character < range.start.character
|
|
21
|
+
|| pos.line == range.end.line && pos.character > range.end.character)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isMultiline(node: CstNode): boolean {
|
|
25
|
+
return node.range.start.line != node.range.end.line
|
|
26
|
+
}
|