forked from JanDeDobbeleer/oh-my-posh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsegment.go
316 lines (292 loc) · 9.27 KB
/
segment.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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package main
import (
"errors"
"fmt"
"strings"
"time"
)
// Segment represent a single segment and it's configuration
type Segment struct {
Type SegmentType `config:"type"`
Tips []string `config:"tips"`
Style SegmentStyle `config:"style"`
PowerlineSymbol string `config:"powerline_symbol"`
InvertPowerline bool `config:"invert_powerline"`
Foreground string `config:"foreground"`
ForegroundTemplates []string `config:"foreground_templates"`
Background string `config:"background"`
BackgroundTemplates []string `config:"background_templates"`
LeadingDiamond string `config:"leading_diamond"`
TrailingDiamond string `config:"trailing_diamond"`
Properties map[Property]interface{} `config:"properties"`
props *properties
writer SegmentWriter
stringValue string
active bool
env environmentInfo
}
// SegmentTiming holds the timing context for a segment
type SegmentTiming struct {
name string
nameLength int
enabled bool
stringValue string
enabledDuration time.Duration
stringDuration time.Duration
}
// SegmentWriter is the interface used to define what and if to write to the prompt
type SegmentWriter interface {
enabled() bool
string() string
init(props *properties, env environmentInfo)
}
// SegmentStyle the syle of segment, for more information, see the constants
type SegmentStyle string
// SegmentType the type of segment, for more information, see the constants
type SegmentType string
const (
// Session represents the user info segment
Session SegmentType = "session"
// Path represents the current path segment
Path SegmentType = "path"
// Git represents the git status and information
Git SegmentType = "git"
// Exit writes the last exit code
Exit SegmentType = "exit"
// Python writes the virtual env name
Python SegmentType = "python"
// Root writes root symbol
Root SegmentType = "root"
// Time writes the current timestamp
Time SegmentType = "time"
// Text writes a text
Text SegmentType = "text"
// Cmd writes the output of a shell command
Cmd SegmentType = "command"
// Battery writes the battery percentage
Battery SegmentType = "battery"
// Spotify writes the Spotify status for Mac
Spotify SegmentType = "spotify"
// ShellInfo writes which shell we're currently in
ShellInfo SegmentType = "shell"
// Node writes which node version is currently active
Node SegmentType = "node"
// Os write os specific icon
Os SegmentType = "os"
// EnvVar writes the content of an environment variable
EnvVar SegmentType = "envvar"
// Az writes the Azure subscription info we're currently in
Az SegmentType = "az"
// Kubectl writes the Kubernetes context we're currently in
Kubectl SegmentType = "kubectl"
// Dotnet writes which dotnet version is currently active
Dotnet SegmentType = "dotnet"
// Terraform writes the terraform workspace we're currently in
Terraform SegmentType = "terraform"
// Golang writes which go version is currently active
Golang SegmentType = "go"
// Julia writes which julia version is currently active
Julia SegmentType = "julia"
// Powerline writes it Powerline style
Powerline SegmentStyle = "powerline"
// Plain writes it without ornaments
Plain SegmentStyle = "plain"
// Diamond writes the prompt shaped with a leading and trailing symbol
Diamond SegmentStyle = "diamond"
// YTM writes YouTube Music information and status
YTM SegmentType = "ytm"
// ExecutionTime writes the execution time of the last run command
ExecutionTime SegmentType = "executiontime"
// Ruby writes which ruby version is currently active
Ruby SegmentType = "ruby"
// Aws writes the active aws context
Aws SegmentType = "aws"
// Java writes the active java version
Java SegmentType = "java"
// PoshGit writes the posh git prompt
PoshGit SegmentType = "poshgit"
// AZFunc writes current AZ func version
AZFunc SegmentType = "azfunc"
// Crystal writes the active crystal version
Crystal SegmentType = "crystal"
// Dart writes the active dart version
Dart SegmentType = "dart"
// Nbgv writes the nbgv version information
Nbgv SegmentType = "nbgv"
// Rust writes the cargo version information if cargo.toml is present
Rust SegmentType = "rust"
// OWM writes the weather coming from openweatherdata
OWM SegmentType = "owm"
// Memory writes used memory percentage
Memory SegmentType = "memory"
)
func (segment *Segment) string() string {
return segment.writer.string()
}
func (segment *Segment) enabled() bool {
segment.active = segment.writer.enabled()
return segment.active
}
func (segment *Segment) getValue(property Property, defaultValue string) string {
if value, ok := segment.Properties[property]; ok {
return parseString(value, defaultValue)
}
return defaultValue
}
func (segment *Segment) shouldIncludeFolder(cwd string) bool {
cwdIncluded := segment.cwdIncluded(cwd)
cwdExcluded := segment.cwdExcluded(cwd)
return (cwdIncluded && !cwdExcluded)
}
func (segment *Segment) cwdIncluded(cwd string) bool {
value, ok := segment.Properties[IncludeFolders]
if !ok {
// IncludeFolders isn't specified, everything is included
return true
}
list := parseStringArray(value)
if len(list) == 0 {
// IncludeFolders is an empty array, everything is included
return true
}
return segment.cwdMatchesOneOf(cwd, list)
}
func (segment *Segment) cwdExcluded(cwd string) bool {
value, ok := segment.Properties[ExcludeFolders]
if !ok {
value = segment.Properties[IgnoreFolders]
}
list := parseStringArray(value)
return segment.cwdMatchesOneOf(cwd, list)
}
func (segment *Segment) cwdMatchesOneOf(cwd string, regexes []string) bool {
normalizedCwd := strings.ReplaceAll(cwd, "\\", "/")
normalizedHomeDir := strings.ReplaceAll(segment.env.homeDir(), "\\", "/")
for _, element := range regexes {
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalizedElement, "~") {
normalizedElement = normalizedHomeDir + normalizedElement[1:]
}
pattern := fmt.Sprintf("^%s$", normalizedElement)
goos := segment.env.getRuntimeGOOS()
if goos == windowsPlatform || goos == darwinPlatform {
pattern = "(?i)" + pattern
}
matched := matchString(pattern, normalizedCwd)
if matched {
return true
}
}
return false
}
func (segment *Segment) getColor(templates []string, defaultColor string) string {
if len(templates) == 0 {
return defaultColor
}
txtTemplate := &textTemplate{
Context: segment.writer,
Env: segment.env,
}
for _, template := range templates {
txtTemplate.Template = template
value, err := txtTemplate.render()
if err != nil || value == "" {
continue
}
return value
}
return defaultColor
}
func (segment *Segment) shouldInvokeWithTip(tip string) bool {
for _, t := range segment.Tips {
if t == tip {
return true
}
}
return false
}
func (segment *Segment) foreground() string {
color := segment.Foreground
if segment.props != nil {
color = segment.props.foreground
}
return segment.getColor(segment.ForegroundTemplates, color)
}
func (segment *Segment) background() string {
color := segment.Background
if segment.props != nil {
color = segment.props.background
}
return segment.getColor(segment.BackgroundTemplates, color)
}
func (segment *Segment) mapSegmentWithWriter(env environmentInfo) error {
segment.env = env
functions := map[SegmentType]SegmentWriter{
OWM: &owm{},
Session: &session{},
Path: &path{},
Git: &git{},
Exit: &exit{},
Python: &python{},
Root: &root{},
Text: &text{},
Time: &tempus{},
Cmd: &command{},
Battery: &batt{},
Spotify: &spotify{},
ShellInfo: &shell{},
Node: &node{},
Os: &osInfo{},
EnvVar: &envvar{},
Az: &az{},
Kubectl: &kubectl{},
Dotnet: &dotnet{},
Terraform: &terraform{},
Golang: &golang{},
Julia: &julia{},
YTM: &ytm{},
ExecutionTime: &executiontime{},
Ruby: &ruby{},
Aws: &aws{},
Java: &java{},
PoshGit: &poshgit{},
AZFunc: &azfunc{},
Crystal: &crystal{},
Dart: &dart{},
Nbgv: &nbgv{},
Rust: &rust{},
Memory: &memory{},
}
if writer, ok := functions[segment.Type]; ok {
props := &properties{
values: segment.Properties,
foreground: segment.Foreground,
background: segment.Background,
}
writer.init(props, env)
segment.writer = writer
segment.props = props
return nil
}
return errors.New("unable to map writer")
}
func (segment *Segment) setStringValue(env environmentInfo, cwd string) {
defer func() {
err := recover()
if err == nil {
return
}
// display a message explaining omp failed(with the err)
message := fmt.Sprintf("oh-my-posh fatal error rendering %s segment:%s", segment.Type, err)
fmt.Println(message)
segment.stringValue = "error"
segment.active = true
}()
err := segment.mapSegmentWithWriter(env)
if err != nil || !segment.shouldIncludeFolder(cwd) {
return
}
if segment.enabled() {
segment.stringValue = segment.string()
}
}