Add eleven text container languages, highlighted but not formatted - #119
Merged
Conversation
The first step of docs/additional-language-plan.md. TextLanguageIds.All was serving as both the language inventory and the paste detection order, so the eleven new languages could not be added to one without joining the other. All is now the fifteen languages a text container can be set to, in selector order; DetectionOrder is the four that can read a snippet, unchanged. A manual-only identifier is skipped by NormalizeOrder rather than read as plain text, which would move plain text up an order it was never part of. Services carry CanDetect beside CanFormat, and detection is filtered before TryAccept. The eleven languages are selectable and persist, but nothing colors them yet. F6 opens their voting issue instead, through one shared check both format entry points pass before their CanFormat return, so invalid DAX is still a format that did nothing rather than a prompt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…initions The second step of docs/additional-language-plan.md. The spike settled the engine; this builds it. SyntaxHighlighter runs AvalonEdit's DocumentHighlighter over the whole document and flattens the nested sections into the ordered, nonoverlapping spans the colorizer and both exporters already read, so display, edit and export color a snippet the same way from one path. The definitions are Whiteboard's own rather than the ones AvalonEdit bundles, which predate C# raw strings, Java text blocks and modern keywords. A color name in them is a category, mapped to the palette DAX, SQL and KQL already share, so a board with two languages on it reads as one board. Two hazards are worth knowing about, and are commented where they bite: an apostrophe is a digit separator in C and C++, so a character literal has to be matched after the number rather than before it, and an angle bracket opens either a Visual Basic XML literal or a comparison, so the literal is recognized only where a value belongs. A source past 100 KB is left uncolored rather than scanned slowly, and a definition that throws loses its colors, not its text. The adapter needs WPF, so its tests need a host the framework-neutral Core harness cannot give them. SQLBI.Whiteboard.SmokeTests is that host; it is not published, so nothing test-only reaches the installer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The third step of docs/additional-language-plan.md, which finishes the eleven definitions. Nothing in the adapter changed except a rule set resolver, so that TypeScript can import JavaScript's rules rather than repeat them, and a shared color for a variable and for a hole in a string, which are the same thing to a reader. The stateful scanner the spike expected to need is not needed. A slash divides or opens a regular expression, and the token before it decides which: a lookbehind naming the operators, keywords and line starts that a value cannot follow settles every case in the corpus, and a literal anywhere else is left as operators and names rather than swallowing half a line as a string. What the languages needed instead: a nesting rule set for Rust block comments, so the run ends where Rust ends it; the attribute matched before the hash that would otherwise start a PHP comment; a heredoc closed by a line holding nothing but a name, since a span cannot match a delimiter back to its opening; and a number rule that no longer refuses a leading decimal point. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The fourth step of docs/additional-language-plan.md, which closes it. The regression matrix asks every language the same questions rather than a case each, over the snippet written for it: a snippet cut anywhere still colors, both line endings color the same characters, a surrogate pair moves every following span by its two units and changes none of them, and the spans and the text between them put the source back together unchanged. A source past the analyzer limit is left uncolored, and a language switch and a switch back each read the source afresh. The export path is covered where it matters: the runs a container leaves as spell its source exactly, carry its colors, keep the code font and the title, and reach a PowerPoint deck's slide XML and a PDF page. A published build was reviewed: the eleven definitions are inside the assembly, no loose file and no test assembly beside it. Writing the matrix found a hazard in the tests rather than the code: a raw string literal carries the line endings of the file it is written in, so a fixture in this repository is already CRLF and the line-ending case has to build both forms rather than assume one. README, the guide, the shortcuts, the FAQ and the comparison say what a reader now gets, and the version moves to 1.4.0 with its notes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Python, C, C++, Java, C#, JavaScript, TypeScript, Visual Basic .NET, R, Rust and PHP can
be chosen on a text container. They are highlighted on the board, in an edit, and in an
export, and they survive saving and reopening. They are not formatted and are never chosen
by paste; F6 on one of them opens that language's issue on GitHub, and the thumbs-up count
there is what decides which formatter is written next. The plan and the reasoning are in
docs/additional-language-plan.md.Selection and detection are now two lists.
TextLanguageIds.Allwas serving as boththe inventory and the paste detection order, so the eleven could not join one without
joining the other.
Allis now the fifteen languages a container can be set to, andDetectionOrderis the four that can read a snippet. A language chosen by hand is skippedby
NormalizeOrderrather than read as plain text, which would have moved plain text up anorder it was never part of; decision 28 in
docs/decisions.mdcarries that qualification.The archive format does not change, so a board saved with one of these opens in an older
release as plain text with its source intact.
The highlighting is lexical, from definitions we own. A spike over the pinned AvalonEdit
settled the engine:
DocumentHighlighterover the whole document, with nested sectionsflattened into the ordered, non-overlapping spans the colorizer and both exporters already
read, so display, edit and export colour a snippet from one path. The bundled definitions
were rejected — they predate C# raw strings, Java text blocks and JavaScript template
literals — and eleven of our own are embedded instead. A colour name in them is a category
mapped to the palette DAX, SQL and KQL already share, so two languages on one board read as
one board. A source past 100 KB is left uncoloured rather than coloured slowly, and a
definition that throws loses its colours, not its text.
The constructs that fought back are commented where they bite: an apostrophe is a digit
separator in C and C++, so a character literal is matched after the number; an angle bracket
opens either a Visual Basic XML literal or a comparison; a hash opens either a PHP comment
or an attribute; a slash divides or opens a regular expression, and only the token before it
says which. The stateful scanner the spike expected to need was not needed in the end.
Tests needed a second harness. The adapter runs on WPF, which the framework-neutral Core
harness cannot load, so
tests/SQLBI.Whiteboard.SmokeTestshosts what only the applicationcan answer. It asks every language the same questions rather than a case each: a snippet cut
anywhere still colours, both line endings colour the same characters, a surrogate pair moves
every following span by its two UTF-16 units and changes none of them, and the spans and the
text between them put the source back together unchanged. It also checks that an editable
export's runs spell their source exactly and reach a deck's slide XML. It is not published,
so the signing list and the installer are untouched.
Version moves to 1.4.0, and README, the guide, the shortcuts, the FAQ and the comparison say
what a reader now gets.
🤖 Generated with Claude Code