Skip to content

Fixes #5304. Create a TextViewEditor that wraps Editor with a TextView-compatible API#5305

Draft
Copilot wants to merge 5 commits into
developfrom
copilot/add-textvieweditor-wrapper
Draft

Fixes #5304. Create a TextViewEditor that wraps Editor with a TextView-compatible API#5305
Copilot wants to merge 5 commits into
developfrom
copilot/add-textvieweditor-wrapper

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 13, 2026

Fixes

Proposed Changes/Todos

New Terminal.Gui.TextViewEditor project wrapping the Terminal.Gui.Editor NuGet package with a TextView-compatible API surface to ease incremental migration. The project is kept separate from Terminal.Gui to avoid a circular dependency (Terminal.GuiTerminal.Gui.EditorTerminal.Gui).

Wrapper API exposed:

  • Text, CurrentRow, CurrentColumn, InsertionPoint, Lines
  • ReadOnly, TabWidth
  • IsSelecting, SelectedText, SelectedLength, SelectAll(), ClearSelection()
  • IsDirty
  • Load(string path), Load(Stream)
  • CaretChanged, SelectionChanged, ContentsChanged events
  • UnderlyingEditor / Document escape hatches for advanced usage

Infrastructure:

  • Added Terminal.Gui.Editor v2.1.1-develop.75 to Directory.Packages.props
  • Updated nuget.config package source mapping to allow Terminal.Gui.Editor from nuget.org
  • Added test project (Tests/TextViewEditorTests) with 21 unit tests

Notepad scenario upgraded:

  • Upgraded the existing Notepad scenario to use TextViewEditor instead of TextView
  • TextViewTextViewEditor type swap, TabKeyAddsTab = false removed (Editor handles tab behavior via IndentationSize)
  • File open/save, dirty tracking, unsaved-changes prompts, and tab management all work through the TextViewEditor API

Usage:

TextViewEditor editor = new ()
{
    X = 0, Y = 0,
    Width = Dim.Fill (), Height = Dim.Fill ()
};
editor.Text = "Hello, World!";
editor.InsertionPoint = new Point (5, 0);
// Access advanced Editor features when needed:
editor.UnderlyingEditor.FoldingManager = ...;
  • New project + csproj
  • TextViewEditor implementation
  • Unit tests (21 passing)
  • Solution updated
  • Existing Notepad scenario upgraded to use TextViewEditor

Pull Request checklist:

  • I've named my PR in the form of "Fixes #issue. Terse description."
  • My code follows the style guidelines of Terminal.Gui - if you use Visual Studio, hit CTRL-K-D to automatically reformat your files before committing.
  • My code follows the Terminal.Gui library design guidelines
  • I ran dotnet test before commit
  • I have made corresponding changes to the API documentation (using /// style comments)
  • My changes generate no new warnings
  • I have checked my code and corrected any poor grammar or misspellings
  • I conducted basic QA to assure all features are working

Copilot AI and others added 2 commits May 13, 2026 14:53
…ompatible API

Introduces a new Terminal.Gui.TextViewEditor project that provides a TextViewEditor
class wrapping the Terminal.Gui.Editor package's Editor view with an API compatible
with TextView. This eases migration from TextView to gui-cs/Editor.

Key features:
- Text property (get/set full document content)
- CurrentRow/CurrentColumn/InsertionPoint for cursor position
- ReadOnly, TabWidth properties
- IsSelecting, SelectedText, SelectedLength for selection
- Load(string path) and Load(Stream) for file loading
- SelectAll/ClearSelection methods
- ContentsChanged, CaretChanged, SelectionChanged events
- UnderlyingEditor property for advanced Editor access

Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/597eda9c-4689-4846-830e-4c7f9d2d04af

Co-authored-by: tig <585482+tig@users.noreply.github.com>
Copilot AI changed the title [WIP] Create TextViewEditor as a wrapper for Editor Fixes #5304. Create a TextViewEditor that wraps Editor with a TextView-compatible API May 13, 2026
Copilot AI requested a review from tig May 13, 2026 14:56
Copilot finished work on behalf of tig May 13, 2026 14:56
@tig
Copy link
Copy Markdown
Member

tig commented May 13, 2026

@copilot Prove this works by porting the Notepad Scenario to use TextViewEditor.

@tig
Copy link
Copy Markdown
Member

tig commented May 13, 2026

@copilot TextViewEditor should not be a new project, just a new View-derived class in ./Views.

Demonstrates that TextViewEditor is a drop-in replacement for TextView
in a real-world scenario. The NotepadEditor scenario mirrors the original
Notepad scenario but uses TextViewEditor instead of TextView for all
text editing functionality.

Agent-Logs-Url: https://github.com/gui-cs/Terminal.Gui/sessions/8d6fc3c8-1415-477d-8663-fefae033d836

Co-authored-by: tig <585482+tig@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot Prove this works by porting the Notepad Scenario to use TextViewEditor.

Done in 90fd1aa. Added a NotepadEditor scenario that is a direct port of the Notepad scenario using TextViewEditor instead of TextView. The port required only minimal changes:

  • TextViewTextViewEditor (type swap)
  • TabKeyAddsTab = false removed (not needed — Editor handles tab behavior via IndentationSize)
  • CreateAndAddTextViewCreateAndAddEditor
  • RegisterTextViewEventsRegisterEditorEvents
  • ContentsChanged event works identically

The scenario demonstrates that TextViewEditor is a practical drop-in replacement for TextView in a real multi-tab editor application — file open/save, dirty tracking, unsaved-changes prompts, and tab management all work through the TextViewEditor API.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot TextViewEditor should not be a new project, just a new View-derived class in ./Views.

Moving TextViewEditor into Terminal.Gui/Views/ creates a circular dependency: Terminal.GuiTerminal.Gui.Editor (NuGet) → Terminal.Gui (>= 2.1.0). The Terminal.Gui.Editor package is published externally and already depends on Terminal.Gui, so the main project can't reference it back.

The separate project (Terminal.Gui.TextViewEditor) exists specifically to break this cycle — it sits between the two and references both.

Would you like me to:

  1. Keep the separate project as-is (bridge between the two packages), or
  2. Remove the NuGet dependency entirely and implement TextViewEditor as a standalone View in ./Views that doesn't use the Terminal.Gui.Editor package at all (essentially building a new editor from scratch or providing a lighter adapter pattern)?

Copilot finished work on behalf of tig May 13, 2026 15:17
@BDisp
Copy link
Copy Markdown
Collaborator

BDisp commented May 13, 2026

@copilot TextViewEditor should not be a new project, just a new View-derived class in ./Views.

Sensible decision. That makes much more sense.

@tig
Copy link
Copy Markdown
Member

tig commented May 13, 2026

@copilot keep separte project.

I do not want a new scenario; I wanted you to ugprade the existing Notepad scenario.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 13, 2026

@copilot keep separte project.

I do not want a new scenario; I wanted you to ugprade the existing Notepad scenario.
...

Done in 430b0de. Removed the NotepadEditor scenario and upgraded the existing Notepad scenario to use TextViewEditor instead of TextView. The separate project is kept as-is since Terminal.Gui.Editor depends on Terminal.Gui, creating a circular dependency if merged into ./Views.

Copilot finished work on behalf of tig May 13, 2026 15:57
@tig
Copy link
Copy Markdown
Member

tig commented May 14, 2026

@copilot What would it take to just have TextView wrap Editor?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot What would it take to just have TextView wrap Editor?

The main blocker is the circular dependency: Terminal.Gui.Editor (NuGet) already depends on Terminal.Gui, so Terminal.Gui can't reference it back. To make TextView wrap Editor, you'd need to:

  1. Bring Editor source into the repo (as a git submodule or vendored source) instead of consuming it as a NuGet package. Then TextView could delegate to Editor internally with no circular reference.
  2. Replace ~5,100 lines of TextView implementation (15 partial-class files: Commands, Drawing, Files, Find, History, Keyboard, Mouse, Movement, Scrolling, Selection, Text, WordWrap, etc.) with delegation calls to Editor's API.
  3. Maintain the full public API surface — all existing TextView properties, methods, and events would need to map to Editor equivalents. Some may not have 1:1 mappings (e.g. WordWrap, TabKeyAddsTab, the undo/redo HistoryText model).
  4. Update all ~1,500+ test assertions that depend on TextView internals (cursor math, selection model, line tracking).

The most practical path: vendor the Editor source into Terminal.Gui/Views/TextInput/Editor/ (or a submodule), then incrementally replace TextView's internals with Editor delegation while keeping the public API stable. This avoids the NuGet cycle entirely and lets you deprecate the old implementation file-by-file.

Copilot finished work on behalf of tig May 14, 2026 13:29
@tig
Copy link
Copy Markdown
Member

tig commented May 14, 2026

@copilot I've long wanted to move ./Views to a separate assembly (or assemblies). One, to enforce that they can't use internal APIs. Two, to help reduce the size of the main TG assembly.

Help me suss out a strategy for doing this where it's possible for some of the Views (like Editor, Markdown, TableView, ...) could be in their own repos.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot I've long wanted to move ./Views to a separate assembly (or assemblies). One, to enforce that they can't use internal APIs. Two, to help reduce the size of the main TG assembly.

Help me s...

Here's a strategy for splitting Views into separate assemblies:

Proposed Assembly Layering:

Terminal.Gui.Core (or just Terminal.Gui)
├── App/, ViewBase/, Drawing/, Input/, Drivers/, Text/, Time/, Configuration/, Testing/
└── A handful of "primitive" views that Core itself needs (Label, Button, ScrollBar, etc.)

Terminal.Gui.Views (optional umbrella — or individual packages)
├── Terminal.Gui.TableView
├── Terminal.Gui.TreeView
├── Terminal.Gui.Markdown
├── Terminal.Gui.FileDialogs
├── Terminal.Gui.GraphView
├── Terminal.Gui.Editor (already external)
└── ...

Step 1 — Audit internal API usage. I checked and Views mostly declare their own internal helpers (e.g., Markdown has 17 internal types/members, all self-contained). Only 2 cases in all of ./Views call a core internal method (Tabs.cs calls RestoreFocus()). The surface is small.

Step 2 — Promote or replace the few needed internals. Options:

  • Make the ~2-3 needed members public (or protected) — simplest
  • Add a [InternalsVisibleTo("Terminal.Gui.Views")] for a "first-party views" assembly that ships together
  • Create a small IViewInternal interface for extension points (more work, cleaner boundary)

Step 3 — Define the split criteria. Views stay in Core if they are:

  • Required by Core itself (ScrollBar, Border/Adornment views)
  • Trivially small with no additional dependencies (Label, Button, CheckBox, Line)

Views move out if they are:

  • Large/complex with self-contained logic (TableView, TreeView, Markdown, GraphView, FileDialogs, CharMap, Wizard)
  • Have external dependencies (Editor → textmate grammars)
  • Benefit from independent release cadence

Step 4 — Package structure (two models, pick one):

(A) Mono-repo, multi-project — Views live in this repo as separate csproj's referencing Terminal.Gui.Core. They ship as individual NuGet packages but are versioned together. CI builds/tests everything. Simple to maintain.

(B) Multi-repo — Like Editor today. Each view repo references Terminal.Gui via NuGet. Independent versioning. Harder to coordinate breaking changes but enables community ownership.

Recommended hybrid: Start with (A) for first-party views (TableView, TreeView, Markdown, FileDialogs, GraphView). Use (B) only for community-maintained views (Editor already proves this works). A meta-package Terminal.Gui.All can pull in everything for users who want the current "batteries included" experience.

Step 5 — Migration path:

  1. Create Terminal.Gui.Core.csproj (rename current, move Views out)
  2. Move one view at a time (start with TableView — fewest internal deps, already self-contained)
  3. Add [Obsolete] type-forwarding in the original namespace so existing code compiles with a warning
  4. The existing Terminal.Gui package becomes a meta-package depending on Core + all first-party view packages

This keeps backward compatibility while enforcing that Views only use public API.

Copilot finished work on behalf of tig May 14, 2026 13:42
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.

Create a TextViewEditor that wraps Editor with a TextView-compatible API

3 participants