Files
terminal/tui/input.go
T
2026-07-12 17:01:37 -04:00

78 lines
1.4 KiB
Go

package tui
import (
"github.com/lixenwraith/terminal"
)
// InputOpts configures single-line input field
type InputOpts struct {
Label string
LabelFg terminal.RGB
Text string
Cursor int // Cursor position in text (rune index)
CursorBg terminal.RGB
TextFg terminal.RGB
Bg terminal.RGB
}
// Input renders labeled text input field on row y, handling cursor display and horizontal scrolling
func (r Region) Input(y int, opts InputOpts) {
if y < 0 || y >= r.H || r.W < 5 {
return
}
x := 0
// Label
if opts.Label != "" {
for _, ch := range opts.Label {
if x >= r.W {
break
}
r.Cell(x, y, ch, opts.LabelFg, opts.Bg, terminal.AttrNone)
x++
}
}
// Available width for input text
inputW := r.W - x
if inputW < 3 {
return
}
runes := []rune(opts.Text)
cursor := opts.Cursor
if cursor > len(runes) {
cursor = len(runes)
}
if cursor < 0 {
cursor = 0
}
// Horizontal scroll to keep cursor visible
scroll := 0
if cursor >= inputW-1 {
scroll = cursor - inputW + 2
}
// Render visible portion
for i := 0; i < inputW; i++ {
runeIdx := scroll + i
ch := ' '
if runeIdx < len(runes) {
ch = runes[runeIdx]
}
bg := opts.Bg
if runeIdx == cursor {
bg = opts.CursorBg
}
r.Cell(x+i, y, ch, opts.TextFg, bg, terminal.AttrNone)
}
// Cursor at end if past text
if cursor == len(runes) && cursor-scroll < inputW {
r.Cell(x+cursor-scroll, y, ' ', opts.TextFg, opts.CursorBg, terminal.AttrNone)
}
}