termui

repository·master·Indexed 12 days ago

https://github.com/gizak/termui

A cross-platform, highly customizable terminal dashboard and widget library for Go, built on top of termbox-go. It provides a set of premade widgets such as BarChart, Gauge, List, and Plot, and supports mouse, keyboard, and resizing events for creating complex TUI (Terminal User Interface) applications. The stable v3 release is managed via Go modules.

Tokens
6.7K
Snippets
34
Records
41
Agent score
96%

What's inside termui

  1. Install termui using Go modules

    master

    termui is managed via Go modules. You do not need to run go get manually as Go will handle dependencies upon import.

    Important: When using Go modules, you must include /v3 in your import statements to target the stable v3 release.

    import (
    	ui "github.com/gizak/termui/v3"
    	"github.com/gizak/termui/v3/widgets"
    )
  2. Create a basic termui application

    master

    To use termui, you must initialize the UI, defer its closure, create widgets, and enter an event loop to handle user input or terminal events.

    Basic lifecycle:

    1. Call ui.Init() to initialize the terminal.
    2. Use defer ui.Close() to ensure the terminal is restored on exit.
    3. Create widgets using the widgets package.
    4. Position widgets using SetRect(left, top, right, bottom).
    5. Call ui.Render(widget) to draw the widget to the screen.
    6. Use ui.PollEvents() to listen for keyboard, mouse, or resize events.
    package main
    
    import (
    	"log"
    
    	ui "github.com/gizak/termui/v3"
    	"github.com/gizak/termui/v3/widgets"
    )
    
    func main() {
    	if err := ui.Init(); err != nil {
    		log.Fatalf("failed to initialize termui: %v", err)
    	}
    	defer ui.Close()
    
    	p := widgets.NewParagraph()
    	p.Text = "Hello World!"
    	p.SetRect(0, 0, 25, 5)
    
    	ui.Render(p)
    
    	for e := range ui.PollEvents() {
    		if e.Type == ui.KeyboardEvent {
    			break
    		}
    	}
    }
  3. Install termui using Dep

    master

    If you are using the dep dependency manager, add the library using:

    dep ensure -add github.com/gizak/termui

    Note: Unlike Go modules, when using Dep, you should not include /v3 in your import statements.

    dep ensure -add github.com/gizak/termui
  4. Configure global widget themes using RootTheme

    master

    The termui package provides a global Theme variable of type RootTheme that controls the default Style and Color settings for all widgets. You can customize the appearance of your entire UI by modifying this global variable before initializing your widgets.

    RootTheme contains sub-themes for specific widget types, such as BlockTheme, BarChartTheme, GaugeTheme, etc. Modifying these values ensures that all widgets of that type follow your custom styling automatically.

    // Example: Customizing the global theme before creating widgets
    termui.Theme.Default = termui.NewStyle(termui.ColorCyan)
    termui.Theme.Block.Border = termui.NewStyle(termui.ColorYellow)
    termui.Theme.Tab.Active = termui.NewStyle(termui.ColorGreen)
  5. Available termui widgets

    master

    termui provides several premade widgets for common dashboard use cases. You can find specific implementation examples in the _examples/ directory of the repository.

    • BarChart
    • Canvas (for drawing braille dots)
    • Gauge
    • Image
    • List
    • Tree
    • Paragraph
    • PieChart
    • Plot (for scatterplots and linecharts)
    • Sparkline
    • StackedBarChart
    • Table
    • Tabs
  6. Create a grid layout with NewGrid()

    master

    NewGrid() initializes a new Grid instance. A Grid is a layout container that embeds a Block and manages a collection of GridItem objects. By default, a new grid has its Border set to false.

    To populate the grid with content, use the Set() method, which accepts a variadic list of entries (typically GridItems created via NewCol or NewRow).

    grid := termui.NewGrid()
    grid.Set(
        termui.NewRow(0.5, widget1),
        termui.NewRow(0.5, widget2),
    )
  7. Parse embedded styles with ParseStyles

    master

    The ParseStyles function converts a string containing embedded style syntax into a slice of Cell objects. This allows you to define text styling directly within a string.

    Syntax: [text](fg:<color>,mod:<attribute>,bg:<color>)

    • Text: The content to be styled, wrapped in square brackets [].
    • Style Block: The styling instructions, wrapped in parentheses ().
    • Ordering: The order of style items (fg, bg, mod) does not matter.
    • Optionality: All style fields are optional.
    • Default Style: Any text not wrapped in style syntax will use the provided defaultStyle.

    Example:

    // Returns cells where 'Hello' is red and bold, and 'World' uses the default style
    cells := termui.ParseStyles("[Hello](fg:red,mod:bold) World", termui.Style{})
    cells := termui.ParseStyles("[Hello](fg:red,mod:bold) World", termui.Style{})
  8. Create a new Style using NewStyle()

    master

    The NewStyle function is a helper to construct a Style with a variable number of arguments:

    • 1 argument: fg (Color)
    • 2 arguments: fg (Color), bg (Color)
    • 3 arguments: fg (Color), bg (Color), modifier (Modifier)

    Note: Arguments must match the expected types (Color or Modifier) or the function will panic due to type assertion.

    import "github.com/gizak/termui"
    
    // 1 argument: Foreground only
    s1 := termui.NewStyle(termui.ColorRed)
    
    // 2 arguments: Foreground and Background
    s2 := termui.NewStyle(termui.ColorRed, termui.ColorBlack)
    
    // 3 arguments: Foreground, Background, and Modifier
    s3 := termui.NewStyle(termui.ColorGreen, termui.ColorBlack, termui.ModifierBold)
  9. Render a Block using Draw()

    master

    The Draw(buf *Buffer) method implements the Drawable interface. It renders the block's border (if Border is true) and the Title text at the top of the block (offset by 2 units from the left edge).

    // buf is a pointer to the current termui Buffer
    block.Draw(buf)
  10. Draw points and lines on a Canvas

    master

    The Canvas widget provides methods to draw primitive shapes using image.Point coordinates and termui.Color values:

    • SetPoint(p image.Point, color Color): Sets a single pixel at the specified point p with the given color.
    • SetLine(p0, p1 image.Point, color Color): Draws a line between points p0 and p1 using the specified color.

    Note that these coordinates are relative to the internal drawille.Canvas coordinate system. When the widget's Draw(buf *Buffer) method is called, it clips the drawing to the widget's Rectangle and renders it to the terminal buffer.

    // Drawing a single point
    canvas.SetPoint(image.Point{X: 10, Y: 10}, termui.ColorBlue)
    
    // Drawing a line
    canvas.SetLine(image.Point{X: 0, Y: 0}, image.Point{X: 20, Y: 20}, termui.ColorRed)
  11. Use Alignment constants for positioning elements

    master

    The Alignment type is used to specify the horizontal alignment of elements within a UI component. It is defined as a uint and provides three standard alignment options: AlignLeft, AlignCenter, and AlignRight.

    // Example usage of Alignment constants
    var myAlignment termui.Alignment = termui.AlignCenter
  12. Implement the Drawable interface for custom widgets

    master

    To create custom widgets that can be rendered by termui, you must implement the Drawable interface. This interface allows the rendering engine to determine the widget's dimensions, update its bounds, and execute its drawing logic into a buffer.

    An implementation of Drawable must provide the following methods:

    • GetRect() image.Rectangle: Returns the current bounding rectangle of the widget.
    • SetRect(x, y, w, h int): Sets the widget's bounding rectangle using top-left coordinates (x, y) and dimensions (width, height).
    • Draw(*Buffer): Performs the actual drawing logic, writing cells into the provided *Buffer.
    • Lock() and Unlock(): Part of the sync.Locker interface, used to ensure thread-safe drawing operations.
    type Drawable interface {
    	GetRect() image.Rectangle
    	SetRect(int, int, int, int)
    	Draw(*Buffer)
    	sync.Locker
    }