tvxterm

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Apr 7, 2026 License: MIT Imports: 12 Imported by: 0

README

tvxterm

GoDoc

tvxterm is a terminal emulator widget for tview.

It gives you a small VT-style emulator plus a tview.Primitive, so you can embed an interactive terminal inside terminal UIs written in Go.

Features

  • tview primitive for rendering terminal output
  • PTY backend for local shell and command execution
  • stream backend for SSH sessions or custom transports
  • UTF-8, wide rune, combining rune, and scrollback support
  • terminal input handling for keyboard, paste, focus, and mouse reporting
  • OSC title tracking and callback hooks

Package Layout

The package name is tvxterm, and it can be imported directly from the repository root.

import "github.com/blacknon/tvxterm"

Installation

go get github.com/blacknon/tvxterm

Quick Start

package main

import (
	"log"
	"os"
	"os/exec"

	"github.com/rivo/tview"

	"github.com/blacknon/tvxterm"
)

func main() {
	app := tview.NewApplication()
	term := tvxterm.New(app)

	cmd := exec.Command(shell())
	cmd.Env = append(os.Environ(), "TERM=xterm-256color")

	backend, err := tvxterm.NewPTYBackend(cmd, 80, 24)
	if err != nil {
		log.Fatal(err)
	}
	defer backend.Close()

	term.Attach(backend)

	if err := app.SetRoot(term, true).SetFocus(term).Run(); err != nil {
		log.Fatal(err)
	}
}

func shell() string {
	if sh := os.Getenv("SHELL"); sh != "" {
		return sh
	}
	return "/bin/sh"
}

Backends

PTY backend

Use NewPTYBackend when you want to run a local shell or process inside a pseudo terminal.

cmd := exec.Command("/bin/sh")
backend, err := tvxterm.NewPTYBackend(cmd, 80, 24)
Stream backend

Use NewStreamBackend when another library already owns the session and only gives you io.Reader / io.Writer.

backend := tvxterm.NewStreamBackend(reader, writer, resizeFunc, closeFunc)
term.Attach(backend)

This is useful for:

  • SSH clients
  • container exec sessions
  • remote agent transports
  • custom REPL bridges

Example

A runnable sample is included:

go run ./sample/localpty

What the sample shows:

  • local shell execution through PTYBackend
  • window title updates from OSC sequences
  • status line updates
  • local scrollback control with PageUp / PageDown
  • exit with Ctrl+Q

Additional samples:

go run ./sample/muxpty
go run ./sample/go-sshlib-shell
  • sample/muxpty: terminal mux style sample with dynamic pane splitting Ctrl+A c creates a new page, Ctrl+A % / Ctrl+A " splits the current page, Ctrl+A n/p switches pages, Ctrl+A o moves pane focus, Ctrl+A w opens the page list
  • sample/go-sshlib-shell: go-sshlib session rendered inside a tvxterm view via StreamBackend Ctrl+A c creates a new page, Ctrl+A % / Ctrl+A " splits a new SSH pane in the current page, Ctrl+A n/p switches pages, Ctrl+A o moves focus, Ctrl+A w opens the page list

For sample/go-sshlib-shell, you can use flags:

go run ./sample/go-sshlib-shell \
  -host example.com \
  -port 22 \
  -user myuser \
  -key-path $HOME/.ssh/id_ed25519 \
  -key-passphrase ''

Or password authentication:

go run ./sample/go-sshlib-shell \
  -host example.com \
  -port 22 \
  -user myuser \
  -password mypassword

Environment variables TVXTERM_SSH_HOST, TVXTERM_SSH_PORT, TVXTERM_SSH_USER, TVXTERM_SSH_PASSWORD, TVXTERM_SSH_KEY_PATH, and TVXTERM_SSH_KEY_PASSPHRASE can also be used as defaults.

API Overview

The main exported pieces are:

  • View: the tview widget
  • Backend: transport abstraction for terminal I/O
  • PTYBackend: local PTY-backed process launcher
  • StreamBackend: adapter for generic streams
  • Emulator: exported terminal state machine for testing or advanced use

Useful hooks on View:

  • Attach(backend) to connect a session
  • SetBackendExitHandler(...) to react when the backend closes
  • SetTitleHandler(...) to receive title updates
  • ScrollbackUp, ScrollbackDown, ScrollbackPageUp, ScrollbackPageDown

Notes

  • This library is focused on embedding terminal sessions into tview applications.
  • The emulator is intentionally small rather than a full xterm clone.
  • Alternate screen, colors, mouse reporting, bracketed paste, and title handling are supported, but some terminal features may still be incomplete.

License

MIT. See LICENSE.

Documentation

Overview

Package tvxterm provides a small terminal widget for tview.

The package is built around three pieces:

  • View: a tview primitive that renders terminal state
  • Backend: a transport abstraction for PTY, SSH, or custom streams
  • Emulator: a small VT-like state machine that turns bytes into cells

View and Backend form the primary public API for embedding terminal sessions into applications. Emulator and Snapshot are also exported so callers can test, inspect, or reuse the byte-to-cell pipeline directly when needed.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Backend

type Backend interface {
	io.Reader
	io.Writer
	Resize(cols, rows int) error
	Close() error
}

Backend is the transport abstraction for the terminal widget. Anything that can read terminal output, accept terminal input, and resize a terminal session can be attached.

type Cell

type Cell struct {
	Ch       rune
	Comb     []rune
	Style    tcell.Style
	Width    int
	Occupied bool
}

Cell is a single rendered terminal cell.

type Emulator

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

Emulator is a deliberately small VT-like emulator.

It is responsible for converting terminal bytes into a cell grid plus a small amount of terminal state. Applications embedding View usually do not need to use Emulator directly, but it remains exported for testing and advanced use.

func NewEmulator

func NewEmulator(cols, rows int) *Emulator

NewEmulator creates an emulator with the given initial size.

func (*Emulator) DrainResponses

func (e *Emulator) DrainResponses() [][]byte

DrainResponses returns terminal responses generated by the emulator, such as DSR or DA replies, and clears the pending response queue.

func (*Emulator) Resize

func (e *Emulator) Resize(cols, rows int)

Resize changes the emulator's visible cell dimensions.

func (*Emulator) Snapshot

func (e *Emulator) Snapshot() Snapshot

Snapshot returns a copy of the current visible screen state.

func (*Emulator) SnapshotAt

func (e *Emulator) SnapshotAt(offset int) Snapshot

SnapshotAt returns a view of the screen including local scrollback.

An offset of 0 returns the live screen. Positive offsets walk backward into retained scrollback rows.

func (*Emulator) Write

func (e *Emulator) Write(p []byte) (int, error)

Write feeds terminal output bytes into the emulator.

type PTYBackend

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

PTYBackend wraps a local PTY-backed process.

func NewPTYBackend

func NewPTYBackend(cmd *exec.Cmd, cols, rows int) (*PTYBackend, error)

NewPTYBackend starts cmd under a PTY and returns a Backend implementation for it with the requested initial size.

func (*PTYBackend) Close

func (b *PTYBackend) Close() error

func (*PTYBackend) Read

func (b *PTYBackend) Read(p []byte) (int, error)

func (*PTYBackend) Resize

func (b *PTYBackend) Resize(cols, rows int) error

func (*PTYBackend) Write

func (b *PTYBackend) Write(p []byte) (int, error)

type Snapshot

type Snapshot struct {
	Cols           int
	Rows           int
	CursorX        int
	CursorY        int
	CursorVis      bool
	CursorBlink    bool
	AppCursor      bool
	AppKeypad      bool
	ColumnMode132  bool
	AutoWrap       bool
	UsingAlt       bool
	ReverseVideo   bool
	BracketedPaste bool
	FocusReporting bool
	MouseX10       bool
	MouseVT200     bool
	MouseButtonEvt bool
	MouseAnyEvt    bool
	MouseSGR       bool
	ScrollTop      int
	ScrollBottom   int
	ScrollbackRows int
	WindowTitle    string
	Cells          [][]Cell
}

Snapshot is an immutable copy of the emulator's visible state.

type StreamBackend

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

StreamBackend adapts generic terminal-like streams to Backend. This is useful when another library owns session creation and only exposes stdin/stdout plus optional resize/close hooks.

func NewStreamBackend

func NewStreamBackend(reader io.Reader, writer io.Writer, resize func(cols, rows int) error, close func() error) *StreamBackend

NewStreamBackend wraps generic terminal-like streams plus optional resize and close hooks into a Backend.

func (*StreamBackend) Close

func (b *StreamBackend) Close() error

func (*StreamBackend) Read

func (b *StreamBackend) Read(p []byte) (int, error)

func (*StreamBackend) Resize

func (b *StreamBackend) Resize(cols, rows int) error

func (*StreamBackend) Write

func (b *StreamBackend) Write(p []byte) (int, error)

type StyleState

type StyleState struct {
	FG        tcell.Color
	BG        tcell.Color
	Bold      bool
	Underline bool
	Reverse   bool
}

StyleState is the emulator's logical text style before it is converted into a tcell.Style for drawing.

type View

type View struct {
	*tview.Box
	// contains filtered or unexported fields
}

View is a tview primitive that renders a terminal stream inside a boxed widget. Design intent:

  • frontend: tview primitive
  • state: tiny VT-like emulator
  • backend: PTY/SSH/anything implementing Backend

This mirrors the separation used by gowid's terminal widget: input/output are not tied to a subprocess launcher, and drawing happens from an intermediate terminal state rather than directly from raw bytes.

func New

func New(app *tview.Application) *View

New creates a terminal view bound to the given tview application.

The application reference is used for redraw scheduling and optional focus/paste integration. Passing nil is allowed for tests or headless use.

func (*View) Attach

func (v *View) Attach(backend Backend)

Attach connects a backend to the view and starts reading from it.

Callers typically create one backend per view and attach it once.

func (*View) Blur

func (v *View) Blur()

func (*View) Close

func (v *View) Close() error

Close closes the current backend and releases debug-log resources.

func (*View) Draw

func (v *View) Draw(screen tcell.Screen)

func (*View) Focus

func (v *View) Focus(delegate func(p tview.Primitive))

func (*View) HasFocus

func (v *View) HasFocus() bool

func (*View) InputHandler

func (v *View) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive))

func (*View) MouseHandler

func (v *View) MouseHandler() func(action tview.MouseAction, event *tcell.EventMouse, setFocus func(p tview.Primitive)) (consumed bool, capture tview.Primitive)

func (*View) PasteHandler

func (v *View) PasteHandler() func(text string, setFocus func(p tview.Primitive))

func (*View) ScrollbackDown

func (v *View) ScrollbackDown(lines int)

ScrollbackDown moves the local scrollback view downward by the given number of lines. Non-positive values are treated as 1.

func (*View) ScrollbackPageDown

func (v *View) ScrollbackPageDown()

ScrollbackPageDown moves the local scrollback view down by one visible page.

func (*View) ScrollbackPageUp

func (v *View) ScrollbackPageUp()

ScrollbackPageUp moves the local scrollback view by one visible page.

func (*View) ScrollbackStatus

func (v *View) ScrollbackStatus() (offset int, rows int)

ScrollbackStatus returns the current local scroll offset and the total number of available scrollback rows.

func (*View) ScrollbackUp

func (v *View) ScrollbackUp(lines int)

ScrollbackUp moves the local scrollback view upward by the given number of lines. Non-positive values are treated as 1.

func (*View) SendKey added in v0.1.1

func (v *View) SendKey(event *tcell.EventKey) bool

SendKey writes a single key event to the attached backend using the same encoding rules as interactive input handling.

func (*View) SendPaste added in v0.1.1

func (v *View) SendPaste(text string) bool

SendPaste writes pasted text to the attached backend, preserving bracketed paste behavior when enabled by the remote terminal.

func (*View) SetBackendExitHandler

func (v *View) SetBackendExitHandler(fn func(*View, error)) *View

SetBackendExitHandler installs a callback invoked when the attached backend read loop exits with an error or EOF.

func (*View) SetTitleHandler

func (v *View) SetTitleHandler(fn func(*View, string)) *View

SetTitleHandler installs a callback for OSC title updates observed from the terminal stream.

Directories

Path Synopsis
sample
go-sshlib-shell command
localpty command
muxpty command

Jump to

Keyboard shortcuts

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