diff --git a/grammars/csharp.tmLanguage b/grammars/csharp.tmLanguage index 179c2bc..64df1f2 100644 --- a/grammars/csharp.tmLanguage +++ b/grammars/csharp.tmLanguage @@ -8620,6 +8620,10 @@ include #preprocessor-pragma-checksum + + include + #preprocessor-app-directive + preprocessor-define-or-undef @@ -8950,6 +8954,198 @@ + preprocessor-app-directive + + begin + \s*(:)\s* + beginCaptures + + 1 + + name + punctuation.separator.colon.cs + + + end + (?=$) + patterns + + + include + #preprocessor-app-directive-package + + + include + #preprocessor-app-directive-property + + + include + #preprocessor-app-directive-project + + + include + #preprocessor-app-directive-sdk + + + include + #preprocessor-app-directive-generic + + + + preprocessor-app-directive-package + + match + \b(package)\b\s*([_[:alpha:]][_.[:alnum:]]*)?(@)?(.*)?\s* + captures + + 1 + + name + keyword.preprocessor.package.cs + + 2 + + patterns + + + include + #preprocessor-app-directive-package-name + + + + 3 + + name + punctuation.separator.at.cs + + 4 + + name + string.unquoted.preprocessor.message.cs + + + + preprocessor-app-directive-property + + match + \b(property)\b\s*([_[:alpha:]][_[:alnum:]]*)?(=)?(.*)?\s* + captures + + 1 + + name + keyword.preprocessor.property.cs + + 2 + + name + entity.name.variable.preprocessor.symbol.cs + + 3 + + name + punctuation.separator.equals.cs + + 4 + + name + string.unquoted.preprocessor.message.cs + + + + preprocessor-app-directive-project + + match + \b(project)\b\s*(.*)?\s* + captures + + 1 + + name + keyword.preprocessor.project.cs + + 2 + + name + string.unquoted.preprocessor.message.cs + + + + preprocessor-app-directive-sdk + + match + \b(sdk)\b\s*([_[:alpha:]][_.[:alnum:]]*)?(@)?(.*)?\s* + captures + + 1 + + name + keyword.preprocessor.sdk.cs + + 2 + + patterns + + + include + #preprocessor-app-directive-package-name + + + + 3 + + name + punctuation.separator.at.cs + + 4 + + name + string.unquoted.preprocessor.message.cs + + + + preprocessor-app-directive-package-name + + patterns + + + match + (\.)([_[:alpha:]][_[:alnum:]]*) + captures + + 1 + + name + punctuation.dot.cs + + 2 + + name + entity.name.variable.preprocessor.symbol.cs + + + + + name + entity.name.variable.preprocessor.symbol.cs + match + [_[:alpha:]][_[:alnum:]]* + + + + preprocessor-app-directive-generic + + match + \b(.*)?\s* + captures + + 1 + + name + string.unquoted.preprocessor.message.cs + + + preprocessor-expression patterns diff --git a/grammars/csharp.tmLanguage.cson b/grammars/csharp.tmLanguage.cson index 0be8ac1..7b1884c 100644 --- a/grammars/csharp.tmLanguage.cson +++ b/grammars/csharp.tmLanguage.cson @@ -5201,6 +5201,9 @@ repository: { include: "#preprocessor-pragma-checksum" } + { + include: "#preprocessor-app-directive" + } ] "preprocessor-define-or-undef": match: "\\b(?:(define)|(undef))\\b\\s*\\b([_[:alpha:]][_[:alnum:]]*)\\b" @@ -5347,6 +5350,97 @@ repository: name: "string.quoted.double.cs" "5": name: "string.quoted.double.cs" + "preprocessor-app-directive": + begin: "\\s*(:)\\s*" + beginCaptures: + "1": + name: "punctuation.separator.colon.cs" + end: "(?=$)" + patterns: [ + { + include: "#preprocessor-app-directive-package" + } + { + include: "#preprocessor-app-directive-property" + } + { + include: "#preprocessor-app-directive-project" + } + { + include: "#preprocessor-app-directive-sdk" + } + { + include: "#preprocessor-app-directive-generic" + } + ] + "preprocessor-app-directive-package": + match: "\\b(package)\\b\\s*([_[:alpha:]][_.[:alnum:]]*)?(@)?(.*)?\\s*" + captures: + "1": + name: "keyword.preprocessor.package.cs" + "2": + patterns: [ + { + include: "#preprocessor-app-directive-package-name" + } + ] + "3": + name: "punctuation.separator.at.cs" + "4": + name: "string.unquoted.preprocessor.message.cs" + "preprocessor-app-directive-property": + match: "\\b(property)\\b\\s*([_[:alpha:]][_[:alnum:]]*)?(=)?(.*)?\\s*" + captures: + "1": + name: "keyword.preprocessor.property.cs" + "2": + name: "entity.name.variable.preprocessor.symbol.cs" + "3": + name: "punctuation.separator.equals.cs" + "4": + name: "string.unquoted.preprocessor.message.cs" + "preprocessor-app-directive-project": + match: "\\b(project)\\b\\s*(.*)?\\s*" + captures: + "1": + name: "keyword.preprocessor.project.cs" + "2": + name: "string.unquoted.preprocessor.message.cs" + "preprocessor-app-directive-sdk": + match: "\\b(sdk)\\b\\s*([_[:alpha:]][_.[:alnum:]]*)?(@)?(.*)?\\s*" + captures: + "1": + name: "keyword.preprocessor.sdk.cs" + "2": + patterns: [ + { + include: "#preprocessor-app-directive-package-name" + } + ] + "3": + name: "punctuation.separator.at.cs" + "4": + name: "string.unquoted.preprocessor.message.cs" + "preprocessor-app-directive-package-name": + patterns: [ + { + match: "(\\.)([_[:alpha:]][_[:alnum:]]*)" + captures: + "1": + name: "punctuation.dot.cs" + "2": + name: "entity.name.variable.preprocessor.symbol.cs" + } + { + name: "entity.name.variable.preprocessor.symbol.cs" + match: "[_[:alpha:]][_[:alnum:]]*" + } + ] + "preprocessor-app-directive-generic": + match: "\\b(.*)?\\s*" + captures: + "1": + name: "string.unquoted.preprocessor.message.cs" "preprocessor-expression": patterns: [ { diff --git a/src/csharp.tmLanguage.yml b/src/csharp.tmLanguage.yml index af7aab4..775c5aa 100644 --- a/src/csharp.tmLanguage.yml +++ b/src/csharp.tmLanguage.yml @@ -3388,6 +3388,7 @@ repository: - include: '#preprocessor-line' - include: '#preprocessor-pragma-warning' - include: '#preprocessor-pragma-checksum' + - include: '#preprocessor-app-directive' preprocessor-define-or-undef: match: \b(?:(define)|(undef))\b\s*\b([_[:alpha:]][_[:alnum:]]*)\b @@ -3490,6 +3491,66 @@ repository: '4': { name: string.quoted.double.cs } '5': { name: string.quoted.double.cs } + preprocessor-app-directive: + begin: \s*(:)\s* + beginCaptures: + '1': { name: punctuation.separator.colon.cs } + end: (?=$) + patterns: + - include: '#preprocessor-app-directive-package' + - include: '#preprocessor-app-directive-property' + - include: '#preprocessor-app-directive-project' + - include: '#preprocessor-app-directive-sdk' + - include: '#preprocessor-app-directive-generic' + + preprocessor-app-directive-package: + match: \b(package)\b\s*([_[:alpha:]][_.[:alnum:]]*)?(@)?(.*)?\s* + captures: + '1': { name: keyword.preprocessor.package.cs } + '2': + patterns: + - include: '#preprocessor-app-directive-package-name' + '3': { name: punctuation.separator.at.cs } + '4': { name: string.unquoted.preprocessor.message.cs } + + preprocessor-app-directive-property: + match: \b(property)\b\s*([_[:alpha:]][_[:alnum:]]*)?(=)?(.*)?\s* + captures: + '1': { name: keyword.preprocessor.property.cs } + '2': { name: entity.name.variable.preprocessor.symbol.cs } + '3': { name: punctuation.separator.equals.cs } + '4': { name: string.unquoted.preprocessor.message.cs } + + preprocessor-app-directive-project: + match: \b(project)\b\s*(.*)?\s* + captures: + '1': { name: keyword.preprocessor.project.cs } + '2': { name: string.unquoted.preprocessor.message.cs } + + preprocessor-app-directive-sdk: + match: \b(sdk)\b\s*([_[:alpha:]][_.[:alnum:]]*)?(@)?(.*)?\s* + captures: + '1': { name: keyword.preprocessor.sdk.cs } + '2': + patterns: + - include: '#preprocessor-app-directive-package-name' + '3': { name: punctuation.separator.at.cs } + '4': { name: string.unquoted.preprocessor.message.cs } + + preprocessor-app-directive-package-name: + patterns: + - match: (\.)([_[:alpha:]][_[:alnum:]]*) + captures: + '1': { name: punctuation.dot.cs } + '2': { name: entity.name.variable.preprocessor.symbol.cs } + - name: entity.name.variable.preprocessor.symbol.cs + match: '[_[:alpha:]][_[:alnum:]]*' + + preprocessor-app-directive-generic: + match: \b(.*)?\s* + captures: + '1': { name: string.unquoted.preprocessor.message.cs } + preprocessor-expression: patterns: - begin: \( diff --git a/test/preprocessor.tests.ts b/test/preprocessor.tests.ts index f6c6015..bf43e70 100644 --- a/test/preprocessor.tests.ts +++ b/test/preprocessor.tests.ts @@ -696,4 +696,169 @@ public ActionResult Register() ]); }); }); + + describe("AppDirectives", () => { + it("#:package", async () => { + const input = `#:package`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Package, + ]); + }); + + it("#:package with name", async () => { + const input = `#:package Foo.Goo`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Package, + Token.Identifier.PreprocessorSymbol("Foo"), + Token.Punctuation.Dot, + Token.Identifier.PreprocessorSymbol("Goo"), + ]); + }); + + it("#:package with name and version", async () => { + const input = `#:package Foo.Goo@1.0.0`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Package, + Token.Identifier.PreprocessorSymbol("Foo"), + Token.Punctuation.Dot, + Token.Identifier.PreprocessorSymbol("Goo"), + Token.Punctuation.At, + Token.PreprocessorMessage("1.0.0"), + ]); + }); + + it("#:project", async () => { + const input = `#:project`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Project, + ]); + }); + + it("#:project with path", async () => { + const input = `#:project ./path/to/project`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Project, + Token.PreprocessorMessage("./path/to/project"), + ]); + }); + + it("#:property", async () => { + const input = `#:property`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Property, + ]); + }); + + it("#:property with name", async () => { + const input = `#:property Foo_Property`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Property, + Token.Identifier.PreprocessorSymbol("Foo_Property"), + ]); + }); + + it("#:property with name and value", async () => { + const input = `#:property Foo_Property=Some Value`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Property, + Token.Identifier.PreprocessorSymbol("Foo_Property"), + Token.Punctuation.Equals, + Token.PreprocessorMessage("Some Value"), + ]); + }); + + it("#:sdk", async () => { + const input = `#:sdk`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Sdk, + ]); + }); + + it("#:sdk with name", async () => { + const input = `#:sdk Foo.Sdk`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Sdk, + Token.Identifier.PreprocessorSymbol("Foo"), + Token.Punctuation.Dot, + Token.Identifier.PreprocessorSymbol("Sdk"), + ]); + }); + + it("#:sdk with name and version", async () => { + const input = `#:sdk Foo.Sdk@1.0.0`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.Keyword.Preprocessor.Sdk, + Token.Identifier.PreprocessorSymbol("Foo"), + Token.Punctuation.Dot, + Token.Identifier.PreprocessorSymbol("Sdk"), + Token.Punctuation.At, + Token.PreprocessorMessage("1.0.0"), + ]); + }); + + it("#:", async () => { + const input = `#:`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + ]); + }); + + it("#: with generic message", async () => { + const input = `#:this is a generic directive`; + const tokens = await tokenize(input); + + tokens.should.deep.equal([ + Token.Punctuation.Hash, + Token.Punctuation.Colon, + Token.PreprocessorMessage("this is a generic directive"), + ]); + }); + }); }); \ No newline at end of file diff --git a/test/utils/tokenize.ts b/test/utils/tokenize.ts index 12beffd..e6cde77 100644 --- a/test/utils/tokenize.ts +++ b/test/utils/tokenize.ts @@ -376,13 +376,17 @@ export namespace Token { export const Hidden = createToken('hidden', 'keyword.preprocessor.hidden.cs'); export const If = createToken('if', 'keyword.preprocessor.if.cs'); export const Line = createToken('line', 'keyword.preprocessor.line.cs'); + export const Load = createToken('load', 'keyword.preprocessor.load.cs'); + export const Package = createToken('package', 'keyword.preprocessor.package.cs'); export const Pragma = createToken('pragma', 'keyword.preprocessor.pragma.cs'); + export const Property = createToken('property', 'keyword.preprocessor.property.cs'); + export const Project = createToken('project', 'keyword.preprocessor.project.cs'); + export const R = createToken('r', 'keyword.preprocessor.r.cs'); export const Region = createToken('region', 'keyword.preprocessor.region.cs'); export const Restore = createToken('restore', 'keyword.preprocessor.restore.cs'); + export const Sdk = createToken('sdk', 'keyword.preprocessor.sdk.cs'); export const Undef = createToken('undef', 'keyword.preprocessor.undef.cs'); export const Warning = createToken('warning', 'keyword.preprocessor.warning.cs'); - export const R = createToken('r', 'keyword.preprocessor.r.cs'); - export const Load = createToken('load', 'keyword.preprocessor.load.cs'); } export const AttributeSpecifier = (text: string) => createToken(text, 'keyword.other.attribute-specifier.cs'); @@ -591,12 +595,15 @@ export namespace Token { export const Accessor = createToken('.', 'punctuation.accessor.cs'); export const AccessorPointer = createToken('->', 'punctuation.accessor.pointer.cs'); export const Asterisk = createToken('*', 'punctuation.separator.asterisk.cs') + export const At = createToken('@', 'punctuation.separator.at.cs'); export const CloseBrace = createToken('}', 'punctuation.curlybrace.close.cs'); export const CloseBracket = createToken(']', 'punctuation.squarebracket.close.cs'); export const CloseParen = createToken(')', 'punctuation.parenthesis.close.cs'); export const Colon = createToken(':', 'punctuation.separator.colon.cs'); export const ColonColon = createToken('::', 'punctuation.separator.coloncolon.cs'); + export const Dot = createToken('.', 'punctuation.dot.cs'); export const Comma = createToken(',', 'punctuation.separator.comma.cs'); + export const Equals = createToken('=', 'punctuation.separator.equals.cs'); export const Hash = createToken('#', 'punctuation.separator.hash.cs') export const OpenBrace = createToken('{', 'punctuation.curlybrace.open.cs'); export const OpenBracket = createToken('[', 'punctuation.squarebracket.open.cs');