editor

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jan 22, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
const FavoritesEntryName = "★ Favorites"

FavoritesEntryName is the display name for the favorites virtual directory

Variables

View Source
var AsciiBoxChars = BoxChars{
	TopLeft:     "+",
	TopRight:    "+",
	BottomLeft:  "+",
	BottomRight: "+",
	Horizontal:  "-",
	Vertical:    "|",
	TeeLeft:     "+",
	TeeRight:    "+",
	Lock:        "*",
	Ellipsis:    "...",
}

AsciiBoxChars provides ASCII fallback characters

View Source
var FestivusQuotes = []string{
	"A Festivus for the rest of us!",
	"I got a lot of problems with you people!",
	"I find tinsel distracting.",
	"It's a Festivus miracle!",
	"Serenity now!",
	"The tradition of Festivus begins with the airing of grievances.",
	"Until you pin me, George, Festivus is not over!",
	"No bagel, no bagel, no bagel!",
	"I find your belief system fascinating.",
	"This new holiday is scratching me right where I itch.",
	"Weren't there feats of strength that ended up with you crying?",
	"Instead there's a pole. Requires no decoration.",
	"We don't care and it shows.",
	"You couldn't smooth a silk sheet with a hot babe in it.",
	"Another piece of the puzzle falls into place.",
	"Instead of a tree didn't your father put up an aluminum pole?",
	"Happy Festivus.",
	"What's Festivus?",
	"It's a stupid holiday my father invented. It doesn't exist.",
	"Happy Festivus, Georgie.",
	"Frank invented a holiday? He's so prolific.",
	"As I rained blows upon him, I realized there had to be another way.",
	"But out of that a new holiday was born.",
	"Festivus is back!",
	"I'll get the pole out of the crawl space.",
	"What is that? Is that the pole?",
	"Festivus is your heritage. It's part of who you are.",
	"That's why I hate it.",
	"You're just weak. You're weak.",
	"It's time for the Festivus feats of strength.",
	"I don't really celebrate Christmas. I celebrate Festivus.",
	"I was afraid that I would be persecuted for my beliefs.",
	"It's made from aluminum. Very high strength to weight ratio.",
	"Not the feats of strength!",
	"Oh, please. Somebody stop this.",
	"Stop crying and fight your father.",
	"I give! I give!",
	"This is the best Festivus ever!",
	"When George was growing up his father hated all the commercial religious aspects of Christmas, so he made up his own holiday.",
	"At the Festivus dinner you gather your family around and tell them all the ways they have disappointed you over the past year.",
	"George, you're forgetting how much Festivus has meant to us all.",
}

FestivusQuotes are displayed randomly in the About dialog. Feel free to add more Seinfeld Festivus quotes!

View Source
var UnicodeBoxChars = BoxChars{
	TopLeft:     "┌",
	TopRight:    "┐",
	BottomLeft:  "└",
	BottomRight: "┘",
	Horizontal:  "─",
	Vertical:    "│",
	TeeLeft:     "├",
	TeeRight:    "┤",
	Lock:        "🔒",
	Ellipsis:    "…",
}

UnicodeBoxChars provides Unicode box drawing characters

Functions

This section is empty.

Types

type BoxChars

type BoxChars struct {
	TopLeft     string
	TopRight    string
	BottomLeft  string
	BottomRight string
	Horizontal  string
	Vertical    string
	TeeLeft     string
	TeeRight    string
	Lock        string
	Ellipsis    string
}

BoxChars holds characters used for drawing dialog boxes

type Buffer

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

Buffer implements a gap buffer for efficient text editing. The gap is always at the cursor position, making inserts/deletes O(1) amortized.

func NewBuffer

func NewBuffer() *Buffer

NewBuffer creates a new empty buffer.

func NewBufferFromString

func NewBufferFromString(s string) *Buffer

NewBufferFromString creates a buffer initialized with the given text.

func (*Buffer) ByteAt

func (b *Buffer) ByteAt(pos int) byte

ByteAt returns the byte at the given logical position.

func (*Buffer) CursorPosition

func (b *Buffer) CursorPosition() int

CursorPosition returns the current cursor position (byte offset).

func (*Buffer) DeleteAfter

func (b *Buffer) DeleteAfter(n int) string

DeleteAfter deletes n bytes after the cursor.

func (*Buffer) DeleteBefore

func (b *Buffer) DeleteBefore(n int) string

DeleteBefore deletes n bytes before the cursor.

func (*Buffer) DeleteRuneAfter

func (b *Buffer) DeleteRuneAfter() string

DeleteRuneAfter deletes the rune immediately after the cursor.

func (*Buffer) DeleteRuneBefore

func (b *Buffer) DeleteRuneBefore() string

DeleteRuneBefore deletes the rune immediately before the cursor.

func (*Buffer) Insert

func (b *Buffer) Insert(s string)

Insert inserts text at the current cursor position.

func (*Buffer) InsertRune

func (b *Buffer) InsertRune(r rune)

InsertRune inserts a single rune at the current cursor position.

func (*Buffer) Length

func (b *Buffer) Length() int

Length returns the total number of bytes in the buffer (excluding the gap).

func (*Buffer) LineColToPosition

func (b *Buffer) LineColToPosition(line, col int) int

LineColToPosition converts line and column (both 0-indexed) to byte offset.

func (*Buffer) LineCount

func (b *Buffer) LineCount() int

LineCount returns the number of lines in the buffer.

func (*Buffer) LineEndOffset

func (b *Buffer) LineEndOffset(line int) int

LineEndOffset returns the byte offset of the end of the given line (0-indexed). This is the position just before the newline, or the end of the buffer.

func (*Buffer) LineStartOffset

func (b *Buffer) LineStartOffset(line int) int

LineStartOffset returns the byte offset of the start of the given line (0-indexed).

func (*Buffer) Lines

func (b *Buffer) Lines() []string

Lines returns all lines in the buffer.

func (*Buffer) MoveCursor

func (b *Buffer) MoveCursor(pos int)

MoveCursor moves the gap to the specified byte position.

func (*Buffer) PositionToLineCol

func (b *Buffer) PositionToLineCol(pos int) (line, col int)

PositionToLineCol converts a byte offset to line and column (both 0-indexed).

func (*Buffer) Replace

func (b *Buffer) Replace(start, end int, text string)

Replace replaces text between start and end positions with new text.

func (*Buffer) RuneAt

func (b *Buffer) RuneAt(pos int) (rune, int)

RuneAt returns the rune at the given byte position.

func (*Buffer) RuneCount

func (b *Buffer) RuneCount() int

RuneCount returns the total number of UTF-8 characters in the buffer.

func (*Buffer) String

func (b *Buffer) String() string

String returns the entire buffer contents as a string.

func (*Buffer) Substring

func (b *Buffer) Substring(start, end int) string

Substring returns a portion of the buffer from byte positions start to end.

func (*Buffer) WordCount

func (b *Buffer) WordCount() int

WordCount returns the number of words in the buffer (unicode-aware). Words are sequences of non-whitespace characters separated by whitespace.

type Cursor

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

Cursor manages the cursor position within a buffer.

func NewCursor

func NewCursor(buf *Buffer) *Cursor

NewCursor creates a new cursor for the given buffer.

func (*Cursor) ByteOffset

func (c *Cursor) ByteOffset() int

ByteOffset returns the current cursor position as a byte offset.

func (*Cursor) Col

func (c *Cursor) Col() int

Col returns the current column number (0-indexed).

func (*Cursor) Line

func (c *Cursor) Line() int

Line returns the current line number (0-indexed).

func (*Cursor) MoveDown

func (c *Cursor) MoveDown() bool

MoveDown moves the cursor down one line, trying to maintain the column.

func (*Cursor) MoveLeft

func (c *Cursor) MoveLeft() bool

MoveLeft moves the cursor left by one character (rune).

func (*Cursor) MoveRight

func (c *Cursor) MoveRight() bool

MoveRight moves the cursor right by one character (rune).

func (*Cursor) MoveToEnd

func (c *Cursor) MoveToEnd()

MoveToEnd moves the cursor to the end of the buffer.

func (*Cursor) MoveToLineEnd

func (c *Cursor) MoveToLineEnd()

MoveToLineEnd moves the cursor to the end of the current line.

func (*Cursor) MoveToLineStart

func (c *Cursor) MoveToLineStart()

MoveToLineStart moves the cursor to the start of the current line.

func (*Cursor) MoveToStart

func (c *Cursor) MoveToStart()

MoveToStart moves the cursor to the start of the buffer.

func (*Cursor) MoveUp

func (c *Cursor) MoveUp() bool

MoveUp moves the cursor up one line, trying to maintain the column.

func (*Cursor) MoveWordLeft

func (c *Cursor) MoveWordLeft() bool

MoveWordLeft moves the cursor to the start of the previous word.

func (*Cursor) MoveWordRight

func (c *Cursor) MoveWordRight() bool

MoveWordRight moves the cursor to the start of the next word.

func (*Cursor) Position

func (c *Cursor) Position() Position

Position returns the current cursor position as line and column.

func (*Cursor) SetByteOffset

func (c *Cursor) SetByteOffset(offset int)

SetByteOffset sets the cursor to a specific byte offset.

func (*Cursor) SetPosition

func (c *Cursor) SetPosition(line, col int)

SetPosition sets the cursor to a specific line and column.

func (*Cursor) Sync

func (c *Cursor) Sync()

Sync ensures the buffer's gap is at the cursor position.

type DialogBuilder

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

DialogBuilder helps construct consistent dialogs

func (*DialogBuilder) AddBottomBorder

func (db *DialogBuilder) AddBottomBorder()

AddBottomBorder adds the bottom border

func (*DialogBuilder) AddCenteredText

func (db *DialogBuilder) AddCenteredText(text string)

AddCenteredText adds a line of centered text

func (*DialogBuilder) AddEmptyLine

func (db *DialogBuilder) AddEmptyLine()

AddEmptyLine adds an empty line with borders

func (*DialogBuilder) AddSelectableItem

func (db *DialogBuilder) AddSelectableItem(text string, isSelected bool)

AddSelectableItem adds an item that can be selected (highlighted when selected)

func (*DialogBuilder) AddSeparator

func (db *DialogBuilder) AddSeparator()

AddSeparator adds a horizontal separator line

func (*DialogBuilder) AddText

func (db *DialogBuilder) AddText(text string)

AddText adds a line of text (left-aligned, padded)

func (*DialogBuilder) AddTitleBorder

func (db *DialogBuilder) AddTitleBorder(title string)

AddTitleBorder adds the top border with an embedded title

func (*DialogBuilder) CenterText

func (db *DialogBuilder) CenterText(s string) string

CenterText centers text within innerWidth

func (*DialogBuilder) GetPosition

func (db *DialogBuilder) GetPosition(viewportWidth, viewportHeight, listStart, listCount int) DialogPosition

GetPosition returns the dialog's position information for mouse handling

func (*DialogBuilder) Height

func (db *DialogBuilder) Height() int

Height returns the current height of the dialog

func (*DialogBuilder) InnerWidth

func (db *DialogBuilder) InnerWidth() int

InnerWidth returns the inner width (for external calculations)

func (*DialogBuilder) Lines

func (db *DialogBuilder) Lines() []string

Lines returns the built dialog lines

func (*DialogBuilder) Overlay

func (db *DialogBuilder) Overlay(viewportContent string, viewportWidth, viewportHeight int) string

Overlay renders the dialog centered on the viewport content

func (*DialogBuilder) PadText

func (db *DialogBuilder) PadText(s string) string

PadText pads text to innerWidth (left-aligned)

type DialogPosition

type DialogPosition struct {
	StartX    int
	StartY    int
	Width     int
	Height    int
	ListStart int // Y offset where selectable list starts (relative to dialog)
	ListEnd   int // Y offset where selectable list ends
}

DialogPosition calculates the dialog position for mouse handling

func (DialogPosition) MouseInDialog

func (dp DialogPosition) MouseInDialog(mouseX, mouseY int) (bool, int, int)

MouseInDialog checks if mouse coordinates are inside the dialog Returns: inside bool, relX int, relY int

func (DialogPosition) MouseInList

func (dp DialogPosition) MouseInList(relY int) int

MouseInList checks if mouse Y is in the selectable list area Returns the list index or -1 if not in list

type Document

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

Document holds the state for a single open file/buffer

type Editor

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

Editor is the main Bubbletea model for the text editor

func New

func New() *Editor

New creates a new editor instance with default config

func NewWithConfig

func NewWithConfig(cfg *config.Config) *Editor

NewWithConfig creates a new editor instance with the given configuration

func (*Editor) Init

func (e *Editor) Init() tea.Cmd

Init implements tea.Model

func (*Editor) LoadFile

func (e *Editor) LoadFile(filename string) error

LoadFile loads a file into the editor

func (*Editor) NewDialogBuilder

func (e *Editor) NewDialogBuilder(width int) *DialogBuilder

NewDialogBuilder creates a new dialog builder

func (*Editor) SaveFile

func (e *Editor) SaveFile() bool

SaveFile saves the buffer to the current filename Returns true if save was initiated (might be async if prompting for filename)

func (*Editor) SetConfigError

func (e *Editor) SetConfigError(filePath, errMsg string)

SetConfigError sets the config error state and shows the error dialog

func (*Editor) SetFilename

func (e *Editor) SetFilename(filename string)

SetFilename sets the filename for the editor

func (*Editor) Update

func (e *Editor) Update(msg tea.Msg) (tea.Model, tea.Cmd)

Update implements tea.Model

func (*Editor) View

func (e *Editor) View() string

View implements tea.Model

type FileEntry

type FileEntry struct {
	Name       string
	IsDir      bool
	Size       int64
	Readable   bool   // For directories: whether we can read/enter it
	IsFavorite bool   // Whether this item is favorited
	FullPath   string // Full path (used in favorites view)
	IsSpecial  bool   // True for special entries like "★ Favorites" or ".."
}

FileEntry represents a file or directory in the file browser

type Mode

type Mode int

Mode represents the editor mode

const (
	ModeNormal Mode = iota
	ModeMenu
	ModeFind
	ModeFindReplace
	ModePrompt
	ModeHelp
	ModeAbout
	ModeFileBrowser
	ModeSaveAs
	ModeTheme
	ModeRecentFiles
	ModeRecentDirs
	ModeKeybindings
	ModeConfigError
	ModeSettings
	ModeEncoding
)

type Position

type Position struct {
	Line int
	Col  int
}

Position represents a position in the text as line and column (both 0-indexed).

type PromptAction

type PromptAction int

PromptAction represents what to do with the prompt result

const (
	PromptNone PromptAction = iota
	PromptSaveAs
	PromptOpen
	PromptConfirmNew
	PromptConfirmOpen
	PromptConfirmClose
	PromptConfirmQuit
	PromptConfirmOverwrite
	PromptGoToLine
	PromptThemeCopyName
	PromptFileChanged      // File changed on disk - reload?
	PromptConfirmLossySave // Confirm save with character loss
)

type Selection

type Selection struct {
	Active bool // Whether there is an active selection
	Anchor int  // Byte offset where selection started
	Cursor int  // Byte offset where selection ends (current cursor position)
}

Selection represents a text selection in the buffer. The selection spans from Anchor to Cursor, where Anchor is where the selection started and Cursor is the current position (and can be before or after Anchor).

func NewSelection

func NewSelection() *Selection

NewSelection creates a new inactive selection.

func (*Selection) Clear

func (s *Selection) Clear()

Clear clears the selection.

func (*Selection) Contains

func (s *Selection) Contains(pos int) bool

Contains returns true if the given position is within the selection.

func (*Selection) EndPos

func (s *Selection) EndPos() int

EndPos returns the end position (higher of Anchor and Cursor).

func (*Selection) GetText

func (s *Selection) GetText(buf *Buffer) string

GetText returns the selected text from the given buffer.

func (*Selection) IsEmpty

func (s *Selection) IsEmpty() bool

IsEmpty returns true if the selection is empty or inactive.

func (*Selection) Length

func (s *Selection) Length() int

Length returns the length of the selection in bytes.

func (*Selection) Normalize

func (s *Selection) Normalize() (start, end int)

Normalize returns the selection with start <= end.

func (*Selection) SelectAll

func (s *Selection) SelectAll(buf *Buffer)

SelectAll selects all text in the buffer.

func (*Selection) SelectLine

func (s *Selection) SelectLine(buf *Buffer, pos int)

SelectLine selects the entire line at the given position in the buffer.

func (*Selection) SelectWord

func (s *Selection) SelectWord(buf *Buffer, pos int)

SelectWord selects the word at the given position in the buffer.

func (*Selection) Start

func (s *Selection) Start(pos int)

Start begins a new selection at the given position.

func (*Selection) StartPos

func (s *Selection) StartPos() int

StartPos returns the start position (lower of Anchor and Cursor).

func (*Selection) Update

func (s *Selection) Update(pos int)

Update updates the cursor end of the selection.

type UndoEntry

type UndoEntry struct {
	// Position where the change occurred (byte offset)
	Position int
	// Text that was deleted (empty for pure insertions)
	Deleted string
	// Text that was inserted (empty for pure deletions)
	Inserted string
	// Cursor position before the change
	CursorBefore int
	// Cursor position after the change
	CursorAfter int
	// Timestamp of the change (for grouping)
	Timestamp time.Time
}

UndoEntry represents a single change that can be undone/redone.

type UndoStack

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

UndoStack manages undo and redo operations.

func NewUndoStack

func NewUndoStack(maxSize int) *UndoStack

NewUndoStack creates a new undo stack with the given maximum size.

func (*UndoStack) BreakMerge

func (u *UndoStack) BreakMerge()

BreakMerge forces the next change to not merge with previous ones.

func (*UndoStack) CanRedo

func (u *UndoStack) CanRedo() bool

CanRedo returns true if there are entries to redo.

func (*UndoStack) CanUndo

func (u *UndoStack) CanUndo() bool

CanUndo returns true if there are entries to undo.

func (*UndoStack) Clear

func (u *UndoStack) Clear()

Clear clears both the undo and redo stacks.

func (*UndoStack) Push

func (u *UndoStack) Push(entry *UndoEntry)

Push adds a new entry to the undo stack. This clears the redo stack since we're making a new change.

func (*UndoStack) Redo

func (u *UndoStack) Redo() *UndoEntry

Redo pops and returns the last entry from the redo stack, or nil if empty. The entry is moved back to the undo stack.

func (*UndoStack) SetGroupingInterval

func (u *UndoStack) SetGroupingInterval(d time.Duration)

SetGroupingInterval sets the interval for grouping changes.

func (*UndoStack) Undo

func (u *UndoStack) Undo() *UndoEntry

Undo pops and returns the last entry from the undo stack, or nil if empty. The entry is moved to the redo stack.

Jump to

Keyboard shortcuts

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