A reusable text-editing View for Terminal.Gui. Drop it into your TUI app and you get the editing experience users already expect (caret movement, selection, clipboard, undo/redo, search & replace, folding, syntax highlighting, word wrap) without writing any of it yourself.
Ships as a single NuGet package: Terminal.Gui.Editor.
This is a library. It exists so that anyone building a Terminal.Gui application (developers, agents, tool authors) can embed a competent multi-line text editor into their UI with a couple of lines of code. The audience is people who need an edit field that can hold code or prose, not people shopping for a standalone editor.
Think of Editor the way you'd think of a rich-text control in a desktop framework: a building block for the editing surface inside your app. A script box in an IDE-like tool, a config pane in a TUI dashboard, a chat composer, a notes view, the body of a code-review widget, the input area of an LLM agent's terminal front-end. Whatever it is you're building, Editor is the part that handles "user types and edits text."
This is not a standalone editor and not trying to be one. It is not a competitor to vim, Emacs, Helix, micro, nano, or any other terminal editor; those are products with their own ecosystems, configs, and communities, and the world doesn't need another one. The ted app in this repo is a demo of the View, not a product. A real end-user editor built on top of this library, clet, lives in its own repo.
- Document layer (
Terminal.Gui.Documentand sub-namespaces). UI-framework-independent. Rope-backedTextDocument,TextAnchor,UndoStack,FoldingManager, search strategies, indentation strategies, and the xshd-driven highlighting engine. Adapted from AvaloniaEdit's pure-data layers. - Editor view (
Terminal.Gui.Editornamespace). AnEditor : Viewsubclass consuming the document layer through a cell-grid rendering pipeline (VisualLineBuilder→CellVisualLine, with pluggableIVisualLineTransformers andIBackgroundRenderers for consumers that want to layer their own visual behaviour on top).
examples/ted is a reference TUI ap showing how to wire Editor into a real window: menubar + editor + status bar, File / Edit / Options menus, find & replace dialog, language + theme selectors, line numbers, fold indicators, word-wrap togle, tab controls, mouse, context menu, save-changes prompt. It's a demo of the View, not a product; its job is to make every feature reachable so you can see what's available before puling the package into your own app.
Run it against any file:
sh dotnet run --project examples/ted - path/to/file.cs dotnet run -project examples/ted -- -read-only path/to/file.cs
For a user-facing editor built on this library, se clet.
Alpha, shipped 2026-05-12 of the develop rolling pre-release stream. See specs/plan.md for the beta roadmap and remaining work ([Obsolete] on TG TextView lands with the beta).
Editor is a View. The standard TG machinery applies:
- Commands + keybindings. All editor actions are
Commandbindings, remappable viaKeyBindingsor ConfigurationManager. - Themes. Colors come from the active
Scheme; switch themes at runtime and the editor reflows. - Layout.
Pos/Dimconstraints;Padding/Border/Marginadornments (the gutter is aViewinsidePadding). - Scrollbars. Set
ViewportSettings = ViewportSettingsFlags.HasScrollBars. - Mouse, clipboard, popovers, dialogs, localization. TG primitives, no editor-side bridging.
- Typing, Backspace / Delete, Enter, with Unicode + grapheme-aware width.
- Caret backed by a
TextAnchor(AnchorMovementType.AfterInsertion); sticky virtual column across vertical moves through short lines. - Selection: any TG-bound "extend" movement command (
Command.LeftExtend,RightEndExtend,PageDownExtend, …) extends the selection;Command.SelectAllselects all; typing or paste replaces selection. - Clipboard:
Command.Cut,Command.Copy,Command.Paste; selection-aware, single-step undo, aborts cut if the clipboard write fails. Uses TG'sIClipboard, so cut/copy/paste interoperates with whatever the OS clipboard contains. - Undo / redo with sane granularity (
Command.Undo,Command.Redo). Compound operations (Enter + auto-indent, replace-all, paste over selection) collapse into one undo step viaDocument.RunUpdate (). - Read-only mode:
Editor.ReadOnly = trueblocks edits, undo/redo, and clipboard mutations while keeping navigation and selection live. - Multi-caret editing: Ctrl+Click to place additional carets; type, Backspace, Delete, or Enter at all of them simultaneously. Escape collapses back to one caret. Every multi-caret operation is a single undo step. See
examples/ted/docs/multi-caret.mdfor details.
IndentationSize,ConvertTabsToSpaces,ShowTabs(renders a glyph in the first cell of each tab); all bindable, all observable from the consumer's UI.Tab/Shift+Tabindent / unindent. With a selection, indents the selected line range.- Indentation-aware Backspace.
- Pluggable
IIndentationStrategy; the default copies the previous line's leading whitespace on Enter (wrapped in a single undo group).
- Cell-grid pipeline:
VisualLineBuilder→CellVisualLine→CellVisualLineElement(TextRunElement,TabElement). - Pluggable
IVisualLineTransformers (syntax highlight, folding markers, …) andIBackgroundRenderers (selection, current line, search hits). Consumers can layer their own transformers on top. - LRU visual-line caches with ranged invalidation from
Document.Changed; incremental max-width tracking avoids the O(N) all-lines walk on every edit. - Word wrap:
Editor.WordWrapsoft-wraps at whitespace boundaries (hard-breaks when none), continuation rows flush at column 0.
FoldingManager+FoldingTransformercollapse / expand regions.- Foldings auto-expand if the caret moves inside one.
BraceFoldingStrategyandXmlFoldingStrategyincluded; consumers can add their own.Command.Collapsetoggles the fold under the caret.FoldingGutterpaints +/− indicators; click to toggle.
Editor.GutterOptionsis a[Flags]enum:LineNumbers | Folding. Combine to show both, or hide both.- Gutter is a real
Viewsubview ofPadding(not painted by hand), so it composes with TG popovers, menus, and focus traversal.
- Pluggable
ISearchStrategy:Normal(string),RegEx,WholeWords, withMatchCase. Construct viaSearchStrategyFactory.Createor assign your own. FindRequested/ReplaceRequestedevents fire so consumers can open whatever Find UI they want (ted opens aDialog-based form; an agent-driven app could open something else, or skip the UI entirely and drive the API directly).- Forward / backward navigation through hits with wrap-around.
SearchHitRendererhighlights every match in the viewport; invalidated automatically on document edits.ReplaceAllis one undo step.
- xshd-driven
DocumentHighlighter+HighlightingColorizer, installed automatically when you setHighlightingDefinition. - Built-in definitions (looked up via
HighlightingManager.Instance): C#, C++, Java, JavaScript, Python, PowerShell, TSQL, VB, JSON, HTML, XML, CSS, Markdown. - Highlight colors compose with the active TG
Scheme; pick a theme via the Configuration Manager and the editor follows. - TextMate grammars are a post-beta follow-up (see
specs/textmate-grammars/spec.md).
These are the defaults. They are Command-bound and remappable via TG's KeyBindings API or ConfigurationManager.
| Command | Default key | Notes |
|---|---|---|
Command.Cut / Copy / Paste |
Ctrl+X / Ctrl+C / Ctrl+V |
TG IClipboard |
Command.Undo / Redo |
Ctrl+Z / Ctrl+Y (also Ctrl+Shift+Z) |
|
Command.SelectAll |
Ctrl+A |
TG base layer |
Command.NewLine |
Enter |
Auto-indents if a strategy is installed |
Command.DeleteCharLeft / DeleteCharRight |
Backspace / Delete |
|
Command.Start / End |
Ctrl+Home / Ctrl+End |
|
Command.LeftStart / RightEnd |
Home / End |
TG base layer |
Command.Up / Down / Left / Right / PageUp / PageDown |
arrows + PgUp/PgDn | TG base layer |
Command.*Extend variants |
Shift+ above | Selection-extending |
Command.Collapse |
Ctrl+M |
Toggle fold under caret |
| Find / FindNext / FindPrev / Replace | Ctrl+F / F3 / Shift+F3 / Ctrl+H |
Ctrl+F / Ctrl+H raise events for the consumer's UI |
| Indent / Unindent | Tab / Shift+Tab |
Range-aware with selection |
| Scroll | mouse wheel (incl. horizontal) | Bubbles up from gutter subviews |
Override at the consumer level with the standard TG pattern:
editor.KeyBindings.Remove (Key.X.WithCtrl);
editor.KeyBindings.Add (Key.W.WithCtrl, Command.Cut);…or ship a Configuration Manager JSON profile that does the same.
Install the package (requires the .NET 10 SDK and Terminal.Gui):
dotnet add package Terminal.Gui.EditorDrop the editor into a Terminal.Gui app. Editor is just a View, so it gets TG's layout, scheme, scrollbars, and Configuration Manager for free:
using Terminal.Gui.App;
using Terminal.Gui.Configuration;
using Terminal.Gui.Document;
using Terminal.Gui.Editor;
using Terminal.Gui.Highlighting;
using Terminal.Gui.ViewBase;
// Pick up themes / keymaps / preferences from the user's TG config.
ConfigurationManager.Enable (ConfigLocations.All);
using IApplication app = Application.Create ();
app.Init ();
Editor editor = new ()
{
// TG constraint-based layout: anchor below a menubar, fill above a status bar.
X = 0,
Y = Pos.Bottom (menu),
Width = Dim.Fill (),
Height = Dim.Fill (statusBar),
// TG scrollbars come free with this flag.
ViewportSettings = ViewportSettingsFlags.HasScrollBars,
GutterOptions = GutterOptions.LineNumbers | GutterOptions.Folding,
ConvertTabsToSpaces = true,
HighlightingDefinition = HighlightingManager.Instance.GetDefinitionByExtension (".cs")
};
editor.Document = new TextDocument (File.ReadAllText ("Program.cs"));
Window win = new () { Title = "My Editor" };
win.Add (menu, editor, statusBar);
app.Run (win);See examples/ted/TedApp.cs for the full version: menus, status bar, find/replace dialog, theme dropdown, all wired through standard TG primitives.
specs/ Planning and design docs (spec-kit)
src/ Terminal.Gui.Editor library (document layer + Editor view)
tests/ xUnit.v3 test projects (correctness + perf smoke)
benchmarks/ BenchmarkDotNet suite + CI baseline
examples/ ted (standalone demo app)
third_party/ AvaloniaEdit fork policy + per-file modification log
Requires the .NET 10 SDK (preview). Solution file is Terminal.Gui.Editor.slnx (XML solution format).
dotnet restore Terminal.Gui.Editor.slnx
dotnet build Terminal.Gui.Editor.slnx
# Correctness suites; run on every push/PR across ubuntu/macos/windows.
dotnet run --project tests/Terminal.Gui.Editor.Tests
dotnet run --project tests/Terminal.Gui.Editor.IntegrationTests
# Perf smoke + BenchmarkDotNet baseline gate; ubuntu-latest only in CI
# (.github/workflows/perf.yml). Run locally in Release config.
dotnet run --project tests/Terminal.Gui.Editor.PerformanceTests -c ReleaseWhy do //, ///, ==, !=, =>, and similar character sequences look wrong when I change styling on just one character?
This is a font ligature issue, not an Editor bug. Many popular programming fonts (Cascadia Code, Fira Code, JetBrains Mono, Iosevka, Hasklig, Victor Mono, etc.) replace common multi-character sequences with single-glyph ligatures. When the Editor applies a different text style (underline, blink, reverse, different color) to just one character in a ligature sequence, the terminal must break the ligature and re-render the characters individually. Some terminals handle this gracefully; others re-render the entire ligature glyph with the new style, making it look like all characters in the sequence are affected.
This impacts any feature that changes the attribute of a single character within a ligature-eligible sequence: multi-caret overlays, selection start/end boundaries, syntax highlighting boundaries that land mid-ligature, search-hit highlighting, etc.
Workarounds:
- Use a non-ligature font. Consolas, Courier New, DejaVu Sans Mono, Ubuntu Mono, and any font without an active ligature table will render correctly.
- Disable ligatures in your terminal. In Windows Terminal, add
"font": { "features": { "liga": 0, "calt": 0 } }to your profile insettings.json. Other terminals have similar settings. - Use a ligature font that handles partial-style changes well. Terminal rendering of partially-styled ligatures varies by terminal emulator and font; some combinations work better than others.
This is a general limitation of cell-based TUI rendering in ligature-aware terminals and is not specific to this library. Terminal.Gui, Neovim, micro, and other TUI editors that render per-cell attributes all exhibit the same behavior.
MIT; see LICENSE.
Portions of the document layer are adapted from AvaloniaEdit (MIT). See third_party/AvaloniaEdit/UPSTREAM.md for the pinned upstream commit and per-file modification log.
