Files
levi/internal/console/console.go

100 lines
1.4 KiB
Go
Raw Permalink Normal View History

2026-03-25 08:39:31 +09:00
package console
import (
"fmt"
"io"
"os"
"unicode/utf8"
"golang.org/x/term"
)
var state *term.State
func Raw() {
if state != nil {
term.Restore(int(os.Stdin.Fd()), state)
state = nil
}
s, err := term.MakeRaw(int(os.Stdin.Fd()))
if err != nil {
panic(err)
}
state = s
}
func Cooked() {
if state == nil {
panic("state is nil")
}
term.Restore(int(os.Stdin.Fd()), state)
}
func Clear() {
fmt.Print("\x1b[2J")
}
func HomeCursor() {
fmt.Print("\x1b[H")
}
func MoveCursor(x, y int) {
fmt.Printf("\x1b[%d;%dH", y+1, x+1)
2026-03-25 08:39:31 +09:00
}
func HideCursor() {
fmt.Print("\x1b[?25l")
}
func ShowCursor() {
fmt.Print("\x1b[?25h")
}
func Size() (int, int) {
w, h, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
panic(err)
}
return w, h
}
func runeSize(b byte) int {
switch {
case b&0x80 == 0:
2026-03-25 08:39:31 +09:00
return 1
case b&0xe0 == 0xc0:
2026-03-25 08:39:31 +09:00
return 2
case b&0xf0 == 0xe0:
2026-03-25 08:39:31 +09:00
return 3
case b&0xf8 == 0xf0:
2026-03-25 08:39:31 +09:00
return 4
default:
return -1 // invalid
}
}
func ReadRune() rune {
buf := make([]byte, 1)
_, err := io.ReadFull(os.Stdin, buf)
if err != nil {
panic(err)
}
expected := runeSize(buf[0])
if expected == -1 {
panic("Invalid UTF-8 head")
}
full := make([]byte, expected)
full[0] = buf[0]
if expected > 1 {
_, err := io.ReadFull(os.Stdin, full[1:])
if err != nil {
panic(err)
}
}
r, size := utf8.DecodeRune(full)
if r == utf8.RuneError && size == 1 {
panic("Invalid UTF-8 body")
}
return r
}