Repository navigation
🐛 fix: a code editor keeps its Tab in a dialog, and undo after a pasted carriage return restores the text - #733
Merged
edgarmesquita merged 15 commits intoOct 10, 2026
Conversation
…nd redo replays it The document breaks lines on CR, CRLF and LF alike, and an edit recorded the text as it was handed, which the history split on LF alone: pasting "x\ry" into "abc" after its first character gave "ax" and "ybc", and undo left "a" and "ybc". An edit now carries the text the document holds, and its range breaks lines where the document does, whoever made it. Closes #600.
The dialog's focus trap heard Tab in the capture phase, before the editor's input: with the editor last, Tab moved the focus to the first control and the line was never indented, and Shift+Tab did the same with the editor first. The trap now hears the key on its way back up and cycles only a Tab nothing consumed, the question Photon's host asks its code target before it moves the focus.
…very Tab, reported as #732
… of code-history and modal-focus
There was a problem hiding this comment.
🟡 Changes recommended
CodeHistory.Record ainda permite que uma edição digitada com CR seja agrupada com o próximo caractere.
1 open finding
What changed in this PR
Corrige o comportamento de Tab em editores dentro de diálogos e restaura corretamente o histórico após colagens com CR/CRLF.
Changes:
- Faz o focus trap respeitar controles que consumiram Tab.
- Normaliza quebras de linha registradas no histórico.
- Adiciona testes, especificações OpenSpec e registro no ledger.
| File | Description |
|---|---|
tests/eQuantic.UI.Native.Engine.Tests/CodeClipboardTests.cs |
Testa colagem, undo, redo e normalização. |
src/eQuantic.UI.Runtime/src/shared/components/CodeEditorController.ts |
Registra o texto normalizado. |
src/eQuantic.UI.Runtime/src/shared/components/CodeEdit.ts |
Calcula intervalos para CR, CRLF e LF. |
src/eQuantic.UI.Runtime/src/shared/code-editor.spec.ts |
Testa Tab nas extremidades do diálogo. |
src/eQuantic.UI.Runtime/src/dom/focus-trap.ts |
Move o tratamento de Tab para bubbling. |
src/eQuantic.UI.Runtime/src/dom/focus-trap.spec.ts |
Verifica Tab consumido pelo controle. |
src/eQuantic.UI.Code/Editing/CodeEditorController.cs |
Normaliza o texto registrado nos edits. |
src/eQuantic.UI.Code/Document/CodeEdit.cs |
Torna intervalos e inserções sensíveis a CR. |
openspec/specs/modal-focus/spec.md |
Especifica o compartilhamento de Tab. |
openspec/specs/code-history/spec.md |
Especifica normalização, undo e redo. |
openspec/changes/archive/2026-10-08-an-editor-keeps-tab-in-a-dialog-and-undoes-a-pasted-cr/tasks.md |
Registra as tarefas concluídas. |
openspec/changes/archive/2026-10-08-an-editor-keeps-tab-in-a-dialog-and-undoes-a-pasted-cr/specs/modal-focus/spec.md |
Arquiva o delta de foco modal. |
openspec/changes/archive/2026-10-08-an-editor-keeps-tab-in-a-dialog-and-undoes-a-pasted-cr/specs/code-history/spec.md |
Arquiva o delta de histórico. |
openspec/changes/archive/2026-10-08-an-editor-keeps-tab-in-a-dialog-and-undoes-a-pasted-cr/proposal.md |
Documenta escopo e impacto. |
openspec/changes/archive/2026-10-08-an-editor-keeps-tab-in-a-dialog-and-undoes-a-pasted-cr/design.md |
Documenta as decisões técnicas. |
docs/LEDGER.md |
Registra as correções de #598 e #600. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
…feed does Copilot's first round on #733. The history asked whether an edit broke a line by LF alone, so a typed lone CR, which a host recording its own edits may hand it, ran on into the character typed after it, and one undo took back both. The edit now says whether it breaks a line by the document's rule, and the history and IsSimpleInsert ask it.
There was a problem hiding this comment.
🟢 Approval recommended
As correções são consistentes entre engine e runtime e possuem cobertura direta dos casos regressivos.
0 open findings
1 resolved since last review
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
CodeEdit's twin conflicted where both sides had regenerated it, and is regenerated again from the merged C#. The ledger line moves to the end.
The code editor's spec conflicted where both sides added tests at its end: both are kept, and the dialog's tests now clean the page after each one, since the completion list's tests from #653 run after them and a layer left marked pulled their focus into itself. The ledger line moves to the end, and the twins regenerate unchanged.
No conflict. The ledger line moves to the end.
No conflict. The ledger line moves to the end, and the twins' pins hold.
No conflict. The ledger line moves to the end.
No conflict. The ledger line moves to the end, and the twins regenerate unchanged.
7 of 9 tasks
edgarmesquita
pushed a commit
that referenced
this pull request
Oct 10, 2026
Merging main left this pull request's entry above #733's, which landed before it. The list is in the order things land, so it moves to the end, unchanged.
edgarmesquita
added a commit
that referenced
this pull request
Oct 10, 2026
…lows .NET's chunks (#748) Closes #679 It is a sub-issue of #565 (the transpiler's fences hold on every path). ## What Every `StringBuilder` member a page reaches answers as .NET's does in the browser, or fails the build where it cannot cross: - **`AppendFormat` and `AppendJoin`** append what `string.Format` and `string.Join` write, through the same lowering, bound by the same parameters and under the same culture policy. - **`Capacity` is .NET's.** The runtime keeps the sizes of the chunks .NET allocates, so `Capacity` follows every edit: an append fills the last chunk and opens one as large as the text so far (up to 8,000) or as what is left, an insert or a longer replace makes room as `MakeRoom` does (in place in a small chunk with room, otherwise a chunk of at least 16, one per source chunk for a replace), a removal unlinks the chunks it empties, and a shorter `Length` keeps `min(Capacity, max(Length * 6 / 5, the last chunk))`. `MaxCapacity`, `EnsureCapacity`, the `Capacity` setter and the constructors that take a capacity, a maximum or a range answer and refuse as .NET's do, in .NET's order. Text that fits the last chunk goes in past `MaxCapacity`, as on .NET. - **The `Chars` indexer** is the twin's `item` and `setItem`, refused past the text as .NET refuses it. **`Length`** cuts the text or fills it with `\0`. **`Equals(StringBuilder)`** compares the text whatever the capacity, while `Equals(object)` stays identity. **`CopyTo`** copies into a `char[]`. - **What cannot cross is refused at the build**: a provider other than the current culture on `Append` and `AppendLine` with an interpolation (EQ2108), `GetChunks` and an overload over a span or a memory (EQ1004). A `params` span is the values written one by one, and crosses. - **A member that .NET makes of several appends makes them as .NET does.** An interpolated `Append($"…")` or `AppendLine($"…")` appends each part in turn, as .NET's interpolation handler does, so a hole that reads the builder sees the parts before it (`$"{b.Length}{b.Length}"` held "00" where .NET holds "01"), each part grows the chunks, a refusal keeps the parts before it, and a hole prints as a plain interpolation's does, where an enum reached the builder as its camelCase key. `AppendLine(value)` appends the newline after the value, `Append(StringBuilder)` checks the maximum before it copies, and a `Replace` past the maximum keeps the chunks it replaced first. - **A named argument is bound to its parameter**, each still evaluated in the order written: the twin takes C#'s parameters by position. - Every text the builder makes is built before its chunks change, and one longer than the browser's string can hold is .NET's `OutOfMemoryException`, not JavaScript's `RangeError`. For an app: `sb.AppendFormat("{0}-{1}", 1, 2)`, `sb[0]`, `sb.Capacity` and `sb.Length = 4` work in the browser, where they were TypeErrors, undefined or writes nobody read, and `sb.Append($"{sb.Length}…")` writes what .NET writes. Nothing an app writes changes, and the public surface does not move. ## Why The BCL audit graded every `StringBuilder` member `native`, which only said that a strategy answered. The runtime's builder had `append`, `appendLine`, `insert`, `remove`, `replace`, `clear`, `toString` and a `length` getter, and eqc wrote every other member under its own name, so a page reached TypeErrors and undefined values behind a green build (#679, found while fixing #650 in #667). ## OpenSpec `openspec/changes/archive/2026-10-07-a-builder-has-the-members-a-page-reaches`, archived into `openspec/specs/transpiler-bcl`. ## Proof - `StringBuilderConformanceTests`, both sides executed: 31 of the first 88 new cases failed on the base, the rest pinning members that answered by accident. `Capacity` matches .NET 10 on 41 measured sequences. - The review (`/code-review high`) found nine things, each measured on .NET 10 with `dotnet fsi` before it was fixed: the room an insert or a replace opens (`Capacity` 16 on .NET where the browser said 6), the ranged constructor's refusals, the constructor's order of refusals, `CopyTo`'s order, the refusal of an insert past `MaxCapacity` (`requiredLength`, and `OutOfMemoryException` for a counted insert), text that fits the last chunk past `MaxCapacity`, `OutOfMemoryException` in place of a `RangeError`, and emptied chunks left in the list. 11 of its 12 new conformance cases fail on the commit before. - The BCL audit's verdicts move as meant (`AppendFormat` and `AppendJoin` are `eq`, `GetChunks` is fenced), and EQ2108 gains `StringBuilderStrategy` as a reporting site with its documented meaning, which `docs/DIAGNOSTICS.md` now names. - The served runtime: main records 213,928 bytes gzipped and serves 214,116 after #733. This branch measures 216,219, past the record's 1%, so it moves the record to 216,148 (bf400ef, measured on the main of #690, which 216,219 stays inside), in a commit that says what the bytes bought. - Suites, each alone and read by its exit code. On the main of #689: Compiler (1,824), Conformance (4,555 of 4,556, one skipped) and Web (988, the wiki guards on this pull request's wiki branch). On the main of #733, this head: the runtime's `TestRuntime` (2,262) and Server (318, the budget included), with Compiler, Conformance and Web rerunning. - Copilot's second round found two defects, fixed in 229d3c8, and measuring them on .NET 10 found four more in the same model, fixed with them. A named argument reached the twin in the order written (`CopyTo(count: 2, destination: a, …)` read the count as the source index): a call that names an argument goes through `ParameterTemplate`, each still evaluated in the order written. Only `String.repeat` mapped a `RangeError`: every text the builder makes goes through one guard, built before the chunks change. In V8 (Node 24), append, insert and replace past the engine's longest string threw `RangeError: Invalid string length` on the commit before and throw `OutOfMemoryException` now, the builder unchanged. The four more: an interpolated append part by part, `AppendLine`'s newline as an append of its own, `Append(StringBuilder)`'s check of the maximum, and a `Replace` that refuses chunk by chunk. On the commit before, 14 of the 16 new conformance cases, 10 of the 12 new compiler cases and the 3 new runtime cases fail, the runtime's under V8 and JavaScriptCore alike. The cases that pass there pin what must not change: `Append(object)` holding a builder is a string's append, a builder appended to itself is its text, and a string's append stays one append. `Append(T)` of a float, a double or an enum still prints what the browser holds, filed as #750. - Copilot's first round found two defects, fixed in e7a65cc: the span fence let a span passed whole to a `params` overload through (only the values a call expands into it cross now, EQ1004 otherwise), and a capacity past `Array.MaxLength` was accepted where .NET throws `OutOfMemoryException` (measured for the constructors, `Capacity` and `EnsureCapacity`). The one new compiler case and the three new conformance cases fail on the commit before. ## Checklist - [x] `dotnet test` on the affected test projects, and `dotnet build src/eQuantic.UI.Runtime -t:TestRuntime` if TypeScript changed (the embedded Bun runs `tsc`, then `vitest run`) - [ ] This PR's checks include a run named CI with jobs in it (`build-packages`, `test (ubuntu-latest)`, `test (windows-latest)`, `openspec`, `session-start`, `wiki-checkout`). A workflow whose expression does not parse creates zero jobs, and the ruleset's required checks then keep the PR blocked. GitHub lists the workflow by its file path instead of `CI`. While GitHub Actions has no credits, the same run is on eQuantic Space (`eqs runs ls`) - [x] `./scripts/check-openspec.sh` passes: the OpenSpec change validates strictly, and it is archived before the merge - [ ] `dotnet build samples/DefaultUIDashboard` (and `PhotonDesktop` / `WalletMobile` if the native track changed) (CI's `samples` job builds them) - [x] A broken contract has a line in the migration notes (we are in preview: break freely, hide nothing): no C# an app writes changes. A builder member that was a TypeError now answers, and `GetChunks`, a span overload and a provider other than the current culture fail the build where they failed in the browser. - [x] The documentation changed with the behaviour: this repository's Markdown here (`docs/DIAGNOSTICS.md`, the ledger), and the wiki page in English AND Portuguese, in one commit on a branch of the wiki repository named exactly like this pull request's branch (`SupportedFeatures.md`) - [x] One `docs/LEDGER.md` line for this event, citing the issue - [x] The diff reviewed by its author before the PR opened (in Claude Code, `/code-review high`); every Copilot thread answered and resolved; a new round asked for only after a defect, and three rounds at most - [x] No "widget" in prose; the project's word is *component* --------- Co-authored-by: Edgar Mesquita <edgar@equantic.tech>
edgarmesquita
pushed a commit
that referenced
this pull request
Oct 10, 2026
edgarmesquita
pushed a commit
that referenced
this pull request
Oct 11, 2026
Merges 20066eb, the third of the five steps that bring this branch up to main eb33f44. It carries #666, #672, #688, #653, #699, #689, #690, #696, #733 and #748, and #748 is the one that meets this branch's source. How each source conflict was resolved: - ValueFlow.cs: both sides taught FlowsIntoText the hole of an interpolated string a handler takes (sb.Append($"...")), this branch by the hole's syntax (an AppendFormatted with no alignment and no format clause) and #748 by the bound operation (an argument of the handler's call that is the call's only argument written). #748's rule is kept, since it reads the operation the hole is, and the hole's text is still this branch's: a value that flows into text goes through StringConversion, which writes it in the page's culture. - InterpolatedStringStrategy.cs: #748 moved a hole's lowering into Hole(), which the builder's part by part append calls too, and this branch had changed the number kind the hole passes. Main's Hole() is kept with this branch's kind in it: FormatKind.Of where a specifier is written, and FormatKind.OfText with none, every number but a double. - StringBuilderStrategy.cs: #748 rewrote the dispatch (the span and GetChunks fences, named arguments bound through ParameterTemplate, AppendFormat, AppendJoin, the interpolated append part by part, appendBuilder and equalsBuilder), and this branch had written the value of Append, AppendLine and Insert in the culture through its own bound call. Main's dispatch is kept, and the value goes in front of it through the same ParameterTemplate.Call, its convert writing the value argument through StringConversion and every other argument as it is, each evaluated in the order it is written. A value that is text already passes as it is, as before (ValueInTheCulture, IsText). BoundArguments.Call, which this branch added for that value alone, goes: nothing else calls it. - docs/DIAGNOSTICS.md: EQ2108 keeps this branch's Convert.ToString and gains #748's builder clause, EQ2109 stays retired, and EQ2110 keeps this branch's reading-only meaning. - diagnostics.baseline.txt: EQ2108 gains #748's StringBuilderStrategy, EQ2109 stays out, and EQ2110 stays this branch's, ParseCulture alone. - bcl-surface.baseline.txt takes main's side and is regenerated after the last step. The runtime's twins in conflict take main's side, and every twin is regenerated after the last step. docs/LEDGER.md merged as a union, and this branch's line moves back to the end of the events.
5 of 6 tasks
edgarmesquita
added a commit
that referenced
this pull request
Oct 11, 2026
Closes #756 The bump to `0.2.0-preview.61`, cut from main at 9305100 (#637) at Edgar's request. It carries forty-five pull requests since `.60`: a component that hears the server on a typed topic (#647), a page that requires its authorization and a Server Action that refuses another site's request (#686, #737), a layout that follows its box and type that follows the window (#648, #665), a control's press and focus on every target with a 24dp floor under a pointer (#617, #628), the code editor's completion (#618, #653, #733), a hot reload under `dotnet watch` that keeps the page's state (#666, #672), the image optimizer on SkiaSharp (#730), the places where the producers drew one tree differently, with Photon's hit-testing and its text layout (#688, #690, #699, #739, #741, #749), a number and a date printed in the page's culture (#637), and a long family of browser answers made .NET's (#579, #588, #594, #607, #608, #621, #654, #656, #660, #661, #667, #668, #689, #696, #697, #705, #707, #708, #709, #715, #731, #748, #752), with a page that answers HEAD (#610) and the conformance harness's own comparison (#609). ## What this commit does - `Directory.Build.props`: `0.2.0-preview.60` → `0.2.0-preview.61`. - `./scripts/public-api.sh ship`: nine projects, 462 declarations join the shipped surface and 43 retire, and every `Unshipped` is empty afterwards. Checked after the fold, per project and compared as sets: the lines that left `Shipped` are exactly the 43 `*REMOVED*` lines declared on main, and the lines that joined are exactly its 462 declarations, so an orphan could not vanish unnoticed. The line diff reads +463 −549: the version line, 462 lines into `Shipped` and 43 out of it, and the 505 that leave the `Unshipped` files. - The analyzer accepts the fold: the solution builds with no RS0016 or RS0017. And it read the files: one bogus declaration appended to an `Unshipped` failed the build with RS0017. - Against `v0.2.0-preview.60` the `Shipped` diff has those 43 lines gone and no other, so no pull request rewrote a shipped line in place this time, as #512 did in `.60`. ## What the retirements are Read out of the `*REMOVED*` lines, each paired with the line that joined under the same member and attributed by the commit that wrote it, not from the log. Only `ServerActionHub` left with nothing in its place, and the rest changed shape: - `ServerActionHub` and its constructor (#647): the hub, its route `/_equantic/hub` and the `AddSignalR()` call `AddUI` made are gone. An app that injected `IHubContext<ServerActionHub>` publishes through `IServerEventPublisher`, and one that maps hubs of its own calls `AddSignalR()` itself. - `ICodeCompletionProvider.CompleteAsync` (#618) takes a `CodeCompletionContext` and answers a `CodeCompletionList`. `CurlyBraceLanguage.Keywords` was the protected abstract set a language overrode, and it is the public list a completion offers now. - `Drawing`'s constructor, `Drawing.Width` and `UI.Drawing` (#648) hold the width as a `SizeValue`. `new Drawing(art, 240)` converts, and a read into a `float` becomes `drawing.Width.Value`. - `ImageOptimizer()` and `BlurPlaceholderGenerator()` (#730) take the `ImageOptimizationOptions`. `UseImageOptimization` registers both, so only an app that built one with `new` meets it. - `HitRegion` (#690) gains `Drawn` after `Bounds`, so building one and deconstructing one both change. `CodeRegion` (#653), `SheetRegion` and `TextRegion` (#690) gain optional members at the end, so only a positional deconstruction changes. - `ServerActionsMiddleware`'s constructor (#737) takes an `IOptionsMonitor<ServerActionsOptions>`. `UseServerActions()` builds it, so only an app that constructs the middleware itself meets it. - Four signatures widened at the end by optional parameters, which compiles as before from source: `UI.Positioned` by the four fractions and the two shifts (#648), `UI.Pressable` by `canRequestFocus` (#653), `WebRealizer.Lower` by `density` (#688) and `PhotonRealizer.Realize` by `sizedLike` (#690). - `eQuantic.UI.Compiler`, which no app references, 21 lines: eleven of #661 (`JsTemplate`'s `Annotate`, with its constructor, its `Deconstruct` and the factory that took it, and six LINQ strategies that crossed to the IR and lost their text `Convert`), four of #608 (`ValueMember`, `ComponentDependencyResolver`'s constructor and `RecordTypeEmitter.CanEmit`), two of #637 (`Eq.AsInteger` and `Eq.AsSingle`), two of #654 (`UserDefinedOperators.Binary` and `Unary`), and `HashSetStrategy` (#594) and `RangeIndexerStrategy` (#707) crossing to the IR. One break is an addition, which no `*REMOVED*` line shows. `CurlyBraceLanguage.ReservedWords` (#618) is a new abstract member, so a language derived from it renames its `Keywords` override to `ReservedWords`. I listed every member that joined an interface or an abstract class already shipped, and it is the only one an implementer has to write: `ICodeLanguage.Keywords` and `ICodeCompletionProvider.ResolveAsync` have default implementations. The additions are 118 in `eQuantic.UI.Code` (the completion), 116 in `Primitives` (the server events vocabulary, `FluidSize`, `Positioned`'s fractions and shifts, `BoxStyle.Pressed`, `GridTrack.AutoFill`, `Touch.MinPointerTarget`), 98 in `Server` (server events, the origins a Server Action allows), 86 in the compiler, 19 in `Native.Components`, 12 in `Web`, 7 in `Components`, 4 in `Native.Framework` and 2 in `Images`. ## The rest of the surface `developer-surface.baseline.txt` gains two configuration sections since `v0.2.0-preview.60`, `EQuantic:ServerActions` (#737) and `EQuantic:ServerEvents` (#647), and loses nothing: no MSBuild property or template parameter came or went. What an app meets with no signature moving: - Three new build errors. EQ1009 (#608, #621, #708) stops two constructors that take the same number of arguments, in a class, a record or a struct that reaches the browser, where the twin kept one and a `new` that meant another ran it. EQ2014 (#708) stops an exception built or tested where a type argument it carries is a type parameter. EQ2013 (#647) stops a `ServerTopic<T>` built over a type parameter, which only new code can meet. - Refusals widened under existing codes: EQ1007 by a second indexer and a sequence over two types (#707, #708), EQ2004 by a stored `Range`, a method group over a .NET extension and a .NET collection's own `GetEnumerator()` (#656, #707, #708), EQ2007 by a comparer handed to `ToDictionary`, `ToLookup`, `GroupBy` or `Distinct` (#707), and EQ2010 by an extension method of a server-only class and a type nested in one (#654, #705, #731). - Two refusals a running app meets on the server: a Server Action called from another origin answers 403 until the app lists that origin (#737), and a class-level `[Authorize]` guards the page as well as its actions (#686). - `image/avif` in the optimizer's `Formats` stops the app at startup (#730), and a `Spacer` of weight below 1 or a negative `Flexible` weight throws where it is written (#741). - EQ2109 is retired and EQ2110 is about reading a number now, since a number written as text follows the page's culture on both sides (#637). The rest are browser answers made .NET's and drawings made alike across the producers, listed in the tag. ## The wiki's version marks `WikiVersionMarkTests` compares a mark only once a tag holds its symbol, so the `.61` tag is when this release's marks are judged for the first time. Emulated before the tag, with the test's own pattern and lookup and a `.61` at 9305100: 145 marks, no mismatch. The thirteen it judges first resolve to `.61`, as written: `StartFraction`, `GridTrack.AutoFill`, `canRequestFocus`, `DENSITY_COOKIE`, `Drawing`'s `SizeValue` width, `WithPageAuthorization`, `AllowServerActionOrigins`, `IServerEvents`, `MapGetAndHead`, `UseServerEvents`, `TwinIsData` on the tokens, `BoxStyle.Pressed` and `ScrolledThreshold`. ## The tag's gate, rehearsed `gate-templates` runs only on a `v*` tag, so a template that does not build costs a release attempt. Rehearsed on main at 9305100, before this branch: 50 packages packed at `1.0.0-dev`, the three web and the four native template shapes scaffolded and built in Release against that feed alone, with no warning and with every eQuantic package restored at the version packed, the published `runtime.js` identical byte for byte to the Server package's, and the dashboard template served, hydrated and navigated in a browser with no console error. ## Not in this release No pull request is open. Forty-eight bugs are, none of them a regression against `.60`. Three issues came out of this stretch and wait for a decision or their turn: #753 (`string.Split` with an array of separators, a count or a null separator), #754 (an app's exception class in a snippet compiled on its own) and #755 (whether generic code should carry its type arguments at run time, which EQ2014 fences). The release notes travel in the annotated tag. The wiki's Upgrading page carries the distilled entry in both languages, on the wiki branch `chore/0.2.0-preview.61`, which merges into the wiki's master when this merges and before the tag. The `docs/LEDGER.md` line for the release follows the tag, as `.60`'s did, because it names the commit the tag lands on. ## Checklist - [x] The diff reviewed by its author before the PR opened: a version line and a mechanical fold, verified as sets above - [x] `dotnet test` on this branch: Compiler 1898, Server 374, Conformance 5087 with one skipped, Web 1021, and the runtime's own 2355 in 170 files, none aborted - [ ] This PR's checks include a run named CI with jobs in it - [x] `./scripts/public-api.sh ship` run, every `Unshipped` empty, the retirements read from the diff - [x] The documentation changed with the release: the Upgrading entry in English and Portuguese, on the wiki branch `chore/0.2.0-preview.61`, with the wiki guards passing against it (9 of 9, and the vocabulary guard fails on that page when a word it refuses is written into it) - [x] Copilot's rounds answered: one round, approval recommended with no finding and no thread, so the loop ends there Co-authored-by: Edgar Mesquita <edgar@equantic.tech>
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.

Closes #598
Closes #600
What
A code editor behaves the same inside a dialog and after any paste, with no line of an app changed.
CodeEditorController.Changedcarries the text the document holds: a paste with CR or CRLF arrives with LF.Neither the public surface nor the developer surface moves.
Why
CodeEdit.InsertedRangebreaks lines as the document does, whoever builds the edit.Reported on its own: a spreadsheet takes every Tab and releases none on either target, so the keyboard cannot leave one inside a dialog either (#732).
OpenSpec
an-editor-keeps-tab-in-a-dialog-and-undoes-a-pasted-cr, archived. It createscode-historyandmodal-focus.Proof
CodeClipboardTests: undo and redo after pasting a lone CR, a CRLF, a LF and a mix, the edit a listener hears, and the range of an edit built by hand. On main's engine the five with a lone CR fail, and CRLF and LF pass there too, as the issue says.ATypedLoneCarriageReturn_EndsTheRunOfTyping, from Copilot's first round: the history's run of typing ended at LF alone, so a typed lone CR a host recorded ran on into the next character, and one undo took back both. It fails on the history before the fix.focus-trap.spec.ts: a Tab the focused control consumed is not cycled.code-editor.spec.ts: the real code surface, lowered and mounted at either end of a marked layer, indents on Tab, outdents on Shift+Tab, and moves on after Escape. On main's trap all four fail, the last one because the editor indented after the trap had already moved the focus.CodeEdit.ts,CodeEditorController.ts,CodeHistory.ts) with their pins (14), the runtime'stscand vitest 2253, Native.Engine 1925 (main e5ad1df merged), the Web suite's docs and wiki guards (15), andsamples/DefaultUIDashboardbuilt.Checklist
dotnet teston the affected test projects, anddotnet build src/eQuantic.UI.Runtime -t:TestRuntime./scripts/check-openspec.shpasses, and the change is archived before the mergedotnet build samples/DefaultUIDashboarddocs/LEDGER.mdline, citing both issues/code-review high, six findings: the spreadsheet that keeps every Tab reported as A spreadsheet never gives Tab back, so the keyboard cannot leave it #732 and fenced in the design, the rest stated)