podman
249 строк · 5.0 Кб
1// Provides basic bulding blocks for advanced console UI
2//
3// Coordinate system:
4//
5// 1/1---X---->
6// |
7// Y
8// |
9// v
10//
11// Documentation for ANSI codes: http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
12//
13// Inspired by: http://www.darkcoding.net/software/pretty-command-line-console-output-on-unix-in-python-and-go-lang/
14package goterm
15
16import (
17"bufio"
18"bytes"
19"fmt"
20"os"
21"strings"
22)
23
24// Reset all custom styles
25const RESET = "\033[0m"
26
27// Reset to default color
28const RESET_COLOR = "\033[32m"
29
30// Return cursor to start of line and clean it
31const RESET_LINE = "\r\033[K"
32
33// List of possible colors
34const (
35BLACK = iota
36RED
37GREEN
38YELLOW
39BLUE
40MAGENTA
41CYAN
42WHITE
43)
44
45var Output *bufio.Writer = bufio.NewWriter(os.Stdout)
46
47func getColor(code int) string {
48return fmt.Sprintf("\033[3%dm", code)
49}
50
51func getBgColor(code int) string {
52return fmt.Sprintf("\033[4%dm", code)
53}
54
55// Set percent flag: num | PCT
56//
57// Check percent flag: num & PCT
58//
59// Reset percent flag: num & 0xFF
60const shift = uint(^uint(0)>>63) << 4
61const PCT = 0x8000 << shift
62
63type winsize struct {
64Row uint16
65Col uint16
66Xpixel uint16
67Ypixel uint16
68}
69
70// Global screen buffer
71// Its not recommended write to buffer dirrectly, use package Print,Printf,Println fucntions instead.
72var Screen *bytes.Buffer = new(bytes.Buffer)
73
74// GetXY gets relative or absolute coordinates
75// To get relative, set PCT flag to number:
76//
77// // Get 10% of total width to `x` and 20 to y
78// x, y = tm.GetXY(10|tm.PCT, 20)
79//
80func GetXY(x int, y int) (int, int) {
81if y == -1 {
82y = CurrentHeight() + 1
83}
84
85if x&PCT != 0 {
86x = int((x & 0xFF) * Width() / 100)
87}
88
89if y&PCT != 0 {
90y = int((y & 0xFF) * Height() / 100)
91}
92
93return x, y
94}
95
96type sf func(int, string) string
97
98// Apply given transformation func for each line in string
99func applyTransform(str string, transform sf) (out string) {
100out = ""
101
102for idx, line := range strings.Split(str, "\n") {
103out += transform(idx, line)
104}
105
106return
107}
108
109// Clear screen
110func Clear() {
111Output.WriteString("\033[2J")
112}
113
114// Move cursor to given position
115func MoveCursor(x int, y int) {
116fmt.Fprintf(Screen, "\033[%d;%dH", y, x)
117}
118
119// Move cursor up relative the current position
120func MoveCursorUp(bias int) {
121fmt.Fprintf(Screen, "\033[%dA", bias)
122}
123
124// Move cursor down relative the current position
125func MoveCursorDown(bias int) {
126fmt.Fprintf(Screen, "\033[%dB", bias)
127}
128
129// Move cursor forward relative the current position
130func MoveCursorForward(bias int) {
131fmt.Fprintf(Screen, "\033[%dC", bias)
132}
133
134// Move cursor backward relative the current position
135func MoveCursorBackward(bias int) {
136fmt.Fprintf(Screen, "\033[%dD", bias)
137}
138
139// Move string to possition
140func MoveTo(str string, x int, y int) (out string) {
141x, y = GetXY(x, y)
142
143return applyTransform(str, func(idx int, line string) string {
144return fmt.Sprintf("\033[%d;%dH%s", y+idx, x, line)
145})
146}
147
148// ResetLine returns carrier to start of line
149func ResetLine(str string) (out string) {
150return applyTransform(str, func(idx int, line string) string {
151return fmt.Sprintf("%s%s", RESET_LINE, line)
152})
153}
154
155// Make bold
156func Bold(str string) string {
157return applyTransform(str, func(idx int, line string) string {
158return fmt.Sprintf("\033[1m%s\033[0m", line)
159})
160}
161
162// Apply given color to string:
163//
164// tm.Color("RED STRING", tm.RED)
165//
166func Color(str string, color int) string {
167return applyTransform(str, func(idx int, line string) string {
168return fmt.Sprintf("%s%s%s", getColor(color), line, RESET)
169})
170}
171
172func Highlight(str, substr string, color int) string {
173hiSubstr := Color(substr, color)
174return strings.Replace(str, substr, hiSubstr, -1)
175}
176
177func HighlightRegion(str string, from, to, color int) string {
178return str[:from] + Color(str[from:to], color) + str[to:]
179}
180
181// Change background color of string:
182//
183// tm.Background("string", tm.RED)
184//
185func Background(str string, color int) string {
186return applyTransform(str, func(idx int, line string) string {
187return fmt.Sprintf("%s%s%s", getBgColor(color), line, RESET)
188})
189}
190
191// Width gets console width
192func Width() int {
193ws, err := getWinsize()
194
195if err != nil {
196return -1
197}
198
199return int(ws.Col)
200}
201
202// CurrentHeight gets current height. Line count in Screen buffer.
203func CurrentHeight() int {
204return strings.Count(Screen.String(), "\n")
205}
206
207// Flush buffer and ensure that it will not overflow screen
208func Flush() {
209for idx, str := range strings.SplitAfter(Screen.String(), "\n") {
210if idx > Height() {
211return
212}
213
214Output.WriteString(str)
215}
216
217Output.Flush()
218Screen.Reset()
219}
220
221func Print(a ...interface{}) (n int, err error) {
222return fmt.Fprint(Screen, a...)
223}
224
225func Println(a ...interface{}) (n int, err error) {
226return fmt.Fprintln(Screen, a...)
227}
228
229func Printf(format string, a ...interface{}) (n int, err error) {
230return fmt.Fprintf(Screen, format, a...)
231}
232
233func Context(data string, idx, max int) string {
234var start, end int
235
236if len(data[:idx]) < (max / 2) {
237start = 0
238} else {
239start = idx - max/2
240}
241
242if len(data)-idx < (max / 2) {
243end = len(data) - 1
244} else {
245end = idx + max/2
246}
247
248return data[start:end]
249}
250