Add MenuArrows rule to flag incorrect menu navigation separators#137
Conversation
Flags the use of > or => as menu separators instead of the correct → character, as defined in the style guide (https://www.elastic.co/docs/contribute-docs/style-guide/ui-writing). Made-with: Cursor
Vale Linting ResultsSummary: 10 warnings, 10 suggestions found
|
| File | Line | Rule | Message |
|---|---|---|---|
| .github/test-fixtures/sample-violations.md | 7 | Elastic.Articles | Use 'an FAQ' instead of 'a FAQ'. The article depends on pronunciation, not spelling. |
| .github/test-fixtures/sample-violations.md | 7 | Elastic.Articles | Use 'an HTML' instead of 'a HTML'. The article depends on pronunciation, not spelling. |
| .github/test-fixtures/sample-violations.md | 7 | Elastic.Articles | Use 'an SQL' instead of 'a SQL'. The article depends on pronunciation, not spelling. |
| .github/test-fixtures/sample-violations.md | 11 | Elastic.BritishSpellings | Use American English spelling 'optimize' instead of British English 'optimise'. |
| .github/test-fixtures/sample-violations.md | 11 | Elastic.BritishSpellings | Use American English spelling 'customize' instead of British English 'customise'. |
| .github/test-fixtures/sample-violations.md | 11 | Elastic.BritishSpellings | Use American English spelling 'behavior' instead of British English 'behaviour'. |
| .github/test-fixtures/sample-violations.md | 27 | Elastic.DontUse | Don't use 'just'. |
| .github/test-fixtures/sample-violations.md | 27 | Elastic.DontUse | Don't use 'please'. |
| .github/test-fixtures/sample-violations.md | 27 | Elastic.DontUse | Don't use 'aka'. |
| .github/test-fixtures/sample-violations.md | 35 | Elastic.Articles | Use 'an HTML' instead of 'a HTML'. The article depends on pronunciation, not spelling. |
💡 Suggestions (10)
| File | Line | Rule | Message |
|---|---|---|---|
| .github/test-fixtures/sample-violations.md | 15 | Elastic.WordChoice | Consider using 'efficiently' instead of 'Simply', unless the term is in the UI. |
| .github/test-fixtures/sample-violations.md | 15 | Elastic.WordChoice | Consider using 'allowlist' instead of 'whitelist', unless the term is in the UI. |
| .github/test-fixtures/sample-violations.md | 15 | Elastic.WordChoice | Consider using 'blocklist' instead of 'blacklist', unless the term is in the UI. |
| .github/test-fixtures/sample-violations.md | 15 | Elastic.WordChoice | Consider using 'efficient' instead of 'easy', unless the term is in the UI. |
| .github/test-fixtures/sample-violations.md | 19 | Elastic.OxfordComma | Use the Oxford comma in 'reading, writing and executing.'. |
| .github/test-fixtures/sample-violations.md | 23 | Elastic.Wordiness | Consider using 'to' instead of 'In order to'. |
| .github/test-fixtures/sample-violations.md | 23 | Elastic.Wordiness | Consider using 'because' instead of 'due to the fact that'. |
| .github/test-fixtures/sample-violations.md | 23 | Elastic.Wordiness | Consider using 'many' instead of 'a large number of'. |
| .github/test-fixtures/sample-violations.md | 31 | Elastic.Exclamation | Use exclamation points sparingly. Consider removing the exclamation point. |
| .github/test-fixtures/sample-violations.md | 31 | Elastic.Exclamation | Use exclamation points sparingly. Consider removing the exclamation point. |
The Vale linter checks documentation changes against the Elastic Docs style guide.
To use Vale locally or report issues, refer to Elastic style guide for Vale.
theletterf
left a comment
There was a problem hiding this comment.
Thanks!
I would suggest going for a substitution extension point, so that editors can do quick replacements of what is a hard to type character like the arrow:
extends: substitution
message: "Use '%s' to separate menu items, not '%s'. Example: Select Manage index → Add lifecycle policy."
link: 'https://www.elastic.co/docs/contribute-docs/style-guide/ui-writing'
level: suggestion
nonword: true
action:
name: replace
swap:
"(=>)": "→"
'[A-Za-z]{3,}\s(>)\s[A-Za-z]{3,}': "→"
WDYT?
Made-with: Cursor
Made-with: Cursor
|
Thanks @theletterf — you were right. Vale does support backreferences in substitution replacements. Switched to |
Made-with: Cursor
|
Reverting the substitution approach after further testing. The fix works correctly for plain text (Vale produces a precise column span), but for bold markup like |
Add quick-fix actions for menu separator warnings and a raw-scope companion rule for bold UI paths while keeping local Vale config aligned with CI. Made-with: GPT-5.5 Made-with: Cursor
|
Thanks Florent. I pushed an update that keeps the main rule as I also added a companion Local testing with
The rule can still flag prose comparisons such as |
Resolve the Vale config conflict by keeping the branch's CI-aligned scope ignores while preserving main's vocabulary and spelling settings. Made-with: GPT-5.5 Made-with: Cursor
Summary
Adds a new
MenuArrowsrule that flags incorrect menu navigation separators and suggests the correct→character, as specified in the Writing about the UI style guide (Menus component row: "Use arrows (→) to tell the user where to find the command").What the rule catches
Two tokens cover the two wrong patterns writers use:
Token 1:
=>Catches
=>used as a menu separator in all cases. This is an unambiguous pattern —=>in prose documentation almost exclusively appears as a misused menu separator, and Vale already excludes code blocks and inline code spans automatically.Token 2:
[A-Za-z]{3,}\s>\s[A-Za-z]{3,}Catches
>used as a menu separator. The pattern requires at least 3 letters immediately on both sides of>. The design decisions:x > yorab > cd, which are the main source of false positives for a bare>pattern. Real UI menu labels are always full words (e.g.File,New,Management).{3,}quantifier stops at the first non-letter, socount > 10is skipped because10contains no letters, andx > 0is skipped for the same reason.`...`) before running existence rules, so`a > b`in code is never flagged.**before matching, so**File** > **New**is seen asFile > Newand correctly caught.Known limitation
Vale deduplicates matches within the same paragraph when two consecutive lines share the same leading bold term. For example, if a paragraph contains both
**Settings** > **Advanced**and**Settings** > **Basic**without a blank line between them, only the first line is flagged. This is a Vale internals behaviour that cannot be worked around at the regex level.Made with Cursor