tt/term/term.go

191 lines
3.7 KiB
Go

package term
import (
"errors"
"fmt"
"os"
)
const ESC = "\x1b"
const CSI = ESC + "["
const Reset = CSI + "0m"
// Colors
const (
BlackFg = "30"
BlackBg = "40"
RedFg = "31"
RedBg = "41"
GreenFg = "32"
GreenBg = "42"
YellowFg = "33"
YellowBg = "43"
BlueFg = "34"
BlueBg = "44"
MagentaFg = "35"
MagentaBg = "35"
CyanFg = "36"
CyanBg = "46"
WhiteFg = "37"
WhiteBg = "47"
)
func Color(col string) string {
return CSI + col + "m"
}
// Other CSI
func CursorUp(amount int) string {
return fmt.Sprintf("%s%dA", CSI, amount)
}
func CursorDown(amount int) string {
return fmt.Sprintf("%s%dB", CSI, amount)
}
func CursorForward(amount int) string {
return fmt.Sprintf("%s%dC", CSI, amount)
}
func CursorBack(amount int) string {
return fmt.Sprintf("%s%dD", CSI, amount)
}
// Not ANSI.SYS
func CursorNextLine(amount int) string {
return fmt.Sprintf("%s%dE", CSI, amount)
}
// Not ANSI.SYS
func CursorPreviousLine(amount int) string {
return fmt.Sprintf("%s%dF", CSI, amount)
}
// Not ANSI.SYS
// Moves cursor to column amount
func CursorHorizontalAbsolute(amount int) string {
return fmt.Sprintf("%s%dG", CSI, amount)
}
// Moves the cursor on the 1-based grid in the terminal
func CursorPostition(x, y int) string {
return fmt.Sprintf("%s%d;%dH", CSI, x, y)
}
type EraseInDisplayMode int
const (
ClearFromCursor EraseInDisplayMode = iota // clear from cursor to the end of the screen
ClearToCursor // clear to cursor from the begining of the screen
ClearEntireScreen
ClearEntireScreenAndScrollbackBuffer // xterm extension
)
func EraseInDisplay(mode EraseInDisplayMode) string {
return fmt.Sprintf("%s%dJ", CSI, mode)
}
type EraseInLineMode int
const (
FromCursorToEnd EraseInLineMode = iota
FromCursorToBegin
EntireLine
)
func EraseInLine(mode EraseInLineMode) string {
return fmt.Sprintf("%s%dK", CSI, mode)
}
// Not ANSI.SYS
func ScrollUp(amount int) string {
return fmt.Sprintf("%s%dS", CSI, amount)
}
// Not ANSI.SYS
func ScrollDown(amount int) string {
return fmt.Sprintf("%s%dT", CSI, amount)
}
// Moves the cursor on the 1-based grid in the terminal
// Same as Cursor Position but a format effector, not a editor function
// see https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands
func HorizontalVerticalPosition(x, y int) string {
return fmt.Sprintf("%s%d;%dH", CSI, x, y)
}
// Gets the cursor position by transmitting CSIn;mR n = row, m = column
// see https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands
// Use GetCursorPosition to get x and y
func DeviceStatusReport() string {
return CSI + "6n"
}
var DidNotGetCsi = errors.New("could not get csi from Device Status Report sequence")
func GetCursorPosition() (row, column int, err error) {
// _, err = os.Stdin.Seek(0, 2)
// if err != nil {
// return
// }
os.Stdout.Write([]byte(DeviceStatusReport()))
// CSI is ESC and [
csiBuffer := [2]byte{}
os.Stdin.Read(csiBuffer[:])
if string(csiBuffer[:]) != CSI {
err = DidNotGetCsi
return
}
miniBuff := [1]byte{}
for {
_, err = os.Stdin.Read(miniBuff[:])
if err != nil {
return
}
if miniBuff[0] == ';' {
break
}
if '0' <= miniBuff[0] && miniBuff[0] <= '9' {
row *= 10
row += int(miniBuff[0] - '0')
} else {
err = fmt.Errorf("invalid byte for number %b", miniBuff[0])
return
}
}
for {
_, err = os.Stdin.Read(miniBuff[:])
if err != nil {
return
}
if miniBuff[0] == 'R' {
break
}
if '0' <= miniBuff[0] && miniBuff[0] <= '9' {
column *= 10
column += int(miniBuff[0] - '0')
} else {
err = fmt.Errorf("invalid byte for number %b", miniBuff[0])
return
}
}
return
}
func Exit(val int) {
// LeaveRawMode()
os.Exit(val)
}