package main import ( "errors" "fmt" "oh-my-posh/environment" "oh-my-posh/properties" "runtime/debug" "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 properties.Map `config:"properties"` writer SegmentWriter stringValue string active bool env environment.Environment } // 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 Template() string Init(props properties.Properties, env environment.Environment) } // 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" // PLASTIC represents the plastic scm status and information PLASTIC SegmentType = "plastic" // 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" // SHELL writes which shell we're currently in SHELL SegmentType = "shell" // NODE writes which node version is currently active NODE SegmentType = "node" // OS write os specific icon OS SegmentType = "os" // 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" // SYSTEMINFO writes system information (memory, cpu, load) SYSTEMINFO SegmentType = "sysinfo" // ANGULAR writes which angular cli version us currently active ANGULAR SegmentType = "angular" // PHP writes which php version is currently active PHP SegmentType = "php" // NIGHTSCOUT is an open source diabetes system NIGHTSCOUT SegmentType = "nightscout" // STRAVA is a sports activity tracker STRAVA SegmentType = "strava" // WAKATIME writes tracked time spend in dev editors WAKATIME SegmentType = "wakatime" // WIFI writes details about the current WIFI connection WIFI SegmentType = "wifi" // WINREG queries the Windows registry. WINREG SegmentType = "winreg" // Brewfather segment BREWFATHER SegmentType = "brewfather" // IPIFY segment IPIFY SegmentType = "ipify" ) func (segment *Segment) string() string { template := &textTemplate{ Template: segment.writer.Template(), Context: segment.writer, Env: segment.env, } text, err := template.render() if err != nil { return err.Error() } return text } func (segment *Segment) enabled() bool { segment.active = segment.writer.Enabled() return segment.active } func (segment *Segment) getValue(property properties.Property, defaultValue string) string { if value, ok := segment.Properties[property]; ok { return properties.ParseString(value, defaultValue) } return defaultValue } func (segment *Segment) shouldIncludeFolder() bool { cwdIncluded := segment.cwdIncluded() cwdExcluded := segment.cwdExcluded() return (cwdIncluded && !cwdExcluded) } func (segment *Segment) cwdIncluded() bool { value, ok := segment.Properties[properties.IncludeFolders] if !ok { // IncludeFolders isn't specified, everything is included return true } list := properties.ParseStringArray(value) if len(list) == 0 { // IncludeFolders is an empty array, everything is included return true } return environment.DirMatchesOneOf(segment.env, segment.env.Pwd(), list) } func (segment *Segment) cwdExcluded() bool { value, ok := segment.Properties[properties.ExcludeFolders] if !ok { value = segment.Properties[properties.IgnoreFolders] } list := properties.ParseStringArray(value) return environment.DirMatchesOneOf(segment.env, segment.env.Pwd(), list) } 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 { return segment.getColor(segment.ForegroundTemplates, segment.Foreground) } func (segment *Segment) background() string { return segment.getColor(segment.BackgroundTemplates, segment.Background) } func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error { segment.env = env functions := map[SegmentType]SegmentWriter{ OWM: &Owm{}, SESSION: &Session{}, PATH: &Path{}, GIT: &Git{}, PLASTIC: &Plastic{}, EXIT: &Exit{}, PYTHON: &Python{}, ROOT: &Root{}, TEXT: &Text{}, TIME: &Time{}, CMD: &Cmd{}, BATTERY: &Battery{}, SPOTIFY: &Spotify{}, SHELL: &Shell{}, NODE: &Node{}, OS: &Os{}, 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{}, SYSTEMINFO: &SystemInfo{}, ANGULAR: &Angular{}, PHP: &Php{}, NIGHTSCOUT: &Nightscout{}, STRAVA: &Strava{}, WAKATIME: &Wakatime{}, WIFI: &Wifi{}, WINREG: &WindowsRegistry{}, BREWFATHER: &Brewfather{}, IPIFY: &IPify{}, } if segment.Properties == nil { segment.Properties = make(properties.Map) } if writer, ok := functions[segment.Type]; ok { writer.Init(segment.Properties, env) segment.writer = writer return nil } return errors.New("unable to map writer") } func (segment *Segment) setStringValue(env environment.Environment) { defer func() { err := recover() if err == nil { return } // display a message explaining omp failed(with the err) message := fmt.Sprintf("\noh-my-posh fatal error rendering %s segment:%s\n\n%s\n", segment.Type, err, debug.Stack()) fmt.Println(message) segment.stringValue = "error" segment.active = true }() err := segment.mapSegmentWithWriter(env) if err != nil || !segment.shouldIncludeFolder() { return } if segment.enabled() { segment.stringValue = segment.string() } }