Fundamentals 12 min read

Mastering Terminal Output: VT100 History, ANSI Escape Codes, and Go Colorful UI

This article explores the evolution of computer terminals, explains VT100 and ANSI escape sequences, and demonstrates how to create colorful text, progress bars, and responsive window handling in Go using pseudo‑TTYs and signal processing for a richer command‑line experience.

360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
360 Zhihui Cloud Developer
Mastering Terminal Output: VT100 History, ANSI Escape Codes, and Go Colorful UI

Terminal History

The terminal (terminal) is the input‑output device of a computer system, and its concept has evolved through three stages: character terminals, graphical terminals, and network terminals.

TeleTYpe (TTY) devices were used in early computers where many users shared a single host; they transmitted keystrokes via dedicated cables and printed output on paper, becoming the ancestor of modern consoles.

VT100 was produced by DEC in the late 1970s. Although it had a monochrome display, it supported visual effects such as blinking, text deletion, bold, and underline, and defined many control sequences. VT100 compatibility became a de‑facto standard for later terminals.

VT100 control codes, also known as ANSI Escape Sequences, start with the ESC character (\x1b). They are used by most modern Telnet clients to emulate VT100 terminals.

VT100 Control Codes

<code>\033[0m    // Reset all attributes
\033[1m    // Set bright
\033[4m    // Underline
\033[5m    // Blink
\033[7m    // Reverse video
\033[8m    // Conceal
\033[nA    // Move cursor up n lines
\033[nB    // Move cursor down n lines
\033[nC    // Move cursor right n columns
\033[nD    // Move cursor left n columns
\033[y;xH  // Set cursor position
\033[2J    // Clear screen
\033[K    // Erase to end of line
\033[s    // Save cursor position
\033[u    // Restore cursor position
\033[?25l // Hide cursor
\033[?25h // Show cursor</code>

Foreground colors are set with \033[30m ‑ \033[37m (black to white) and background colors with \033[40m ‑ \033[47m .

Go Colorful Text Example

<code>package main
import "fmt"
func main() {
    fmt.Print("\x1b[4;30;46m") // underline, black foreground, cyan background
    fmt.Print("Hello World")
    fmt.Println("\x1b[0m") // reset attributes
}</code>

The code prints "Hello World" with underline, black text, and cyan background using VT100 control codes. Libraries such as fatih/color wrap these sequences for easier use.

Go Progress Bar

The progress bar is rendered by repeatedly clearing the line, printing a bar composed of "=" and "-" characters, and restoring the cursor position.

<code>package main
import (
    "fmt"
    "strings"
    "time"
)
func renderBar(count, total int) {
    barWidth := 30
    done := int(float64(barWidth) * float64(count) / float64(total))
    fmt.Printf("Progress: \x1b[33m%3d%%\x1b[0m ", count*100/total)
    fmt.Printf("[%s%s]", strings.Repeat("=", done), strings.Repeat("-", barWidth-done))
}
func main() {
    total := 50
    for i := 1; i <= total; i++ {
        fmt.Print("\x1b7")   // save cursor
        fmt.Print("\x1b[2k") // clear line
        renderBar(i, total)
        time.Sleep(50 * time.Millisecond)
        fmt.Print("\x1b8")   // restore cursor
    }
    fmt.Println()
}</code>

To adapt the bar width to the terminal size, the code can query the window dimensions.

Terminal Window Size and Signal Handling

Window size can be obtained via syscall.Syscall with SYS_IOCTL and TIOCGWINSZ , or more conveniently with unix.IoctlGetWinsize . The size is stored in a winsize struct containing rows and columns.

<code>type winsize struct {
    Row uint16
    Col uint16
    X   uint16
    Y   uint16
}
func getWinSize(fd int) (row, col uint16, err error) {
    var ws *winsize
    ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(ws)))
    if int(ret) == -1 {
        return 0, 0, errno
    }
    return ws.Row, ws.Col, nil
}</code>

On Unix/macOS, the SIGWINCH signal notifies the program of window size changes. Handling this signal allows the UI to redraw correctly.

<code>package main
import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
    "golang.org/x/sys/unix"
)
var wscol int = 20
func updateWSCol() error {
    ws, err := unix.IoctlGetWinsize(syscall.Stdout, unix.TIOCGWINSZ)
    if err != nil { return err }
    wscol = int(ws.Col)
    return nil
}
func renderBar() {
    fmt.Print("\x1b7")
    fmt.Print("\x1b[2k")
    defer fmt.Print("\x1b8")
    // draw bar based on wscol
}
func main() {
    sigwinch := make(chan os.Signal, 1)
    signal.Notify(sigwinch, syscall.SIGWINCH)
    go func() {
        for range sigwinch {
            _ = updateWSCol()
            renderBar()
        }
    }()
    // demo loop
    for i := 1; i <= 50; i++ {
        renderBar()
        time.Sleep(time.Second)
    }
    fmt.Println()
}</code>

When the terminal is resized, the program receives SIGWINCH , retrieves the new dimensions, and can redraw the UI accordingly. Simple approaches may clear the whole screen to avoid rendering glitches.

Summary

By combining the ANSI/VT100 control code specifications with languages such as Python, Bash, Go, Java, C, or PHP, developers can create rich terminal UI applications. Understanding terminal history, control sequences, window size handling, and signal processing enables building sophisticated command‑line tools.

gocommand lineprogress barterminalANSI escape codesVT100
360 Zhihui Cloud Developer
Written by

360 Zhihui Cloud Developer

360 Zhihui Cloud is an enterprise open service platform that aims to "aggregate data value and empower an intelligent future," leveraging 360's extensive product and technology resources to deliver platform services to customers.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.