aboutsummaryrefslogtreecommitdiff
path: root/plugin
diff options
context:
space:
mode:
Diffstat (limited to 'plugin')
-rw-r--r--plugin/README.md2
-rw-r--r--plugin/ThirdPartyNotices.md6
-rw-r--r--plugin/examples/highlighting.cps10
-rw-r--r--plugin/syntaxes/cie-pseudocode.tmLanguage.json42
-rw-r--r--plugin/test/highlighting.test.js26
-rw-r--r--plugin/test/indentation.test.js10
6 files changed, 75 insertions, 21 deletions
diff --git a/plugin/README.md b/plugin/README.md
index 48738dc..b0d6c01 100644
--- a/plugin/README.md
+++ b/plugin/README.md
@@ -20,7 +20,7 @@ Open a `.cps` file. The language mode should show **CIE Pseudocode**.
## Features
-- C++ style syntax colors that follow your dark theme.
+- C++ style syntax colors that follow your dark theme, including PP_DEFINE, PP_UNDEF, PP_IFDEF, PP_IFNDEF and PP_ENDIF. Preprocessor conditions do not add indentation.
- Automatic Tab indentation and outdent for block keywords.
- **Format Selection**: select code, then press **Cmd+K, Cmd+F** on macOS or **Ctrl+K, Ctrl+F** on Windows/Linux. Only indentation changes.
- Colored `()` and `[]` pairs; unmatched brackets turn red. Quotes and comments are ignored.
diff --git a/plugin/ThirdPartyNotices.md b/plugin/ThirdPartyNotices.md
index e24f2c8..b195ffa 100644
--- a/plugin/ThirdPartyNotices.md
+++ b/plugin/ThirdPartyNotices.md
@@ -5,9 +5,9 @@ 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. 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. Literal
-escapes reuse `constant.character.escape`; the adjacent C string suffix borrows
+reuse C++ scopes. OVERLOAD borrows a declaration modifier, PP_* directives borrow
+C++ preprocessor keyword and macro-name scopes, and INCLUDE_OBJ borrows #include;
+ellipses use the C++ variadic scope. Literal escapes reuse `constant.character.escape`; the adjacent C string suffix borrows
`keyword.other.suffix.literal.user-defined.string.cpp`. Custom types, template
parameters and angle delimiters use the corresponding C++ type and template
scopes; class-method receivers reuse `variable.language.this.cpp`.
diff --git a/plugin/examples/highlighting.cps b/plugin/examples/highlighting.cps
index 10d93d8..a7ec8c6 100644
--- a/plugin/examples/highlighting.cps
+++ b/plugin/examples/highlighting.cps
@@ -75,3 +75,13 @@ ENDCLASS
DECLARE Count : Counter
CALL Count.Add(Limit)
OUTPUT Count.Get()
+
+// Preprocessor conditions do not add indentation.
+PP_DEFINE Demo
+PP_IFDEF Demo
+OUTPUT "Enabled"
+PP_IFNDEF OtherDemo
+OUTPUT "Nested condition"
+PP_ENDIF
+PP_ENDIF
+PP_UNDEF Demo
diff --git a/plugin/syntaxes/cie-pseudocode.tmLanguage.json b/plugin/syntaxes/cie-pseudocode.tmLanguage.json
index 16a4ac4..14ef33c 100644
--- a/plugin/syntaxes/cie-pseudocode.tmLanguage.json
+++ b/plugin/syntaxes/cie-pseudocode.tmLanguage.json
@@ -418,6 +418,9 @@
"include": "#strings"
},
{
+ "include": "#preprocessor"
+ },
+ {
"include": "#class"
},
{
@@ -442,17 +445,6 @@
"include": "#return_type"
},
{
- "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"
},
@@ -599,6 +591,34 @@
"include": "#type_tokens"
}
]
+ },
+ "preprocessor": {
+ "begin": "^\\s*(?:(PP_DEFINE)|(PP_UNDEF)|(PP_IFDEF|PP_IFNDEF)|(PP_ENDIF))\\b",
+ "end": "$",
+ "beginCaptures": {
+ "1": {
+ "name": "keyword.control.directive.define.cpp"
+ },
+ "2": {
+ "name": "keyword.control.directive.undef.cpp"
+ },
+ "3": {
+ "name": "keyword.control.directive.conditional.cpp"
+ },
+ "4": {
+ "name": "keyword.control.directive.conditional.cpp"
+ }
+ },
+ "name": "meta.preprocessor.cie-pseudocode",
+ "patterns": [
+ {
+ "include": "#line_comment"
+ },
+ {
+ "match": "[A-Za-z_][A-Za-z0-9_]*",
+ "name": "entity.name.function.preprocessor.cpp"
+ }
+ ]
}
},
"injections": {
diff --git a/plugin/test/highlighting.test.js b/plugin/test/highlighting.test.js
index c8ee3f7..1edac7b 100644
--- a/plugin/test/highlighting.test.js
+++ b/plugin/test/highlighting.test.js
@@ -155,13 +155,27 @@ test('supported keywords reuse C++ scopes without matching identifiers or quoted
}
});
-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);
+test('preprocessor directives reuse C++ scopes and shield switch names from ordinary keywords', () => {
+ for (const [word, scope] of [
+ ['PP_DEFINE', 'keyword.control.directive.define.cpp'],
+ ['PP_UNDEF', 'keyword.control.directive.undef.cpp'],
+ ['PP_IFDEF', 'keyword.control.directive.conditional.cpp'],
+ ['PP_IFNDEF', 'keyword.control.directive.conditional.cpp'],
+ ['PP_ENDIF', 'keyword.control.directive.conditional.cpp']
+ ]) {
+ assert.ok(scopesAt(`\t${word} __LIB // comment`, word).includes(scope));
+ for (const text of [word.toLowerCase(), `${word}Value`, `_${word}`, `X ${word}`, `// ${word}`, `OUTPUT "${word}"`]) {
+ assert.ok(!scopesAt(text, word.toLowerCase() === text ? text : word).includes(scope), text);
+ }
}
+ for (const word of ['__LIB', 'FUNCTION', 'INTEGER']) {
+ assert.ok(scopesAt(`PP_DEFINE ${word}`, word).includes('entity.name.function.preprocessor.cpp'));
+ }
+ assert.ok(scopesAt('PP_IFDEF Flag // PP_ENDIF', 'PP_ENDIF').some(s => s.startsWith('comment.')));
+ assert.ok(!scopesAt('#LIB', 'LIB').some(s => s.startsWith('keyword.control.directive.')));
+});
+
+test('ellipses use the C++ variadic scope', () => {
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);
}
diff --git a/plugin/test/indentation.test.js b/plugin/test/indentation.test.js
index 9140ed3..e71540f 100644
--- a/plugin/test/indentation.test.js
+++ b/plugin/test/indentation.test.js
@@ -82,3 +82,13 @@ test('escaped quotes keep block keywords inside literals masked', () => {
'THEN', String.raw`OUTPUT "escaped \" ENDIF //"`, 'ENDIF'
]), [0, 0, 1, 0]);
});
+
+test('preprocessor conditions preserve ordinary block depth without adding indentation', () => {
+ const lines = [
+ 'PP_DEFINE Flag', 'PP_IFDEF Flag', 'PROCEDURE Demo()', 'PP_IFNDEF Other',
+ 'IF Ready THEN', 'OUTPUT 1', 'ENDIF', 'PP_ENDIF', 'PP_UNDEF Flag',
+ 'ENDPROCEDURE', 'PP_ENDIF'
+ ];
+ assert.deepEqual(lineDepths(lines), [0, 0, 0, 1, 1, 2, 1, 1, 1, 0, 0]);
+ assert.deepEqual(indentationEdits(['PP_IFDEF Flag', 'OUTPUT 1', 'PP_ENDIF'], 0, 2), []);
+});