Documentation
¶
Index ¶
- func BuildArgs(template []string, fields map[string]string) []string
- func MarshalLayout(n *LayoutNode) (json.RawMessage, error)
- func SaveInstances(path string, store InstanceStore) error
- type Direction
- type EditorPos
- type EditorSel
- type HighlightMode
- type InstanceStore
- type LayoutNode
- func (n *LayoutNode) CollectRects(ox, oy, w, h int, out *[]PaneRect)
- func (n *LayoutNode) FillPlaceholder(pane *PaneModel) bool
- func (n *LayoutNode) FindLeaf(paneID string) *LayoutNode
- func (n *LayoutNode) FindPaneAt(x, y, ox, oy, w, h int) *PaneModel
- func (n *LayoutNode) FindPaneRectAt(x, y, ox, oy, w, h int) *PaneRect
- func (n *LayoutNode) HasPlaceholder() bool
- func (n *LayoutNode) IsLeaf() bool
- func (n *LayoutNode) Leaves() []*PaneModel
- func (n *LayoutNode) PaneIDs() map[string]bool
- func (n *LayoutNode) PrunePlaceholders() bool
- func (n *LayoutNode) RemoveLeaf(paneID string) bool
- func (n *LayoutNode) SplitLeaf(paneID string, dir SplitDir) *LayoutNode
- type Model
- type NotesEditor
- func (n *NotesEditor) ApproxBytes() uint64
- func (n *NotesEditor) BeginSelection(row, col int)
- func (n *NotesEditor) ClearSelection()
- func (n *NotesEditor) Close() error
- func (n *NotesEditor) Content() string
- func (n *NotesEditor) Dirty() bool
- func (n *NotesEditor) ExtendSelection(row, col int)
- func (n *NotesEditor) ExtractSelection() string
- func (n *NotesEditor) HandleKey(key string) (notesAction, tea.Cmd)
- func (n *NotesEditor) HandlePaste(text string)
- func (n *NotesEditor) HasSelection() bool
- func (n *NotesEditor) MaybeAutoSave()
- func (n *NotesEditor) PaneID() string
- func (n *NotesEditor) Resize(w, h int)
- func (n *NotesEditor) Save() error
- func (n *NotesEditor) SaveErr() string
- func (n *NotesEditor) SetCursor(row, col int)
- func (n *NotesEditor) View(width, height int, focused bool) string
- type NotificationCenter
- func (nc *NotificationCenter) AddEvent(e ipc.PaneEventPayload)
- func (nc *NotificationCenter) Count() int
- func (nc *NotificationCenter) DismissAll()
- func (nc *NotificationCenter) DismissSelected() string
- func (nc *NotificationCenter) HandleKey(key string) (action, eventID, paneID string)
- func (nc *NotificationCenter) SelectedEvent() *ipc.PaneEventPayload
- func (nc *NotificationCenter) View(height int) string
- type PaneInfo
- type PaneModel
- func (p *PaneModel) AppendOutput(data []byte)
- func (p *PaneModel) Dispose()
- func (p *PaneModel) ResetScroll()
- func (p *PaneModel) ResetVT()
- func (p *PaneModel) ResizeVT(cols, rows int)
- func (p *PaneModel) ScrollDown(lines int)
- func (p *PaneModel) ScrollToRelY(relY, innerH int)
- func (p *PaneModel) ScrollUp(lines int)
- func (p *PaneModel) View() string
- type PaneOutputMsg
- type PaneRect
- type PaneRef
- type PluginErrorMsg
- type SavedInstance
- type Selection
- type SelectionAnchor
- type SerializedNode
- type SplitDir
- type TabInfo
- type TabModel
- func (t *TabModel) ActivePaneModel() *PaneModel
- func (t *TabModel) ExitFocus()
- func (t *TabModel) FocusMode() bool
- func (t *TabModel) Leaves() []*PaneModel
- func (t *TabModel) NavigateDirection(dir Direction) bool
- func (t *TabModel) NextPane()
- func (t *TabModel) PrevPane()
- func (t *TabModel) RemovePane(paneID string)
- func (t *TabModel) Resize(w, h int)
- func (t *TabModel) SplitAtPane(paneID string, dir SplitDir) *LayoutNode
- func (t *TabModel) ToggleFocus()
- func (t *TabModel) View() string
- type TextEditor
- func (e *TextEditor) ApproxBytes() uint64
- func (e *TextEditor) Content() string
- func (e *TextEditor) GutterWidth() int
- func (e *TextEditor) HandleKey(key string) (saved, closed bool, cmd tea.Cmd)
- func (e *TextEditor) InsertMultiLine(text string)
- func (e *TextEditor) Render() string
- func (e *TextEditor) Save() error
- type WorkspaceStateMsg
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
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.
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 ¶
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 ¶
IsEmpty returns true if the selection has zero width (anchor == cursor).
func (*EditorSel) Normalized ¶
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 (Model) ConfigChanged ¶
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) WindowSize ¶
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 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 (*PaneModel) AppendOutput ¶
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) ScrollDown ¶
func (*PaneModel) ScrollToRelY ¶ added in v1.15.0
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).
type PaneOutputMsg ¶
Messages from daemon
type PluginErrorMsg ¶
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 ¶
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 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 (*TabModel) ActivePaneModel ¶
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) Leaves ¶ added in v1.18.6
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
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:
- smallest gap along the direction axis,
- largest perpendicular overlap,
- 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 ¶
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) 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).
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.