diff --git a/analyzer-views/src/colors.ts b/analyzer-views/src/colors.ts index 68e9dae..e6e61a7 100644 --- a/analyzer-views/src/colors.ts +++ b/analyzer-views/src/colors.ts @@ -1,12 +1,12 @@ // The colours VisualText gives NLP++ tokens, as the VS Code extension sets them. // -// The extension's grammars name scopes of their own -- keyword.node.tree, -// keyword.rewrite.tree, keyword.concept.kbb2 -- which no theme knows, so VS Code themes -// would colour them all as plain keywords. The extension therefore ships +// The grammars use standard TextMate scope names (nlpplus-tmbundle#3), so any theme +// colours NLP++ reasonably. On top of that the extension ships its own // editor.tokenColorCustomizations in the .vscode/settings.json of its repository and of // the analyzer repositories (vscode-nlp/.vscode/settings.json), with one set of rules for // light themes and one for dark. Parse trees are the clearest case: node names green, -// rewrites bold, offsets blue, "fired" red. +// rewrites bold, offsets blue, "fired" red. A rule for an old scope name that covered +// several things lists all of their new names (vscode-nlp src/language/scopeMigration.ts). // // Copied from there rule for rule, so the two can be compared, and folded into the shiki // themes in highlight.ts. PURE: no DOM. @@ -18,41 +18,41 @@ export interface TokenRule { export const LIGHT_RULES: TokenRule[] = [ { scope: "entity.name.function.letter.nlp", settings: { foreground: "#dc1b1b" } }, { scope: "entity.name.function.nlp", settings: { foreground: "#000000" } }, - { scope: "variable.parameter.nlp", settings: { foreground: "#696969", fontStyle: "bold" } }, - { scope: "keyword.attribute.nlp", settings: { foreground: "#e655f3" } }, - { scope: "keyword.constants.nlp", settings: { foreground: "#0a7b83", fontStyle: "bold" } }, + { scope: ["variable.parameter.nlp", "keyword.control.kb"], settings: { foreground: "#696969", fontStyle: "bold" } }, + { scope: "entity.other.attribute-name.nlp", settings: { foreground: "#e655f3" } }, + { scope: "constant.language.nlp", settings: { foreground: "#0a7b83", fontStyle: "bold" } }, { scope: ["keyword.operator.nlp", "keyword.operator.word.nlp"], settings: { foreground: "#1f6feb" } }, - { scope: "constant.numeric.tree", settings: { foreground: "#5596f0" } }, - { scope: "keyword.fired.tree", settings: { foreground: "#dc1b1b", fontStyle: "bold" } }, - { scope: "keyword.rewrite.tree", settings: { foreground: "#000000", fontStyle: "bold" } }, - { scope: "keyword.node.tree", settings: { foreground: "#4e8e3c", fontStyle: "bold" } }, + { scope: ["constant.numeric.tree", "constant.numeric.kbb"], settings: { foreground: "#5596f0" } }, + { scope: "keyword.other.fired.tree", settings: { foreground: "#dc1b1b", fontStyle: "bold" } }, + { scope: "entity.name.type.tree", settings: { foreground: "#000000", fontStyle: "bold" } }, + { scope: "string.unquoted.token.tree", settings: { foreground: "#4e8e3c", fontStyle: "bold" } }, { scope: "source.txxt", settings: { foreground: "#a5a5a5" } }, { scope: "keyword.other.txxt", settings: { foreground: "#6e60eb", fontStyle: "bold" } }, { scope: "comment.line.txxt", settings: { foreground: "#dd2c2c", fontStyle: "bold" } }, { scope: "variable.parameter.txxt", settings: { foreground: "#535353", fontStyle: "bold" } }, - { scope: "keyword.other.kbb", settings: { foreground: "#5d00d6", fontStyle: "bold" } }, - { scope: "keyword.concept.kbb", settings: { foreground: "#7e7e7e", fontStyle: "bold" } }, - { scope: "keyword.concept.kbb1", settings: { foreground: "#2eb657", fontStyle: "bold" } }, - { scope: "keyword.concept.kbb2", settings: { foreground: "#e049d9", fontStyle: "bold" } }, + { scope: "entity.name.type.level0.kbb", settings: { foreground: "#5d00d6", fontStyle: "bold" } }, + { scope: "entity.name.type.level1.kbb", settings: { foreground: "#7e7e7e", fontStyle: "bold" } }, + { scope: "entity.name.type.level2.kbb", settings: { foreground: "#2eb657", fontStyle: "bold" } }, + { scope: "entity.name.type.level3.kbb", settings: { foreground: "#e049d9", fontStyle: "bold" } }, ]; export const DARK_RULES: TokenRule[] = [ { scope: "entity.name.function.letter.nlp", settings: { foreground: "#dc1b1b" } }, { scope: "entity.name.function.nlp", settings: { foreground: "#8f8f8f", fontStyle: "bold" } }, - { scope: "variable.parameter.nlp", settings: { foreground: "#f8fa87", fontStyle: "bold" } }, - { scope: "keyword.attribute.nlp", settings: { foreground: "#f293fb" } }, - { scope: "keyword.constants.nlp", settings: { foreground: "#4ec9b0", fontStyle: "bold" } }, + { scope: ["variable.parameter.nlp", "keyword.control.kb"], settings: { foreground: "#f8fa87", fontStyle: "bold" } }, + { scope: "entity.other.attribute-name.nlp", settings: { foreground: "#f293fb" } }, + { scope: "constant.language.nlp", settings: { foreground: "#4ec9b0", fontStyle: "bold" } }, { scope: ["keyword.operator.nlp", "keyword.operator.word.nlp"], settings: { foreground: "#8ab4f8" } }, - { scope: "constant.numeric.tree", settings: { foreground: "#93bffb" } }, - { scope: "keyword.fired.tree", settings: { foreground: "#dc1b1b", fontStyle: "bold" } }, - { scope: "keyword.rewrite.tree", settings: { foreground: "#f8fa87", fontStyle: "bold" } }, - { scope: "keyword.node.tree", settings: { foreground: "#4e8e3c", fontStyle: "bold" } }, + { scope: ["constant.numeric.tree", "constant.numeric.kbb"], settings: { foreground: "#93bffb" } }, + { scope: "keyword.other.fired.tree", settings: { foreground: "#dc1b1b", fontStyle: "bold" } }, + { scope: "entity.name.type.tree", settings: { foreground: "#f8fa87", fontStyle: "bold" } }, + { scope: "string.unquoted.token.tree", settings: { foreground: "#4e8e3c", fontStyle: "bold" } }, { scope: "source.txxt", settings: { foreground: "#7e7e7e" } }, { scope: "variable.parameter.txxt", settings: { foreground: "#f8fa87" } }, - { scope: "keyword.other.kbb", settings: { foreground: "#896eff", fontStyle: "bold" } }, - { scope: "keyword.concept.kbb", settings: { foreground: "#e3ee50", fontStyle: "bold" } }, - { scope: "keyword.concept.kbb1", settings: { foreground: "#2eb657", fontStyle: "bold" } }, - { scope: "keyword.concept.kbb2", settings: { foreground: "#e049d9", fontStyle: "bold" } }, + { scope: "entity.name.type.level0.kbb", settings: { foreground: "#896eff", fontStyle: "bold" } }, + { scope: "entity.name.type.level1.kbb", settings: { foreground: "#e3ee50", fontStyle: "bold" } }, + { scope: "entity.name.type.level2.kbb", settings: { foreground: "#2eb657", fontStyle: "bold" } }, + { scope: "entity.name.type.level3.kbb", settings: { foreground: "#e049d9", fontStyle: "bold" } }, ]; // The tree scopes the extension's rules colour, for the self test to check they arrived. diff --git a/analyzer-views/src/grammars/README.md b/analyzer-views/src/grammars/README.md index 8e60b42..bc221df 100644 --- a/analyzer-views/src/grammars/README.md +++ b/analyzer-views/src/grammars/README.md @@ -1,6 +1,6 @@ # NLP++ TextMate grammars A copy of `syntaxes/` from [VisualText/nlpplus-tmbundle](https://github.com/VisualText/nlpplus-tmbundle) -at `ab5328e`, under its MIT license (`LICENSE`, beside this file). These are the grammars the NLP++ +at `655c78d`, under its MIT license (`LICENSE`, beside this file). These are the grammars the NLP++ VS Code extension uses. Shiki tokenizes with them (`../highlight.ts`), for `` and for NLP Studio's Monaco editor. diff --git a/analyzer-views/src/grammars/dict.tmLanguage.json b/analyzer-views/src/grammars/dict.tmLanguage.json index d29cb6f..3153579 100644 --- a/analyzer-views/src/grammars/dict.tmLanguage.json +++ b/analyzer-views/src/grammars/dict.tmLanguage.json @@ -15,7 +15,10 @@ "patterns": [ { "include": "#comment-line" - }, + }, + { + "include": "#comment-block" + }, { "include": "#attribute-equals" }, @@ -37,16 +40,16 @@ "match": "^([^=]+)(\\s)([\\w\\d]+)(\\s)*(=)", "captures": { "1": { - "name": "comment.line.dict" + "name": "entity.name.tag.dict" }, "2": { - "name": "entity.nothing.dict" + "name": "meta.whitespace.dict" }, "3": { - "name": "keyword.region.dict" + "name": "support.type.property-name.dict" }, "4": { - "name": "keyword.region.dict" + "name": "meta.whitespace.dict" }, "5": { "name": "keyword.operator.dict" @@ -55,16 +58,16 @@ }, "value": { "match": "[\\w\\d]+", - "name": "entity.name.function.dict" + "name": "string.unquoted.value.dict" }, "other-attrs": { "match": "([\\w]+)(\\s)*(=)", "captures": { "1": { - "name": "keyword.region.dict" + "name": "support.type.property-name.dict" }, "2": { - "name": "keyword.region.dict" + "name": "meta.whitespace.dict" }, "3": { "name": "keyword.operator.dict" @@ -75,10 +78,25 @@ "match": "\\s*#.*$\\n?", "name": "comment.line.dict" }, + "comment-block": { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "comment.block.begin.dict" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "comment.block.end.dict" + } + }, + "name": "comment.block.dict" + }, "qstring-double": { "begin": "\"", "end": "\\\"|(?:[^\\\\\\n]$)", - "name": "string.double.dict", + "name": "string.quoted.double.dict", "patterns": [ { "include": "#string-character-escape" diff --git a/analyzer-views/src/grammars/kb.tmLanguage.json b/analyzer-views/src/grammars/kb.tmLanguage.json index 378cc01..a699973 100644 --- a/analyzer-views/src/grammars/kb.tmLanguage.json +++ b/analyzer-views/src/grammars/kb.tmLanguage.json @@ -6,7 +6,7 @@ "name": "kb", "patterns": [ { - "name": "variable.parameter.nlp", + "name": "keyword.control.kb", "match": "\\b(?i:(add|bind|ind|quit|take))\\b" }, { @@ -28,6 +28,9 @@ { "include": "#comment-line" }, + { + "include": "#comment-block" + }, { "include": "#number" }, @@ -46,7 +49,7 @@ "qstring-double": { "begin": "\"", "end": "\\\"|(?:[^\\\\\\n]$)", - "name": "string.double.kb", + "name": "string.quoted.double.kb", "patterns": [ { "include": "#string-character-escape" @@ -63,7 +66,22 @@ }, "comment-line": { "match": "\\s*#.*$\\n?", - "name": "comment.line.dict" + "name": "comment.line.kb" + }, + "comment-block": { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "comment.block.begin.kb" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "comment.block.end.kb" + } + }, + "name": "comment.block.kb" } } } \ No newline at end of file diff --git a/analyzer-views/src/grammars/kbb.tmLanguage.json b/analyzer-views/src/grammars/kbb.tmLanguage.json index 80bcfc7..9fce346 100644 --- a/analyzer-views/src/grammars/kbb.tmLanguage.json +++ b/analyzer-views/src/grammars/kbb.tmLanguage.json @@ -16,6 +16,9 @@ { "include": "#comment-line" }, + { + "include": "#comment-block" + }, { "include": "#top-concept" }, @@ -41,22 +44,22 @@ }, "top-concept": { "match": "^([\\w\\d]+)$", - "name": "keyword.other.kbb" + "name": "entity.name.type.level0.kbb" }, "concept-name": { - "name": "keyword.concept.kbb", + "name": "entity.name.type.level1.kbb", "match": "^[\\s][\\s][\\w\\d][^:^\\[]+[:]?" }, "concept-name1": { - "name": "keyword.concept.kbb1", + "name": "entity.name.type.level2.kbb", "match": "^[\\s][\\s][\\s][\\s][\\w\\d][^:^\\[]+[:]?" }, "concept-name2": { - "name": "keyword.concept.kbb2", + "name": "entity.name.type.level3.kbb", "match": "^[\\s][\\s][\\s][\\s][\\s][\\s][\\w\\d][^:^\\[]+[:]?" }, "attribute-name": { - "name": "constant.numeric.tree", + "name": "constant.numeric.kbb", "match": "\\b[\\w\\d]+=" }, "attributes": { @@ -75,7 +78,7 @@ "qstring-double": { "begin": "\"", "end": "\\\"|(?:[^\\\\\\n]$)", - "name": "string.double.kbb", + "name": "string.quoted.double.kbb", "patterns": [ { "include": "#string-character-escape" @@ -92,7 +95,22 @@ }, "comment-line": { "match": "\\s*#.*$\\n?", - "name": "comment.line.dict" + "name": "comment.line.kbb" + }, + "comment-block": { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "comment.block.begin.kbb" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "comment.block.end.kbb" + } + }, + "name": "comment.block.kbb" } } } \ No newline at end of file diff --git a/analyzer-views/src/grammars/nlp.tmLanguage.json b/analyzer-views/src/grammars/nlp.tmLanguage.json index 6663ba1..116b824 100644 --- a/analyzer-views/src/grammars/nlp.tmLanguage.json +++ b/analyzer-views/src/grammars/nlp.tmLanguage.json @@ -10,11 +10,11 @@ "include": "#expression" }, { - "name": "keyword.region.nlp", + "name": "keyword.control.directive.region.nlp", "match": "(@(@)?)(CHECK|CODE|DECL|MULTI|NODES|PATH|POST|PRE|RULES)\\b" }, { - "name": "keyword.constants.nlp", + "name": "constant.language.nlp", "match": "\\b_ROOT\\b" }, { @@ -85,7 +85,7 @@ "begin": "([_\\w]+)\\s*((\\[[^\\]]*\\]))*\\s*(<-)", "beginCaptures": { "1": { - "name": "variable.rewrite.nlp" + "name": "entity.name.type.rewrite.nlp" }, "2": { "patterns": [ @@ -95,13 +95,13 @@ ] }, "3": { - "name": "variable.rewrite-symbol.nlp" + "name": "meta.attribute.rewrite.nlp" } }, "end": "@@", "endCaptures": { "0": { - "name": "keyword.region.nlp" + "name": "keyword.control.directive.region.nlp" } }, "patterns": [ @@ -118,7 +118,7 @@ "include": "#escaped-char" }, { - "include": "#comment-line" + "include": "#comment" } ] }, @@ -126,13 +126,13 @@ "begin": "\\[", "beginCaptures": { "0": { - "name": "punctuation.square.open" + "name": "punctuation.square.open.nlp" } }, "end": "\\]", "endCaptures": { "0": { - "name": "punctuation.square.close" + "name": "punctuation.square.close.nlp" } }, "patterns": [ @@ -152,7 +152,7 @@ "include": "#attribute" }, { - "include": "#comment-line" + "include": "#comment" }, { "include": "#string" @@ -167,8 +167,8 @@ "name": "meta.rules.rule.attribute.nlp" }, "constant-nodes": { - "name": "keyword.constants.nlp", - "match": "\\b_(xWILD|xNUM|xALPHA|xWHITE|xNIL|xSTART|xEND|xCTRL)\\b" + "name": "constant.language.nlp", + "match": "\\b_(xALPHA|xANY|xBLANK|xCAPLET|xCAP|xCTRL|xEMOJI|xEND|xEOF|xLET|xNIL|xNUM|xPUNCT|xSTART|xVAR|xWHITE|xWILD)\\b" }, "attribute-equals": { "begin": "([_\\w]+)\\s*(=)\\s*(\\()", @@ -181,16 +181,16 @@ ] }, "2": { - "name": "keyword.equals.nlp" + "name": "keyword.operator.assignment.nlp" }, "3": { - "name": "punctuation.paren.open" + "name": "punctuation.paren.open.nlp" } }, "end": "\\)", "endCaptures": { "0": { - "name": "punctuation.paren.open" + "name": "punctuation.paren.close.nlp" } }, "patterns": [ @@ -209,11 +209,11 @@ ] }, "attribute": { - "name": "keyword.attribute.nlp", - "match": "\\b(?i:(attr|attrs|da|deacc|deaccent|except|excepts|fail|fails|gp|group|layer|layers|look|lookahead|match|matches|max|min|nest|o|one|opt|option|optional|pass|passes|plus|recurse|ren|rename|s|singlet|star|t|tree|trig|trigger|unsealed))\\b" + "name": "entity.other.attribute-name.nlp", + "match": "\\b(?i:(attr|attrs|base|da|deacc|deaccent|except|excepts|fail|fails|gp|group|layer|layers|look|lookahead|match|matches|max|min|nest|o|one|opt|option|optional|pass|passes|plus|recurse|ren|rename|s|singlet|star|t|tree|trig|trigger|unsealed))\\b" }, "escaped-char": { - "name": "constant.character.escape", + "name": "constant.character.escape.nlp", "match": "\\\\." }, "token": { @@ -261,7 +261,7 @@ "qstring-double": { "begin": "\"", "end": "\\\"|(?:[^\\\\\\n]$)", - "name": "string.double.nlp", + "name": "string.quoted.double.nlp", "patterns": [ { "include": "#string-character-escape" @@ -273,7 +273,7 @@ "name": "constant.character.escape.nlp" }, "literal": { - "name": "literal.nlp", + "name": "meta.literal.nlp", "patterns": [ { "include": "#numeric-literal" diff --git a/analyzer-views/src/grammars/seq.tmLanguage.json b/analyzer-views/src/grammars/seq.tmLanguage.json index 0a85a8e..9070ef4 100644 --- a/analyzer-views/src/grammars/seq.tmLanguage.json +++ b/analyzer-views/src/grammars/seq.tmLanguage.json @@ -69,7 +69,7 @@ "qstring-double": { "begin": "\"", "end": "\\\"|(?:[^\\\\\\n]$)", - "name": "string.double.seq", + "name": "string.quoted.double.seq", "patterns": [ { "include": "#string-character-escape" @@ -81,7 +81,7 @@ "name": "constant.character.escape.seq" }, "literal": { - "name": "literal.seq", + "name": "meta.literal.seq", "patterns": [ { "include": "#numeric-literal" diff --git a/analyzer-views/src/grammars/tree.tmLanguage.json b/analyzer-views/src/grammars/tree.tmLanguage.json index 4d67e93..67d3e19 100644 --- a/analyzer-views/src/grammars/tree.tmLanguage.json +++ b/analyzer-views/src/grammars/tree.tmLanguage.json @@ -30,10 +30,10 @@ }, "node-name": { "match": "^([\\s]+)([^_\\s]+)", - "name": "keyword.node.tree" + "name": "string.unquoted.token.tree" }, "rewrites": { - "name": "keyword.rewrite.tree", + "name": "entity.name.type.tree", "match": "\\b_[\\w]+\\b" }, "attributes": { @@ -55,7 +55,7 @@ "qstring-double": { "begin": "\"", "end": "\\\"|(?:[^\\\\\\n]$)", - "name": "string.double.tree", + "name": "string.quoted.double.tree", "patterns": [ { "include": "#string-character-escape" @@ -67,7 +67,7 @@ "name": "constant.character.escape.tree" }, "literal": { - "name": "literal.tree", + "name": "meta.literal.tree", "patterns": [ { "include": "#numeric-literal" @@ -86,15 +86,15 @@ }, "fired": { "match": "\\b(?i:(fired))\\b", - "name": "keyword.fired.tree" + "name": "keyword.other.fired.tree" }, "types": { "match": "\\b(?i:(alpha|ctrl|emoji|node|num|punct|white))\\b", - "name": "keyword.attribute.tree" + "name": "storage.type.tree" }, "comment-line": { "match": "\\s*#.*$\\n?", - "name": "comment.line.dict" + "name": "comment.line.tree" } } } \ No newline at end of file diff --git a/analyzer-views/src/grammars/txxt.tmLanguage.json b/analyzer-views/src/grammars/txxt.tmLanguage.json index da8f440..4bec7a5 100644 --- a/analyzer-views/src/grammars/txxt.tmLanguage.json +++ b/analyzer-views/src/grammars/txxt.tmLanguage.json @@ -11,7 +11,7 @@ ], "repository": { "expression": { - "name": "meta.expression.tree", + "name": "meta.expression.txxt", "patterns": [ { "include": "#angle-match" diff --git a/analyzer-views/src/highlight.ts b/analyzer-views/src/highlight.ts index d8b1414..d3022b0 100644 --- a/analyzer-views/src/highlight.ts +++ b/analyzer-views/src/highlight.ts @@ -5,9 +5,9 @@ // loaded on first use -- the grammars and themes are chunks nobody pays for until code is // on screen. renders its tokens; NLP Studio hands the same highlighter to Monaco. // -// THE EXTENSION'S COLOURS. The grammars name scopes of their own (keyword.node.tree, -// keyword.concept.kbb2, ...) that no stock theme knows, so the extension's rules for them -// (colors.ts) go into light-plus and dark-plus first. +// THE EXTENSION'S COLOURS. The grammars use standard scope names, so light-plus and +// dark-plus colour them on their own; the extension's own rules (colors.ts) go in first +// so a parse tree is green, bold and red the way VS Code shows it. // // BOTH THEMES AT ONCE. Tokens carry their light and dark colours as --shiki-light and // --shiki-dark, and style.css picks one, so a theme change repaints without tokenising. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 4c7902f..5f9f8b0 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -135,13 +135,12 @@ files the analyzer wrote, problems, and the engine's log. Its parse trees open i `kbView`/`textView` give them. `analyzer-views/src/icons.ts` holds that artwork inlined from `vscode-nlp/resources` (MIT), shapes carrying `currentColor` so one copy serves both themes and a switched-off pass is the same shape in grey rather than a second drawing. -- **Tree colours are the extension's.** The grammars name scopes no stock theme knows - (`keyword.node.tree`, `keyword.rewrite.tree`, `keyword.concept.kbb2`), which is why VS Code - colours them through `editor.tokenColorCustomizations` in the `.vscode/settings.json` that - `vscode-nlp` and the analyzer repositories ship. `analyzer-views/src/colors.ts` holds those +- **Tree colours are the extension's.** The grammars use standard scope names, which any + theme colours, but VS Code also colours them through `editor.tokenColorCustomizations` in + the `.vscode/settings.json` that `vscode-nlp` and the analyzer repositories ship. `analyzer-views/src/colors.ts` holds those rules, rule for rule, for light and for dark, and `analyzer-views/src/highlight.ts` folds them into both shiki themes, for the editor and for `` alike. - Without them a tree is one flat keyword colour. + Without them a tree takes the stock theme's colours rather than the extension's. - **Pass numbers are the engine's.** A switched-off pass (`/nlp name`) keeps its number and a folder or stub has none. That was measured, not assumed, and both the page (`analyzer-views/src/sequence.ts`) and the server number `analyzer.seq` the same way.