Skip to content

Add metadata-backed XAML typo Quick Fixes - #376

Merged
Jaylyn Barbee (Jaylyn-Barbee) merged 13 commits into
mainfrom
chiaramooney-xaml-typo-quick-fixes
Nov 12, 2026
Merged

Jaylyn Barbee (Jaylyn-Barbee) merged 13 commits into
mainfrom
chiaramooney-xaml-typo-quick-fixes

Conversation

@chiaramooney

@chiaramooney Chiara Mooney (chiaramooney) commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Description

Improves the non-AI XAML Quick Fixes for misspelled property names and values. Name and value fixes stay separate, reusing the existing spelling-fix path:

  • Related names: when no typo match exists, an unknown property name can fall back to up to three related names, closest first. Words shorter than 3 letters (such as Is) never count as shared. They are completions of a partially typed name (Visib -> Visibility), or else the names sharing the most whole words with it (FrozenColumnCount -> FrozenEdge, BackgroundColor -> Background). Related names are never the preferred (Auto Fix) action.
  • Typos: swapped letters count as one typo (Txet -> Text).
  • Booleans: misspelled Boolean values suggest True/False (Ture -> True) instead of always replacing with False.

Usage Example

<!-- input -->
<tabular:TableViewTemplateColumn FrozenEdgeCount="1" />

<!-- quick fix: Change 'FrozenEdgeCount' to 'FrozenEdge' -->
<tabular:TableViewTemplateColumn FrozenEdge="1" />

Related Issue

N/A

Type of Change

  • ✨ New feature
  • 📝 Documentation
  • 🧪 Test update

Checklist

  • New tests added for new functionality (if applicable)
  • Ran .\scripts\build-vsce.ps1 locally
  • Tested locally on Windows (if applicable)
  • README.md updated (if applicable)

Screenshots / Demo

N/A

Additional Notes

Validation run on the current head:

  • dotnet test server\test\WinUiXaml.LanguageServer.Tests (full language-server suite): passed (1036/1036) after rebasing onto main.
  • npm run test:xaml-smoke: passed, including real-SDK cases Gird, Txet, Ture, Strech, MaxHieght (preferred typo fixes), VisibilityCount, Visib, ForegroundColor, and BackgroundColor (unpreferred related names).
  • .\scripts\build-vsce.ps1 -Package: passed (72.5 MB VSIX with the Native AOT server for win-x64 and win-arm64).

AI Description

This section is auto-generated by AI when the PR is opened or updated. To opt out, delete this entire section including the marker comments.

@github-actions

github-actions Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

⏳ Build in progress — the VSIX size below is from a previous commit and will update when the current build finishes.

VSIX Build

Artifact Baseline Current Delta
VS Code Extension (VSIX) 72.44 MB 72.46 MB 📈 +26.8 KB (+0.04%)

Updated 2026-11-12 21:03:10 UTC · commit 70535d3 · workflow run

@chiaramooney
Chiara Mooney (chiaramooney) marked this pull request as ready for review November 12, 2026 15:21
@Jaylyn-Barbee

Copy link
Copy Markdown
Contributor

PR review (automated, scope: 10 files, +317/-12)

No critical or high findings. Spelling-fix path, Related wire flag (typed and JsonElement reads), preferred-action suppression, and swap-aware Distance (early-bail pruning stays valid for the transposition term) check out.

Medium

  • XamlCodeActions.cs (InvalidAttributeValueCode case): the mechanical default-value fix is now skipped whenever any suggestion exists. For booleans that is intended (Ture -> True). Please confirm the same skip is acceptable for enum-typed values where a weak Levenshtein match previously fell through to the default-value fix; a test for a non-boolean enum with a near-miss value would pin this.

Low

  • XamlSuggestions.RelatedNames: Words() and Distinct() run over every candidate for each unknown attribute on each validation pass. Fine for typical types, but worth a quick check on types with very large attribute sets (e.g. FrameworkElement derivatives with many attached names).
  • RelatedNames completions bypass the 3-letter word rule (only target.Length >= 3), so short prefixes like Wid/Hei produce completions; this looks intended, a test documenting it would help.
  • Tests: no negative test showing a Related suggestion is never IsPreferred when the diagnostic goes through the real validator (only the wire-shape test covers it for the BackgroundColor case).

Docs: README Code actions row updated. Packaging/security: no impact found (no new inputs, no manifest/pipeline changes).

Add direct Quick Fix suggestions for misspelled XAML properties and invalid values, including combined replacements such as FrozenEdgeCount=1 to FrozenEdge=Leading. Extend coverage with focused unit tests and smoke scenarios, and keep README IntelliSense docs concise.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A value containing < means the closing quote belongs to later markup, so only the name-span rename is offered. Adds a regression test for a missing quote before another element.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Owner-qualified assignments to the same property now block duplicate replacements, while attached properties from other owners no longer suppress valid renames. Invalid-value spelling fixes re-check the current member so a stale diagnostic cannot rewrite a renamed property.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Detect a missing closing quote by the character after the value, so swallowed attributes are never rewritten and the name-only rename survives an unterminated value. Offer one rename per tied property name, named choices for unnamed numbers on non-flags enums, and unpreferred True/False for invalid Booleans. Share one attribute value-type resolver between the validator and quick fixes, which also gives attached properties a default-literal fix, and trim padded enum values before suggesting. Restore the full code-actions list in the README.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Share one swallowed-value check across rename and invalid-value fixes, and treat a value ending in = as swallowed. Star the closest property name whenever it is strictly closer than the next match, and stop treating 2-letter swaps as one typo. Invalid-value guesses (default numbers, Booleans, small enum choices) are no longer preferred, and misspelled Boolean names now get the plain rename.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the per-character swallowed-quote checks with one positive rule: a value is only rewritten when it is closed, single-line, and free of quote or markup characters. Decide the star once from the unfiltered ranking, and keep a close name as a plain rename unless exactly one value is certain. Restore main's default-literal fix for correctly named properties, keeping only the shared type resolver and the value-shape guard.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reuse main's spelling path for names and values instead of combined name+value edits. Unknown control and property names fall back to a single related name (unique partial-name completion or one whole word added or removed), offered as an unpreferred fix. Drop the stale-diagnostic checks and guarded edits, skip already-set properties, and suggest True/False for Boolean values.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Hiding an already-set property promoted the next match to the preferred fix, so Auto Fix could silently rename MaxHieght to MinHeight. Suggesting the closest name lets the duplicate-property diagnostic surface the conflict instead.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Offer the one candidate sharing the most whole PascalCase words with an unknown name (at least one, no ties) instead of requiring exactly one word added or removed. This maps DataGrid-style names such as FrozenColumnCount to FrozenEdge on TableView columns while staying unpreferred.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Instead of offering nothing when several names tie, list up to three related names closest first: completions of a partially typed name, else the names sharing the most whole words, preferring fewer unrelated words. None are preferred.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Unknown control names keep main's typo and import fixes, since matching words across every type in a namespace surfaced unrelated types. Words under three letters such as Is no longer count as shared, so IsDefault-style names stop matching every IsX property.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@chiaramooney
Chiara Mooney (chiaramooney) force-pushed the chiaramooney-xaml-typo-quick-fixes branch from d2620f5 to 70535d3 Compare November 12, 2026 20:02
@Jaylyn-Barbee

Copy link
Copy Markdown
Contributor

PR review #2 (head 70535d3, independent model: GPT-6.1 Sol)

No critical or high findings.

Medium

  • XamlSuggestions.cs:159-163 with XamlValidator.Elements.cs:327-340: transposition matching now accepts swallowed markup. For a resolved Button, Visibility="Visbile/> yields the suggestion Visible (distance 3, previously 4). The parser includes /> in the unterminated value, so the preferred spelling action replaces the whole span, deleting the tag terminator without restoring the quote. Suggest suppressing value replacements for unterminated or markup-swallowing spans, and adding malformed-quote regression tests.

No other significant security, performance, or docs findings. Builds and tests were not run in this review.

An unterminated value such as Visibility="Visbile/> pulls the tag terminator into the value, so a spelling or default-value fix would delete it. Offer value replacements only for closed, single-line literals without quote or markup characters.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@chiaramooney

Copy link
Copy Markdown
Collaborator Author

🤖 AI-assisted reply, verify before acting.

Thanks Jaylyn Barbee (@Jaylyn-Barbee)! Responses to both reviews:

Swallowed markup (review #2, medium): fixed in d7e9b1d. Reproduced: Visibility="Visbile/> at end of file offered a preferred Change 'Visbile/>' to 'Visible' that deleted the />. Invalid values now get spelling suggestions, and the "Replace with default" fix, only when the value is a closed, single-line literal with no quote or markup characters. The new UnterminatedValueSwallowingMarkup_OffersNoValueReplacement test covers Visbile/> (enum) and Ture/> (Boolean); both failed before the fix.

Default-value fix skipped for enums (review #1, medium): no behavior change for enums. GetDefaultLiteral returns null for enum types, so main never offered a default-value fix for an enum value. Skipping it when suggestions exist only affects Booleans, where Ture -> True is the intended result.

Low items, not changing:

  • RelatedNames cost: it runs only for an unknown property name with no typo match, over that element's property names, so it's linear in a few hundred names.
  • Completions with short prefixes (Wid, Hei) are intended (3-character minimum); Font and Visib in XamlSuggestionsTests document it.
  • RelatedPropertyName_IsAnUnpreferredRenameThatKeepsTheValue already runs the real validator and asserts the related fix is not preferred.

@Jaylyn-Barbee

Copy link
Copy Markdown
Contributor

PR review #3 (head d7e9b1d, independent model: Claude Opus 5.5)

No critical, high, or medium findings. The latest commit fully fixes the earlier swallowed-markup finding: unterminated values (run to EOF) are rejected by the closing-quote check, and values closed by a later quote are rejected via NonLiteralChars (>, =, <, newline, other quote). Both the suggestion data (XamlValidator.Elements.cs) and the default-value fix (XamlCodeActions.cs) are guarded. The swap-aware Distance early-exit remains correct.

Low

  • Test coverage: UnterminatedValueSwallowingMarkup_OffersNoValueReplacement only uses inputs that run to end of file, so the IndexOfAny(NonLiteralChars) branch is not exercised. Add a case closed by a later quote, e.g. Visibility="Visbile/> followed by <Grid Tag="x"/>, or IsEnabled="Ture Tag="x"/>.
  • Informational, pre-existing and out of scope: the same EOF /> deletion can occur for Setter attached-property members (XamlValidator.Elements.cs ~643) and x:Bind Mode (XamlValidator.Bindings.cs ~244). Reusing IsClosedLiteral there would harden them.

Builds and tests were not run in this review.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Jaylyn-Barbee
Jaylyn Barbee (Jaylyn-Barbee) merged commit d5e5c97 into main Nov 12, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants