@@ -2,11 +2,13 @@ package cliui
2
2
3
3
import (
4
4
"os"
5
+ "testing"
6
+ "time"
5
7
6
- "github.com/charmbracelet/charm/ui/common"
7
- "github.com/charmbracelet/lipgloss"
8
8
"github.com/muesli/termenv"
9
9
"golang.org/x/xerrors"
10
+
11
+ "github.com/coder/pretty"
10
12
)
11
13
12
14
var Canceled = xerrors .New ("canceled" )
@@ -15,55 +17,142 @@ var Canceled = xerrors.New("canceled")
15
17
var DefaultStyles Styles
16
18
17
19
type Styles struct {
18
- Bold ,
19
- Checkmark ,
20
20
Code ,
21
- Crossmark ,
22
21
DateTimeStamp ,
23
22
Error ,
24
23
Field ,
25
24
Keyword ,
26
- Paragraph ,
27
25
Placeholder ,
28
26
Prompt ,
29
27
FocusedPrompt ,
30
28
Fuchsia ,
31
- Logo ,
32
29
Warn ,
33
- Wrap lipgloss .Style
30
+ Wrap pretty .Style
34
31
}
35
32
36
- func init () {
37
- lipgloss .SetDefaultRenderer (
38
- lipgloss .NewRenderer (os .Stdout , termenv .WithColorCache (true )),
39
- )
33
+ var color = termenv .NewOutput (os .Stdout ).ColorProfile ()
34
+
35
+ // TestColor sets the color profile to the given profile for the duration of the
36
+ // test.
37
+ // WARN: Must not be used in parallel tests.
38
+ func TestColor (t * testing.T , tprofile termenv.Profile ) {
39
+ old := color
40
+ color = tprofile
41
+ t .Cleanup (func () {
42
+ color = old
43
+ })
44
+ }
45
+
46
+ var (
47
+ Green = color .Color ("#04B575" )
48
+ Red = color .Color ("#ED567A" )
49
+ Fuchsia = color .Color ("#EE6FF8" )
50
+ Yellow = color .Color ("#ECFD65" )
51
+ Blue = color .Color ("#5000ff" )
52
+ )
53
+
54
+ func isTerm () bool {
55
+ return color != termenv .Ascii
56
+ }
57
+
58
+ // Bold returns a formatter that renders text in bold
59
+ // if the terminal supports it.
60
+ func Bold (s string ) string {
61
+ if ! isTerm () {
62
+ return s
63
+ }
64
+ return pretty .Sprint (pretty .Bold (), s )
65
+ }
40
66
41
- // All Styles are set after we change the DefaultRenderer so that the ColorCache
42
- // is in effect, mitigating the severe performance issue seen here:
43
- // https://github.com/coder/coder/issues/7884.
67
+ // BoldFmt returns a formatter that renders text in bold
68
+ // if the terminal supports it.
69
+ func BoldFmt () pretty.Formatter {
70
+ if ! isTerm () {
71
+ return pretty.Style {}
72
+ }
73
+ return pretty .Bold ()
74
+ }
44
75
45
- charmStyles := common .DefaultStyles ()
76
+ // Timestamp formats a timestamp for display.
77
+ func Timestamp (t time.Time ) string {
78
+ return pretty .Sprint (DefaultStyles .DateTimeStamp , t .Format (time .Stamp ))
79
+ }
46
80
81
+ // Keyword formats a keyword for display.
82
+ func Keyword (s string ) string {
83
+ return pretty .Sprint (DefaultStyles .Keyword , s )
84
+ }
85
+
86
+ // Placeholder formats a placeholder for display.
87
+ func Placeholder (s string ) string {
88
+ return pretty .Sprint (DefaultStyles .Placeholder , s )
89
+ }
90
+
91
+ // Wrap prevents the text from overflowing the terminal.
92
+ func Wrap (s string ) string {
93
+ return pretty .Sprint (DefaultStyles .Wrap , s )
94
+ }
95
+
96
+ // Code formats code for display.
97
+ func Code (s string ) string {
98
+ return pretty .Sprint (DefaultStyles .Code , s )
99
+ }
100
+
101
+ // Field formats a field for display.
102
+ func Field (s string ) string {
103
+ return pretty .Sprint (DefaultStyles .Field , s )
104
+ }
105
+
106
+ func ifTerm (fmt pretty.Formatter ) pretty.Formatter {
107
+ if ! isTerm () {
108
+ return pretty .Nop
109
+ }
110
+ return fmt
111
+ }
112
+
113
+ func init () {
114
+ // We do not adapt the color based on whether the terminal is light or dark.
115
+ // Doing so would require a round-trip between the program and the terminal
116
+ // due to the OSC query and response.
47
117
DefaultStyles = Styles {
48
- Bold : lipgloss .NewStyle ().Bold (true ),
49
- Checkmark : charmStyles .Checkmark ,
50
- Code : charmStyles .Code ,
51
- Crossmark : charmStyles .Error .Copy ().SetString ("✘" ),
52
- DateTimeStamp : charmStyles .LabelDim ,
53
- Error : charmStyles .Error ,
54
- Field : charmStyles .Code .Copy ().Foreground (lipgloss.AdaptiveColor {Light : "#000000" , Dark : "#FFFFFF" }),
55
- Keyword : charmStyles .Keyword ,
56
- Paragraph : charmStyles .Paragraph ,
57
- Placeholder : lipgloss .NewStyle ().Foreground (lipgloss.AdaptiveColor {Light : "#585858" , Dark : "#4d46b3" }),
58
- Prompt : charmStyles .Prompt .Copy ().Foreground (lipgloss.AdaptiveColor {Light : "#9B9B9B" , Dark : "#5C5C5C" }),
59
- FocusedPrompt : charmStyles .FocusedPrompt .Copy ().Foreground (lipgloss .Color ("#651fff" )),
60
- Fuchsia : charmStyles .SelectedMenuItem .Copy (),
61
- Logo : charmStyles .Logo .Copy ().SetString ("Coder" ),
62
- Warn : lipgloss .NewStyle ().Foreground (
63
- lipgloss.AdaptiveColor {Light : "#04B575" , Dark : "#ECFD65" },
64
- ),
65
- Wrap : lipgloss .NewStyle ().Width (80 ),
118
+ Code : pretty.Style {
119
+ ifTerm (pretty .XPad (1 , 1 )),
120
+ pretty .FgColor (Red ),
121
+ pretty .BgColor (color .Color ("#2c2c2c" )),
122
+ },
123
+ DateTimeStamp : pretty.Style {
124
+ pretty .FgColor (color .Color ("#7571F9" )),
125
+ },
126
+ Error : pretty.Style {
127
+ pretty .FgColor (Red ),
128
+ },
129
+ Field : pretty.Style {
130
+ pretty .XPad (1 , 1 ),
131
+ pretty .FgColor (color .Color ("#FFFFFF" )),
132
+ pretty .BgColor (color .Color ("#2b2a2a" )),
133
+ },
134
+ Keyword : pretty.Style {
135
+ pretty .FgColor (Green ),
136
+ },
137
+ Placeholder : pretty.Style {
138
+ pretty .FgColor (color .Color ("#4d46b3" )),
139
+ },
140
+ Prompt : pretty.Style {
141
+ pretty .FgColor (color .Color ("#5C5C5C" )),
142
+ pretty .Wrap ("> " , "" ),
143
+ },
144
+ Warn : pretty.Style {
145
+ pretty .FgColor (Yellow ),
146
+ },
147
+ Wrap : pretty.Style {
148
+ pretty .LineWrap (80 ),
149
+ },
66
150
}
151
+
152
+ DefaultStyles .FocusedPrompt = append (
153
+ DefaultStyles .Prompt ,
154
+ pretty .FgColor (Blue ),
155
+ )
67
156
}
68
157
69
158
// ValidateNotEmpty is a helper function to disallow empty inputs!
0 commit comments