feat: implement end-to-end code folding#96
Conversation
Lift AvaloniaEdit folding data model (FoldingManager, FoldingSection, NewFolding, XmlFoldingStrategy) into Terminal.Gui.Document.Folding namespace. Add rendering pipeline integration via FoldingTransformer and FoldingMarkerElement. Editor integration: - FoldingManager property with auto-install of FoldingTransformer - DrawVisibleLines skips folded lines via GetVisibleLineNumbers() mapping - ContentSize adjusts for hidden lines - Caret auto-expands folds when navigating into them - Ctrl+M toggle fold command - Gutter shows fold indicators (▸/▾/│) with click-to-toggle ted integration: - BraceFoldingStrategy for C-family/JSON brace folding - Auto-updates folds on document changes Tests: 19 new folding tests (FoldingManager, BraceFoldingStrategy, FoldingTransformer) All 345 tests pass with 0 errors, 0 warnings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c8d31f9663
ℹ️ 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".
Factor Gutter into two distinct subviews: - LineNumberGutter: line numbers and line-selection mouse handling - FoldingGutter: fold indicators (▸/▾/│) with Command.Toggle bound to MouseFlags.LeftButtonClicked via MouseBindings/AddCommand pattern This replaces the monolithic OnMouseEvent with proper command bindings, enabling independent styling and logic separation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a9c0c3172b
ℹ️ 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".
…ter priming, caret-in-fold - Invalidate _cachedVisibleLineNumbers on Document replacement (P1) - Compute hidden line count as union of folded ranges to avoid double-counting nested folds (P1) - Prime syntax highlighter from mapped document line number, not viewport row index, when folds exist above viewport (P1) - Move EnsureCaretNotInFold from FoldingChanged to SetCaretOffset so collapsing a fold doesn't immediately re-expand it (P2) - Fix whitespace formatting in TedApp.cs (CI failure) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9ff774d16e
ℹ️ 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".
… is set The FoldingManager setter was missing the UpdateLineNumberPadding() call, so SyncLayout() never ran and the FoldingGutter subview was never created. LineNumberGutter also used Viewport.Width (0 before layout) instead of Dim.Fill(). Both subviews now use Dim-based layout. Added 4 new GutterTests that fail without this fix: - Gutter_Has_LineNumberGutter_SubView_Without_Folding - Gutter_Has_Both_SubViews_With_Folding - LineNumberGutter_Width_Is_Fill_Not_Zero - FoldingGutter_Has_Toggle_MouseBinding Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Swapped Gutter subview order so LineNumberGutter is at X=0 with Width=Dim.Fill(2) and FoldingGutter is at X=Pos.Right(lineNumbers) with Width=2. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Editor/src/Terminal.Gui.Editor/Editor.cs
Lines 90 to 92 in 024059a
Updating Editor.Document swaps _document but leaves FoldingManager untouched, so the installed folding pipeline can still reference fold offsets from the previous document. If callers reuse the editor and assign a new TextDocument without also recreating FoldingManager, visible-line mapping and content height calculations run against stale fold state, which can hide or skip valid lines in the new file. The document swap path should clear or rebind folding state atomically.
ℹ️ 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".
Address P1 CR feedback: viewport.Y is an index into the visible-line list, but EnsureCaretVisible, cursor placement, and MousePositionToOffset were using raw document line indices. Added GetCaretVisibleLineIndex() that maps the caret's document line to its position in the visible-line list, and updated all viewport-coordinate consumers: - EnsureCaretVisible: uses GetCaretVisibleLineIndex() - UpdateCursorPosition: uses GetCaretVisibleLineIndex() - MousePositionToOffset: maps through GetVisibleLineNumbers() MoveCaretVertically continues using GetCaretLineIndex() (document-level navigation is correct there — folding skip is handled by EnsureCaretNotInFold). Also merges develop (UPSTREAM.md conflict: Folding + Indentation rows). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Deduplicate folded sections by start offset before applying transforms. Only the leftmost fold on a line is applied — once collapsed, the tail is hidden and subsequent folds are subsumed. Fixes double-marker issue when GetFoldingsContaining and AllFoldings overlap or nested folds start on the same line. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c20249957f
ℹ️ 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".
Merge develop which landed the AvaloniaEdit highlighting lift. Conflicts: - Editor.Drawing.cs: kept folding visible-line mapping, dropped old SyntaxHighlighter/PrepareSyntaxHighlighter (replaced by HighlightingColorizer) - TedApp.cs: kept folding init, dropped old SyntaxHighlighter setup - UPSTREAM.md: combined Folding + Highlighting entries Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 514d27ac82
ℹ️ 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".
Introduce [Flags] GutterOptions enum with None=0, LineNumbers=1, Folding=2. Replace Editor.ShowLineNumbers bool with Editor.GutterOptions property. Gutter.SyncLayout now dynamically adds/removes LineNumberGutter and FoldingGutter subviews based on the flags (and FoldingManager presence). Update ted, unit tests, and integration tests accordingly. Add two new test cases: Folding_Only and Folding_Flag_Without_FoldingManager. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 'Fold Indicators' checkbox to ted's Options menu so users can independently toggle the folding gutter column on/off (R9 compliance). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 233f612c31
ℹ️ 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".
Gutter, LineNumberGutter, and FoldingGutter add MouseBindings for WheeledUp→ScrollUp and WheeledDown→ScrollDown without AddCommand handlers. When fired, DefaultCommandNotBoundHandler invokes TryBubbleUp which reaches the Editor (Padding's Parent) because Editor sets CommandsToBubbleUp to include ScrollUp/ScrollDown/ScrollLeft/ScrollRight. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
GetVisibleLineNumbers() previously used GetFoldingAtLine() which returns only the first fold found. If multiple collapsed folds start on the same line with different end offsets, lines inside the longer fold could leak into the visible-line map. Now scans all folded sections starting on the line and skips past the maximum end line. Addresses PR review feedback (P2). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move LineNumberGutter to LineNumberGutter.cs and FoldingGutter to FoldingGutter.cs, leaving only the Gutter class in Gutter.cs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add AGENTS.md pointing agents to CLAUDE.md for project rules. - Rename GetLineNumberPaddingWidth to GetGutterWidth and UpdateLineNumberPadding to UpdateGutterWidth since the method now computes width for both line numbers and folding columns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…itor Align the namespace with the assembly name. This is the same change as PR #98 (copilot/fix-editor-namespace-issue) applied directly to the folding-ui branch. - Changed RootNamespace in .csproj from Terminal.Gui.Views to Terminal.Gui.Editor - Updated all namespace declarations (Terminal.Gui.Views -> Terminal.Gui.Editor, Terminal.Gui.Views.Rendering -> Terminal.Gui.Editor.Rendering) - Updated embedded resource prefix in Resources.cs - Updated using directives across tests, examples, and benchmarks - Re-added 'using Terminal.Gui.Views' where TG's own view types are needed - Updated specs/docs references Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d4a03718b8
ℹ️ 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".
Summary
Implements the folding feature as specified in \specs/folding/spec.md\ and \specs/folding-ui/spec.md.
What's included
Folding data model (lifted from AvaloniaEdit \d7a6b63, heavily adapted):
Rendering pipeline integration:
Editor integration:
ted integration (R9 compliance):
Tests
Upstream tracking