tui

package
v1.31.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2026 License: MIT Imports: 40 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildArgs

func BuildArgs(template []string, fields map[string]string) []string

BuildArgs expands {placeholder} tokens in an arg template using field values.

func MarshalLayout

func MarshalLayout(n *LayoutNode) (json.RawMessage, error)

MarshalLayout serializes a LayoutNode tree to JSON.

func SaveInstances

func SaveInstances(path string, store InstanceStore) error

SaveInstances writes the instance store to a JSON file atomically.

Types

type Direction added in v1.3.0

type Direction int

Direction identifies one of the four spatial-navigation directions used by NavigateDirection.

const (
	DirLeft Direction = iota
	DirRight
	DirUp
	DirDown
)

type EditorPos

type EditorPos struct {
	Row int // 0-based line index in Lines[]
	Col int // 0-based rune column
}

EditorPos identifies a position in the editor's rune-indexed line space.

type EditorSel

type EditorSel struct {
	Anchor EditorPos // where selection started (fixed)
	Cursor EditorPos // where selection extends to (moves with keys)
}

EditorSel tracks a text selection within the TextEditor.

func (*EditorSel) ColRange

func (s *EditorSel) ColRange(row, lineRuneLen int) (startCol, endCol int)

ColRange returns the selected column range [startCol, endCol) for a given row. endCol is exclusive (one past the last selected rune) for easy slicing. Returns (-1, -1) if the row is not in the selection.

func (*EditorSel) IsEmpty

func (s *EditorSel) IsEmpty() bool

IsEmpty returns true if the selection has zero width (anchor == cursor).

func (*EditorSel) Normalized

func (s *EditorSel) Normalized() (start, end EditorPos)

Normalized returns start/end ordered top-to-bottom, left-to-right.

type HighlightMode

type HighlightMode int

HighlightMode selects which syntax highlighter the editor renders with.

const (
	// HighlightTOML applies TOML keyword/comment colouring (default — used by
	// the TOML editor accessible via F1 → Plugins).
	HighlightTOML HighlightMode = iota
	// HighlightPlain disables syntax colouring. Used by pane notes.
	HighlightPlain
)

type InstanceStore

type InstanceStore map[string][]SavedInstance

InstanceStore holds saved instances keyed by plugin name.

func LoadInstances

func LoadInstances(path string) InstanceStore

LoadInstances reads the instance store from a JSON file. Returns an empty store if the file doesn't exist.

type LayoutNode

type LayoutNode struct {
	Pane  *PaneModel // non-nil for leaf nodes
	Split SplitDir   // meaningful only for internal nodes
	Ratio float64    // fraction allocated to Left child (0.0–1.0)
	Left  *LayoutNode
	Right *LayoutNode
}

LayoutNode is a binary tree node for pane layout. Leaf nodes hold a *PaneModel; internal nodes hold two children and a split direction.

func DeserializeLayout

func DeserializeLayout(s *SerializedNode, panes map[string]*PaneModel) *LayoutNode

DeserializeLayout reconstructs a LayoutNode tree from a SerializedNode tree. Panes are looked up by ID from the provided map. Missing panes become placeholder nodes (nil Pane) that should be pruned by the caller.

func NewLeaf

func NewLeaf(pane *PaneModel) *LayoutNode

NewLeaf creates a leaf node wrapping a pane.

func (*LayoutNode) CollectRects added in v1.3.0

func (n *LayoutNode) CollectRects(ox, oy, w, h int, out *[]PaneRect)

CollectRects walks the layout tree and appends a PaneRect for every leaf. Used by spatial pane navigation (TabModel.NavigateDirection) to pick the closest neighbor in a given direction without re-implementing the layout arithmetic.

func (*LayoutNode) FillPlaceholder

func (n *LayoutNode) FillPlaceholder(pane *PaneModel) bool

FillPlaceholder finds the first placeholder leaf (nil Pane) and fills it. Returns true if a placeholder was found and filled.

func (*LayoutNode) FindLeaf

func (n *LayoutNode) FindLeaf(paneID string) *LayoutNode

FindLeaf returns the leaf node with the given pane ID, or nil.

func (*LayoutNode) FindPaneAt

func (n *LayoutNode) FindPaneAt(x, y, ox, oy, w, h int) *PaneModel

FindPaneAt returns the pane at screen coordinates (x, y), given the node's origin (ox, oy) and dimensions (w, h). Mirrors resizeNode() split logic.

func (*LayoutNode) FindPaneRectAt

func (n *LayoutNode) FindPaneRectAt(x, y, ox, oy, w, h int) *PaneRect

FindPaneRectAt returns the pane and its screen rectangle at coordinates (x, y).

func (*LayoutNode) HasPlaceholder

func (n *LayoutNode) HasPlaceholder() bool

HasPlaceholder returns true if the tree contains a leaf with nil Pane.

func (*LayoutNode) IsLeaf

func (n *LayoutNode) IsLeaf() bool

IsLeaf returns true if this node holds a pane (no children).

func (*LayoutNode) Leaves

func (n *LayoutNode) Leaves() []*PaneModel

Leaves returns all panes via in-order traversal (left-to-right, top-to-bottom).

func (*LayoutNode) PaneIDs

func (n *LayoutNode) PaneIDs() map[string]bool

PaneIDs returns the set of all pane IDs in the tree.

func (*LayoutNode) PrunePlaceholders

func (n *LayoutNode) PrunePlaceholders() bool

PrunePlaceholders removes any placeholder leaves (nil Pane) by promoting siblings. Returns true if the tree was modified.

func (*LayoutNode) RemoveLeaf

func (n *LayoutNode) RemoveLeaf(paneID string) bool

RemoveLeaf removes the leaf with paneID from the tree by promoting the sibling to the parent's position. Returns false if paneID is the sole root leaf or is not found.

func (*LayoutNode) SplitLeaf

func (n *LayoutNode) SplitLeaf(paneID string, dir SplitDir) *LayoutNode

SplitLeaf replaces the leaf with paneID with an internal node. The existing pane becomes the Left child; a placeholder leaf (nil Pane) is created as the Right child and returned so the caller can fill it. Returns nil if paneID is not found.

type Model

type Model struct {
	// contains filtered or unexported fields
}

func NewModel

func NewModel(client *ipc.Client, cfg config.Config, version string, registry *plugin.Registry, stalePlugins []plugin.StalePlugin) Model

func (Model) Config

func (m Model) Config() config.Config

Config returns the current config (may be modified by user actions).

func (Model) ConfigChanged

func (m Model) ConfigChanged() bool

ConfigChanged reports whether the config was modified and needs saving.

func (Model) FlushNotes

func (m Model) FlushNotes()

FlushNotes writes any pending notes edits to disk. Safe to call when notes mode is inactive (no-op).

Precondition: must be invoked AFTER tea.Program.Run has returned, when the Update goroutine is no longer pumping events. Calling concurrently with the Update loop is unsafe — the editor is mutable shared state.

func (Model) Init

func (m Model) Init() tea.Cmd

func (Model) Update

func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd)

func (Model) View

func (m Model) View() tea.View

func (Model) WindowSize

func (m Model) WindowSize() (width, height int)

WindowSize returns the last known window dimensions for persistence.

type NotesEditor

type NotesEditor struct {
	// contains filtered or unexported fields
}

NotesEditor is a plain-text notes editor bound to a pane. It wraps the generic TextEditor and provides its own save path (bypassing TextEditor's TOML validation) and a debounced auto-save policy.

func NewNotesEditor

func NewNotesEditor(notesDir, paneID, paneName string, viewW, viewH int) (*NotesEditor, error)

NewNotesEditor loads the notes file for paneID (creating the editor even when the file does not yet exist) and returns an editor positioned at the top of the document.

func (*NotesEditor) ApproxBytes added in v1.9.0

func (n *NotesEditor) ApproxBytes() uint64

ApproxBytes returns a lower-bound in-memory byte count for the editor buffer. Used by the Memory dialog to attribute notes memory per pane.

func (*NotesEditor) BeginSelection

func (n *NotesEditor) BeginSelection(row, col int)

BeginSelection starts a fresh selection anchored at (row, col) and places the cursor there. Subsequent ExtendSelection calls grow the selection from this anchor.

func (*NotesEditor) ClearSelection

func (n *NotesEditor) ClearSelection()

ClearSelection discards any active selection without moving the cursor.

func (*NotesEditor) Close

func (n *NotesEditor) Close() error

Close flushes pending unsaved changes to disk and returns any save error.

func (*NotesEditor) Content

func (n *NotesEditor) Content() string

Content returns the current editor buffer as a single string.

func (*NotesEditor) Dirty

func (n *NotesEditor) Dirty() bool

Dirty reports whether there are unsaved edits.

func (*NotesEditor) ExtendSelection

func (n *NotesEditor) ExtendSelection(row, col int)

ExtendSelection moves the selection's cursor end to (row, col), keeping the anchor fixed. Used during mouse drag.

func (*NotesEditor) ExtractSelection

func (n *NotesEditor) ExtractSelection() string

ExtractSelection returns the currently selected editor text, or "" if no selection is active.

func (*NotesEditor) HandleKey

func (n *NotesEditor) HandleKey(key string) (notesAction, tea.Cmd)

HandleKey processes a key press. Returns:

  • action: what the outer model should do (`notesActionNone` to keep editing, `notesActionExit` to leave notes mode)
  • cmd: an optional tea command (e.g., for async paste)

ctrl+s and esc are intercepted before being passed to the TextEditor so the editor's TOML-specific Save() and its close-on-esc behaviour do not fire.

func (*NotesEditor) HandlePaste

func (n *NotesEditor) HandlePaste(text string)

HandlePaste applies pasted content at the cursor position.

func (*NotesEditor) HasSelection

func (n *NotesEditor) HasSelection() bool

HasSelection reports whether a non-empty selection is currently active in the notes editor. Used by mouse handlers to decide whether a right-click should copy editor text or fall through to the pane path.

func (*NotesEditor) MaybeAutoSave

func (n *NotesEditor) MaybeAutoSave()

MaybeAutoSave saves when the debounce window has elapsed since the last edit. No-op if the editor is clean or the user is still actively editing.

func (*NotesEditor) PaneID

func (n *NotesEditor) PaneID() string

PaneID returns the pane this editor is bound to.

func (*NotesEditor) Resize

func (n *NotesEditor) Resize(w, h int)

Resize updates the editor's viewport dimensions.

func (*NotesEditor) Save

func (n *NotesEditor) Save() error

Save writes the current content to disk and clears the dirty flag on both the wrapper and the inner TextEditor. Safe to call when not dirty — it is a no-op in that case. Ensures the saved file ends with a newline so it behaves like a normal POSIX text file.

func (*NotesEditor) SaveErr

func (n *NotesEditor) SaveErr() string

SaveErr returns the most recent save error, if any.

func (*NotesEditor) SetCursor

func (n *NotesEditor) SetCursor(row, col int)

SetCursor moves the editor's cursor to (row, col) in the document and clears any active selection. Used by mouse-driven cursor positioning. Coordinates are clamped to valid line/column bounds.

func (*NotesEditor) View

func (n *NotesEditor) View(width, height int, focused bool) string

View renders the notes editor inside a bordered box of the given size. The box includes a header with the pane name + dirty indicator and a footer with quick-reference hints. The focused parameter controls border colour: bright when the editor has keyboard focus, dim when the bound pane has focus (set via Tab in the surrounding model).

type NotificationCenter

type NotificationCenter struct {
	// contains filtered or unexported fields
}

NotificationCenter manages the notification sidebar state.

func NewNotificationCenter

func NewNotificationCenter(width, maxEvents int) *NotificationCenter

NewNotificationCenter creates a notification center with the given sidebar width and max events.

func (*NotificationCenter) AddEvent

func (nc *NotificationCenter) AddEvent(e ipc.PaneEventPayload)

AddEvent prepends an event. When an event with the same ID is already queued, the entry is updated in place AND moved to the front — this is the echo of the daemon's eventQueue.Push aggregation, where a repeat (PaneID, Title) event reuses the prior event's ID and bumps Data["count"]. Without the move-to-front the sidebar would silently drop bumps and the user would never see the ×N count grow.

Cursor invariant: the cursor follows the LOGICAL event the user is on, not the index. If the move-to-front shifts other events past the cursor's position, we rewrite cursor to point at the event with the same ID it had before — so a user staring at "claude-code (×3)" does not silently jump to a different card when "claude-code (×4)" arrives.

func (*NotificationCenter) Count

func (nc *NotificationCenter) Count() int

Count returns the number of pending events.

func (*NotificationCenter) DismissAll

func (nc *NotificationCenter) DismissAll()

DismissAll removes all events.

func (*NotificationCenter) DismissSelected

func (nc *NotificationCenter) DismissSelected() string

DismissSelected removes the selected event and returns its ID.

func (*NotificationCenter) HandleKey

func (nc *NotificationCenter) HandleKey(key string) (action, eventID, paneID string)

HandleKey processes a key press when the sidebar is focused. Returns: action ("navigate", "dismiss", "dismiss_all", "unfocus", "none"), eventID (for dismiss), paneID (for navigate).

func (*NotificationCenter) SelectedEvent

func (nc *NotificationCenter) SelectedEvent() *ipc.PaneEventPayload

SelectedEvent returns the currently selected event, or nil.

func (*NotificationCenter) View

func (nc *NotificationCenter) View(height int) string

View renders the sidebar at the given height.

type PaneInfo

type PaneInfo struct {
	ID           string
	TabID        string
	CWD          string
	Name         string
	Type         string
	Muted        bool
	Eager        bool
	Overlay      bool
	Pending      bool // deferred restore — not yet lazy-spawned
	SessionID    string
	HistoryLines int
}

type PaneModel

type PaneModel struct {
	ID    string
	Type  string // plugin type ("terminal", "claude-code", etc.)
	Name  string // user-given name (empty if not set)
	CWD   string // current working directory from daemon
	Muted bool   // notification mute (daemon-authoritative; mirrored here for border rendering)
	Eager bool   // eager-restore flag (daemon-authoritative; mirrored for the tab marker)

	Width  int
	Height int
	Active bool

	Pending      bool   // deferred restore — not yet lazy-spawned (daemon-authoritative)
	SessionID    string // tracked session id (daemon-authoritative; restore checklist)
	HistoryLines int    // ghost-buffer line count (daemon-authoritative; restore checklist)
	// contains filtered or unexported fields
}

func NewPaneModel

func NewPaneModel(id string, bufSize int) *PaneModel

func (*PaneModel) AppendOutput

func (p *PaneModel) AppendOutput(data []byte)

func (*PaneModel) Dispose added in v1.18.6

func (p *PaneModel) Dispose()

Dispose closes the VT emulator, stopping its drainVTResponses goroutine and releasing the scrollback grid. Must be called for every PaneModel removed from the layout tree — without it each closed pane leaks a parked goroutine plus up to a 10,000-line scrollback. The PaneModel must not be rendered or written to afterwards. Idempotent: a second call is a no-op.

func (*PaneModel) ResetScroll

func (p *PaneModel) ResetScroll()

func (*PaneModel) ResetVT

func (p *PaneModel) ResetVT()

ResetVT creates a fresh VT emulator at the current dimensions, clearing ghost buffer state so live output starts with a clean cursor position.

func (*PaneModel) ResizeVT

func (p *PaneModel) ResizeVT(cols, rows int)

func (*PaneModel) ScrollDown

func (p *PaneModel) ScrollDown(lines int)

func (*PaneModel) ScrollToRelY added in v1.15.0

func (p *PaneModel) ScrollToRelY(relY, innerH int)

ScrollToRelY positions the scrollback so that the scrollbar thumb's TOP row lands at relY (relative to the content area, 0..innerH-1). Inverse of the thumb-position formula in renderScrollback — a click at row R puts the thumb's top at R, matching standard GUI scrollbar UX.

CONTRACT (must stay in sync with renderScrollback):

renderScrollback:  thumbSize = max(1, h*h/totalLines)
                   thumbPos  = viewStart * (h - thumbSize) / scrollRange
                              where scrollRange = totalLines - h = sbLen
this fn (inverse): viewStart = relY * sbLen / (innerH - thumbSize)

Drift between the two is a silent UX bug. The integer math is safe on every supported quil platform (Go int is 64-bit on amd64 and arm64); even a million-line scrollback with a thousand-row pane multiplies to well under 2^63.

Out-of-range relY clamps to the valid scroll extent. Returns silently (no-op) when there's no scrollback to scroll into or the visible area is large enough to hold every line (no scrollable range).

func (*PaneModel) ScrollUp

func (p *PaneModel) ScrollUp(lines int)

func (*PaneModel) View

func (p *PaneModel) View() string

type PaneOutputMsg

type PaneOutputMsg struct {
	PaneID string
	Data   []byte
	Ghost  bool
}

Messages from daemon

type PaneRect

type PaneRect struct {
	Pane         *PaneModel
	OX, OY, W, H int
}

PaneRect holds a pane and its screen-space rectangle.

type PaneRef

type PaneRef struct {
	TabIndex int
	PaneID   string
}

PaneRef stores a pane location for navigation history.

type PluginErrorMsg

type PluginErrorMsg struct {
	PaneID  string
	Title   string
	Message string
}

PluginErrorMsg is received when the daemon detects a plugin error pattern.

type SavedInstance

type SavedInstance struct {
	ID          string            `json:"id"`
	Name        string            `json:"name"`
	Fields      map[string]string `json:"fields"`
	Description string            `json:"description,omitempty"`
}

SavedInstance is a user-created instance of a plugin (e.g., an SSH connection).

func (SavedInstance) DisplayAddr

func (si SavedInstance) DisplayAddr() string

DisplayAddr formats a saved instance's fields into a short address string. Tries user@host:port, falls back to showing the first non-name, non-description field.

type Selection

type Selection struct {
	PaneID string
	Anchor SelectionAnchor // where selection started (fixed)
	Cursor SelectionAnchor // where selection extends to (moves with keys/mouse)
}

Selection tracks a text selection within a single pane.

func (*Selection) ColRange

func (s *Selection) ColRange(absLine, width int) (startCol, endCol int)

ColRange returns the selected column range for a given absolute line. Returns (-1, -1) if the line is not in the selection.

func (*Selection) Normalized

func (s *Selection) Normalized() (start, end SelectionAnchor)

Normalized returns start/end ordered top-to-bottom, left-to-right.

type SelectionAnchor

type SelectionAnchor struct {
	Col  int // 0-based column within pane content (excludes border)
	Line int // absolute line: 0..sbLen-1 = scrollback, sbLen..sbLen+h-1 = screen
}

SelectionAnchor identifies a cell in the combined scrollback+screen space.

type SerializedNode

type SerializedNode struct {
	PaneID string          `json:"pane_id,omitempty"`
	Split  *SplitDir       `json:"split,omitempty"`
	Ratio  float64         `json:"ratio,omitempty"`
	Left   *SerializedNode `json:"left,omitempty"`
	Right  *SerializedNode `json:"right,omitempty"`
}

SerializedNode is a JSON-friendly representation of a LayoutNode tree. Leaf nodes have PaneID set; internal nodes have Split, Ratio, Left, Right.

func SerializeLayout

func SerializeLayout(n *LayoutNode) *SerializedNode

SerializeLayout converts a LayoutNode tree into a SerializedNode tree.

func UnmarshalLayout

func UnmarshalLayout(data json.RawMessage) (*SerializedNode, error)

UnmarshalLayout deserializes JSON into a SerializedNode tree.

type SplitDir

type SplitDir int

SplitDir determines how child nodes are arranged.

const (
	SplitHorizontal SplitDir = iota // children side-by-side (left | right)
	SplitVertical                   // children stacked (top / bottom)
)

type TabInfo

type TabInfo struct {
	ID     string
	Name   string
	Color  string
	Panes  []string
	Layout json.RawMessage
}

type TabModel

type TabModel struct {
	ID         string
	Name       string
	Color      string
	Root       *LayoutNode // binary split tree (nil = empty tab)
	ActivePane string      // pane ID of the active pane
	Width      int
	Height     int
	// contains filtered or unexported fields
}

TabModel represents a single tab containing a tree of panes.

func NewTabModel

func NewTabModel(id, name string) *TabModel

func (*TabModel) ActivePaneModel

func (t *TabModel) ActivePaneModel() *PaneModel

ActivePaneModel returns the currently active pane, or nil. When the overlay is visible it acts as the single active pane — all input and scroll events route through this choke point. Unlike treeActivePaneModel, a stale ActivePane is REPAIRED here: the returned fallback leaf is adopted (t.ActivePane rewritten, Active flag set).

func (*TabModel) ExitFocus

func (t *TabModel) ExitFocus()

ExitFocus exits focus mode if active.

func (*TabModel) FocusMode

func (t *TabModel) FocusMode() bool

FocusMode returns whether focus mode is active.

func (*TabModel) Leaves added in v1.18.6

func (t *TabModel) Leaves() []*PaneModel

Leaves returns the tab's panes in layout order, cached until the tree mutates. Every method that mutates the tree (or assigns Root) must call invalidateLeaves.

func (*TabModel) NavigateDirection added in v1.3.0

func (t *TabModel) NavigateDirection(dir Direction) bool

NavigateDirection moves focus to the closest pane in the given direction, if any exists. Returns true when focus changed. Semantics mirror tmux's `select-pane -L/R/U/D` and vim's window-motion commands: candidates must lie strictly in the half-plane on the target side and must overlap the active pane's perpendicular range. Tie-breakers are applied in order:

  1. smallest gap along the direction axis,
  2. largest perpendicular overlap,
  3. smallest perpendicular center-to-center distance (tmux/vim parity — when two equally-close candidates have the same overlap, the one whose center is closer to the active pane's center on the perpendicular axis wins, matching the user's muscle memory).

Does nothing in focus mode or when the tab is empty.

func (*TabModel) NextPane

func (t *TabModel) NextPane()

NextPane advances focus to the next pane (in-order traversal order).

func (*TabModel) PrevPane

func (t *TabModel) PrevPane()

PrevPane moves focus to the previous pane.

func (*TabModel) RemovePane

func (t *TabModel) RemovePane(paneID string)

RemovePane removes the pane with the given ID, promoting its sibling. If the removed pane was active, focus moves to the first leaf.

func (*TabModel) Resize

func (t *TabModel) Resize(w, h int)

Resize recomputes dimensions for the entire layout tree.

func (*TabModel) SplitAtPane

func (t *TabModel) SplitAtPane(paneID string, dir SplitDir) *LayoutNode

SplitAtPane splits the pane with the given ID, inserting a placeholder for the new pane. Returns the placeholder node (caller fills Pane later).

func (*TabModel) ToggleFocus

func (t *TabModel) ToggleFocus()

ToggleFocus toggles pane focus mode on/off. No-op on single-pane tabs (already fills the tab).

func (*TabModel) View

func (t *TabModel) View() string

View renders the entire pane layout.

type TextEditor

type TextEditor struct {
	Lines      []string
	CursorRow  int // rune-based row
	CursorCol  int // rune-based column
	ScrollTop  int
	ViewHeight int
	ViewWidth  int
	FilePath   string
	Dirty      bool
	SaveErr    string
	Sel        *EditorSel // active selection (nil = none)
	// Highlight selects the syntax highlighter. Defaults to HighlightTOML.
	Highlight HighlightMode
	// ReadOnly disables every key path that would mutate the document
	// (typing, paste, cut, save, enter/backspace/delete, tab/space). Cursor
	// movement, selection, and clipboard COPY (Enter on a selection,
	// right-click) still work. Used by the F1 → log viewers so users can
	// scroll and copy log content without accidentally overwriting the
	// underlying file with Ctrl+S.
	ReadOnly bool
	// PageSize is the cursor jump distance for Alt+Up / Alt+Down. 0 falls
	// back to a built-in default (see editorDefaultPageSize). Used by the
	// log viewer to navigate large files quickly without holding Down.
	PageSize int
	// SoftWrap makes long logical lines wrap onto the next visual row
	// instead of being hard-truncated with a trailing "~". When enabled,
	// ScrollTop is a visual-row index and cursor Up/Down/Home/End work on
	// visual rows. Paragraph jumps (ctrl+up/down) and PageSize jumps
	// (alt+up/down) remain logical-line based. Only NotesEditor opts in
	// — the TOML plugin editor and F1 log viewer keep truncation.
	SoftWrap bool
}

TextEditor is a minimal multi-line text editor with optional syntax highlighting.

func NewTextEditor

func NewTextEditor(content, filePath string, viewW, viewH int) *TextEditor

NewTextEditor creates an editor from file content.

func (*TextEditor) ApproxBytes added in v1.9.0

func (e *TextEditor) ApproxBytes() uint64

ApproxBytes returns a lower-bound estimate of the editor's in-memory size. Sums UTF-8 byte lengths of all lines plus one newline byte per line boundary. Does not account for Go slice overhead or unused capacity. Used by the Memory dialog for ranking; precision is not important.

func (*TextEditor) Content

func (e *TextEditor) Content() string

Content returns raw text (no ANSI codes) for saving.

func (*TextEditor) GutterWidth

func (e *TextEditor) GutterWidth() int

GutterWidth returns the visible width (in columns) of the line-number gutter for the current document. It is `max(3, digits(len(Lines))) + 1` — three digits minimum plus one trailing space. Both Render() and the mouse-to-document coordinate helper (notesEditorPosAt) use this so the body content's left edge stays in sync with what the user sees.

func (*TextEditor) HandleKey

func (e *TextEditor) HandleKey(key string) (saved, closed bool, cmd tea.Cmd)

func (*TextEditor) InsertMultiLine

func (e *TextEditor) InsertMultiLine(text string)

InsertMultiLine inserts text that may contain newlines at the cursor position. If a selection is active, it is deleted first. No-op when ReadOnly.

func (*TextEditor) Render

func (e *TextEditor) Render() string

func (*TextEditor) Save

func (e *TextEditor) Save() error

Save validates TOML syntax and writes to disk atomically.

type WorkspaceStateMsg

type WorkspaceStateMsg struct {
	ActiveTab string
	Tabs      []TabInfo
	Panes     []PaneInfo
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL