diff --git a/CHANGELOG.md b/CHANGELOG.md index 5edf407..58dd571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ All notable changes to the **Bison/Flex Language Support** extension will be documented in this file. -## [1.5.2] - 2026-04-03 +## [1.5.2] - 2026-04-05 + +### Added + +- **Flex — Code Lens for abbreviations** (#39): abbreviation definitions in the definitions section now show a clickable "N references" Code Lens, consistent with start conditions and Bison rules. Clicking opens the References panel with all `{ABBR}` usages in the rules section. ### Fixed diff --git a/server/src/providers/codeLens.ts b/server/src/providers/codeLens.ts index b1b2ed8..f6601b4 100644 --- a/server/src/providers/codeLens.ts +++ b/server/src/providers/codeLens.ts @@ -3,8 +3,9 @@ import { DocumentModel, BisonDocument, FlexDocument, isBisonDocument } from '../ /** * Code Lenses: - * Bison rules → "N references" + "⬤ entry point" (start symbol only) - * Flex SC decls → "N references" + * Bison rules → "N references" + "⬤ entry point" (start symbol only) + * Flex SC decls → "N references" + * Flex abbreviations → "N references" * * The "N references" lens triggers `bisonFlex.showReferences` (registered * client-side) which calls `editor.action.showReferences` with pre-built args. @@ -71,5 +72,21 @@ function getFlexCodeLenses(doc: FlexDocument, uri: string): CodeLens[] { }); } + for (const [name, abbr] of doc.abbreviations) { + const line = abbr.location.start.line; + const lensRange = Range.create(line, 0, line, 0); + const refCount = doc.abbreviationRefs.get(name)?.length ?? 0; + + lenses.push({ + range: lensRange, + command: Command.create( + `$(references) ${refCount} reference${refCount !== 1 ? 's' : ''}`, + 'bisonFlex.showReferences', + uri, + { line, character: abbr.location.start.character }, + ), + }); + } + return lenses; } diff --git a/tests/test-diagnostic-codes.ts b/tests/test-diagnostic-codes.ts index 7830645..111cdfc 100644 --- a/tests/test-diagnostic-codes.ts +++ b/tests/test-diagnostic-codes.ts @@ -622,6 +622,35 @@ console.log('\n=== TEST: isWordPattern — complex patterns do not shadow keywor assert(unreachable.length >= 1, 'isWordPattern: simple [A-Z_]+ still shadows keyword "IF" → flex/unreachable-rule expected'); } +// ───────────────────────────────────────────────────────────────────────────── +// Issue #39 — Code Lens for abbreviations +// ───────────────────────────────────────────────────────────────────────────── +console.log('\n=== TEST: Issue #39 — Code Lens for abbreviations ==='); + +{ + const { getCodeLenses } = require('../server/src/providers/codeLens'); + const src = [ + '%option noyywrap', + 'DIGIT [0-9]+', + 'WORD [a-z]+', + '%%', + '{DIGIT} { return 1; }', + '{DIGIT} { return 2; }', + '%%', + ].join('\n'); + const doc = require('../server/src/parser/flexParser').parseFlexDocument(src); + const lenses = getCodeLenses(doc, 'file:///test.l'); + + // DIGIT is on line 1, WORD on line 2 + const digitLens = lenses.find((l: any) => l.range.start.line === 1); + const wordLens = lenses.find((l: any) => l.range.start.line === 2); + + assert(!!digitLens, '#39: Code Lens produced for DIGIT abbreviation'); + assert(digitLens?.command?.title?.includes('2'), '#39: DIGIT lens shows 2 references (used twice in rules)'); + assert(!!wordLens, '#39: Code Lens produced for WORD abbreviation'); + assert(wordLens?.command?.title?.includes('0'), '#39: WORD lens shows 0 references (unused)'); +} + // ───────────────────────────────────────────────────────────────────────────── // Bison audit checks // ─────────────────────────────────────────────────────────────────────────────