This article is a translation of x/termで作るTUIアプリケーション開発
Introduction
Recently, I created a terminal-based typing game using Go's x/term package. In this article, I'll share the features of the x/term package and insights gained from TUI application development.
As a practical example of a TUI application using x/term, I'm developing a git client tool called ggc. If you find it interesting, I'd appreciate a Star on GitHub.
What is the x/term Package?
x/term
is one of Go's experimental packages that provides low-level functionality for terminal operations. Previously available as golang.org/x/crypto/ssh/terminal
, it's now an independent package called golang.org/x/term
.
Key Features
- Getting Terminal Size
width, height, err := term.GetSize(int(os.Stdout.Fd()))
- Low-level Key Input Detection
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
log.Fatal(err)
}
defer term.Restore(int(os.Stdin.Fd()), oldState)
- Echo Control
- Terminal Mode Control
These features enable you to create interactive TUI applications with cursor position control and immediate key input detection.
Implementing the Typing Game
1. Basic Design
Here are the core features of the typing game:
- Random English text display
- Immediate key input detection
- Accuracy measurement
- Error count tracking
2. Terminal State Management
The most important aspect when using x/term is managing terminal state:
// Set terminal to raw mode
oldState, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
log.Fatal(err)
}
// Restore terminal state on program exit
defer term.Restore(int(os.Stdin.Fd()), oldState)
// Signal handling
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
go func() {
<-sigCh
term.Restore(int(os.Stdin.Fd()), oldState)
os.Exit(0)
}()
3. Display Control
We control the display using ANSI escape sequences:
// Hide cursor
fmt.Print("\033[?25l")
defer fmt.Print("\033[?25h") // Restore cursor visibility on exit
// Clear screen
fmt.Print("\033[2J")
// Move cursor position (to x=10, y=5)
fmt.Printf("\033[%d;%dH", 5, 10)
4. Performance Optimization
Here are some key points for ensuring display stability:
- Buffer control
- Screen update optimization
- Asynchronous processing using goroutines
Implementation Tips
1. Error Handling and Recovery
// Panic recovery handling
defer func() {
if r := recover(); r != nil {
term.Restore(int(os.Stdin.Fd()), oldState)
fmt.Printf("Recovered from panic: %v\n", r)
}
}()
2. Cross-platform Support
var clear string
if runtime.GOOS == "windows" {
clear = "cls"
} else {
clear = "clear"
}
cmd := exec.Command(clear)
cmd.Stdout = os.Stdout
cmd.Run()
Conclusion
While TUI application development with x/term requires low-level control, it offers great flexibility. The typing game implementation shown here demonstrates basic patterns that can be applied to create various TUI applications.
Speaking of which, there's an excellent tool called ggc that leverages this technology. It implements a intuitive Git client by skillfully utilizing x/term's features for incremental search UI, key input handling, and display control. If you're interested, try installing it with go install github.com/bmf-san/ggc@latest
.
Top comments (0)