diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ec2359..83bff40e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +- Syntax highlighting for `Feature`, `Rule` `Scenario`, and `Scenario Outline` keywords ([#249](https://github.com/cucumber/language-service/pull/249)) + ## [1.7.0] - 2025-05-18 ### Added - Syntax highlighting for comments (`#`) ([#245](https://github.com/cucumber/language-service/pull/245)) diff --git a/src/service/getGherkinSemanticTokens.ts b/src/service/getGherkinSemanticTokens.ts index bd3baaa3..8e4463d9 100644 --- a/src/service/getGherkinSemanticTokens.ts +++ b/src/service/getGherkinSemanticTokens.ts @@ -8,7 +8,10 @@ import { parseGherkinDocument } from '../gherkin/parseGherkinDocument.js' // The default vs theme can only highlight certain tokens. See the list of those tokens in // https://microsoft.github.io/monaco-editor/monarch.html export const semanticTokenTypes: SemanticTokenTypes[] = [ - SemanticTokenTypes.keyword, // Feature, Scenario, Given etc + SemanticTokenTypes.keyword, // Background, Given, When, Then, etc. + SemanticTokenTypes.namespace, // Feature keyword + SemanticTokenTypes.class, // Rule keyword + SemanticTokenTypes.function, // Scenario keyword SemanticTokenTypes.parameter, // step parameters SemanticTokenTypes.string, // DocString content and ``` delimiter, table cells (except example table header rows) SemanticTokenTypes.type, // @tags and DocString ```type @@ -77,10 +80,10 @@ export function getGherkinSemanticTokens( return makeLocationToken(tag.location, tag.name, SemanticTokenTypes.type, arr) }, feature(feature, arr) { - return makeLocationToken(feature.location, feature.keyword, SemanticTokenTypes.keyword, arr) + return makeLocationToken(feature.location, feature.keyword, SemanticTokenTypes.namespace, arr) }, rule(rule, arr) { - return makeLocationToken(rule.location, rule.keyword, SemanticTokenTypes.keyword, arr) + return makeLocationToken(rule.location, rule.keyword, SemanticTokenTypes.class, arr) }, background(background, arr) { return makeLocationToken( @@ -92,7 +95,12 @@ export function getGherkinSemanticTokens( }, scenario(scenario, arr) { inScenarioOutline = (scenario.examples || []).length > 0 - return makeLocationToken(scenario.location, scenario.keyword, SemanticTokenTypes.keyword, arr) + return makeLocationToken( + scenario.location, + scenario.keyword, + SemanticTokenTypes.function, + arr + ) }, examples(examples, arr) { inExamples = true diff --git a/test/service/getGherkinSemanticTokens.test.ts b/test/service/getGherkinSemanticTokens.test.ts index 2b982027..3777f0e9 100644 --- a/test/service/getGherkinSemanticTokens.test.ts +++ b/test/service/getGherkinSemanticTokens.test.ts @@ -21,26 +21,27 @@ Feature: a This is a description and so is this - Background: - Given a repeating step + Rule: + Background: + Given a repeating step - Scenario: b - Given I have 42 cukes in my belly - """sometype - hello - world - """ - And a table - | a | bbb | - | cc | dd | - And I should be on the map + Scenario: b + Given I have 42 cukes in my belly + """sometype + hello + world + """ + And a table + | a | bbb | + | cc | dd | + And I should be on the map - Scenario Outline: c - Given a and + Scenario Outline: c + Given a and - Examples: - | foo | bar | - | a | b | + Examples: + | foo | bar | + | a | b | ` const parameterTypeRegistry = new ParameterTypeRegistry() const cucumberExpression = new CucumberExpression( @@ -61,10 +62,11 @@ Feature: a ['# some comment', SemanticTokenTypes.comment], ['@foo', SemanticTokenTypes.type], ['@bar', SemanticTokenTypes.type], - ['Feature', SemanticTokenTypes.keyword], + ['Feature', SemanticTokenTypes.namespace], + ['Rule', SemanticTokenTypes.class], ['Background', SemanticTokenTypes.keyword], ['Given ', SemanticTokenTypes.keyword], - ['Scenario', SemanticTokenTypes.keyword], + ['Scenario', SemanticTokenTypes.function], ['Given ', SemanticTokenTypes.keyword], ['42', SemanticTokenTypes.parameter], ['belly', SemanticTokenTypes.parameter], @@ -79,7 +81,7 @@ Feature: a ['cc', SemanticTokenTypes.string], ['dd', SemanticTokenTypes.string], ['And ', SemanticTokenTypes.keyword], - ['Scenario Outline', SemanticTokenTypes.keyword], + ['Scenario Outline', SemanticTokenTypes.function], ['Given ', SemanticTokenTypes.keyword], ['', SemanticTokenTypes.variable], ['', SemanticTokenTypes.variable], @@ -96,18 +98,20 @@ Feature: a // Note that 'When' step uses two spaces, to align the text with 'Given' const gherkinSource = ` Feature: making drinks - Scenario Outline: - Given a - When I make - Examples: - | ingredient | drink | - | apple | apple juice | + Rule: + Scenario Outline: + Given a + When I make + Examples: + | ingredient | drink | + | apple | apple juice | ` const semanticTokens = getGherkinSemanticTokens(gherkinSource, []) const actual = tokenize(gherkinSource, semanticTokens.data) const expected: TokenWithType[] = [ - ['Feature', SemanticTokenTypes.keyword], - ['Scenario Outline', SemanticTokenTypes.keyword], + ['Feature', SemanticTokenTypes.namespace], + ['Rule', SemanticTokenTypes.class], + ['Scenario Outline', SemanticTokenTypes.function], ['Given ', SemanticTokenTypes.keyword], ['', SemanticTokenTypes.variable], ['When ', SemanticTokenTypes.keyword],