-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstyledconsole.go
181 lines (151 loc) · 5.31 KB
/
styledconsole.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
// Package styledconsole helps to make your GUI tools user-friendly with methods to pretty-print text, lists, tables, user prompts, progress bars...
package styledconsole
import (
"fmt"
"strings"
"github.com/corentindeboisset/styledconsole/styledprinter"
)
// Section displays the given string as the title of some command section.
func Section(title string) {
titleLen := len(title)
underline := strings.Repeat("=", titleLen)
styledprinter.Write(fmt.Sprintf("<fg=yellow;options=bold>%s\n%s\n</>", title, underline), true)
}
// Text displays the given string as regular text. This is useful to render help messages and instructions for the user running the command.
// This methods support style tags such as "<fg=blue>blue text</>".
func Text(content string) {
styledprinter.Write(content, true)
}
// Listing displays an list of elements
func Listing(items []string) {
for _, item := range items {
styledprinter.Write(fmt.Sprintf(" <fg=yellow>*</> %s", item), true)
}
}
// Table pretty-prints a table with headers. It does not support multiline cells or sytling.
func Table(headers []string, rows [][]string) {
// First we have to determinate the width of every column
columnWidths := getColumnWidths(headers, rows)
termWidth, _ := getWinsize()
columnWidths = getAcceptableColumnWidths(columnWidths, termWidth)
// Prepare the row spearator
sectionSeparator := "+"
for _, width := range columnWidths {
sectionSeparator += fmt.Sprintf("%s+", strings.Repeat("-", width+2))
}
var formattedRows []string
formattedRows = append(formattedRows, sectionSeparator)
formattedRows = append(formattedRows, formatOneRow(headers, columnWidths))
formattedRows = append(formattedRows, sectionSeparator)
for _, row := range rows {
formattedRows = append(formattedRows, formatOneRow(row, columnWidths))
}
formattedRows = append(formattedRows, sectionSeparator)
fmt.Printf("%s\n", strings.Join(formattedRows, "\n"))
}
// NewLine prints a line break.
func NewLine() {
styledprinter.Write("", true)
}
// NewLines print the given amount of new breaks.
func NewLines(newLineCount int) {
if newLineCount > 0 {
styledprinter.Write(strings.Repeat("\n", newLineCount-1), true)
}
}
// Ask prompts a question with the given label.
// A function can be given to ensure the validity of the response. To allow any response (even empty), put nil as validator.
func Ask(label string, validator func(string) bool) (string, error) {
q := question{
Label: label,
IsClosed: false,
IsHidden: false,
DefaultAnswer: "",
Validator: validator,
}
res, err := askQuestion(q)
if err != nil {
return "", err
}
return res, nil
}
// Same as Ask() but if the user's answer is empty, the given defaultAnswer is chosen instead.
func AskWithDefault(label string, defaultAnswer string, validator func(string) bool) (string, error) {
q := question{
Label: label,
IsClosed: false,
IsHidden: false,
DefaultAnswer: defaultAnswer,
Validator: validator,
}
res, err := askQuestion(q)
if err != nil {
return "", err
}
return res, nil
}
// Same as Ask() but the characters typed by the user are not printed in the output, in a linux-style password prompt.
func AskHidden(label string, validator func(string) bool) (string, error) {
q := question{
Label: label,
IsClosed: false,
IsHidden: true,
DefaultAnswer: "",
Validator: validator,
}
res, err := askQuestion(q)
if err != nil {
return "", err
}
return res, nil
}
// Confirm prompts a yes/no question.
func Confirm(label string) (bool, error) {
return askConfirm(label, nil)
}
// ConfirmWithDefault prompts a yes/no question, with a given answer by default if the user's answer is empty.
func ConfirmWithDefault(label string, defaultAnswer bool) (bool, error) {
return askConfirm(label, &defaultAnswer)
}
// Choice prints a list of choices the user can choose between.
// The prompts adapts itself to the size of the terminal.
func Choice(label string, choices []string) (string, error) {
q := question{
Label: label,
IsClosed: true,
Choices: choices,
DefaultChoice: -1,
}
choice, err := askQuestion(q)
if err != nil {
return "", err
}
return choice, nil
}
// ChoiceWithDefault is the same as Choice() but a specific answer index should be given to highlight by default.
func ChoiceWithDefault(label string, choices []string, defaultAnswer int) (string, error) {
q := question{
Label: label,
IsClosed: true,
Choices: choices,
DefaultChoice: defaultAnswer,
}
choice, err := askQuestion(q)
if err != nil {
fmt.Printf("error: %s", err)
return "", err
}
return choice, nil
}
// Success displays the given string highlighted as a successful message (with a green background and an [OK] label).
func Success(content string) {
styledprinter.WriteBlock(fmt.Sprintf("Success:\n%s", content), " ", "bg=green;fg=black", true)
}
// Warning displays the given string highlighted as a warning message (with yellow text and a [Warning] label).
func Warning(content string) {
styledprinter.WriteBlock(fmt.Sprintf("Warning:\n%s", content), "# ", "fg=yellow", true)
}
// Error displays the given string highlighted as an error message (with a red background and the [Error] label).
func Error(content string) {
styledprinter.WriteBlock(fmt.Sprintf("Error:\n%s", content), " ", "bg=red;fg=black", true)
}