ceeed6c32e
Signed-off-by: Ryan Cole <rcyoalne@gmail.com>
258 lines
5.1 KiB
Go
258 lines
5.1 KiB
Go
// Provides basic bulding blocks for advanced console UI
|
|
//
|
|
// Coordinate system:
|
|
//
|
|
// 1/1---X---->
|
|
// |
|
|
// Y
|
|
// |
|
|
// v
|
|
//
|
|
// Documentation for ANSI codes: http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
|
|
//
|
|
// Inspired by: http://www.darkcoding.net/software/pretty-command-line-console-output-on-unix-in-python-and-go-lang/
|
|
package goterm
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// Reset all custom styles
|
|
const RESET = "\033[0m"
|
|
|
|
// Reset to default color
|
|
const RESET_COLOR = "\033[32m"
|
|
|
|
// Return curor to start of line and clean it
|
|
const RESET_LINE = "\r\033[K"
|
|
|
|
// List of possible colors
|
|
const (
|
|
BLACK = iota
|
|
RED
|
|
GREEN
|
|
YELLOW
|
|
BLUE
|
|
MAGENTA
|
|
CYAN
|
|
WHITE
|
|
)
|
|
|
|
var Output *bufio.Writer = bufio.NewWriter(os.Stdout)
|
|
|
|
func getColor(code int) string {
|
|
return fmt.Sprintf("\033[3%dm", code)
|
|
}
|
|
|
|
func getBgColor(code int) string {
|
|
return fmt.Sprintf("\033[4%dm", code)
|
|
}
|
|
|
|
// Set percent flag: num | PCT
|
|
//
|
|
// Check percent flag: num & PCT
|
|
//
|
|
// Reset percent flag: num & 0xFF
|
|
const shift = uint(^uint(0)>>63) << 4
|
|
const PCT = 0x8000 << shift
|
|
|
|
type winsize struct {
|
|
Row uint16
|
|
Col uint16
|
|
Xpixel uint16
|
|
Ypixel uint16
|
|
}
|
|
|
|
// Global screen buffer
|
|
// Its not recommented write to buffer dirrectly, use package Print,Printf,Println fucntions instead.
|
|
var Screen *bytes.Buffer = new(bytes.Buffer)
|
|
|
|
// Get relative or absolute coorditantes
|
|
// To get relative, set PCT flag to number:
|
|
//
|
|
// // Get 10% of total width to `x` and 20 to y
|
|
// x, y = tm.GetXY(10|tm.PCT, 20)
|
|
//
|
|
func GetXY(x int, y int) (int, int) {
|
|
if y == -1 {
|
|
y = CurrentHeight() + 1
|
|
}
|
|
|
|
if x&PCT != 0 {
|
|
x = int((x & 0xFF) * Width() / 100)
|
|
}
|
|
|
|
if y&PCT != 0 {
|
|
y = int((y & 0xFF) * Height() / 100)
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
type sf func(int, string) string
|
|
|
|
// Apply given transformation func for each line in string
|
|
func applyTransform(str string, transform sf) (out string) {
|
|
out = ""
|
|
|
|
for idx, line := range strings.Split(str, "\n") {
|
|
out += transform(idx, line)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Clear screen
|
|
func Clear() {
|
|
Output.WriteString("\033[2J")
|
|
}
|
|
|
|
// Move cursor to given position
|
|
func MoveCursor(x int, y int) {
|
|
fmt.Fprintf(Screen, "\033[%d;%dH", x, y)
|
|
}
|
|
|
|
// Move cursor up relative the current position
|
|
func MoveCursorUp(bias int) {
|
|
fmt.Fprintf(Screen, "\033[%dA", bias)
|
|
}
|
|
|
|
// Move cursor down relative the current position
|
|
func MoveCursorDown(bias int) {
|
|
fmt.Fprintf(Screen, "\033[%dB", bias)
|
|
}
|
|
|
|
// Move cursor forward relative the current position
|
|
func MoveCursorForward(bias int) {
|
|
fmt.Fprintf(Screen, "\033[%dC", bias)
|
|
}
|
|
|
|
// Move cursor backward relative the current position
|
|
func MoveCursorBackward(bias int) {
|
|
fmt.Fprintf(Screen, "\033[%dD", bias)
|
|
}
|
|
|
|
// Move string to possition
|
|
func MoveTo(str string, x int, y int) (out string) {
|
|
x, y = GetXY(x, y)
|
|
|
|
return applyTransform(str, func(idx int, line string) string {
|
|
return fmt.Sprintf("\033[%d;%dH%s", y+idx, x, line)
|
|
})
|
|
}
|
|
|
|
// Return carrier to start of line
|
|
func ResetLine(str string) (out string) {
|
|
return applyTransform(str, func(idx int, line string) string {
|
|
return fmt.Sprintf(RESET_LINE, line)
|
|
})
|
|
}
|
|
|
|
// Make bold
|
|
func Bold(str string) string {
|
|
return applyTransform(str, func(idx int, line string) string {
|
|
return fmt.Sprintf("\033[1m%s\033[0m", line)
|
|
})
|
|
}
|
|
|
|
// Apply given color to string:
|
|
//
|
|
// tm.Color("RED STRING", tm.RED)
|
|
//
|
|
func Color(str string, color int) string {
|
|
return applyTransform(str, func(idx int, line string) string {
|
|
return fmt.Sprintf("%s%s%s", getColor(color), line, RESET)
|
|
})
|
|
}
|
|
|
|
func Highlight(str, substr string, color int) string {
|
|
hiSubstr := Color(substr, color)
|
|
return strings.Replace(str, substr, hiSubstr, -1)
|
|
}
|
|
|
|
func HighlightRegion(str string, from, to, color int) string {
|
|
return str[:from] + Color(str[from:to], color) + str[to:]
|
|
}
|
|
|
|
// Change background color of string:
|
|
//
|
|
// tm.Background("string", tm.RED)
|
|
//
|
|
func Background(str string, color int) string {
|
|
return applyTransform(str, func(idx int, line string) string {
|
|
return fmt.Sprintf("%s%s%s", getBgColor(color), line, RESET)
|
|
})
|
|
}
|
|
|
|
// Get console width
|
|
func Width() int {
|
|
ws, err := getWinsize()
|
|
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
|
|
return int(ws.Col)
|
|
}
|
|
|
|
// Get console height
|
|
func Height() int {
|
|
ws, err := getWinsize()
|
|
if err != nil {
|
|
return -1
|
|
}
|
|
return int(ws.Row)
|
|
}
|
|
|
|
// Get current height. Line count in Screen buffer.
|
|
func CurrentHeight() int {
|
|
return strings.Count(Screen.String(), "\n")
|
|
}
|
|
|
|
// Flush buffer and ensure that it will not overflow screen
|
|
func Flush() {
|
|
for idx, str := range strings.Split(Screen.String(), "\n") {
|
|
if idx > Height() {
|
|
return
|
|
}
|
|
|
|
Output.WriteString(str + "\n")
|
|
}
|
|
|
|
Output.Flush()
|
|
Screen.Reset()
|
|
}
|
|
|
|
func Print(a ...interface{}) (n int, err error) {
|
|
return fmt.Fprint(Screen, a...)
|
|
}
|
|
|
|
func Println(a ...interface{}) (n int, err error) {
|
|
return fmt.Fprintln(Screen, a...)
|
|
}
|
|
|
|
func Printf(format string, a ...interface{}) (n int, err error) {
|
|
return fmt.Fprintf(Screen, format, a...)
|
|
}
|
|
|
|
func Context(data string, idx, max int) string {
|
|
var start, end int
|
|
|
|
if len(data[:idx]) < (max / 2) {
|
|
start = 0
|
|
} else {
|
|
start = idx - max/2
|
|
}
|
|
|
|
if len(data)-idx < (max / 2) {
|
|
end = len(data) - 1
|
|
} else {
|
|
end = idx + max/2
|
|
}
|
|
|
|
return data[start:end]
|
|
}
|