package tx import "golang.org/x/term" import "surdeus.su/core/cli/aes" import "bufio" import "fmt" import "os" import "os/signal" import "syscall" type Signal = os.Signal const ( SignalWinChange = syscall.SIGWINCH ) type Terminal struct { x *term.Terminal file *os.File input *bufio.Reader fd int prevState *term.State signals chan Signal keys chan Key } func NewTerminal(input *os.File) (*Terminal, error) { if input == nil { return nil, ErrNoInputProvided } fd := int(input.Fd()) if !term.IsTerminal(fd) { return nil, ErrNotTerminal } ret := Terminal{} ret.file = input ret.input = bufio.NewReader(input) ret.fd = fd ret.x = term.NewTerminal(input, "") return &ret, nil } func (t *Terminal) MakeRaw() (chan Key, chan Signal, error) { state, err := term.MakeRaw(t.fd) if err != nil { return nil, nil, err } t.prevState = state t.signals = make(chan Signal, 1) signal.Notify( t.signals, syscall.SIGWINCH, ) t.keys = make(chan Key, 1) go func() { for { r, _, _ := t.input.ReadRune() t.keys <- Key(r) } } () return t.keys, t.signals, nil } func (t *Terminal) Restore() error { t.DisableAltBuffer() if t == nil || t.prevState == nil { return nil } err := term.Restore(t.fd, t.prevState) if err != nil { return err } return nil } func (t *Terminal) Size() (int, int, error) { return term.GetSize(t.fd) } func (t *Terminal) ReadLine() (string, error) { return t.x.ReadLine() } /* func (t *Terminal) ReadKey() (Key, int, error) { r, size, err := t.input.ReadRune() return Key(r), size, err } */ func (t *Terminal) Write(bts []byte) (int, error) { return t.x.Write(bts) } func (t *Terminal) Printf( format string, v ...any, ) (int, error) { str := fmt.Sprintf(format, v...) return t.Write([]byte(str)) } func (t *Terminal) Print(v ...any) (int, error) { str := fmt.Sprint(v...) return t.Write([]byte(str)) } func (t *Terminal) MoveCursorRight(n int) { t.Printf(aes.MoveCursorRightFormat, n) } func (t *Terminal) MoveCursorLeft(n int) { t.Printf(aes.MoveCursorLeftFormat, n) } func (t *Terminal) MoveCursorUp(n int) { t.Printf(aes.MoveCursorUpFormat, n) } func (t *Terminal) MoveCursorDown(n int) { t.Printf(aes.MoveCursorDownFormat, n) } func (t *Terminal) MoveCursorBy(xd, yd int) { if xd != 0 { if yd < 0 { t.MoveCursorLeft(xd) } else { t.MoveCursorRight(xd) } } if yd != 0 { if yd < 0 { t.MoveCursorUp(yd) } else { t.MoveCursorDown(yd) } } } func (t *Terminal) MoveCursorTo(x, y int) { t.Printf(aes.MoveCursorToFormat, y, x) } func (t *Terminal) MoveCursorHome() { t.Printf("%s", aes.MoveCursorHome) } func (t *Terminal) SaveCursor() { t.Printf("%s", aes.SaveCursorPositionSCO) } func (t *Terminal) UndoCursor() { t.Printf("%s", aes.UndoCursorPositionSCO) } func (t *Terminal) NextLine(n int) { t.Printf( aes.MoveCursorToBeginOfNextLineDownFormat, n, ) } func (t *Terminal) EraseLine() { t.Print(aes.EraseEntireLine) } func (t *Terminal) EnableAltBuffer() { t.Printf("%s", aes.EnableAltBuffer) } func (t *Terminal) DisableAltBuffer() { t.Printf("%s", aes.DisableAltBuffer) } func (t *Terminal) ClearScreen() { t.Write([]byte(aes.EraseEntireScreen)) }