Skip to content

Extract automatic folding orchestration from Ted into Editor#199

Merged
tig merged 5 commits into
developfrom
tig/tig-extract-automatic-folding-orchestrat
May 21, 2026
Merged

Extract automatic folding orchestration from Ted into Editor#199
tig merged 5 commits into
developfrom
tig/tig-extract-automatic-folding-orchestrat

Conversation

@tig

@tig tig commented May 21, 2026

Copy link
Copy Markdown
Member

Summary

Extracts ~250 lines of folding orchestration from examples/ted/TedApp.cs into Editor itself, implementing Phase 1 of #178.

New API on Editor

// Any consumer can now enable full automatic brace-folding with:
editor.FoldingStrategy = new BraceFoldingStrategy ();
editor.GutterOptions |= GutterOptions.Folding;

Properties added:

  • IFoldingStrategy? FoldingStrategy — when assigned (and AutomaticFolding is true), creates a FoldingManager, subscribes to document changes, and refreshes foldings on structural edits
  • bool AutomaticFolding — auto-enabled when FoldingStrategy is first assigned; can be toggled independently
  • int MaximumAutomaticFoldingDocumentLength — documents exceeding this threshold skip automatic folding (default: 1,000,000)

New Interface

public interface IFoldingStrategy
{
    void UpdateFoldings (FoldingManager manager, TextDocument document);
    bool ChangeMayAffectFoldings (DocumentChangeEventArgs e);
}

What changed

File Change
src/.../Folding/IFoldingStrategy.cs New interface
src/.../Folding/BraceFoldingStrategy.cs Implements IFoldingStrategy; absorbs Ted's OffsetChangeMap-aware structural-change detection
src/.../Folding/XmlFoldingStrategy.cs Implements IFoldingStrategy
src/.../Editor.Folding.cs New partial with properties + lifecycle orchestration
src/.../Editor.cs Hooks InstallAutomaticFolding() from Document setter and Dispose
examples/ted/TedApp.cs Deleted ~250 lines of folding methods, replaced with 1-line config
examples/ted/TedApp.FileOperations.cs Removed InstallFolding() call (Editor handles it)
tests/.../AutomaticFoldingTests.cs 10 new tests covering setup, teardown, structural filtering, large-doc threshold

Test results

  • ✅ 544 unit tests pass
  • ✅ 338 integration tests pass
  • ✅ 1 config test passes

Closes #178

Introduce IFoldingStrategy interface and move automatic folding lifecycle
management into Editor itself. Consumers now enable full brace-folding
with just:

    Editor.FoldingStrategy = new BraceFoldingStrategy ();

Key changes:

- New IFoldingStrategy interface (UpdateFoldings + ChangeMayAffectFoldings)
- BraceFoldingStrategy implements IFoldingStrategy with OffsetChangeMap-aware
  structural-change detection (moved from Ted's ~170 lines)
- XmlFoldingStrategy implements IFoldingStrategy
- New Editor.Folding.cs partial with FoldingStrategy, AutomaticFolding, and
  MaximumAutomaticFoldingDocumentLength properties
- Editor.Document setter calls InstallAutomaticFolding() automatically
- Ted simplified: deleted ~250 lines of folding orchestration, replaced with
  single property assignment
- New AutomaticFoldingTests covering setup, teardown, structural filtering,
  large-doc threshold, and document replacement

Closes #178

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

@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: 1d00458f6e

ℹ️ 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 +107 to +110
if (Document.TextLength > _maximumAutomaticFoldingDocumentLength)
{
SetFoldingDocument (null);
FoldingManager = null;

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 Re-enable folding after size threshold is crossed downward

When the document is over MaximumAutomaticFoldingDocumentLength, this branch tears down folding and unsubscribes from folding-change events, but there is no subsequent path that reinstalls automatic folding when edits shrink the same document back under the limit (normal edits only hit OnDocumentChanged, which does not call InstallAutomaticFolding). In practice, a large file that gets trimmed below the threshold will keep FoldingManager null until callers manually toggle a folding property or replace the document.

Useful? React with 👍 / 👎.

Copilot AI left a comment

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.

Pull request overview

Extracts Ted’s automatic folding orchestration into Terminal.Gui.Editor.Editor, introducing a strategy-based API so consumers can enable automatic folding without duplicating Ted-specific wiring.

Changes:

  • Added IFoldingStrategy and updated existing folding strategies (brace/XML) to implement structural-change filtering.
  • Introduced Editor-level automatic folding lifecycle orchestration (strategy assignment, document swap, large-document guard, change/update handling).
  • Simplified Ted by removing its folding orchestration and relying on Editor configuration; added/updated tests for the new behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Terminal.Gui.Editor.Tests/Folding/AutomaticFoldingTests.cs Adds coverage for automatic folding setup/teardown and change filtering (currently contains an incomplete/compilation-breaking test).
src/Terminal.Gui.Editor/Folding/XmlFoldingStrategy.cs Implements IFoldingStrategy and adds structural-change detection for XML.
src/Terminal.Gui.Editor/Folding/IFoldingStrategy.cs Introduces a strategy interface for folding computation + “change may affect foldings” filtering.
src/Terminal.Gui.Editor/Folding/BraceFoldingStrategy.cs Implements IFoldingStrategy and ports OffsetChangeMap-aware structural-change detection.
src/Terminal.Gui.Editor/Editor.Folding.cs New Editor partial that owns automatic folding orchestration and large-document threshold behavior.
src/Terminal.Gui.Editor/Editor.cs Hooks folding installation on document assignment and unsubscribes folding document events on dispose.
examples/ted/TedApp.FileOperations.cs Removes Ted-side folding install call (Editor now owns it).
examples/ted/TedApp.cs Removes Ted’s folding orchestration and configures folding via Editor.FoldingStrategy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +157 to +169
public void ChangeMayAffectFoldings_Brace_Returns_True_For_Braces ()
{
BraceFoldingStrategy strategy = new ();
TextDocument doc = new ("hello");

// Insert a brace.
doc.Insert (5, "{");

// Manually create the event args to test the strategy method.
// We'll test via a document change that triggers the actual path instead.
}

[Fact]
Comment on lines +73 to +85
public int MaximumAutomaticFoldingDocumentLength
{
get => _maximumAutomaticFoldingDocumentLength;
set
{
if (_maximumAutomaticFoldingDocumentLength == value)
{
return;
}

_maximumAutomaticFoldingDocumentLength = value;
InstallAutomaticFolding ();
}
Comment on lines +94 to +103
if (_foldingStrategy is null || !_automaticFolding || Document is null)
{
SetFoldingDocument (null);

// Clear FoldingManager only if automatic folding was previously active (strategy set).
if (_foldingStrategy is not null || _automaticFolding)
{
FoldingManager = null;
}

// etc.). The Document setter unsubscribes on swap; this covers View-teardown.
_document.Changed -= OnDocumentChanged;
_document.UndoStack.PropertyChanged -= OnUndoStackPropertyChanged;
SetFoldingDocument (null);
- Remove unused 'using Terminal.Gui.Editor' from test file (CI fix)
- Add validation on MaximumAutomaticFoldingDocumentLength (ThrowIfLessThan 0)
- Track FoldingManager ownership (_automaticFoldingOwnsFoldingManager) to avoid
  wiping consumer-provided FoldingManager when automatic folding is disabled
- Clear FoldingManager in Dispose to prevent event handler leaks
- Replace empty ChangeMayAffectFoldings test with two proper tests
- Fix Large_Document test to use multi-line content (avoids visual line OOM)

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

@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: 12dd02e732

ℹ️ 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".


FoldingManager fm = new (Document);
FoldingManager = fm;
_automaticFoldingOwnsFoldingManager = true;

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 Track FoldingManager ownership on external assignment

InstallAutomaticFolding marks the manager as owned (_automaticFoldingOwnsFoldingManager = true) whenever auto-folding installs one, but there is no path that clears ownership if a consumer later assigns editor.FoldingManager manually. In that scenario, a subsequent auto-folding state change (e.g., AutomaticFolding = false, strategy unset, or threshold exceeded) will treat the consumer-provided manager as auto-owned and clear it unexpectedly, even though the comment says externally set managers must not be wiped. This regresses manual folding-manager integration after auto-folding has been enabled once.

Useful? React with 👍 / 👎.

tig and others added 3 commits May 20, 2026 18:38
- Add explicit 'using System.Text' instead of fully-qualified StringBuilder
- Use var for built-in string init
- Use target-typed new for StringBuilder

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a consumer sets FoldingManager directly after auto-folding has installed
one, the ownership flag is now cleared in the setter. This prevents subsequent
auto-folding teardown (strategy unset, AutomaticFolding=false, threshold
exceeded) from wiping a consumer-provided manager.

Added test: External_FoldingManager_Not_Cleared_By_AutomaticFolding_Teardown

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

@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: 5c1b661ba2

ℹ️ 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 +54 to +57
public bool ChangeMayAffectFoldings (DocumentChangeEventArgs e)
{
return ContainsXmlStructuralCharacter (e.InsertedText)
|| ContainsXmlStructuralCharacter (e.RemovedText);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Recompute XML foldings after tag-name/attribute text edits

ChangeMayAffectFoldings only returns true when inserted/removed text contains <, >, /, or newlines, so edits like renaming a tag (foobar) or changing attribute text are treated as non-structural and skip UpdateFoldings. In automatic mode this leaves stale fold regions/titles (and can preserve invalid folds after name mismatches) until some later structural character edit happens. For XML, these plain-text edits can change parse results and folded labels, so they need to trigger a re-scan.

Useful? React with 👍 / 👎.

@tig tig merged commit 66ea89a into develop May 21, 2026
8 checks passed
@tig tig deleted the tig/tig-extract-automatic-folding-orchestrat branch May 21, 2026 14:12
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.

Extract Ted into composable building blocks both ted and clet edit can use

2 participants