diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-21 10:29:27 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-21 10:29:27 +0000 |
| commit | 9939ebe7f0ec25b042c9d83ed651cde0e2ea3a30 (patch) | |
| tree | 7dc877a16689d04ba80cab03ad544533d3a50e2d /plugin | |
| parent | 3cdb5d202faf04993e5aad955078653251cb6073 (diff) | |
feat(plugin): highlight supported keywords and directives
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'plugin')
| -rw-r--r-- | plugin/AGENTS/ARCH.md | 10 | ||||
| -rw-r--r-- | plugin/ThirdPartyNotices.md | 5 | ||||
| -rw-r--r-- | plugin/examples/highlighting.cps | 8 | ||||
| -rw-r--r-- | plugin/syntaxes/cie-pseudocode.tmLanguage.json | 63 | ||||
| -rw-r--r-- | plugin/test/highlighting.test.js | 38 |
5 files changed, 118 insertions, 6 deletions
diff --git a/plugin/AGENTS/ARCH.md b/plugin/AGENTS/ARCH.md index a8986d1..31c5974 100644 --- a/plugin/AGENTS/ARCH.md +++ b/plugin/AGENTS/ARCH.md @@ -97,10 +97,12 @@ only a subset of its syntax: - Highlighted builtins: LENGTH, MID, RIGHT, LEFT, LCASE, UCASE, ASC, CHR, IS_NUM, NUM_TO_STR, STR_TO_NUM and EOF. The compiler's complete table is in `lib/CodeGen/Builtins.h` and also includes MALLOC, FREE and REALLOC. -- CASE, CLASS, CONSTANT, OVERLOAD/OPERATOR and #LIB are supported by the compiler - but lack corresponding plugin language rules. SET, DATE and random-file - operations remain unsupported by the compiler too. Extending editor support - requires an explicit scope change. +- Highlighting covers CASE/ENDCASE/OTHERWISE, CLASS/ENDCLASS/PUBLIC/PRIVATE, + CONSTANT, TEMPLATE, OVERLOAD/OPERATOR, EXTERN declarations, INCLUDE_OBJ, #LIB + and ellipses using C++ scopes. OVERLOAD borrows a declaration modifier, #LIB + borrows #pragma and INCLUDE_OBJ borrows #include. #LIB must occupy its own line. + These rules do not add indentation support for the corresponding constructs. + SET, DATE and random-file operations remain unsupported by the compiler. Language defaults use real Tabs, display width 4, disabled indentation detection, full automatic indentation, on-type formatting and native bracket pair colors. diff --git a/plugin/ThirdPartyNotices.md b/plugin/ThirdPartyNotices.md index 72c3190..581724f 100644 --- a/plugin/ThirdPartyNotices.md +++ b/plugin/ThirdPartyNotices.md @@ -3,7 +3,10 @@ Language configuration and comment/string grammar structures are adapted from Microsoft VS Code’s built-in C++ extension. Exception keywords reuse its `keyword.control.try.cpp`, `keyword.control.catch.cpp` and -`keyword.control.throw.cpp` scopes; ENDTRY uses the TRY scope. +`keyword.control.throw.cpp` scopes; ENDTRY uses the TRY scope. Selection, class, +access, constant, template, operator and external-declaration highlighting also +reuse C++ scopes. OVERLOAD borrows a declaration modifier, #LIB borrows #pragma +and INCLUDE_OBJ borrows #include; ellipses use the C++ variadic scope. https://github.com/microsoft/vscode/tree/main/extensions/cpp diff --git a/plugin/examples/highlighting.cps b/plugin/examples/highlighting.cps index 7b30bb7..b5deaee 100644 --- a/plugin/examples/highlighting.cps +++ b/plugin/examples/highlighting.cps @@ -6,6 +6,8 @@ TYPE Student DECLARE Initial : CHAR ENDTYPE +CONSTANT Limit = 3 + DECLARE Values : ARRAY[1:3] OF INTEGER DECLARE Index : INTEGER DECLARE Total : REAL @@ -45,3 +47,9 @@ TRY CATCH OUTPUT "Caught an exception" ENDTRY + +CASE OF Index + 1 : OUTPUT "First" + 2 TO Limit : OUTPUT "In range" + OTHERWISE : OUTPUT "Other" +ENDCASE diff --git a/plugin/syntaxes/cie-pseudocode.tmLanguage.json b/plugin/syntaxes/cie-pseudocode.tmLanguage.json index 0ae08cc..d0830a8 100644 --- a/plugin/syntaxes/cie-pseudocode.tmLanguage.json +++ b/plugin/syntaxes/cie-pseudocode.tmLanguage.json @@ -9,6 +9,69 @@ "include": "#strings" }, { + "match": "^\\s*(#)(LIB)\\s*$", + "captures": { + "1": { + "name": "punctuation.definition.directive.cpp" + }, + "2": { + "name": "keyword.control.directive.pragma.cpp" + } + } + }, + { + "match": "(?<!\\w)(?:CASE|ENDCASE)(?!\\w)", + "name": "keyword.control.switch.cpp" + }, + { + "match": "(?<!\\w)(?:OTHERWISE)(?!\\w)", + "name": "keyword.control.default.cpp" + }, + { + "match": "(?<!\\w)(?:CONSTANT)(?!\\w)", + "name": "storage.modifier.const.cpp" + }, + { + "match": "(?<!\\w)(?:CLASS|ENDCLASS)(?!\\w)", + "name": "storage.type.class.cpp" + }, + { + "match": "(?<!\\w)(?:PUBLIC)(?!\\w)", + "name": "storage.type.modifier.access.control.public.cpp" + }, + { + "match": "(?<!\\w)(?:PRIVATE)(?!\\w)", + "name": "storage.type.modifier.access.control.private.cpp" + }, + { + "match": "(?<!\\w)(?:TEMPLATE)(?!\\w)", + "name": "storage.type.template.cpp" + }, + { + "match": "(?<!\\w)(?:OPERATOR)(?!\\w)", + "name": "keyword.other.operator.overload.cpp" + }, + { + "match": "(?<!\\w)(?:OVERLOAD)(?!\\w)", + "name": "storage.modifier.cpp" + }, + { + "match": "(?<!\\w)(?:EXTERN)(?!\\w)", + "name": "storage.modifier.specifier.extern.cpp" + }, + { + "match": "(?<!\\w)(?:EXTERN_FUNCTION|EXTERN_PROCEDURE)(?!\\w)", + "name": "storage.modifier.cpp" + }, + { + "match": "(?<!\\w)(?:INCLUDE_OBJ)(?!\\w)", + "name": "keyword.control.directive.include.cpp" + }, + { + "match": "\\.\\.\\.", + "name": "punctuation.vararg-ellipses.cpp" + }, + { "match": "(?<!\\w)(?:TRY|ENDTRY)(?!\\w)", "name": "keyword.control.try.cpp" }, diff --git a/plugin/test/highlighting.test.js b/plugin/test/highlighting.test.js index f7a67db..bfdf0a2 100644 --- a/plugin/test/highlighting.test.js +++ b/plugin/test/highlighting.test.js @@ -58,6 +58,42 @@ test('both assignment characters share the C++ assignment scope', () => { assert.ok(!scopesAt('X - 1', '-').includes('keyword.operator.assignment.cpp')); }); +test('supported keywords reuse C++ scopes without matching identifiers or quoted text', () => { + for (const [words, scope] of [ + [['CASE', 'ENDCASE'], 'keyword.control.switch.cpp'], + [['OTHERWISE'], 'keyword.control.default.cpp'], + [['CONSTANT'], 'storage.modifier.const.cpp'], + [['CLASS', 'ENDCLASS'], 'storage.type.class.cpp'], + [['PUBLIC'], 'storage.type.modifier.access.control.public.cpp'], + [['PRIVATE'], 'storage.type.modifier.access.control.private.cpp'], + [['TEMPLATE'], 'storage.type.template.cpp'], + [['OPERATOR'], 'keyword.other.operator.overload.cpp'], + [['OVERLOAD', 'EXTERN_FUNCTION', 'EXTERN_PROCEDURE'], 'storage.modifier.cpp'], + [['EXTERN'], 'storage.modifier.specifier.extern.cpp'], + [['INCLUDE_OBJ'], 'keyword.control.directive.include.cpp'] + ]) for (const word of words) { + assert.ok(scopesAt(word, word).includes(scope), word); + for (const text of [word.toLowerCase(), `${word}Value`, `_${word}`, `${word}_1`]) { + assert.ok(!scopesAt(text, text).includes(scope), text); + } + assert.ok(scopesAt(`// ${word}`, word).some(s => s.startsWith('comment.'))); + assert.ok(scopesAt(`OUTPUT "${word}"`, word).some(s => s.startsWith('string.'))); + } +}); + +test('library directives require their own line and ellipses use the C++ variadic scope', () => { + assert.ok(scopesAt('\t#LIB ', '#').includes('punctuation.definition.directive.cpp')); + assert.ok(scopesAt('\t#LIB ', 'LIB').includes('keyword.control.directive.pragma.cpp')); + for (const text of ['#lib', '#LIBRARY', '#LIB // comment', 'X #LIB', '// #LIB', 'OUTPUT "#LIB"']) { + assert.ok(!scopesAt(text, '#') + .includes('punctuation.definition.directive.cpp'), text); + } + for (const text of ['TEMPLATE <Types...>', 'EXTERN "C" EXTERN_PROCEDURE print(C_INT, ...)', 'CALL print(Values...)']) { + assert.ok(scopesAt(text, '...').includes('punctuation.vararg-ellipses.cpp'), text); + } + assert.ok(!scopesAt('Value.Field', '.').includes('punctuation.vararg-ellipses.cpp')); +}); + test('exception keywords reuse C++ scopes and ignore non-keyword occurrences', () => { for (const [word, scope] of [ ['TRY', 'keyword.control.try.cpp'], @@ -82,7 +118,7 @@ test('comments, strings, lowercase and keyword prefixes cannot become keywords', for (const text of ['c_int', 'C_INTValue', 'MyC_INT', 'C_TYPE_1']) { assert.ok(!scopesAt(text, text).some(s => s.startsWith('storage.')), text); } - for (const text of ['if X then', 'IFValue <- 1', 'CASE OF X', 'CLASS Example']) { + for (const text of ['if X then', 'IFValue <- 1', 'SET OF X', 'DEFINE X', 'RANDOM']) { assert.ok(!scopesAt(text, text.split(' ')[0]).some( s => /^(keyword|storage)\./.test(s)), text); } |
