From 6dabb02dfa76e58b7538ea38d9d9a0ff27d3609d Mon Sep 17 00:00:00 2001 From: Jiasheng Date: Tue, 31 Oct 2023 17:37:49 +0000 Subject: [PATCH] feat: Make ZModel color schema looks cool and consistent (#791) support #716 --- .../src/language-server/zmodel-module.ts | 2 + .../src/language-server/zmodel-semantic.ts | 103 ++++++++++++++++++ .../schema/syntaxes/zmodel.tmLanguage.json | 22 +++- 3 files changed, 123 insertions(+), 4 deletions(-) create mode 100644 packages/schema/src/language-server/zmodel-semantic.ts diff --git a/packages/schema/src/language-server/zmodel-module.ts b/packages/schema/src/language-server/zmodel-module.ts index 195c41031..ab0f32b45 100644 --- a/packages/schema/src/language-server/zmodel-module.ts +++ b/packages/schema/src/language-server/zmodel-module.ts @@ -26,6 +26,7 @@ import { ZModelLinker } from './zmodel-linker'; import { ZModelScopeComputation, ZModelScopeProvider } from './zmodel-scope'; import ZModelWorkspaceManager from './zmodel-workspace-manager'; import { ZModelDefinitionProvider } from './zmodel-definition'; +import { ZModelSemanticTokenProvider } from './zmodel-semantic'; /** * Declaration of custom services - add your own service classes here. @@ -61,6 +62,7 @@ export const ZModelModule: Module new ZModelFormatter(), CodeActionProvider: (services) => new ZModelCodeActionProvider(services), DefinitionProvider: (services) => new ZModelDefinitionProvider(services), + SemanticTokenProvider: (services) => new ZModelSemanticTokenProvider(services), }, }; diff --git a/packages/schema/src/language-server/zmodel-semantic.ts b/packages/schema/src/language-server/zmodel-semantic.ts new file mode 100644 index 000000000..18e2e5819 --- /dev/null +++ b/packages/schema/src/language-server/zmodel-semantic.ts @@ -0,0 +1,103 @@ +import { + isAttribute, + isAttributeArg, + isConfigField, + isDataModel, + isDataModelAttribute, + isDataModelField, + isDataModelFieldAttribute, + isDataModelFieldType, + isDataSource, + isEnum, + isEnumField, + isFunctionDecl, + isGeneratorDecl, + isInternalAttribute, + isInvocationExpr, + isMemberAccessExpr, + isPlugin, + isPluginField, + isReferenceExpr, +} from '@zenstackhq/language/ast'; +import { AbstractSemanticTokenProvider, AstNode, SemanticTokenAcceptor } from 'langium'; +import { SemanticTokenTypes } from 'vscode-languageserver'; + +export class ZModelSemanticTokenProvider extends AbstractSemanticTokenProvider { + protected highlightElement(node: AstNode, acceptor: SemanticTokenAcceptor): void { + if (isDataModel(node)) { + acceptor({ + node, + property: 'name', + type: SemanticTokenTypes.type, + }); + + acceptor({ + node, + property: 'superTypes', + type: SemanticTokenTypes.type, + }); + } else if (isDataSource(node) || isGeneratorDecl(node) || isPlugin(node) || isEnum(node)) { + acceptor({ + node, + property: 'name', + type: SemanticTokenTypes.type, + }); + } else if ( + isDataModelField(node) || + isConfigField(node) || + isAttributeArg(node) || + isPluginField(node) || + isEnumField(node) + ) { + acceptor({ + node, + property: 'name', + type: SemanticTokenTypes.variable, + }); + } else if (isDataModelFieldType(node)) { + if (node.type) { + acceptor({ + node, + property: 'type', + type: SemanticTokenTypes.type, + }); + } else { + acceptor({ + node, + property: 'reference', + type: SemanticTokenTypes.macro, + }); + } + } else if (isDataModelAttribute(node) || isDataModelFieldAttribute(node) || isInternalAttribute(node)) { + acceptor({ + node, + property: 'decl', + type: SemanticTokenTypes.function, + }); + } else if (isInvocationExpr(node)) { + acceptor({ + node, + property: 'function', + type: SemanticTokenTypes.function, + }); + } else if (isFunctionDecl(node) || isAttribute(node)) { + acceptor({ + node, + property: 'name', + type: SemanticTokenTypes.function, + }); + } else if (isReferenceExpr(node)) { + acceptor({ + node, + property: 'target', + type: SemanticTokenTypes.variable, + }); + } else if (isMemberAccessExpr(node)) { + acceptor({ + node, + property: 'member', + type: SemanticTokenTypes.property, + }); + } + } +} diff --git a/packages/schema/syntaxes/zmodel.tmLanguage.json b/packages/schema/syntaxes/zmodel.tmLanguage.json index f2f2fdfbb..fb5bf9c7e 100644 --- a/packages/schema/syntaxes/zmodel.tmLanguage.json +++ b/packages/schema/syntaxes/zmodel.tmLanguage.json @@ -7,18 +7,28 @@ "include": "#comments" }, { - "name": "keyword.control.zmodel", - "match": "\\b(Any|Asc|attribute|BigInt|Boolean|Bytes|ContextType|datasource|DateTime|Decimal|Desc|enum|FieldReference|Float|function|generator|Int|Json|model|Null|plugin|sort|String)\\b" + "name": "keyword.storage.zmodel", + "match": "\\b(Any|Asc|BigInt|Boolean|Bytes|ContextType|DateTime|Decimal|Desc|FieldReference|Float|Int|Json|Null|Object|String|TransitiveFieldReference|Unsupported|abstract|attribute|datasource|enum|extends|false|function|generator|import|in|model|plugin|sort|true|view)\\b" }, { "name": "string.quoted.double.zmodel", "begin": "\"", - "end": "\"" + "end": "\"", + "patterns": [ + { + "include": "#string-character-escape" + } + ] }, { "name": "string.quoted.single.zmodel", "begin": "'", - "end": "'" + "end": "'", + "patterns": [ + { + "include": "#string-character-escape" + } + ] } ], "repository": { @@ -50,6 +60,10 @@ "name": "comment.line.zmodel" } ] + }, + "string-character-escape": { + "name": "constant.character.escape.zmodel", + "match": "\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|u\\{[0-9A-Fa-f]+\\}|[0-2][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)" } } }