Skip to content

Commit 591e6be

Browse files
authored
Merge pull request #16 from lstreckeisen/CMI-79-Create-SemanticTokenProvider-for-language-server
Cmi 79 create semantic token provider for language server
2 parents 129f7ed + dc60c79 commit 591e6be

22 files changed

+185
-148
lines changed

src/language/ContextMapperDslModule.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function createContextMapperDslServices (context: DefaultSharedModuleCont
7272
ContextMapperDslModule
7373
)
7474
shared.ServiceRegistry.register(ContextMapperDsl)
75-
registerValidationChecks(ContextMapperDsl)
75+
registerValidationChecks(ContextMapperDsl.validation.ValidationRegistry, ContextMapperDsl.validation.ContextMapperDslValidator)
7676
if (!context.connection) {
7777
// We don't run inside a language server
7878
// Therefore, initialize the configuration provider instantly

src/language/ContextMapperDslValidator.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
1-
import type { ValidationChecks } from 'langium'
2-
import type { ContextMapperDslAstType } from './generated/ast.js'
3-
import type { ContextMapperDslServices } from './ContextMapperDslModule.js'
1+
import { AstNode, type ValidationChecks, ValidationRegistry } from 'langium'
42
import { ContextMappingModelValidator } from './validation/ContextMappingModelValidator.js'
53
import { ValueValidator } from './validation/ValueValidator.js'
4+
import { AbstractContextMapperValidator } from './validation/AbstractContextMapperValidator.js'
5+
import type { ContextMapperDslAstType } from './generated/ast.js'
6+
7+
const validators: AbstractContextMapperValidator<AstNode>[] = [
8+
new ContextMappingModelValidator(),
9+
new ValueValidator()
10+
]
611

712
/**
813
* Register custom validation checks.
914
*/
10-
export function registerValidationChecks (services: ContextMapperDslServices) {
11-
const registry = services.validation.ValidationRegistry
12-
const validator = services.validation.ContextMapperDslValidator
13-
const checks: ValidationChecks<ContextMapperDslAstType> = {
14-
ContextMappingModel: new ContextMappingModelValidator().validate,
15-
Value: new ValueValidator().validate
15+
export function registerValidationChecks (registry: ValidationRegistry, validator: ContextMapperDslValidator) {
16+
const validatorChecks: ValidationChecks<ContextMapperDslAstType>[] = []
17+
for (const validator of validators) {
18+
validatorChecks.push(validator.getChecks())
1619
}
20+
const checks: ValidationChecks<ContextMapperDslAstType> = Object.assign({}, ...validatorChecks)
1721
registry.register(checks, validator)
1822
}
1923

src/language/context-mapper-dsl.langium

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ BoundedContext:
5656
(
5757
OPEN
5858
(
59-
('domainVisionStatement' ('=') domainVisionStatement=STRING) &
60-
('type' ('=') type=BoundedContextType) &
59+
('domainVisionStatement' ('=')? domainVisionStatement=STRING) &
60+
('type' ('=')? type=BoundedContextType) &
6161
(('responsibilities' ('=')? responsibilities+=STRING) ("," responsibilities+=STRING)*) &
62-
('implementationTechnology' ('=') implementationTechnology=STRING) &
63-
('knowledgeLevel' ('=') knowledgeLevel=KnowledgeLevel) &
64-
('businessModel' ('=') businessModel=STRING) &
65-
('evolution' ('=') evolution=Evolution)
62+
('implementationTechnology' ('=')? implementationTechnology=STRING) &
63+
('knowledgeLevel' ('=')? knowledgeLevel=KnowledgeLevel) &
64+
('businessModel' ('=')? businessModel=STRING) &
65+
('evolution' ('=')? evolution=Evolution)
6666
)
6767
(
6868
(

src/language/semantictokens/ContextMapperDslSemanticTokenProvider.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { ValueRegisterSemanticTokenProvider } from './vdad/ValueRegisterSemantic
2828
import { ValueWeightingSemanticTokenProvider } from './vdad/ValueWeightingSemanticTokenProvider.js'
2929

3030
export class ContextMapperDslSemanticTokenProvider extends AbstractSemanticTokenProvider {
31-
private semanticTokenProviders: ContextMapperSemanticTokenProvider<AstNode>[] = [
31+
private readonly semanticTokenProviders: ContextMapperSemanticTokenProvider<AstNode>[] = [
3232
new AggregateSemanticTokenProvider(),
3333
new BoundedContextSemanticTokenProvider(),
3434
new SculptorModuleSemanticTokenProvider(),
@@ -53,11 +53,9 @@ export class ContextMapperDslSemanticTokenProvider extends AbstractSemanticToken
5353

5454
protected override highlightElement (node: AstNode, acceptor: SemanticTokenAcceptor) {
5555
if (isContextMappingModel(node)) {
56-
const modelNode = node as ContextMappingModel
57-
58-
if (modelNode.$cstNode) {
59-
this.highlightComments(/\/\*[\s\S]*?\*\//g, modelNode, acceptor)
60-
this.highlightComments(/\/\/[^\n\r]*/g, modelNode, acceptor)
56+
if (node.$cstNode) {
57+
this.highlightComments(/\/\*[\s\S]*?\*\//g, node, acceptor)
58+
this.highlightComments(/\/\/[^\n\r]*/g, node, acceptor)
6159
}
6260
} else {
6361
for (const provider of this.semanticTokenProviders) {
@@ -72,12 +70,15 @@ export class ContextMapperDslSemanticTokenProvider extends AbstractSemanticToken
7270
}
7371

7472
private highlightComments (regex: RegExp, node: ContextMappingModel, acceptor: SemanticTokenAcceptor) {
75-
const text = node.$document!!.textDocument.getText()
73+
if (node.$document == null) {
74+
throw new Error('Document not found')
75+
}
76+
const text = node.$document.textDocument.getText()
7677
for (const match of text.matchAll(regex)) {
77-
if (match == null || match.index == null) {
78+
if (match?.index == null) {
7879
continue
7980
}
80-
const position = node.$document!!.textDocument.positionAt(match.index)
81+
const position = node.$document.textDocument.positionAt(match.index)
8182
acceptor({
8283
type: SemanticTokenTypes.comment,
8384
line: position.line,

src/language/semantictokens/HighlightingHelper.ts

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,6 @@ export function highlightKeyword (node: AstNode, acceptor: SemanticTokenAcceptor
1818
})
1919
}
2020

21-
export function highlightProperty (node: AstNode, acceptor: SemanticTokenAcceptor, property: string) {
22-
acceptor({
23-
node,
24-
type: SemanticTokenTypes.property,
25-
property
26-
})
27-
}
28-
2921
export function highlightType (node: AstNode, acceptor: SemanticTokenAcceptor, property: string, modifiers: string[] = []) {
3022
acceptor({
3123
node,
@@ -35,23 +27,22 @@ export function highlightType (node: AstNode, acceptor: SemanticTokenAcceptor, p
3527
})
3628
}
3729

38-
export function highlightTypeDeclaration (node: AstNode, acceptor: SemanticTokenAcceptor, keyword: string, hasName: Boolean = true) {
30+
export function highlightTypeDeclaration (node: AstNode, acceptor: SemanticTokenAcceptor, keyword: string, hasName: boolean = true) {
3931
highlightKeyword(node, acceptor, keyword)
4032
if (hasName) {
4133
highlightType(node, acceptor, 'name', [SemanticTokenModifiers.declaration])
4234
}
4335
}
4436

45-
export function highlightMemberAttribute (node: AstNode, acceptor: SemanticTokenAcceptor, keywords: string[], property: string, type: SemanticTokenTypes = SemanticTokenTypes.property) {
46-
keywords.forEach(keyword => highlightKeyword(node, acceptor, keyword))
47-
acceptor({
48-
node,
49-
type,
50-
property
51-
})
37+
export function highlightField (node: AstNode, acceptor: SemanticTokenAcceptor, keywords: string[], property: string, type: SemanticTokenTypes = SemanticTokenTypes.enumMember) {
38+
highlightProperty(node, acceptor, keywords, property, type)
5239
}
5340

5441
export function highlightAttribute (node: AstNode, acceptor: SemanticTokenAcceptor, keywords: string[], property: string, type: SemanticTokenTypes = SemanticTokenTypes.type) {
42+
highlightProperty(node, acceptor, keywords, property, type)
43+
}
44+
45+
function highlightProperty (node: AstNode, acceptor: SemanticTokenAcceptor, keywords: string[], property: string, type: SemanticTokenTypes) {
5546
keywords.forEach(keyword => highlightKeyword(node, acceptor, keyword))
5647
acceptor({
5748
node,
Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Aggregate, isAggregate, isUseCase, isUserRequirement, isUserStory } from '../../generated/ast.js'
22
import { SemanticTokenAcceptor } from 'langium/lsp'
33
import { SemanticTokenTypes } from 'vscode-languageserver-types'
4-
import { highlightMemberAttribute, highlightString, highlightTypeDeclaration } from '../HighlightingHelper.js'
4+
import { highlightField, highlightString, highlightTypeDeclaration } from '../HighlightingHelper.js'
55
import { ContextMapperSemanticTokenProvider } from '../ContextMapperSemanticTokenProvider.js'
66
import { AstNode } from 'langium'
77

@@ -18,65 +18,69 @@ export class AggregateSemanticTokenProvider implements ContextMapperSemanticToke
1818
highlightTypeDeclaration(node, acceptor, 'Aggregate')
1919

2020
if (node.responsibilities.length > 0) {
21-
highlightMemberAttribute(node, acceptor, ['responsibilities'], 'responsibilities', SemanticTokenTypes.string)
21+
highlightField(node, acceptor, ['responsibilities'], 'responsibilities', SemanticTokenTypes.string)
2222
}
2323

2424
if (node.userRequirements.length > 0) {
25-
const keywords = []
26-
if (isUseCase(node.userRequirements[0])) {
27-
keywords.push('useCases')
28-
} else if (isUserRequirement(node.userRequirements[0])) {
29-
keywords.push('userRequirements')
30-
keywords.push('features')
31-
} else if (isUserStory(node.userRequirements[0])) {
32-
keywords.push('userStories')
33-
}
34-
35-
highlightMemberAttribute(node, acceptor, keywords, 'userRequirements', SemanticTokenTypes.type)
25+
this.highlightUserRequirements(node, acceptor)
3626
}
3727

3828
if (node.owner) {
39-
highlightMemberAttribute(node, acceptor, ['owner'], 'owner', SemanticTokenTypes.type)
29+
highlightField(node, acceptor, ['owner'], 'owner', SemanticTokenTypes.type)
4030
}
4131

4232
if (node.knowledgeLevel) {
43-
highlightMemberAttribute(node, acceptor, ['knowledgeLevel'], 'knowledgeLevel')
33+
highlightField(node, acceptor, ['knowledgeLevel'], 'knowledgeLevel')
4434
}
4535

4636
if (node.likelihoodForChange) {
47-
highlightMemberAttribute(node, acceptor, ['likelihoodForChange', 'structuralVolatility'], 'likelihoodForChange')
37+
highlightField(node, acceptor, ['likelihoodForChange', 'structuralVolatility'], 'likelihoodForChange')
4838
}
4939

5040
if (node.contentVolatility) {
51-
highlightMemberAttribute(node, acceptor, ['contentVolatility'], 'contentVolatility')
41+
highlightField(node, acceptor, ['contentVolatility'], 'contentVolatility')
5242
}
5343

5444
if (node.availabilityCriticality) {
55-
highlightMemberAttribute(node, acceptor, ['availabilityCriticality'], 'availabilityCriticality')
45+
highlightField(node, acceptor, ['availabilityCriticality'], 'availabilityCriticality')
5646
}
5747

5848
if (node.consistencyCriticality) {
59-
highlightMemberAttribute(node, acceptor, ['consistencyCriticality'], 'consistencyCriticality')
49+
highlightField(node, acceptor, ['consistencyCriticality'], 'consistencyCriticality')
6050
}
6151

6252
if (node.storageSimilarity) {
63-
highlightMemberAttribute(node, acceptor, ['storageSimilarity'], 'storageSimilarity')
53+
highlightField(node, acceptor, ['storageSimilarity'], 'storageSimilarity')
6454
}
6555

6656
if (node.storageSimilarity) {
67-
highlightMemberAttribute(node, acceptor, ['storageSimilarity'], 'storageSimilarity')
57+
highlightField(node, acceptor, ['storageSimilarity'], 'storageSimilarity')
6858
}
6959

7060
if (node.securityCriticality) {
71-
highlightMemberAttribute(node, acceptor, ['securityCriticality'], 'securityCriticality')
61+
highlightField(node, acceptor, ['securityCriticality'], 'securityCriticality')
7262
}
7363

7464
if (node.securityZone) {
75-
highlightMemberAttribute(node, acceptor, ['securityZone'], 'securityZone', SemanticTokenTypes.string)
65+
highlightField(node, acceptor, ['securityZone'], 'securityZone', SemanticTokenTypes.string)
7666
}
7767

7868
if (node.securityAccessGroup) {
79-
highlightMemberAttribute(node, acceptor, ['securityAccessGroup'], 'securityAccessGroup', SemanticTokenTypes.string)
69+
highlightField(node, acceptor, ['securityAccessGroup'], 'securityAccessGroup', SemanticTokenTypes.string)
8070
}
8171
}
72+
73+
private highlightUserRequirements (node: Aggregate, acceptor: SemanticTokenAcceptor) {
74+
const keywords = []
75+
if (isUseCase(node.userRequirements[0])) {
76+
keywords.push('useCases')
77+
} else if (isUserRequirement(node.userRequirements[0])) {
78+
keywords.push('userRequirements')
79+
keywords.push('features')
80+
} else if (isUserStory(node.userRequirements[0])) {
81+
keywords.push('userStories')
82+
}
83+
84+
highlightField(node, acceptor, keywords, 'userRequirements', SemanticTokenTypes.type)
85+
}
8286
}

src/language/semantictokens/boundedContext/BoundedContextSemanticTokenProvider.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BoundedContext, isBoundedContext } from '../../generated/ast.js'
33
import { SemanticTokenTypes } from 'vscode-languageserver-types'
44
import {
55
highlightAttribute,
6-
highlightMemberAttribute,
6+
highlightField,
77
highlightTypeDeclaration
88
} from '../HighlightingHelper.js'
99
import { ContextMapperSemanticTokenProvider } from '../ContextMapperSemanticTokenProvider.js'
@@ -30,31 +30,31 @@ export class BoundedContextSemanticTokenProvider implements ContextMapperSemanti
3030
}
3131

3232
if (node.domainVisionStatement) {
33-
highlightMemberAttribute(node, acceptor, ['domainVisionStatement'], 'domainVisionStatement', SemanticTokenTypes.string)
33+
highlightField(node, acceptor, ['domainVisionStatement'], 'domainVisionStatement', SemanticTokenTypes.string)
3434
}
3535

3636
if (node.type) {
37-
highlightMemberAttribute(node, acceptor, ['type'], 'type')
37+
highlightField(node, acceptor, ['type'], 'type')
3838
}
3939

4040
if (node.responsibilities) {
41-
highlightMemberAttribute(node, acceptor, ['responsibilities'], 'responsibilities', SemanticTokenTypes.string)
41+
highlightField(node, acceptor, ['responsibilities'], 'responsibilities', SemanticTokenTypes.string)
4242
}
4343

4444
if (node.implementationTechnology) {
45-
highlightMemberAttribute(node, acceptor, ['implementationTechnology'], 'implementationTechnology', SemanticTokenTypes.string)
45+
highlightField(node, acceptor, ['implementationTechnology'], 'implementationTechnology', SemanticTokenTypes.string)
4646
}
4747

4848
if (node.knowledgeLevel) {
49-
highlightMemberAttribute(node, acceptor, ['knowledgeLevel'], 'knowledgeLevel')
49+
highlightField(node, acceptor, ['knowledgeLevel'], 'knowledgeLevel')
5050
}
5151

5252
if (node.businessModel) {
53-
highlightMemberAttribute(node, acceptor, ['businessModel'], 'businessModel', SemanticTokenTypes.string)
53+
highlightField(node, acceptor, ['businessModel'], 'businessModel', SemanticTokenTypes.string)
5454
}
5555

5656
if (node.evolution) {
57-
highlightMemberAttribute(node, acceptor, ['evolution'], 'evolution')
57+
highlightField(node, acceptor, ['evolution'], 'evolution')
5858
}
5959
}
6060
}

src/language/semantictokens/boundedContext/SculptorModuleSemanticTokenProvider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isSculptorModule, SculptorModule } from '../../generated/ast.js'
33
import { SemanticTokenAcceptor } from 'langium/lsp'
44
import {
55
highlightKeyword,
6-
highlightMemberAttribute,
6+
highlightField,
77
highlightString,
88
highlightTypeDeclaration
99
} from '../HighlightingHelper.js'
@@ -26,11 +26,11 @@ export class SculptorModuleSemanticTokenProvider implements ContextMapperSemanti
2626
}
2727

2828
if (node.basePackage) {
29-
highlightMemberAttribute(node, acceptor, ['basePackage'], 'basePackage', SemanticTokenTypes.namespace)
29+
highlightField(node, acceptor, ['basePackage'], 'basePackage', SemanticTokenTypes.namespace)
3030
}
3131

3232
if (node.hint) {
33-
highlightMemberAttribute(node, acceptor, ['hint'], 'hint', SemanticTokenTypes.string)
33+
highlightField(node, acceptor, ['hint'], 'hint', SemanticTokenTypes.string)
3434
}
3535
}
3636
}

src/language/semantictokens/contextMap/ContextMapSemanticTokenProvider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
ContextMap,
44
isContextMap
55
} from '../../generated/ast.js'
6-
import { highlightAttribute, highlightMemberAttribute, highlightTypeDeclaration } from '../HighlightingHelper.js'
6+
import { highlightAttribute, highlightField, highlightTypeDeclaration } from '../HighlightingHelper.js'
77
import { ContextMapperSemanticTokenProvider } from '../ContextMapperSemanticTokenProvider.js'
88
import { AstNode } from 'langium'
99

@@ -16,11 +16,11 @@ export class ContextMapSemanticTokenProvider implements ContextMapperSemanticTok
1616
highlightTypeDeclaration(node, acceptor, 'ContextMap', node.name != null)
1717

1818
if (node.type) {
19-
highlightMemberAttribute(node, acceptor, ['type'], 'type')
19+
highlightField(node, acceptor, ['type'], 'type')
2020
}
2121

2222
if (node.state) {
23-
highlightMemberAttribute(node, acceptor, ['state'], 'state')
23+
highlightField(node, acceptor, ['state'], 'state')
2424
}
2525

2626
if (node.boundedContexts.length > 0) {

0 commit comments

Comments
 (0)