cli

package
v0.2.16 Latest Latest
Warning

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

Go to latest
Published: Dec 27, 2025 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package cli provides a CLI-based terminal emulator adapter for PurfecTerm.

This package implements a "terminal within a terminal" - it runs a terminal emulator inside an actual CLI terminal, handling all VT100/ANSI escape sequence interpretation through its own interpreter and rendering the result in a window within the actual CLI screen.

Features

  • Full VT100/ANSI escape sequence interpretation via PurfecTerm's parser
  • Scrollback buffer with Shift+PageUp/PageDown navigation
  • Multiple border styles (single, double, heavy, rounded)
  • Optional status bar showing cursor position and scroll status
  • Window resizing that tracks the host terminal (SIGWINCH)
  • Differential rendering for efficiency (only updates changed cells)
  • True color (24-bit) and 256-color support
  • Full attribute support: bold, italic, underline, strikethrough, blink, reverse

Basic Usage

import "github.com/phroun/purfecterm/cli"

opts := cli.Options{
    AutoSize:      true,                   // Fill available space
    BorderStyle:   cli.BorderRounded,      // Rounded border
    Title:         "My Terminal",
    ShowStatusBar: true,
}

term, err := cli.New(opts)
if err != nil {
    log.Fatal(err)
}

// Start the terminal (enters raw mode)
if err := term.Start(); err != nil {
    log.Fatal(err)
}
defer term.Stop()

// Run a shell
if err := term.RunShell(); err != nil {
    log.Fatal(err)
}

// Wait for shell to exit
term.Wait()

Scrollback Navigation

While running, the following keys navigate the scrollback buffer:

  • Shift+PageUp: Scroll up one page
  • Shift+PageDown: Scroll down one page
  • Shift+Up: Scroll up one line
  • Shift+Down: Scroll down one line
  • Shift+Home: Jump to top of scrollback
  • Shift+End: Jump to bottom (current output)

Any regular input automatically scrolls to the bottom.

Architecture

The package consists of three main components:

  • Terminal: Main struct that manages the PTY, buffer, and coordinates rendering/input
  • Renderer: Handles rendering the terminal buffer to the actual terminal using ANSI codes
  • InputHandler: Reads raw input, parses escape sequences, handles scrollback navigation

The Terminal wraps the core purfecterm.Buffer and purfecterm.Parser, reusing all the VT100/ANSI parsing logic from the main PurfecTerm package. This ensures consistent terminal emulation behavior across Qt, GTK, and CLI adapters.

Package cli provides a CLI-based terminal emulator adapter for PurfecTerm. It renders a terminal emulator within an actual CLI terminal, handling all VT100/ANSI escape sequence interpretation through its own interpreter and rendering the result in a window within the actual CLI screen.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BorderStyle

type BorderStyle int

BorderStyle defines the visual style for the terminal window border

const (
	BorderNone    BorderStyle = iota // No border
	BorderSingle                     // Single-line box drawing characters
	BorderDouble                     // Double-line box drawing characters
	BorderHeavy                      // Heavy/thick box drawing characters
	BorderRounded                    // Rounded corners (single line)
)

type InputHandler

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

InputHandler manages keyboard input from the host terminal

func NewInputHandler

func NewInputHandler(term *Terminal) *InputHandler

NewInputHandler creates a new input handler

func (*InputHandler) HandleMouseInput

func (h *InputHandler) HandleMouseInput(x, y int, button int, pressed bool)

HandleMouseInput processes mouse events (if mouse tracking is enabled) This is a placeholder for future mouse support

func (*InputHandler) InputLoop

func (h *InputHandler) InputLoop()

InputLoop reads and processes input from stdin using direct-key-handler

type Options

type Options struct {
	Cols           int                    // Terminal width in columns (default: auto-detect or 80)
	Rows           int                    // Terminal height in rows (default: auto-detect or 24)
	ScrollbackSize int                    // Number of scrollback lines (default: 10000)
	Scheme         purfecterm.ColorScheme // Color scheme (default: DefaultColorScheme())
	Shell          string                 // Shell to run (default: $SHELL or /bin/sh)
	WorkingDir     string                 // Initial working directory (default: current dir)

	// Display options
	BorderStyle BorderStyle // Border style around the terminal window
	Title       string      // Window title (displayed in top border if applicable)
	OffsetX     int         // X offset from top-left of actual terminal (0 = left edge)
	OffsetY     int         // Y offset from top-left of actual terminal (0 = top edge)

	// If true, the terminal window auto-sizes to fill available space
	AutoSize bool

	// If true, render a status bar at the bottom
	ShowStatusBar bool

	// Embedded mode: when true, the terminal acts as a widget within a larger TUI.
	// It will NOT enter raw mode, switch to alternate screen, or start its own input loop.
	// The parent application is responsible for:
	//   - Managing raw mode for the host terminal
	//   - Calling HandleInput() to send keystrokes when focused
	//   - Calling Render() or RenderToString() to display the terminal
	Embedded bool
}

Options configures terminal creation

type Rect

type Rect struct {
	X, Y          int // Top-left position
	Width, Height int // Size
}

Rect represents a rectangle for clipping

func (Rect) Contains

func (r Rect) Contains(x, y int) bool

Contains returns true if the point (x, y) is within the rectangle

func (Rect) Intersect

func (r Rect) Intersect(other Rect) Rect

Intersect returns the intersection of two rectangles

func (Rect) IsEmpty

func (r Rect) IsEmpty() bool

IsEmpty returns true if the rectangle has zero area

type RenderedCell

type RenderedCell struct {
	Char      rune
	Combining string
	Fg, Bg    purfecterm.Color
	Bold      bool
	Italic    bool
	Underline bool
	Blink     bool
	Reverse   bool
}

RenderedCell represents a single cell ready for display

type Renderer

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

Renderer handles rendering the terminal buffer to the actual CLI terminal

func NewRenderer

func NewRenderer(term *Terminal) *Renderer

NewRenderer creates a new renderer for the terminal

func (*Renderer) ForceFullRedraw

func (r *Renderer) ForceFullRedraw()

ForceFullRedraw clears the cached state and forces a complete redraw

func (*Renderer) NeedsRender

func (r *Renderer) NeedsRender() bool

NeedsRender returns true if there are pending changes to render

func (*Renderer) Render

func (r *Renderer) Render()

Render performs a full or differential render of the terminal

func (*Renderer) RenderLoop

func (r *Renderer) RenderLoop()

RenderLoop runs the main render loop

func (*Renderer) RenderToString

func (r *Renderer) RenderToString() string

RenderToString renders the terminal and returns the ANSI escape sequence string instead of writing to stdout. This is useful for embedded mode where the parent TUI needs to composite the terminal with other widgets. Note: This always performs a full render (no differential optimization). If a clip rectangle is set, only cells within that rectangle are rendered.

func (*Renderer) RequestRender

func (r *Renderer) RequestRender()

RequestRender marks that a render is needed

type Terminal

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

Terminal is a complete terminal emulator running within a CLI terminal

func New

func New(opts Options) (*Terminal, error)

New creates a new CLI terminal emulator

func (*Terminal) Buffer

func (t *Terminal) Buffer() *purfecterm.Buffer

Buffer returns the underlying terminal buffer

func (*Terminal) Clear

func (t *Terminal) Clear()

Clear clears the terminal screen

func (*Terminal) ClearClipRect

func (t *Terminal) ClearClipRect()

ClearClipRect disables clipping, allowing the full terminal to render.

func (*Terminal) ClearScrollback

func (t *Terminal) ClearScrollback()

ClearScrollback clears the scrollback buffer

func (*Terminal) Close

func (t *Terminal) Close() error

Close is an alias for Stop

func (*Terminal) Feed

func (t *Terminal) Feed(data []byte)

Feed writes data directly to the terminal display (bypassing PTY)

func (*Terminal) FeedString

func (t *Terminal) FeedString(data string)

FeedString writes a string to the terminal display

func (*Terminal) GetBounds

func (t *Terminal) GetBounds() (x, y, cols, rows int)

GetBounds returns the terminal's current position and size. Returns offsetX, offsetY, columns, rows.

func (*Terminal) GetCellAt

func (t *Terminal) GetCellAt(col, row int) RenderedCell

GetCellAt returns a single rendered cell at the given position. Returns an empty cell if coordinates are out of bounds.

func (*Terminal) GetCells

func (t *Terminal) GetCells() [][]RenderedCell

GetCells returns the terminal's content as a 2D grid of rendered cells. This allows a TUI compositor to handle rendering and clipping directly. The grid includes the terminal content (not border/status bar). Returns cells[row][col] where row 0 is the top.

func (*Terminal) GetClipRect

func (t *Terminal) GetClipRect() Rect

GetClipRect returns the current clipping rectangle, or an empty Rect if clipping is disabled.

func (*Terminal) GetHostSize

func (t *Terminal) GetHostSize() (cols, rows int)

GetHostSize returns the host terminal size

func (*Terminal) GetMaxScrollOffset

func (t *Terminal) GetMaxScrollOffset() int

GetMaxScrollOffset returns the maximum scroll offset

func (*Terminal) GetMinOuterSize

func (t *Terminal) GetMinOuterSize() (width, height int)

GetMinOuterSize returns the minimum total size including border and status bar.

func (*Terminal) GetMinSize

func (t *Terminal) GetMinSize() (cols, rows int)

GetMinSize returns the minimum usable terminal size. The terminal enforces a minimum of 20 columns and 5 rows.

func (*Terminal) GetOffset

func (t *Terminal) GetOffset() (x, y int)

GetOffset returns the terminal's current screen position

func (*Terminal) GetOuterSize

func (t *Terminal) GetOuterSize() (width, height int)

GetOuterSize returns the total size including border and status bar. This is useful for layout calculations in a TUI toolkit.

func (*Terminal) GetScrollOffset

func (t *Terminal) GetScrollOffset() int

GetScrollOffset returns the current scroll offset

func (*Terminal) GetSelectedText

func (t *Terminal) GetSelectedText() string

GetSelectedText returns currently selected text

func (*Terminal) GetSize

func (t *Terminal) GetSize() (cols, rows int)

GetSize returns the terminal size in columns and rows

func (*Terminal) GetTerminalCapabilities

func (t *Terminal) GetTerminalCapabilities() *TerminalCapabilities

GetTerminalCapabilities returns the terminal capabilities

func (*Terminal) HandleInput

func (t *Terminal) HandleInput(data []byte) bool

HandleInput processes input from the parent TUI (for embedded mode). The parent TUI should call this method when the terminal has focus and receives keyboard input. Returns true if the input was consumed.

func (*Terminal) HandleKeyString

func (t *Terminal) HandleKeyString(key string) bool

HandleKeyString processes a key event by name (for embedded mode). Accepts key names in direct-key-handler format: "a", "Enter", "Up", "C-c", "M-x", "S-Tab", etc. Returns true if the input was consumed.

func (*Terminal) HandleResize

func (t *Terminal) HandleResize(hostCols, hostRows int)

HandleResize notifies the terminal of a host terminal resize (for embedded mode). The parent TUI should call this when it detects a resize.

func (*Terminal) IsEmbedded

func (t *Terminal) IsEmbedded() bool

IsEmbedded returns whether the terminal is running in embedded mode

func (*Terminal) IsFocused

func (t *Terminal) IsFocused() bool

IsFocused returns whether the terminal currently has focus

func (*Terminal) IsRunning

func (t *Terminal) IsRunning() bool

IsRunning returns true if a command is running

func (*Terminal) NeedsRender

func (t *Terminal) NeedsRender() bool

NeedsRender returns true if the terminal has pending changes to render. Useful for TUI toolkits to optimize render cycles.

func (*Terminal) RenderToString

func (t *Terminal) RenderToString() string

RenderToString returns the terminal's rendered output as an ANSI escape sequence string. This is useful for embedded mode where the parent TUI needs to composite the terminal with other widgets. The parent can write this string to stdout at the appropriate time during its render cycle.

func (*Terminal) Renderer

func (t *Terminal) Renderer() *Renderer

Renderer returns the terminal's renderer for advanced usage

func (*Terminal) Reset

func (t *Terminal) Reset()

Reset resets the terminal to initial state

func (*Terminal) Resize

func (t *Terminal) Resize(cols, rows int)

Resize resizes the terminal

func (*Terminal) RunCommand

func (t *Terminal) RunCommand(name string, args ...string) error

RunCommand runs a command in the terminal

func (*Terminal) RunShell

func (t *Terminal) RunShell() error

RunShell starts the default shell in the terminal

func (*Terminal) SaveScrollbackANS

func (t *Terminal) SaveScrollbackANS() string

SaveScrollbackANS returns the scrollback with ANSI codes preserved

func (*Terminal) SaveScrollbackText

func (t *Terminal) SaveScrollbackText() string

SaveScrollbackText returns the scrollback buffer as plain text

func (*Terminal) ScrollDown

func (t *Terminal) ScrollDown(n int)

ScrollDown scrolls the view down by n lines (toward current output)

func (*Terminal) ScrollToBottom

func (t *Terminal) ScrollToBottom()

ScrollToBottom scrolls to the bottom (current output)

func (*Terminal) ScrollToTop

func (t *Terminal) ScrollToTop()

ScrollToTop scrolls to the top of scrollback

func (*Terminal) ScrollUp

func (t *Terminal) ScrollUp(n int)

ScrollUp scrolls the view up by n lines (into scrollback)

func (*Terminal) SetClipRect

func (t *Terminal) SetClipRect(rect Rect)

SetClipRect sets a clipping rectangle for partial visibility. Only cells within this rectangle will be rendered. This is useful when the terminal is inside a scrollable container or partially obscured by other widgets. The rectangle is in screen coordinates (same coordinate system as OffsetX/OffsetY). Pass an empty/zero Rect to disable clipping.

func (*Terminal) SetColorScheme

func (t *Terminal) SetColorScheme(scheme purfecterm.ColorScheme)

SetColorScheme sets the terminal color scheme

func (*Terminal) SetFocused

func (t *Terminal) SetFocused(focused bool)

SetFocused sets the focus state of the terminal (for embedded mode). When focused, the terminal will process input and show its cursor. When unfocused, input is ignored and the cursor is hidden.

func (*Terminal) SetInputCallback

func (t *Terminal) SetInputCallback(fn func([]byte) bool)

SetInputCallback sets a callback for intercepting input Return true from the callback to consume the input

func (*Terminal) SetOffset

func (t *Terminal) SetOffset(x, y int)

SetOffset changes the terminal's position on screen (for embedded mode). This allows dynamic repositioning without recreating the terminal.

func (*Terminal) SetOnBell

func (t *Terminal) SetOnBell(fn func())

SetOnBell sets a callback for when the terminal bell is triggered. Useful for parent TUI to show visual notification when terminal needs attention.

func (*Terminal) SetOnExit

func (t *Terminal) SetOnExit(fn func(int))

SetOnExit sets a callback for when the child process exits

func (*Terminal) SetOnFocus

func (t *Terminal) SetOnFocus(fn func(focused bool))

SetOnFocus sets a callback for focus state changes

func (*Terminal) SetOnResize

func (t *Terminal) SetOnResize(fn func(cols, rows int))

SetOnResize sets a callback for terminal resize events

func (*Terminal) SetTitle

func (t *Terminal) SetTitle(title string)

SetTitle sets the terminal window title

func (*Terminal) Start

func (t *Terminal) Start() error

Start initializes the terminal, enters raw mode, and starts rendering. In embedded mode, this only starts the render loop; the parent TUI is responsible for raw mode and input handling.

func (*Terminal) Stop

func (t *Terminal) Stop() error

Stop stops the terminal and restores the original terminal state

func (*Terminal) Wait

func (t *Terminal) Wait()

Wait waits for the terminal process to exit

func (*Terminal) Write

func (t *Terminal) Write(data []byte) (int, error)

Write writes to the terminal's PTY (sends input to child process)

func (*Terminal) WriteString

func (t *Terminal) WriteString(s string) (int, error)

WriteString writes a string to the terminal's PTY

type TerminalCapabilities

type TerminalCapabilities struct {
	TermType      string
	IsTerminal    bool
	IsRedirected  bool
	SupportsANSI  bool
	SupportsColor bool
	ColorDepth    int // 0, 8, 16, 256, or 24
	Width         int
	Height        int
	SupportsInput bool
	EchoEnabled   bool
	LineMode      bool
}

TerminalCapabilities describes the capabilities of the terminal

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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