fasttui

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 4, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README

fasttui

fasttui is a Go port of @mariozechner/pi-tui: the same differential renderer, bracketed paste handling, autocomplete, and component value semantics

Features

  • Differential Rendering: Three-strategy rendering system that only updates what changed
  • Synchronized Output: Uses CSI 2026 for atomic screen updates (no flicker)
  • Bracketed Paste Mode: Handles large pastes correctly with markers for >10 line pastes
  • Component-based: Simple Component interface with render() method
  • Theme Support: Components accept theme interfaces for customizable styling
  • Built-in Components: Text, TruncatedText, Input, Editor, Markdown, Loader, SelectList, SettingsList, Spacer, Image, Box, Container
  • Inline Images: Renders images in terminals that support Kitty or iTerm2 graphics protocols
  • Autocomplete Support: File paths and slash commands

License

Apache License 2.0

Documentation

Index

Constants

View Source
const (
	CursorMarker = "\x1b_pi:c\x07"
	SegmentReset = "\x1b[0m\x1b]8;;\x07"
)

Variables

View Source
var CURSOR_MARKER = "\x1b_pi:c\x07"
View Source
var SEGMENT_RESET = "\x1b[0m\x1b]8;;\x07"

Functions

func ApplyBackgroundToLine

func ApplyBackgroundToLine(line string, width int, bgFn func(string) string) string

func BuildWidthExceedErrorMsg

func BuildWidthExceedErrorMsg(lineIndex int, lineWidth int, termWidth int, crashLogPath string) string

BuildWidthExceedErrorMsg builds an error message for when a rendered line exceeds the terminal width.

func ExtractAnsiCode

func ExtractAnsiCode(s string, pos int) (code string, length int, ok bool)

ExtractAnsiCode extracts an ANSI escape sequence starting at the given position. It supports three types of sequences:

  • CSI (Control Sequence Introducer): ESC [ ... terminator (e.g., ESC[31m for red text)
  • OSC (Operating System Command): ESC ] ... BEL or ESC \ (e.g., ESC]8;;url for hyperlinks)
  • APC (Application Program Command): ESC _ ... BEL or ESC \ (e.g., ESC_pi:c for cursor marker)

Returns the complete escape sequence, its length, and whether extraction succeeded.

func ExtractSegments

func ExtractSegments(line string, beforeEnd int, afterStart int, afterLen int, strictAfter bool) (string, int, string, int)

func GetCrashLogPath

func GetCrashLogPath() string

GetCrashLogPath returns the path to the crash log file.

func GetCursorMarker

func GetCursorMarker() string

func GetSegmentReset

func GetSegmentReset() string

func GetSegmenter

func GetSegmenter() any

func GraphemeWidth

func GraphemeWidth(s string) int

func IsPunctuationChar

func IsPunctuationChar(char string) bool

func IsWhitespaceChar

func IsWhitespaceChar(char string) bool

func LogCrashInfo

func LogCrashInfo(width int, lineIndex int, line string, newLines []string)

LogCrashInfo logs detailed crash information including terminal width, line index, and all rendered lines.

func SliceByColumn

func SliceByColumn(line string, startCol int, length int, strict bool) string

func TruncateToWidth

func TruncateToWidth(text string, maxWidth int, ellipsis string, pad bool) string

func VisibleWidth

func VisibleWidth(s string) int

func WrapTextWithAnsi

func WrapTextWithAnsi(text string, width int) []string

func WriteCrashLog

func WriteCrashLog(path string, data string)

WriteCrashLog writes crash data to the specified path.

func WriteDebugLog

func WriteDebugLog(firstChanged, viewportTop, finalCursorRow, hardwareCursorRow,
	renderEnd, cursorRow, cursorCol, height int, tCursorRow int, newLines, previousLines []string)

WriteDebugLog writes detailed debug information about the rendering process.

Types

type AnsiCodeTracker

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

AnsiCodeTracker tracks the current state of ANSI escape codes in a text stream. It maintains the active text formatting attributes (bold, italic, colors, etc.) and can reconstruct the ANSI codes needed to continue formatting on a new line.

Example usage:

tracker := NewAnsiCodeTracker()
tracker.Process("\x1b[1;31m")  // bold + red foreground
codes := tracker.GetActiveCodes()  // returns "\x1b[1;31m"

func NewAnsiCodeTracker

func NewAnsiCodeTracker() *AnsiCodeTracker

NewAnsiCodeTracker creates a new ANSI code tracker with all formatting disabled.

Example:

tracker := NewAnsiCodeTracker()

func (*AnsiCodeTracker) Clear

func (t *AnsiCodeTracker) Clear()

Clear is an alias for Reset. It clears all active formatting attributes.

Example:

tracker.Clear()  // same as tracker.Reset()

func (*AnsiCodeTracker) GetActiveCodes

func (t *AnsiCodeTracker) GetActiveCodes() string

GetActiveCodes returns an ANSI escape sequence that represents all currently active formatting attributes. This is useful for continuing formatting on a new line. Returns an empty string if no formatting is active.

Example:

tracker.Process("\x1b[1;31m")     // bold + red
codes := tracker.GetActiveCodes()  // returns "\x1b[1;31m"

// Use case: wrapping text while preserving formatting
line1 := "\x1b[1;31mHello"
tracker.Process("\x1b[1;31m")
line2 := tracker.GetActiveCodes() + "World\x1b[0m"

func (*AnsiCodeTracker) GetLineEndReset

func (t *AnsiCodeTracker) GetLineEndReset() string

GetLineEndReset returns an ANSI code to reset underline formatting at the end of a line. This is useful because underline formatting can extend beyond the text content. Returns "\x1b[24m" (turn off underline) if underline is active, empty string otherwise.

Example:

tracker.Process("\x1b[4m")         // underline
reset := tracker.GetLineEndReset()  // returns "\x1b[24m"
line := "text" + reset              // prevents underline from extending

func (*AnsiCodeTracker) HasActiveCodes

func (t *AnsiCodeTracker) HasActiveCodes() bool

HasActiveCodes returns true if any formatting attributes are currently active.

Example:

tracker := NewAnsiCodeTracker()
tracker.HasActiveCodes()        // returns false
tracker.Process("\x1b[1m")      // bold
tracker.HasActiveCodes()        // returns true

func (*AnsiCodeTracker) Process

func (t *AnsiCodeTracker) Process(ansiCode string)

Process parses an ANSI escape code and updates the tracker's internal state. It handles SGR (Select Graphic Rendition) codes for text formatting and colors.

Supported codes:

  • 0: Reset all attributes
  • 1: Bold, 2: Dim, 3: Italic, 4: Underline, 5: Blink
  • 7: Inverse, 8: Hidden, 9: Strikethrough
  • 21-29: Turn off corresponding attributes
  • 30-37, 90-97: Foreground colors
  • 40-47, 100-107: Background colors
  • 38;5;n: 256-color foreground
  • 48;5;n: 256-color background
  • 38;2;r;g;b: RGB foreground
  • 48;2;r;g;b: RGB background

Example:

tracker.Process("\x1b[1;31m")     // bold + red
tracker.Process("\x1b[38;5;208m") // 256-color orange
tracker.Process("\x1b[0m")        // reset all

func (*AnsiCodeTracker) Reset

func (t *AnsiCodeTracker) Reset()

Reset clears all active formatting attributes, returning the tracker to its initial state.

Example:

tracker.Process("\x1b[1;31m")  // bold + red
tracker.Reset()                 // clear all formatting
tracker.HasActiveCodes()        // returns false

type Component

type Component interface {
	Render(width int) []string
	HandleInput(data string)
	WantsKeyRelease() bool
	Invalidate()
}

type Container

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

func NewContainer

func NewContainer() *Container

func (*Container) AddChild

func (c *Container) AddChild(component Component)

func (*Container) Clear

func (c *Container) Clear()

func (*Container) GetChildren

func (c *Container) GetChildren() []Component

func (*Container) HandleInput

func (c *Container) HandleInput(data string)

func (*Container) InsertChildAt

func (c *Container) InsertChildAt(index int, component Component)

func (*Container) Invalidate

func (c *Container) Invalidate()

func (*Container) RemoveChild

func (c *Container) RemoveChild(component Component)

func (*Container) RemoveChildAt

func (c *Container) RemoveChildAt(index int)

func (*Container) Render

func (c *Container) Render(width int) []string

func (*Container) WantsKeyRelease

func (c *Container) WantsKeyRelease() bool

type Focusable

type Focusable interface {
	Component
	SetFocused(bool)
	IsFocused() bool
}

type Overlay

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

type OverlayAnchor

type OverlayAnchor string
const (
	AnchorCenter       OverlayAnchor = "center"
	AnchorTopLeft      OverlayAnchor = "top-left"
	AnchorTopRight     OverlayAnchor = "top-right"
	AnchorBottomLeft   OverlayAnchor = "bottom-left"
	AnchorBottomRight  OverlayAnchor = "bottom-right"
	AnchorTopCenter    OverlayAnchor = "top-center"
	AnchorBottomCenter OverlayAnchor = "bottom-center"
	AnchorLeftCenter   OverlayAnchor = "left-center"
	AnchorRightCenter  OverlayAnchor = "right-center"
)

type OverlayHandle

type OverlayHandle interface {
	Hide()
	SetHidden(hidden bool)
	// contains filtered or unexported methods
}

type OverlayLayout

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

type OverlayOption

type OverlayOption struct {
	Width     int
	MiniWidth int
	MaxHeight int
	Anchor    OverlayAnchor
	Offset    OverlayAnchor
	Row       int
	Col       int
	OffsetX   int
	OffsetY   int
	Margin    any
	Visible   func(width int, height int) bool
}

func (OverlayOption) ResolveLayout

func (o OverlayOption) ResolveLayout(overlayHeight int, termWidth int, termHeight int) OverlayLayout

type SliceResult

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

func SliceWithWidth

func SliceWithWidth(line string, startCol int, length int, strict bool) SliceResult

type TUI

type TUI struct {
	Container
	// contains filtered or unexported fields
}

func NewTUI

func NewTUI(terminal Terminal, showHardwareCursor bool) *TUI

func (*TUI) ForceRender

func (t *TUI) ForceRender()

func (*TUI) GetFullRedraws

func (t *TUI) GetFullRedraws() int

func (*TUI) GetShowHardwareCursor

func (t *TUI) GetShowHardwareCursor() bool

func (*TUI) HandleInput

func (t *TUI) HandleInput(data string)

func (*TUI) HasOverlay

func (t *TUI) HasOverlay() bool

func (*TUI) HideOverlay

func (t *TUI) HideOverlay()

func (*TUI) QueryCellSize

func (t *TUI) QueryCellSize()

func (*TUI) SetClearOnShrink

func (t *TUI) SetClearOnShrink(enabled bool)

func (*TUI) SetFocus

func (t *TUI) SetFocus(component Component)

SetFocus sets the component that currently receives keyboard input. In a TUI, only one interactive component (editor, selector, list, etc.) can receive input at a time. This method switches the "input focus": first unfocus the old component, then focus the new one.

func (*TUI) SetShowHardwareCursor

func (t *TUI) SetShowHardwareCursor(enabled bool)

func (*TUI) ShowOverlay

func (t *TUI) ShowOverlay(component Component, options OverlayOption) (func(), func(bool), func() bool)

func (*TUI) Start

func (t *TUI) Start()

func (*TUI) Stop

func (t *TUI) Stop()

func (*TUI) TriggerRender

func (t *TUI) TriggerRender()

type Terminal

type Terminal interface {
	Start(onInput func(data string), onResize func()) error
	Stop()
	Write(data string)
	GetSize() (int, int)
	IsKittyProtocolActive() bool
	MoveBy(lines int)
	HideCursor()
	ShowCursor()
	ClearLine()
	ClearFromCursor()
	ClearScreen()
	SetTitle(title string)
}

Directories

Path Synopsis
_examples
chat command
input command
key command
select command

Jump to

Keyboard shortcuts

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