Go terminal/console support package providing low-level terminal manipulation functions
npx @tessl/cli install tessl/golang-golang-org-x-term@0.37.0The term package provides support functions for dealing with terminals, as commonly found on UNIX systems. It offers low-level terminal manipulation capabilities including putting terminals into raw mode, reading passwords without echo, querying terminal dimensions, and providing a VT100 terminal implementation for line-based input with readline-like functionality.
go get golang.org/x/term@v0.37.0import "golang.org/x/term"package main
import (
"fmt"
"os"
"golang.org/x/term"
)
func main() {
// Save the current state and put terminal in raw mode
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
// Terminal is now in raw mode
fmt.Println("Terminal is in raw mode")
}package main
import (
"fmt"
"os"
"golang.org/x/term"
)
func main() {
fmt.Print("Enter password: ")
password, err := term.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
fmt.Printf("\nPassword entered: %s\n", password)
}package main
import (
"fmt"
"io"
"os"
"golang.org/x/term"
)
func main() {
// Put terminal in raw mode first
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
// Create a VT100 terminal
terminal := term.NewTerminal(os.Stdin, "> ")
for {
line, err := terminal.ReadLine()
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
fmt.Printf("You entered: %s\n", line)
}
}Check if a file descriptor is a terminal.
func IsTerminal(fd int) boolParameters:
fd int: File descriptor to checkReturns:
bool: Returns true if the given file descriptor is a terminal, false otherwisePut a terminal into raw mode and restore it later.
func MakeRaw(fd int) (*State, error)Puts the terminal connected to the given file descriptor into raw mode and returns the previous state of the terminal so that it can be restored.
Parameters:
fd int: File descriptor of the terminal to put into raw modeReturns:
*State: Previous terminal state that can be used to restore the terminalerror: Error if the operation failsfunc Restore(fd int, oldState *State) errorRestores the terminal connected to the given file descriptor to a previous state.
Parameters:
fd int: File descriptor of the terminal to restoreoldState *State: Previous state to restore (typically from MakeRaw or GetState)Returns:
error: Error if the operation failsGet and manage terminal state.
func GetState(fd int) (*State, error)Returns the current state of a terminal which may be useful to restore the terminal after a signal.
Parameters:
fd int: File descriptor of the terminalReturns:
*State: Current terminal stateerror: Error if the operation failsQuery terminal size.
func GetSize(fd int) (width, height int, err error)Returns the visible dimensions of the given terminal. These dimensions don't include any scrollback buffer height.
Parameters:
fd int: File descriptor of the terminalReturns:
width int: Terminal width in columnsheight int: Terminal height in rowserr error: Error if the operation failsRead passwords without local echo.
func ReadPassword(fd int) ([]byte, error)Reads a line of input from a terminal without local echo. This is commonly used for inputting passwords and other sensitive data. The slice returned does not include the \n.
Parameters:
fd int: File descriptor of the terminalReturns:
[]byte: Password data without the trailing newlineerror: Error if the operation fails (may be io.EOF)Create a VT100 terminal for interactive line-based input.
func NewTerminal(c io.ReadWriter, prompt string) *TerminalRuns a VT100 terminal on the given ReadWriter. If the ReadWriter is a local terminal, that terminal must first have been put into raw mode. The prompt is a string that is written at the start of each input line (e.g., "> ").
Parameters:
c io.ReadWriter: ReadWriter for terminal I/Oprompt string: Prompt string to display at the start of each input lineReturns:
*Terminal: New Terminal instance configured with the given ReadWriter and promptRead lines of input from a VT100 terminal.
func (t *Terminal) ReadLine() (line string, err error)Returns a line of input from the terminal. Supports history navigation with up/down arrows, cursor movement, and line editing.
Returns:
line string: Input line read from the terminalerr error: Error if the operation fails (may be io.EOF or ErrPasteIndicator)func (t *Terminal) ReadPassword(prompt string) (line string, err error)Temporarily changes the prompt and reads a password, without echo, from the terminal. The AutoCompleteCallback is disabled during this call.
Parameters:
prompt string: Prompt to display for password inputReturns:
line string: Password entered (without trailing newline)err error: Error if the operation failsManage the prompt displayed by the terminal.
func (t *Terminal) SetPrompt(prompt string)Sets the prompt to be used when reading subsequent lines.
Parameters:
prompt string: New prompt string to displayManage terminal dimensions for proper display.
func (t *Terminal) SetSize(width, height int) errorSets the terminal size. This updates the internal state to match the new dimensions.
Parameters:
width int: Terminal width in columns (minimum 1)height int: Terminal height in rowsReturns:
error: Error if the operation failsWrite data to the terminal.
func (t *Terminal) Write(buf []byte) (n int, err error)Implements the io.Writer interface for the terminal. Handles proper display of output while preserving the current input line and cursor position.
Parameters:
buf []byte: Data to write to the terminalReturns:
n int: Number of bytes writtenerr error: Error if the operation failsControl bracketed paste mode for terminals that support it.
func (t *Terminal) SetBracketedPasteMode(on bool)Requests that the terminal bracket paste operations with markers. Not all terminals support this but, if it is supported, then enabling this mode will stop any autocomplete callback from running due to pastes. Additionally, any lines that are completely pasted will be returned from ReadLine with the error set to ErrPasteIndicator.
Parameters:
on bool: true to enable bracketed paste mode, false to disabletype State struct {
// Contains unexported platform-specific fields
}Contains the state of a terminal. Used to save and restore terminal settings. The internal structure varies by platform (Unix, Windows, Plan 9) but the type provides a consistent interface across all platforms.
Usage:
MakeRaw() and GetState()Restore() to restore previous terminal statetype Terminal struct {
// AutoCompleteCallback, if non-null, is called for each keypress with
// the full input line and the current position of the cursor (in
// bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line
// and the new cursor position.
//
// This will be disabled during ReadPassword.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
// Escape contains a pointer to the escape codes for this terminal.
// It's always a valid pointer, although the escape codes themselves
// may be empty if the terminal doesn't support them.
Escape *EscapeCodes
// History records and retrieves lines of input read by ReadLine which
// a user can retrieve and navigate using the up and down arrow keys.
//
// It is not safe to call ReadLine concurrently with any methods on History.
//
// NewTerminal sets this to a default implementation that records the
// last 100 lines of input.
History History
// Contains unexported fields for internal terminal state
}Contains the state for running a VT100 terminal that is capable of reading lines of input. Provides readline-like functionality with history, cursor movement, line editing, and autocomplete support.
Exported Fields:
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool): Optional callback function invoked for each keypress to provide autocomplete functionality. If it returns ok=true, the returned newLine and newPos replace the current line and cursor position. Disabled during ReadPassword() calls.
Escape *EscapeCodes: Pointer to escape codes for terminal styling. Always a valid pointer, though escape codes may be empty if the terminal doesn't support them.
History History: Interface for managing command history. Allows users to navigate previous input using up/down arrow keys. NewTerminal sets this to a default implementation storing the last 100 lines.
Concurrency:
The Terminal type is not safe for concurrent use. It uses internal locking to protect against concurrent Write() and key press handling, but external synchronization is required for other concurrent access patterns.
type EscapeCodes struct {
// Foreground colors
Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
// Reset all attributes
Reset []byte
}Contains escape sequences that can be written to the terminal in order to achieve different styles of text. Each field contains the ANSI escape sequence as a byte slice.
Fields:
Black []byte: Escape sequence for black foreground colorRed []byte: Escape sequence for red foreground colorGreen []byte: Escape sequence for green foreground colorYellow []byte: Escape sequence for yellow foreground colorBlue []byte: Escape sequence for blue foreground colorMagenta []byte: Escape sequence for magenta foreground colorCyan []byte: Escape sequence for cyan foreground colorWhite []byte: Escape sequence for white foreground colorReset []byte: Escape sequence to reset all text attributes to defaultUsage:
Access via Terminal.Escape field. Write the byte slices directly to the terminal to apply colors.
type History interface {
// Add will be called by Terminal.ReadLine to add
// a new, most recent entry to the history.
// It is allowed to drop any entry, including
// the entry being added (e.g., if it's deemed an invalid entry),
// the least-recent entry (e.g., to keep the history bounded),
// or any other entry.
Add(entry string)
// Len returns the number of entries in the history.
Len() int
// At returns an entry from the history.
// Index 0 is the most-recently added entry and
// index Len()-1 is the least-recently added entry.
// If index is < 0 or >= Len(), it panics.
At(idx int) string
}A History provides a (possibly bounded) queue of input lines read by Terminal.ReadLine. Users can navigate through history entries using up/down arrow keys.
Methods:
Add(entry string): Called by Terminal.ReadLine to add a new entry to the history. Implementations may drop entries (including the new entry, the oldest entry, or any other entry) to maintain size bounds or filter invalid entries.
Len() int: Returns the number of entries currently in the history.
At(idx int) string: Returns an entry from the history. Index 0 is the most recent entry, and index Len()-1 is the oldest entry. Panics if idx < 0 or idx >= Len().
Default Implementation:
NewTerminal sets Terminal.History to a default ring buffer implementation that stores the last 100 lines of input.
Concurrency:
It is not safe to call ReadLine concurrently with any methods on History. The History interface methods may be called by ReadLine, so external synchronization is required if accessing History while ReadLine may be running.
var ErrPasteIndicator = pasteIndicatorError{}May be returned from ReadLine as the error, in addition to valid line data. It indicates that bracketed paste mode is enabled and that the returned line consists only of pasted data. Programs may wish to interpret pasted data more literally than typed data.
Type: error
Usage:
line, err := terminal.ReadLine()
if err == term.ErrPasteIndicator {
// Line was pasted, not typed
// Handle pasted data (e.g., disable auto-formatting)
} else if err != nil {
// Other error
}The package provides platform-specific implementations for:
The API remains consistent across all platforms, with platform-specific behavior handled internally.
Always use defer to ensure terminal state is restored:
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
return err
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
// Use raw mode terminal...Get terminal dimensions for proper display:
width, height, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
// Handle error or use default dimensions
width, height = 80, 24
}// Put terminal in raw mode
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
// Create terminal
terminal := term.NewTerminal(os.Stdin, "$ ")
// Read commands in a loop
for {
line, err := terminal.ReadLine()
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
// Process command
fmt.Printf("Executing: %s\n", line)
}terminal := term.NewTerminal(os.Stdin, "> ")
// Set up autocomplete callback
terminal.AutoCompleteCallback = func(line string, pos int, key rune) (string, int, bool) {
if key == '\t' {
// Implement tab completion
completed := autoComplete(line[:pos])
newLine := completed + line[pos:]
return newLine, len(completed), true
}
return "", 0, false
}
line, err := terminal.ReadLine()os.Stdin.Fd() may not be 0