Skip to content

Update to TG 2.5.x (PR 5416 preview) - #287

Open
tig wants to merge 2 commits into
developfrom
tg25-port
Open

Update to TG 2.5.x (PR 5416 preview)#287
tig wants to merge 2 commits into
developfrom
tg25-port

Conversation

@tig

@tig tig commented Aug 23, 2026

Copy link
Copy Markdown
Member

⚠️ DO NOT MERGE with the pre-release pin in place

This PR pins the repo to a vendored pre-releaseTerminal.Gui 2.5.0-tig-remove-cm-followup.2, a nupkg built from tui-cs/Terminal.Gui#5416 (head e8aba423, sha embedded in InformationalVersion) and committed under local_packages/. Before merging:

  1. Update the TG pin to the public 2.5.x version: <TerminalGuiVersion> in Directory.Build.props (the only central pin — every csproj references $(TerminalGuiVersion)).
  2. Delete local_packages/ and the tgui-pr-5416 package source in nuget.config (delete the file if nothing else was added to it).
  3. Revert the .gitignore exception (!local_packages/*.nupkg / !local_packages/*.snupkg under the # NuGet block).
  4. Re-run dotnet restore + build + all three CI test suites and confirm Terminal.Gui restores from nuget.org.

What this is

Part of the Terminal.Gui v2.5.0 ecosystem-validation gate (tui-cs/Terminal.Gui#5630). tui-cs/Terminal.Gui#5416 (ConfigurationManager removal) is not yet merged/published, so this PR vendors a nupkg built from that PR branch and ports Editor/ted to the 2.5.0 API — the same TEMP-vendoring pattern as tig/winprint#272.

API breaks fixed

  • View.Text is no longer virtual (CWP-compliant, Fixes #5366 - BREAKING CHANGE - Make View.Text notifications CWP-compliant and non-virtual Terminal.Gui#5371). Editor.Text was public override; it is now a new property following TextView's pattern: the setter raises TextChanging (cancellable), writes the Document, mirrors into base View via SetTextDirect, and raises TextChanged; an OnTextChanged override syncs the Document when Text is set through a base View reference. Editor also overrides OnDrawingText to suppress the base text pass — the Editor owns all content rendering.
  • Legacy ConfigurationManager / [ConfigurationProperty] / AppSettingsScope / ConfigLocations are deleted. ted's EditorSettings drops the legacy CM attributes (Microsoft.Extensions.Configuration via TuiConfigurationBuilder was already the primary read path); the ConfigTests project's CM end-to-end test is rewritten against TuiConfigurationBuilder + RuntimeConfig with the nested "EditorSettings" shape.
  • Popover is now a screen-filling transparent overlay that positions its ContentView. The completion popup's mouse hit-testing now uses the ListView's screen frame (not the popover's), and mouse-driven accept is handled from the ListView.Accepted event (MouseBinding context) because popup clicks route to the ListView and never reach Editor.OnMouseEvent anymore. Unit tests assert against ContentView geometry.
  • The ANSI driver sizes asynchronously behind the new startup gate, so tests that need deterministic layout geometry now call Driver.SetScreenSize (…) after Init (the pattern AppFixture already used).
  • TG installs its main-loop SynchronizationContext at Init (Fixes #5579. SynchronizationContext is not correctly implemented in v2 Terminal.Gui#5588). ted's sync-over-async bridges (OpenFile/SaveFile/SaveFileAs, plus the startup file load in Program.cs) deadlocked: awaits posted continuations to the very thread being blocked. They now clear the ambient context while blocking (RunSyncBridge), restoring pre-2.5 thread-pool continuation behavior while keeping TextDocument owner-thread handoff on the calling thread.
  • Selector/dropdown width change: the status-bar theme dropdown pads its label to a fixed width in 2.5; the FileMenu_Shortcuts_Snapshot ANSI golden is regenerated (only that glyph run changed).
  • Microsoft.Extensions.Configuration floors raised to 10.0.11 — Terminal.Gui 2.5.0 depends on MEC 10.0.11 and the repo pinned 10.0.7 (NU1605 downgrade errors otherwise).

Known Terminal.Gui 2.5 regression (skipped test — filed as tui-cs/Terminal.Gui#5638)

EditorTabTests.RawAnsi_Tab_After_ShiftTab_Reindents_Line_On_First_Keypress is skipped with a documented reason: AnsiInputProcessor's 50 ms printable-suppression window (dedup of dual-reported keys) swallows a real \t arriving within 50 ms of a parsed Shift+Tab (ESC[Z) — GetPrintableText () is "\t" for both Tab and Shift+Tab. Filed as tui-cs/Terminal.Gui#5638 (the skip annotation references it); re-enable the test when fixed.

Test results

Suite Result
Terminal.Gui.Editor.Tests 579 passed / 0 failed
Terminal.Gui.Editor.IntegrationTests 352 passed / 0 failed / 1 skipped (TG regression above)
Terminal.Gui.Editor.ConfigTests 1 passed / 0 failed

Post-review: EditorTextCwpTests (8 tests) locks the new Text CWP contract both ways — direct and base-View-reference set/get round-trips, single-fire TextChanging/TextChanged, cancellation — and a review fix hardens the setter's re-entrancy flag with a finally (a throwing TextChanged subscriber previously disabled Document sync for all later polymorphic sets; TextView upstream shares this shape).

Debug and Release builds clean; .claude/hooks/cleanup-cs.ps1 (dotnet format + jb cleanupcode) run.

Follow-up

Refs: tui-cs/Terminal.Gui#5416, tui-cs/Terminal.Gui#5630. Vendoring pattern: tig/winprint#272.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BVbLXNzbus2MTXmiJDBErL

…PI-break port

Temporarily pin to Terminal.Gui 2.5.0-tig-remove-cm-followup.2 from
tui-cs/Terminal.Gui#5416 (built from 5416 head e8aba423) via a vendored
nupkg in local_packages/, until 2.5.x ships on nuget.org (pattern:
tig/winprint#272). Part of the v2.5.0 ecosystem-validation gate
(tui-cs/Terminal.Gui#5630).

Port for 2.5.0 breaking changes:

- View.Text is no longer virtual (CWP, TG #5371): Editor.Text becomes a
  `new` property mirroring TextView's pattern — setter raises
  TextChanging, writes the Document, syncs base via SetTextDirect, and
  raises TextChanged; OnTextChanged override syncs the Document when Text
  is set through a base View reference. OnDrawingText suppresses the base
  text pass (Editor owns rendering).
- ConfigurationManager/[ConfigurationProperty]/AppSettingsScope deleted:
  drop the legacy CM attributes from ted's EditorSettings (MEC is the only
  read path) and rewrite ConfigTests against TuiConfigurationBuilder with
  the nested "EditorSettings" RuntimeConfig shape.
- Popover is now a screen-filling transparent overlay positioning its
  ContentView: completion popup hit-testing uses the ListView's screen
  frame, and mouse-driven Accept is handled from the ListView's Accepted
  event (clicks no longer reach Editor.OnMouseEvent); tests assert
  against ContentView geometry and pin the driver size (ANSI driver now
  sizes asynchronously behind the startup gate).
- TG installs its main-loop SynchronizationContext at Init (TG #5588):
  ted's sync-over-async bridges (OpenFile/SaveFile/SaveFileAs and the
  startup file load) now clear the ambient context while blocking so
  continuations run on the thread pool as before (no deadlock).
- Selector width change: FileMenu_Shortcuts_Snapshot golden regenerated
  (theme dropdown pads its label to a fixed width in 2.5).
- MEC package floors raised to 10.0.11 to satisfy Terminal.Gui 2.5.0.

Known TG 2.5 regression (test skipped, to file upstream):
AnsiInputProcessor's 50ms printable-suppression window swallows a real
Tab arriving within 50ms of a parsed Shift+Tab (ESC[Z).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVbLXNzbus2MTXmiJDBErL

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 54b4efb850

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +138 to +139
// Keep base View._text in sync so a polymorphic getter sees the same value.
SetTextDirect (value);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep the base Text mirror synchronized with document edits

The mirror is updated only when this new setter is used. If text changes through normal typing, editor.Document.Text, or replacement of Document, neither OnDocumentChanged nor the Document setter calls SetTextDirect, so ((View)editor).Text continues returning the previous value (often the initial empty string). Before this commit the virtual override always returned the live document text, so generic consumers holding the editor as a View now observe stale content; update the mirror on every document change and document swap.

Useful? React with 👍 / 👎.

Comment on lines +127 to +128
// Raise View.TextChanging so subscribers holding a View reference can cancel.
if (OnTextChanging (value))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the no-op behavior for identical Text assignments

When editor.Text is assigned its current value, this setter invokes OnTextChanging, replaces the entire document, and raises TextChanged. This violates the inherited View.Text contract that identical assignments raise neither event, so CWP subscribers now receive a change that did not occur and the document unnecessarily records a full replacement. Compare against the current text before starting the notification workflow.

Useful? React with 👍 / 👎.

Comment thread src/Terminal.Gui.Editor/Editor.cs Outdated
Comment on lines +141 to +143
_ownTextSetterActive = true;
RaiseTextChanged ();
_ownTextSetterActive = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reset the Text setter guard when change handlers throw

If an overridden OnTextChanged or any TextChanged subscriber throws from RaiseTextChanged, _ownTextSetterActive remains true. Subsequent assignments through a View reference then take the early branch in OnTextChanged and stop synchronizing the document, leaving the editor permanently inconsistent until another successful assignment through Editor.Text; reset this guard in a finally block.

Useful? React with 👍 / 👎.

Code review of the tg25 port found the `new Text` setter cleared its
_ownTextSetterActive re-entrancy flag outside a finally: a TextChanged
subscriber that throws left the flag stuck true, silently disabling
Document sync for every later polymorphic (base View reference) Text set.
Reset the flag in a finally. (TextView upstream has the same shape —
worth fixing there too.)

Adds EditorTextCwpTests covering the full CWP contract of the property-
hiding pattern both ways: direct and base-reference set/get round-trips,
TextChanging/TextChanged raised exactly once per path, cancellation
leaving Document and mirror untouched, and the throwing-subscriber
regression (written first; failed before the fix).

Also stamps the skipped Tab-after-Shift+Tab test with the now-filed
upstream issue tui-cs/Terminal.Gui#5638.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVbLXNzbus2MTXmiJDBErL

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84c597a40a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +167 to +171
if (_ownTextSetterActive)
{
base.OnTextChanged ();

return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Synchronize reentrant base Text assignments

When a TextChanged subscriber triggered by editor.Text = "first" reentrantly assigns a different value through a View reference, _ownTextSetterActive is still true, so this branch skips copying that nested base value into the document. The nested setter then raises TextChanged while ((View)editor).Text contains the new value but editor.Text/Document.Text still contains the outer value, leaving the two models inconsistent; suppress the sync only when the base value already matches the document rather than for every callback during the outer setter.

Useful? React with 👍 / 👎.

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.

1 participant