refactor: move environment into it's own module

This commit is contained in:
Jan De Dobbeleer 2022-01-26 10:23:18 +01:00 committed by Jan De Dobbeleer
parent f7a07c6b62
commit 906ece2af9
116 changed files with 1016 additions and 870 deletions

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/regex"
"strings" "strings"
) )
@ -122,16 +123,16 @@ func (a *ansiUtils) lenWithoutANSI(text string) int {
return 0 return 0
} }
// replace hyperlinks(file/http/https) // replace hyperlinks(file/http/https)
matches := findAllNamedRegexMatch(`(?P<STR>\x1b]8;;(file|http|https):\/\/(.+?)\x1b\\(?P<URL>.+?)\x1b]8;;\x1b\\)`, text) matches := regex.FindAllNamedRegexMatch(`(?P<STR>\x1b]8;;(file|http|https):\/\/(.+?)\x1b\\(?P<URL>.+?)\x1b]8;;\x1b\\)`, text)
for _, match := range matches { for _, match := range matches {
text = strings.ReplaceAll(text, match[str], match[url]) text = strings.ReplaceAll(text, match[str], match[url])
} }
// replace console title // replace console title
matches = findAllNamedRegexMatch(`(?P<STR>\x1b\]0;(.+)\007)`, text) matches = regex.FindAllNamedRegexMatch(`(?P<STR>\x1b\]0;(.+)\007)`, text)
for _, match := range matches { for _, match := range matches {
text = strings.ReplaceAll(text, match[str], "") text = strings.ReplaceAll(text, match[str], "")
} }
stripped := replaceAllString(ansiRegex, text, "") stripped := regex.ReplaceAllString(ansiRegex, text, "")
stripped = strings.ReplaceAll(stripped, a.escapeLeft, "") stripped = strings.ReplaceAll(stripped, a.escapeLeft, "")
stripped = strings.ReplaceAll(stripped, a.escapeRight, "") stripped = strings.ReplaceAll(stripped, a.escapeRight, "")
runeText := []rune(stripped) runeText := []rune(stripped)
@ -140,7 +141,7 @@ func (a *ansiUtils) lenWithoutANSI(text string) int {
func (a *ansiUtils) generateHyperlink(text string) string { func (a *ansiUtils) generateHyperlink(text string) string {
// hyperlink matching // hyperlink matching
results := findNamedRegexMatch("(?P<all>(?:\\[(?P<name>.+)\\])(?:\\((?P<url>.*)\\)))", text) results := regex.FindNamedRegexMatch("(?P<all>(?:\\[(?P<name>.+)\\])(?:\\((?P<url>.*)\\)))", text)
if len(results) != 3 { if len(results) != 3 {
return text return text
} }
@ -151,7 +152,7 @@ func (a *ansiUtils) generateHyperlink(text string) string {
} }
func (a *ansiUtils) formatText(text string) string { func (a *ansiUtils) formatText(text string) string {
results := findAllNamedRegexMatch("(?P<context><(?P<format>[buis])>(?P<text>[^<]+)</[buis]>)", text) results := regex.FindAllNamedRegexMatch("(?P<context><(?P<format>[buis])>(?P<text>[^<]+)</[buis]>)", text)
for _, result := range results { for _, result := range results {
var formatted string var formatted string
switch result["format"] { switch result["format"] {

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/environment"
"sync" "sync"
"time" "time"
) )
@ -33,7 +34,7 @@ type Block struct {
Segments []*Segment `config:"segments"` Segments []*Segment `config:"segments"`
Newline bool `config:"newline"` Newline bool `config:"newline"`
env Environment env environment.Environment
writer promptWriter writer promptWriter
ansi *ansiUtils ansi *ansiUtils
activeSegment *Segment activeSegment *Segment
@ -42,13 +43,13 @@ type Block struct {
activeForeground string activeForeground string
} }
func (b *Block) init(env Environment, writer promptWriter, ansi *ansiUtils) { func (b *Block) init(env environment.Environment, writer promptWriter, ansi *ansiUtils) {
b.env = env b.env = env
b.writer = writer b.writer = writer
b.ansi = ansi b.ansi = ansi
} }
func (b *Block) initPlain(env Environment, config *Config) { func (b *Block) initPlain(env environment.Environment, config *Config) {
b.ansi = &ansiUtils{} b.ansi = &ansiUtils{}
b.ansi.init(plain) b.ansi.init(plain)
b.writer = &AnsiWriter{ b.writer = &AnsiWriter{

View file

@ -2,13 +2,14 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"github.com/gookit/color" "github.com/gookit/color"
) )
// MakeColors creates instance of AnsiColors to use in AnsiWriter according to // MakeColors creates instance of AnsiColors to use in AnsiWriter according to
// environment and configuration. // environment and configuration.
func MakeColors(env Environment, cfg *Config) AnsiColors { func MakeColors(env environment.Environment, cfg *Config) AnsiColors {
cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1" cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1"
return makeColors(cfg.Palette, !cacheDisabled) return makeColors(cfg.Palette, !cacheDisabled)
} }

View file

@ -7,6 +7,7 @@ import (
json2 "encoding/json" json2 "encoding/json"
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/environment"
"os" "os"
"strconv" "strconv"
"strings" "strings"
@ -56,7 +57,7 @@ func printConfigError(err error, eval bool) {
} }
// GetConfig returns the default configuration including possible user overrides // GetConfig returns the default configuration including possible user overrides
func GetConfig(env Environment) *Config { func GetConfig(env environment.Environment) *Config {
cfg, err := loadConfig(env) cfg, err := loadConfig(env)
if err != nil { if err != nil {
return getDefaultConfig(err.Error()) return getDefaultConfig(err.Error())
@ -64,7 +65,7 @@ func GetConfig(env Environment) *Config {
return cfg return cfg
} }
func loadConfig(env Environment) (*Config, error) { func loadConfig(env environment.Environment) (*Config, error) {
var cfg Config var cfg Config
configFile := *env.Args().Config configFile := *env.Args().Config
eval := *env.Args().Eval eval := *env.Args().Eval

View file

@ -2,11 +2,12 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"strings" "strings"
) )
type consoleTitle struct { type consoleTitle struct {
env Environment env environment.Environment
config *Config config *Config
ansi *ansiUtils ansi *ansiUtils
} }
@ -33,7 +34,7 @@ func (t *consoleTitle) getConsoleTitle() string {
case FolderName: case FolderName:
fallthrough fallthrough
default: default:
title = base(t.getPwd(), t.env) title = environment.Base(t.env, t.getPwd())
} }
title = t.ansi.escapeText(title) title = t.ansi.escapeText(title)
return fmt.Sprintf(t.ansi.title, title) return fmt.Sprintf(t.ansi.title, title)

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -52,11 +54,11 @@ func TestGetConsoleTitle(t *testing.T) {
ConsoleTitleStyle: tc.Style, ConsoleTitleStyle: tc.Style,
ConsoleTitleTemplate: tc.Template, ConsoleTitleTemplate: tc.Template,
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Pwd").Return(tc.Cwd) env.On("Pwd").Return(tc.Cwd)
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("PathSeperator").Return(tc.PathSeperator) env.On("PathSeperator").Return(tc.PathSeperator)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: map[string]string{ Env: map[string]string{
"USERDOMAIN": "MyCompany", "USERDOMAIN": "MyCompany",
}, },
@ -65,7 +67,7 @@ func TestGetConsoleTitle(t *testing.T) {
Root: tc.Root, Root: tc.Root,
HostName: "MyHost", HostName: "MyHost",
PWD: tc.Cwd, PWD: tc.Cwd,
Folder: base(tc.Cwd, env), Folder: "vagrant",
}) })
ansi := &ansiUtils{} ansi := &ansiUtils{}
ansi.init(tc.ShellName) ansi.init(tc.ShellName)
@ -113,10 +115,10 @@ func TestGetConsoleTitleIfGethostnameReturnsError(t *testing.T) {
ConsoleTitleStyle: tc.Style, ConsoleTitleStyle: tc.Style,
ConsoleTitleTemplate: tc.Template, ConsoleTitleTemplate: tc.Template,
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Pwd").Return(tc.Cwd) env.On("Pwd").Return(tc.Cwd)
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: map[string]string{ Env: map[string]string{
"USERDOMAIN": "MyCompany", "USERDOMAIN": "MyCompany",
}, },

View file

@ -1,33 +0,0 @@
package main
const (
FHSS WifiType = "FHSS"
DSSS WifiType = "DSSS"
IR WifiType = "IR"
A WifiType = "802.11a"
HRDSSS WifiType = "HRDSSS"
G WifiType = "802.11g"
N WifiType = "802.11n"
AC WifiType = "802.11ac"
Infrastructure WifiType = "Infrastructure"
Independent WifiType = "Independent"
Any WifiType = "Any"
OpenSystem WifiType = "802.11 Open System"
SharedKey WifiType = "802.11 Shared Key"
WPA WifiType = "WPA"
WPAPSK WifiType = "WPA PSK"
WPANone WifiType = "WPA NONE"
WPA2 WifiType = "WPA2"
WPA2PSK WifiType = "WPA2 PSK"
Disabled WifiType = "disabled"
Unknown WifiType = "Unknown"
None WifiType = "None"
WEP40 WifiType = "WEP40"
TKIP WifiType = "TKIP"
CCMP WifiType = "CCMP"
WEP104 WifiType = "WEP104"
WEP WifiType = "WEP"
)

View file

@ -2,13 +2,14 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"strings" "strings"
"time" "time"
) )
type engine struct { type engine struct {
config *Config config *Config
env Environment env environment.Environment
writer promptWriter writer promptWriter
ansi *ansiUtils ansi *ansiUtils
consoleTitle *consoleTitle consoleTitle *consoleTitle

View file

@ -2,6 +2,8 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/environment"
"oh-my-posh/mock"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -29,7 +31,7 @@ func TestCanWriteRPrompt(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("TerminalWidth").Return(tc.TerminalWidth, tc.TerminalWidthError) env.On("TerminalWidth").Return(tc.TerminalWidth, tc.TerminalWidthError)
ansi := &ansiUtils{} ansi := &ansiUtils{}
ansi.init(plain) ansi.init(plain)
@ -73,7 +75,7 @@ func engineRender(configPath string) error {
execTime = 917.0 execTime = 917.0
) )
args := &Args{ args := &environment.Args{
Debug: &debug, Debug: &debug,
Config: &configPath, Config: &configPath,
Eval: &eval, Eval: &eval,
@ -85,8 +87,8 @@ func engineRender(configPath string) error {
ExecutionTime: &execTime, ExecutionTime: &execTime,
} }
env := &environment{} env := &environment.ShellEnvironment{}
env.init(args) env.Init(args)
defer env.Close() defer env.Close()
cfg := GetConfig(env) cfg := GetConfig(env)

View file

@ -1,4 +1,4 @@
package main package environment
import ( import (
"encoding/json" "encoding/json"

View file

@ -1,4 +1,4 @@
package main package environment
import "sync" import "sync"

View file

@ -1,4 +1,4 @@
package main package environment
import ( import (
"net/http" "net/http"

View file

@ -1,4 +1,4 @@
package main package environment
import ( import (
"bytes" "bytes"
@ -8,6 +8,7 @@ import (
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"oh-my-posh/regex"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -20,24 +21,53 @@ import (
) )
const ( const (
unknown = "unknown" Unknown = "unknown"
windowsPlatform = "windows" WindowsPlatform = "windows"
darwinPlatform = "darwin" DarwinPlatform = "darwin"
linuxPlatform = "linux" LinuxPlatform = "linux"
) )
type commandError struct { type Args struct {
err string ErrorCode *int
exitCode int PrintConfig *bool
ConfigFormat *string
PrintShell *bool
Config *string
Shell *string
PWD *string
PSWD *string
Version *bool
Debug *bool
ExecutionTime *float64
Millis *bool
Eval *bool
Init *bool
PrintInit *bool
ExportPNG *bool
Author *string
CursorPadding *int
RPromptOffset *int
RPrompt *bool
BGColor *string
StackCount *int
Command *string
PrintTransient *bool
Plain *bool
CachePath *bool
} }
func (e *commandError) Error() string { type CommandError struct {
return e.err Err string
ExitCode int
} }
type noBatteryError struct{} func (e *CommandError) Error() string {
return e.Err
}
func (m *noBatteryError) Error() string { type NoBatteryError struct{}
func (m *NoBatteryError) Error() string {
return "no battery" return "no battery"
} }
@ -57,19 +87,19 @@ type Cache interface {
type HTTPRequestModifier func(request *http.Request) type HTTPRequestModifier func(request *http.Request)
type windowsRegistryValueType int type WindowsRegistryValueType int
const ( const (
regQword windowsRegistryValueType = iota RegQword WindowsRegistryValueType = iota
regDword RegDword
regString RegString
) )
type WindowsRegistryValue struct { type WindowsRegistryValue struct {
valueType windowsRegistryValueType ValueType WindowsRegistryValueType
qword uint64 Qword uint64
dword uint32 Dword uint32
str string Str string
} }
type WifiType string type WifiType string
@ -88,6 +118,19 @@ type WifiInfo struct {
Error string Error string
} }
type TemplateCache struct {
Root bool
PWD string
Folder string
Shell string
UserName string
HostName string
Code int
Env map[string]string
OS string
WSL bool
}
type Environment interface { type Environment interface {
Getenv(key string) string Getenv(key string) string
Pwd() string Pwd() string
@ -154,7 +197,7 @@ const (
Debug logType = "debug" Debug logType = "debug"
) )
type environment struct { type ShellEnvironment struct {
args *Args args *Args
cwd string cwd string
cmdCache *commandCache cmdCache *commandCache
@ -164,11 +207,11 @@ type environment struct {
debug bool debug bool
} }
func (env *environment) init(args *Args) { func (env *ShellEnvironment) Init(args *Args) {
env.args = args env.args = args
env.fileCache = &fileCache{} env.fileCache = &fileCache{}
env.fileCache.Init(env.CachePath()) env.fileCache.Init(env.CachePath())
env.resolveConfigPath() env.ResolveConfigPath()
env.cmdCache = &commandCache{ env.cmdCache = &commandCache{
commands: newConcurrentMap(), commands: newConcurrentMap(),
} }
@ -178,13 +221,13 @@ func (env *environment) init(args *Args) {
} }
} }
func (env *environment) resolveConfigPath() { func (env *ShellEnvironment) ResolveConfigPath() {
if env.args == nil || env.args.Config == nil || len(*env.args.Config) == 0 { if env.args == nil || env.args.Config == nil || len(*env.args.Config) == 0 {
return return
} }
// Cygwin path always needs the full path as we're on Windows but not really. // Cygwin path always needs the full path as we're on Windows but not really.
// Doing filepath actions will convert it to a Windows path and break the init script. // Doing filepath actions will convert it to a Windows path and break the init script.
if env.Platform() == windowsPlatform && env.Shell() == bash { if env.Platform() == WindowsPlatform && env.Shell() == "bash" {
return return
} }
configFile := *env.args.Config configFile := *env.args.Config
@ -200,7 +243,7 @@ func (env *environment) resolveConfigPath() {
*env.args.Config = filepath.Clean(configFile) *env.args.Config = filepath.Clean(configFile)
} }
func (env *environment) trace(start time.Time, function string, args ...string) { func (env *ShellEnvironment) trace(start time.Time, function string, args ...string) {
if !env.debug { if !env.debug {
return return
} }
@ -209,7 +252,7 @@ func (env *environment) trace(start time.Time, function string, args ...string)
log.Println(trace) log.Println(trace)
} }
func (env *environment) log(lt logType, function, message string) { func (env *ShellEnvironment) log(lt logType, function, message string) {
if !env.debug { if !env.debug {
return return
} }
@ -217,14 +260,14 @@ func (env *environment) log(lt logType, function, message string) {
log.Println(trace) log.Println(trace)
} }
func (env *environment) Getenv(key string) string { func (env *ShellEnvironment) Getenv(key string) string {
defer env.trace(time.Now(), "Getenv", key) defer env.trace(time.Now(), "Getenv", key)
val := os.Getenv(key) val := os.Getenv(key)
env.log(Debug, "Getenv", val) env.log(Debug, "Getenv", val)
return val return val
} }
func (env *environment) Pwd() string { func (env *ShellEnvironment) Pwd() string {
defer env.trace(time.Now(), "Pwd") defer env.trace(time.Now(), "Pwd")
defer func() { defer func() {
env.log(Debug, "Pwd", env.cwd) env.log(Debug, "Pwd", env.cwd)
@ -234,7 +277,7 @@ func (env *environment) Pwd() string {
} }
correctPath := func(pwd string) string { correctPath := func(pwd string) string {
// on Windows, and being case sensitive and not consistent and all, this gives silly issues // on Windows, and being case sensitive and not consistent and all, this gives silly issues
driveLetter := getCompiledRegex(`^[a-z]:`) driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
return driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper) return driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper)
} }
if env.args != nil && *env.args.PWD != "" { if env.args != nil && *env.args.PWD != "" {
@ -250,7 +293,7 @@ func (env *environment) Pwd() string {
return env.cwd return env.cwd
} }
func (env *environment) HasFiles(pattern string) bool { func (env *ShellEnvironment) HasFiles(pattern string) bool {
defer env.trace(time.Now(), "HasFiles", pattern) defer env.trace(time.Now(), "HasFiles", pattern)
cwd := env.Pwd() cwd := env.Pwd()
pattern = cwd + env.PathSeperator() + pattern pattern = cwd + env.PathSeperator() + pattern
@ -262,7 +305,7 @@ func (env *environment) HasFiles(pattern string) bool {
return len(matches) > 0 return len(matches) > 0
} }
func (env *environment) HasFilesInDir(dir, pattern string) bool { func (env *ShellEnvironment) HasFilesInDir(dir, pattern string) bool {
defer env.trace(time.Now(), "HasFilesInDir", pattern) defer env.trace(time.Now(), "HasFilesInDir", pattern)
pattern = dir + env.PathSeperator() + pattern pattern = dir + env.PathSeperator() + pattern
matches, err := filepath.Glob(pattern) matches, err := filepath.Glob(pattern)
@ -273,13 +316,13 @@ func (env *environment) HasFilesInDir(dir, pattern string) bool {
return len(matches) > 0 return len(matches) > 0
} }
func (env *environment) HasFolder(folder string) bool { func (env *ShellEnvironment) HasFolder(folder string) bool {
defer env.trace(time.Now(), "HasFolder", folder) defer env.trace(time.Now(), "HasFolder", folder)
_, err := os.Stat(folder) _, err := os.Stat(folder)
return !os.IsNotExist(err) return !os.IsNotExist(err)
} }
func (env *environment) FileContent(file string) string { func (env *ShellEnvironment) FileContent(file string) string {
defer env.trace(time.Now(), "FileContent", file) defer env.trace(time.Now(), "FileContent", file)
content, err := ioutil.ReadFile(file) content, err := ioutil.ReadFile(file)
if err != nil { if err != nil {
@ -289,7 +332,7 @@ func (env *environment) FileContent(file string) string {
return string(content) return string(content)
} }
func (env *environment) FolderList(path string) []string { func (env *ShellEnvironment) FolderList(path string) []string {
defer env.trace(time.Now(), "FolderList", path) defer env.trace(time.Now(), "FolderList", path)
content, err := os.ReadDir(path) content, err := os.ReadDir(path)
if err != nil { if err != nil {
@ -305,12 +348,12 @@ func (env *environment) FolderList(path string) []string {
return folderNames return folderNames
} }
func (env *environment) PathSeperator() string { func (env *ShellEnvironment) PathSeperator() string {
defer env.trace(time.Now(), "PathSeperator") defer env.trace(time.Now(), "PathSeperator")
return string(os.PathSeparator) return string(os.PathSeparator)
} }
func (env *environment) User() string { func (env *ShellEnvironment) User() string {
defer env.trace(time.Now(), "User") defer env.trace(time.Now(), "User")
user := os.Getenv("USER") user := os.Getenv("USER")
if user == "" { if user == "" {
@ -319,7 +362,7 @@ func (env *environment) User() string {
return user return user
} }
func (env *environment) Host() (string, error) { func (env *ShellEnvironment) Host() (string, error) {
defer env.trace(time.Now(), "Host") defer env.trace(time.Now(), "Host")
hostName, err := os.Hostname() hostName, err := os.Hostname()
if err != nil { if err != nil {
@ -329,12 +372,12 @@ func (env *environment) Host() (string, error) {
return cleanHostName(hostName), nil return cleanHostName(hostName), nil
} }
func (env *environment) GOOS() string { func (env *ShellEnvironment) GOOS() string {
defer env.trace(time.Now(), "GOOS") defer env.trace(time.Now(), "GOOS")
return runtime.GOOS return runtime.GOOS
} }
func (env *environment) RunCommand(command string, args ...string) (string, error) { func (env *ShellEnvironment) RunCommand(command string, args ...string) (string, error) {
defer env.trace(time.Now(), "RunCommand", append([]string{command}, args...)...) defer env.trace(time.Now(), "RunCommand", append([]string{command}, args...)...)
if cmd, ok := env.cmdCache.get(command); ok { if cmd, ok := env.cmdCache.get(command); ok {
command = cmd command = cmd
@ -356,13 +399,13 @@ func (env *environment) RunCommand(command string, args ...string) (string, erro
return output, nil return output, nil
} }
func (env *environment) RunShellCommand(shell, command string) string { func (env *ShellEnvironment) RunShellCommand(shell, command string) string {
defer env.trace(time.Now(), "RunShellCommand", shell, command) defer env.trace(time.Now(), "RunShellCommand", shell, command)
out, _ := env.RunCommand(shell, "-c", command) out, _ := env.RunCommand(shell, "-c", command)
return out return out
} }
func (env *environment) HasCommand(command string) bool { func (env *ShellEnvironment) HasCommand(command string) bool {
defer env.trace(time.Now(), "HasCommand", command) defer env.trace(time.Now(), "HasCommand", command)
if _, ok := env.cmdCache.get(command); ok { if _, ok := env.cmdCache.get(command); ok {
return true return true
@ -376,12 +419,12 @@ func (env *environment) HasCommand(command string) bool {
return false return false
} }
func (env *environment) ErrorCode() int { func (env *ShellEnvironment) ErrorCode() int {
defer env.trace(time.Now(), "ErrorCode") defer env.trace(time.Now(), "ErrorCode")
return *env.args.ErrorCode return *env.args.ErrorCode
} }
func (env *environment) ExecutionTime() float64 { func (env *ShellEnvironment) ExecutionTime() float64 {
defer env.trace(time.Now(), "ExecutionTime") defer env.trace(time.Now(), "ExecutionTime")
if *env.args.ExecutionTime < 0 { if *env.args.ExecutionTime < 0 {
return 0 return 0
@ -389,12 +432,12 @@ func (env *environment) ExecutionTime() float64 {
return *env.args.ExecutionTime return *env.args.ExecutionTime
} }
func (env *environment) Args() *Args { func (env *ShellEnvironment) Args() *Args {
defer env.trace(time.Now(), "Args") defer env.trace(time.Now(), "Args")
return env.args return env.args
} }
func (env *environment) BatteryInfo() ([]*battery.Battery, error) { func (env *ShellEnvironment) BatteryInfo() ([]*battery.Battery, error) {
defer env.trace(time.Now(), "BatteryInfo") defer env.trace(time.Now(), "BatteryInfo")
batteries, err := battery.GetAll() batteries, err := battery.GetAll()
// actual error, return it // actual error, return it
@ -404,7 +447,7 @@ func (env *environment) BatteryInfo() ([]*battery.Battery, error) {
} }
// there are no batteries found // there are no batteries found
if len(batteries) == 0 { if len(batteries) == 0 {
return nil, &noBatteryError{} return nil, &NoBatteryError{}
} }
// some batteries fail to get retrieved, filter them out if present // some batteries fail to get retrieved, filter them out if present
validBatteries := []*battery.Battery{} validBatteries := []*battery.Battery{}
@ -454,7 +497,7 @@ func (env *environment) BatteryInfo() ([]*battery.Battery, error) {
return validBatteries, nil return validBatteries, nil
} }
func (env *environment) Shell() string { func (env *ShellEnvironment) Shell() string {
defer env.trace(time.Now(), "Shell") defer env.trace(time.Now(), "Shell")
if *env.args.Shell != "" { if *env.args.Shell != "" {
return *env.args.Shell return *env.args.Shell
@ -464,7 +507,7 @@ func (env *environment) Shell() string {
name, err := p.Name() name, err := p.Name()
if err != nil { if err != nil {
env.log(Error, "Shell", err.Error()) env.log(Error, "Shell", err.Error())
return unknown return Unknown
} }
if name == "cmd.exe" { if name == "cmd.exe" {
p, _ = p.Parent() p, _ = p.Parent()
@ -472,14 +515,14 @@ func (env *environment) Shell() string {
} }
if err != nil { if err != nil {
env.log(Error, "Shell", err.Error()) env.log(Error, "Shell", err.Error())
return unknown return Unknown
} }
// Cache the shell value to speed things up. // Cache the shell value to speed things up.
*env.args.Shell = strings.Trim(strings.Replace(name, ".exe", "", 1), " ") *env.args.Shell = strings.Trim(strings.Replace(name, ".exe", "", 1), " ")
return *env.args.Shell return *env.args.Shell
} }
func (env *environment) HTTPRequest(url string, timeout int, requestModifiers ...HTTPRequestModifier) ([]byte, error) { func (env *ShellEnvironment) HTTPRequest(url string, timeout int, requestModifiers ...HTTPRequestModifier) ([]byte, error) {
defer env.trace(time.Now(), "HTTPRequest", url) defer env.trace(time.Now(), "HTTPRequest", url)
ctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout)) ctx, cncl := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout))
defer cncl() defer cncl()
@ -504,7 +547,7 @@ func (env *environment) HTTPRequest(url string, timeout int, requestModifiers ..
return body, nil return body, nil
} }
func (env *environment) HasParentFilePath(path string) (*FileInfo, error) { func (env *ShellEnvironment) HasParentFilePath(path string) (*FileInfo, error) {
defer env.trace(time.Now(), "HasParentFilePath", path) defer env.trace(time.Now(), "HasParentFilePath", path)
currentFolder := env.Pwd() currentFolder := env.Pwd()
for { for {
@ -529,7 +572,7 @@ func (env *environment) HasParentFilePath(path string) (*FileInfo, error) {
} }
} }
func (env *environment) StackCount() int { func (env *ShellEnvironment) StackCount() int {
defer env.trace(time.Now(), "StackCount") defer env.trace(time.Now(), "StackCount")
if *env.args.StackCount < 0 { if *env.args.StackCount < 0 {
return 0 return 0
@ -537,19 +580,19 @@ func (env *environment) StackCount() int {
return *env.args.StackCount return *env.args.StackCount
} }
func (env *environment) Cache() Cache { func (env *ShellEnvironment) Cache() Cache {
return env.fileCache return env.fileCache
} }
func (env *environment) Close() { func (env *ShellEnvironment) Close() {
env.fileCache.Close() env.fileCache.Close()
} }
func (env *environment) Logs() string { func (env *ShellEnvironment) Logs() string {
return env.logBuilder.String() return env.logBuilder.String()
} }
func (env *environment) TemplateCache() *TemplateCache { func (env *ShellEnvironment) TemplateCache() *TemplateCache {
defer env.trace(time.Now(), "TemplateCache") defer env.trace(time.Now(), "TemplateCache")
if env.tmplCache != nil { if env.tmplCache != nil {
return env.tmplCache return env.tmplCache
@ -575,7 +618,7 @@ func (env *environment) TemplateCache() *TemplateCache {
pwd := env.Pwd() pwd := env.Pwd()
pwd = strings.Replace(pwd, env.Home(), "~", 1) pwd = strings.Replace(pwd, env.Home(), "~", 1)
tmplCache.PWD = pwd tmplCache.PWD = pwd
tmplCache.Folder = base(pwd, env) tmplCache.Folder = Base(env, pwd)
tmplCache.UserName = env.User() tmplCache.UserName = env.User()
if host, err := env.Host(); err == nil { if host, err := env.Host(); err == nil {
tmplCache.HostName = host tmplCache.HostName = host
@ -586,6 +629,60 @@ func (env *environment) TemplateCache() *TemplateCache {
return env.tmplCache return env.tmplCache
} }
func DirMatchesOneOf(env Environment, dir string, regexes []string) bool {
normalizedCwd := strings.ReplaceAll(dir, "\\", "/")
normalizedHomeDir := strings.ReplaceAll(env.Home(), "\\", "/")
for _, element := range regexes {
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalizedElement, "~") {
normalizedElement = strings.Replace(normalizedElement, "~", normalizedHomeDir, 1)
}
pattern := fmt.Sprintf("^%s$", normalizedElement)
goos := env.GOOS()
if goos == WindowsPlatform || goos == DarwinPlatform {
pattern = "(?i)" + pattern
}
matched := regex.MatchString(pattern, normalizedCwd)
if matched {
return true
}
}
return false
}
// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
// If the path consists entirely of separators, Base returns a single separator.
func Base(env Environment, path string) string {
if path == "/" {
return path
}
volumeName := filepath.VolumeName(path)
// Strip trailing slashes.
for len(path) > 0 && string(path[len(path)-1]) == env.PathSeperator() {
path = path[0 : len(path)-1]
}
if volumeName == path {
return path
}
// Throw away volume name
path = path[len(filepath.VolumeName(path)):]
// Find the last element
i := len(path) - 1
for i >= 0 && string(path[i]) != env.PathSeperator() {
i--
}
if i >= 0 {
path = path[i+1:]
}
// If empty now, it had only slashes.
if path == "" {
return env.PathSeperator()
}
return path
}
func cleanHostName(hostName string) string { func cleanHostName(hostName string) string {
garbage := []string{ garbage := []string{
".lan", ".lan",

View file

@ -1,4 +1,4 @@
package main package environment
import ( import (
"testing" "testing"
@ -36,7 +36,7 @@ func TestWindowsPathWithDriveLetter(t *testing.T) {
{Case: "registry drive", CWD: `HKLM:\SOFTWARE\magnetic:test\`, Expected: `HKLM:\SOFTWARE\magnetic:test\`}, {Case: "registry drive", CWD: `HKLM:\SOFTWARE\magnetic:test\`, Expected: `HKLM:\SOFTWARE\magnetic:test\`},
} }
for _, tc := range cases { for _, tc := range cases {
env := &environment{ env := &ShellEnvironment{
args: &Args{ args: &Args{
PWD: &tc.CWD, PWD: &tc.CWD,
}, },

View file

@ -1,6 +1,6 @@
//go:build !windows //go:build !windows
package main package environment
import ( import (
"errors" "errors"
@ -12,20 +12,20 @@ import (
terminal "github.com/wayneashleyberry/terminal-dimensions" terminal "github.com/wayneashleyberry/terminal-dimensions"
) )
func (env *environment) Root() bool { func (env *ShellEnvironment) Root() bool {
defer env.trace(time.Now(), "Root") defer env.trace(time.Now(), "Root")
return os.Geteuid() == 0 return os.Geteuid() == 0
} }
func (env *environment) Home() string { func (env *ShellEnvironment) Home() string {
return os.Getenv("HOME") return os.Getenv("HOME")
} }
func (env *environment) WindowTitle(imageName, windowTitleRegex string) (string, error) { func (env *ShellEnvironment) WindowTitle(imageName, windowTitleRegex string) (string, error) {
return "", errors.New("not implemented") return "", errors.New("not implemented")
} }
func (env *environment) IsWsl() bool { func (env *ShellEnvironment) IsWsl() bool {
defer env.trace(time.Now(), "IsWsl") defer env.trace(time.Now(), "IsWsl")
// one way to check // one way to check
// version := env.FileContent("/proc/version") // version := env.FileContent("/proc/version")
@ -34,7 +34,7 @@ func (env *environment) IsWsl() bool {
return env.Getenv("WSL_DISTRO_NAME") != "" return env.Getenv("WSL_DISTRO_NAME") != ""
} }
func (env *environment) IsWsl2() bool { func (env *ShellEnvironment) IsWsl2() bool {
defer env.trace(time.Now(), "IsWsl2") defer env.trace(time.Now(), "IsWsl2")
if !env.IsWsl() { if !env.IsWsl() {
return false return false
@ -43,7 +43,7 @@ func (env *environment) IsWsl2() bool {
return strings.Contains(uname, "WSL2") return strings.Contains(uname, "WSL2")
} }
func (env *environment) TerminalWidth() (int, error) { func (env *ShellEnvironment) TerminalWidth() (int, error) {
defer env.trace(time.Now(), "TerminalWidth") defer env.trace(time.Now(), "TerminalWidth")
width, err := terminal.Width() width, err := terminal.Width()
if err != nil { if err != nil {
@ -52,7 +52,7 @@ func (env *environment) TerminalWidth() (int, error) {
return int(width), err return int(width), err
} }
func (env *environment) Platform() string { func (env *ShellEnvironment) Platform() string {
const key = "environment_platform" const key = "environment_platform"
if val, found := env.Cache().Get(key); found { if val, found := env.Cache().Get(key); found {
return val return val
@ -69,7 +69,7 @@ func (env *environment) Platform() string {
return platform return platform
} }
func (env *environment) CachePath() string { func (env *ShellEnvironment) CachePath() string {
defer env.trace(time.Now(), "CachePath") defer env.trace(time.Now(), "CachePath")
// get XDG_CACHE_HOME if present // get XDG_CACHE_HOME if present
if cachePath := returnOrBuildCachePath(env.Getenv("XDG_CACHE_HOME")); len(cachePath) != 0 { if cachePath := returnOrBuildCachePath(env.Getenv("XDG_CACHE_HOME")); len(cachePath) != 0 {
@ -82,15 +82,15 @@ func (env *environment) CachePath() string {
return env.Home() return env.Home()
} }
func (env *environment) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) { func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) {
return nil, errors.New("not implemented") return nil, errors.New("not implemented")
} }
func (env *environment) InWSLSharedDrive() bool { func (env *ShellEnvironment) InWSLSharedDrive() bool {
return env.IsWsl() && strings.HasPrefix(env.Pwd(), "/mnt/") return env.IsWsl() && strings.HasPrefix(env.Pwd(), "/mnt/")
} }
func (env *environment) ConvertToWindowsPath(path string) string { func (env *ShellEnvironment) ConvertToWindowsPath(path string) string {
windowsPath, err := env.RunCommand("wslpath", "-w", path) windowsPath, err := env.RunCommand("wslpath", "-w", path)
if err == nil { if err == nil {
return windowsPath return windowsPath
@ -98,7 +98,7 @@ func (env *environment) ConvertToWindowsPath(path string) string {
return path return path
} }
func (env *environment) ConvertToLinuxPath(path string) string { func (env *ShellEnvironment) ConvertToLinuxPath(path string) string {
linuxPath, err := env.RunCommand("wslpath", "-u", path) linuxPath, err := env.RunCommand("wslpath", "-u", path)
if err == nil { if err == nil {
return linuxPath return linuxPath
@ -106,6 +106,6 @@ func (env *environment) ConvertToLinuxPath(path string) string {
return path return path
} }
func (env *environment) WifiNetwork() (*WifiInfo, error) { func (env *ShellEnvironment) WifiNetwork() (*WifiInfo, error) {
return nil, errors.New("not implemented") return nil, errors.New("not implemented")
} }

View file

@ -1,6 +1,6 @@
//go:build windows //go:build windows
package main package environment
import ( import (
"errors" "errors"
@ -16,7 +16,7 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
func (env *environment) Root() bool { func (env *ShellEnvironment) Root() bool {
defer env.trace(time.Now(), "Root") defer env.trace(time.Now(), "Root")
var sid *windows.SID var sid *windows.SID
@ -53,7 +53,7 @@ func (env *environment) Root() bool {
return member return member
} }
func (env *environment) Home() string { func (env *ShellEnvironment) Home() string {
home := os.Getenv("HOME") home := os.Getenv("HOME")
defer func() { defer func() {
env.log(Debug, "Home", home) env.log(Debug, "Home", home)
@ -69,22 +69,22 @@ func (env *environment) Home() string {
return home return home
} }
func (env *environment) WindowTitle(imageName, windowTitleRegex string) (string, error) { func (env *ShellEnvironment) WindowTitle(imageName, windowTitleRegex string) (string, error) {
defer env.trace(time.Now(), "WindowTitle", imageName, windowTitleRegex) defer env.trace(time.Now(), "WindowTitle", imageName, windowTitleRegex)
return WindowTitle(imageName, windowTitleRegex) return WindowTitle(imageName, windowTitleRegex)
} }
func (env *environment) IsWsl() bool { func (env *ShellEnvironment) IsWsl() bool {
defer env.trace(time.Now(), "IsWsl") defer env.trace(time.Now(), "IsWsl")
return false return false
} }
func (env *environment) IsWsl2() bool { func (env *ShellEnvironment) IsWsl2() bool {
defer env.trace(time.Now(), "IsWsl2") defer env.trace(time.Now(), "IsWsl2")
return false return false
} }
func (env *environment) TerminalWidth() (int, error) { func (env *ShellEnvironment) TerminalWidth() (int, error) {
defer env.trace(time.Now(), "TerminalWidth") defer env.trace(time.Now(), "TerminalWidth")
handle, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0) handle, err := syscall.Open("CONOUT$", syscall.O_RDWR, 0)
if err != nil { if err != nil {
@ -100,11 +100,11 @@ func (env *environment) TerminalWidth() (int, error) {
return int(info.Size.X), nil return int(info.Size.X), nil
} }
func (env *environment) Platform() string { func (env *ShellEnvironment) Platform() string {
return windowsPlatform return WindowsPlatform
} }
func (env *environment) CachePath() string { func (env *ShellEnvironment) CachePath() string {
defer env.trace(time.Now(), "CachePath") defer env.trace(time.Now(), "CachePath")
// get LOCALAPPDATA if present // get LOCALAPPDATA if present
if cachePath := returnOrBuildCachePath(env.Getenv("LOCALAPPDATA")); len(cachePath) != 0 { if cachePath := returnOrBuildCachePath(env.Getenv("LOCALAPPDATA")); len(cachePath) != 0 {
@ -123,7 +123,7 @@ func (env *environment) CachePath() string {
// //
// Returns a variant type if successful; nil and an error if not. // Returns a variant type if successful; nil and an error if not.
// //
func (env *environment) WindowsRegistryKeyValue(path string) (*windowsRegistryValue, error) { func (env *ShellEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) {
env.trace(time.Now(), "WindowsRegistryKeyValue", path) env.trace(time.Now(), "WindowsRegistryKeyValue", path)
// Format: // Format:
@ -234,34 +234,34 @@ func (env *environment) WindowsRegistryKeyValue(path string) (*windowsRegistryVa
valueString := windows.UTF16PtrToString(uint16p) valueString := windows.UTF16PtrToString(uint16p)
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, string: %s", valueString)) env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, string: %s", valueString))
return &windowsRegistryValue{valueType: regString, str: valueString}, nil return &WindowsRegistryValue{ValueType: RegString, Str: valueString}, nil
case windows.REG_DWORD: case windows.REG_DWORD:
var uint32p *uint32 var uint32p *uint32
uint32p = (*uint32)(unsafe.Pointer(&keyBuf[0])) // more casting goodness uint32p = (*uint32)(unsafe.Pointer(&keyBuf[0])) // more casting goodness
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, DWORD, 0x%08X", *uint32p)) env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, DWORD, 0x%08X", *uint32p))
return &windowsRegistryValue{valueType: regDword, dword: *uint32p}, nil return &WindowsRegistryValue{ValueType: RegDword, Dword: *uint32p}, nil
case windows.REG_QWORD: case windows.REG_QWORD:
var uint64p *uint64 var uint64p *uint64
uint64p = (*uint64)(unsafe.Pointer(&keyBuf[0])) // more casting goodness uint64p = (*uint64)(unsafe.Pointer(&keyBuf[0])) // more casting goodness
env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, QWORD, 0x%016X", *uint64p)) env.log(Debug, "WindowsRegistryKeyValue", fmt.Sprintf("success, QWORD, 0x%016X", *uint64p))
return &windowsRegistryValue{valueType: regQword, qword: *uint64p}, nil return &WindowsRegistryValue{ValueType: RegQword, Qword: *uint64p}, nil
default: default:
errorLogMsg := fmt.Sprintf("Error, no formatter for REG_? type:%d, data size:%d bytes", keyBufType, keyBufSize) errorLogMsg := fmt.Sprintf("Error, no formatter for REG_? type:%d, data size:%d bytes", keyBufType, keyBufSize)
return nil, errors.New(errorLogMsg) return nil, errors.New(errorLogMsg)
} }
} }
func (env *environment) InWSLSharedDrive() bool { func (env *ShellEnvironment) InWSLSharedDrive() bool {
return false return false
} }
func (env *environment) ConvertToWindowsPath(path string) string { func (env *ShellEnvironment) ConvertToWindowsPath(path string) string {
return path return path
} }
func (env *environment) ConvertToLinuxPath(path string) string { func (env *ShellEnvironment) ConvertToLinuxPath(path string) string {
return path return path
} }
@ -273,7 +273,38 @@ var (
hWlanQueryInterface = hapi.NewProc("WlanQueryInterface") hWlanQueryInterface = hapi.NewProc("WlanQueryInterface")
) )
func (env *environment) WifiNetwork() (*wifiInfo, error) { const (
FHSS WifiType = "FHSS"
DSSS WifiType = "DSSS"
IR WifiType = "IR"
A WifiType = "802.11a"
HRDSSS WifiType = "HRDSSS"
G WifiType = "802.11g"
N WifiType = "802.11n"
AC WifiType = "802.11ac"
Infrastructure WifiType = "Infrastructure"
Independent WifiType = "Independent"
Any WifiType = "Any"
OpenSystem WifiType = "802.11 Open System"
SharedKey WifiType = "802.11 Shared Key"
WPA WifiType = "WPA"
WPAPSK WifiType = "WPA PSK"
WPANone WifiType = "WPA NONE"
WPA2 WifiType = "WPA2"
WPA2PSK WifiType = "WPA2 PSK"
Disabled WifiType = "disabled"
None WifiType = "None"
WEP40 WifiType = "WEP40"
TKIP WifiType = "TKIP"
CCMP WifiType = "CCMP"
WEP104 WifiType = "WEP104"
WEP WifiType = "WEP"
)
func (env *ShellEnvironment) WifiNetwork() (*WifiInfo, error) {
env.trace(time.Now(), "WifiNetwork") env.trace(time.Now(), "WifiNetwork")
// Open handle // Open handle
var pdwNegotiatedVersion uint32 var pdwNegotiatedVersion uint32
@ -308,8 +339,8 @@ func (env *environment) WifiNetwork() (*wifiInfo, error) {
return nil, errors.New("Not connected") return nil, errors.New("Not connected")
} }
func (env *environment) parseNetworkInterface(network *WLAN_INTERFACE_INFO, clientHandle uint32) (*wifiInfo, error) { func (env *ShellEnvironment) parseNetworkInterface(network *WLAN_INTERFACE_INFO, clientHandle uint32) (*WifiInfo, error) {
info := wifiInfo{} info := WifiInfo{}
info.Interface = strings.TrimRight(string(utf16.Decode(network.strInterfaceDescription[:])), "\x00") info.Interface = strings.TrimRight(string(utf16.Decode(network.strInterfaceDescription[:])), "\x00")
// Query wifi connection state // Query wifi connection state

View file

@ -1,9 +1,10 @@
//go:build windows //go:build windows
package main package environment
import ( import (
"fmt" "fmt"
"oh-my-posh/regex"
"strings" "strings"
"syscall" "syscall"
"unsafe" "unsafe"
@ -162,7 +163,7 @@ func GetWindowTitle(pid int, windowTitleRegex string) (syscall.Handle, string) {
return 1 // continue enumeration return 1 // continue enumeration
} }
title = syscall.UTF16ToString(b) title = syscall.UTF16ToString(b)
if matchString(windowTitleRegex, title) { if regex.MatchString(windowTitleRegex, title) {
// will cause EnumWindows to return 0 (error) // will cause EnumWindows to return 0 (error)
// but we don't want to enumerate all windows since we got what we want // but we don't want to enumerate all windows since we got what we want
hwnd = h hwnd = h

View file

@ -26,6 +26,7 @@ import (
_ "embed" _ "embed"
"fmt" "fmt"
"math" "math"
"oh-my-posh/regex"
"strconv" "strconv"
"strings" "strings"
@ -421,8 +422,8 @@ func (ir *ImageRenderer) SavePNG(path string) error {
} }
func (ir *ImageRenderer) shouldPrint() bool { func (ir *ImageRenderer) shouldPrint() bool {
for sequence, regex := range ir.ansiSequenceRegexMap { for sequence, re := range ir.ansiSequenceRegexMap {
match := findNamedRegexMatch(regex, ir.ansiString) match := regex.FindNamedRegexMatch(re, ir.ansiString)
if len(match) == 0 { if len(match) == 0 {
continue continue
} }

View file

@ -4,6 +4,8 @@ import (
_ "embed" _ "embed"
"flag" "flag"
"fmt" "fmt"
"oh-my-posh/environment"
"oh-my-posh/regex"
"os" "os"
"strings" "strings"
"time" "time"
@ -40,37 +42,8 @@ const (
plain = "shell" plain = "shell"
) )
type Args struct {
ErrorCode *int
PrintConfig *bool
ConfigFormat *string
PrintShell *bool
Config *string
Shell *string
PWD *string
PSWD *string
Version *bool
Debug *bool
ExecutionTime *float64
Millis *bool
Eval *bool
Init *bool
PrintInit *bool
ExportPNG *bool
Author *string
CursorPadding *int
RPromptOffset *int
RPrompt *bool
BGColor *string
StackCount *int
Command *string
PrintTransient *bool
Plain *bool
CachePath *bool
}
func main() { func main() {
args := &Args{ args := &environment.Args{
ErrorCode: flag.Int( ErrorCode: flag.Int(
"error", "error",
0, 0,
@ -181,8 +154,8 @@ func main() {
fmt.Println(Version) fmt.Println(Version)
return return
} }
env := &environment{} env := &environment.ShellEnvironment{}
env.init(args) env.Init(args)
defer env.Close() defer env.Close()
if *args.PrintShell { if *args.PrintShell {
fmt.Println(env.Shell()) fmt.Println(env.Shell())
@ -267,7 +240,7 @@ func main() {
ansi: ansi, ansi: ansi,
} }
imageCreator.init() imageCreator.init()
match := findNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, *args.Config) match := regex.FindNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, *args.Config)
err := imageCreator.SavePNG(fmt.Sprintf("%s.png", match[str])) err := imageCreator.SavePNG(fmt.Sprintf("%s.png", match[str]))
if err != nil { if err != nil {
fmt.Print(err.Error()) fmt.Print(err.Error())
@ -332,7 +305,7 @@ func getShellInitScript(executable, configFile, script string) string {
return script return script
} }
func getConsoleBackgroundColor(env Environment, backgroundColorTemplate string) string { func getConsoleBackgroundColor(env environment.Environment, backgroundColorTemplate string) string {
if len(backgroundColorTemplate) == 0 { if len(backgroundColorTemplate) == 0 {
return backgroundColorTemplate return backgroundColorTemplate
} }

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -17,8 +19,8 @@ func TestConsoleBackgroundColorTemplate(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: map[string]string{ Env: map[string]string{
"TERM_PROGRAM": tc.Term, "TERM_PROGRAM": tc.Term,
}, },
@ -27,3 +29,40 @@ func TestConsoleBackgroundColorTemplate(t *testing.T) {
assert.Equal(t, tc.Expected, color, tc.Case) assert.Equal(t, tc.Expected, color, tc.Case)
} }
} }
// This can only be tested here due to circular dependencies
// Which might be an indaction of a fault architecture but
// I honestly could not figure out how to do this better
// without making the solution worse.
func TestDirMatchesOneOf(t *testing.T) {
cases := []struct {
GOOS string
HomeDir string
Dir string
Pattern string
Expected bool
}{
{GOOS: environment.LinuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill", Pattern: "/home/bill", Expected: true},
{GOOS: environment.LinuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/foo", Expected: true},
{GOOS: environment.LinuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/Foo", Expected: false},
{GOOS: environment.LinuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~\\\\foo", Expected: true},
{GOOS: environment.LinuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo/bar", Pattern: "~/fo.*", Expected: true},
{GOOS: environment.LinuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/fo\\w", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:\\\\Users\\\\Bill", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:/Users/Bill", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "c:/users/bill", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "~", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/Foo", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/foo", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo\\Bar", Pattern: "~/fo.*", Expected: true},
{GOOS: environment.WindowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/fo\\w", Expected: true},
}
for _, tc := range cases {
env := new(mock.MockedEnvironment)
env.On("GOOS").Return(tc.GOOS)
env.On("Home").Return(tc.HomeDir)
got := environment.DirMatchesOneOf(env, tc.Dir, []string{tc.Pattern})
assert.Equal(t, tc.Expected, got)
}
}

View file

@ -1,4 +1,4 @@
package main package mock
import mock "github.com/stretchr/testify/mock" import mock "github.com/stretchr/testify/mock"

211
src/mock/environment.go Normal file
View file

@ -0,0 +1,211 @@
package mock
import (
"oh-my-posh/environment"
"github.com/distatus/battery"
mock "github.com/stretchr/testify/mock"
)
type MockedEnvironment struct {
mock.Mock
}
func (env *MockedEnvironment) Getenv(key string) string {
args := env.Called(key)
return args.String(0)
}
func (env *MockedEnvironment) Pwd() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Home() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) HasFiles(pattern string) bool {
args := env.Called(pattern)
return args.Bool(0)
}
func (env *MockedEnvironment) HasFilesInDir(dir, pattern string) bool {
args := env.Called(dir, pattern)
return args.Bool(0)
}
func (env *MockedEnvironment) HasFolder(folder string) bool {
args := env.Called(folder)
return args.Bool(0)
}
func (env *MockedEnvironment) FileContent(file string) string {
args := env.Called(file)
return args.String(0)
}
func (env *MockedEnvironment) FolderList(path string) []string {
args := env.Called(path)
return args.Get(0).([]string)
}
func (env *MockedEnvironment) PathSeperator() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) User() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Host() (string, error) {
args := env.Called()
return args.String(0), args.Error(1)
}
func (env *MockedEnvironment) GOOS() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Platform() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) HasCommand(command string) bool {
args := env.Called(command)
return args.Bool(0)
}
func (env *MockedEnvironment) RunCommand(command string, args ...string) (string, error) {
arguments := env.Called(command, args)
return arguments.String(0), arguments.Error(1)
}
func (env *MockedEnvironment) RunShellCommand(shell, command string) string {
args := env.Called(shell, command)
return args.String(0)
}
func (env *MockedEnvironment) ErrorCode() int {
args := env.Called()
return args.Int(0)
}
func (env *MockedEnvironment) ExecutionTime() float64 {
args := env.Called()
return float64(args.Int(0))
}
func (env *MockedEnvironment) Root() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) Args() *environment.Args {
arguments := env.Called()
return arguments.Get(0).(*environment.Args)
}
func (env *MockedEnvironment) BatteryInfo() ([]*battery.Battery, error) {
args := env.Called()
return args.Get(0).([]*battery.Battery), args.Error(1)
}
func (env *MockedEnvironment) Shell() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) WindowTitle(imageName, windowTitleRegex string) (string, error) {
args := env.Called(imageName)
return args.String(0), args.Error(1)
}
func (env *MockedEnvironment) WindowsRegistryKeyValue(path string) (*environment.WindowsRegistryValue, error) {
args := env.Called(path)
return args.Get(0).(*environment.WindowsRegistryValue), args.Error(1)
}
func (env *MockedEnvironment) HTTPRequest(url string, timeout int, requestModifiers ...environment.HTTPRequestModifier) ([]byte, error) {
args := env.Called(url)
return args.Get(0).([]byte), args.Error(1)
}
func (env *MockedEnvironment) HasParentFilePath(path string) (*environment.FileInfo, error) {
args := env.Called(path)
return args.Get(0).(*environment.FileInfo), args.Error(1)
}
func (env *MockedEnvironment) StackCount() int {
args := env.Called()
return args.Int(0)
}
func (env *MockedEnvironment) IsWsl() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) IsWsl2() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) TerminalWidth() (int, error) {
args := env.Called()
return args.Int(0), args.Error(1)
}
func (env *MockedEnvironment) CachePath() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Cache() environment.Cache {
args := env.Called()
return args.Get(0).(environment.Cache)
}
func (env *MockedEnvironment) Close() {
_ = env.Called()
}
func (env *MockedEnvironment) Logs() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) InWSLSharedDrive() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) ConvertToWindowsPath(path string) string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) ConvertToLinuxPath(path string) string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) WifiNetwork() (*environment.WifiInfo, error) {
args := env.Called()
return args.Get(0).(*environment.WifiInfo), args.Error(1)
}
func (env *MockedEnvironment) TemplateCache() *environment.TemplateCache {
args := env.Called()
return args.Get(0).(*environment.TemplateCache)
}
func (env *MockedEnvironment) MockGitCommand(dir, returnValue string, args ...string) {
args = append([]string{"-C", dir, "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...)
env.On("RunCommand", "git", args).Return(returnValue, nil)
}

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/regex"
) )
// Property defines one property of a segment for context // Property defines one property of a segment for context
@ -66,7 +67,7 @@ func (p properties) getColor(property Property, defaultValue string) string {
if IsAnsiColorName(colorString) { if IsAnsiColorName(colorString) {
return colorString return colorString
} }
values := findNamedRegexMatch(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString) values := regex.FindNamedRegexMatch(`(?P<color>#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}|p:.*)`, colorString)
if values != nil && values["color"] != "" { if values != nil && values["color"] != "" {
return values["color"] return values["color"]
} }

View file

@ -1,9 +1,7 @@
package main package regex
import ( import (
"fmt"
"regexp" "regexp"
"strings"
"sync" "sync"
) )
@ -12,7 +10,7 @@ var (
regexCacheLock = sync.RWMutex{} regexCacheLock = sync.RWMutex{}
) )
func getCompiledRegex(pattern string) *regexp.Regexp { func GetCompiledRegex(pattern string) *regexp.Regexp {
// try in cache first // try in cache first
regexCacheLock.RLock() regexCacheLock.RLock()
re := regexCache[pattern] re := regexCache[pattern]
@ -32,9 +30,9 @@ func getCompiledRegex(pattern string) *regexp.Regexp {
return re return re
} }
func findNamedRegexMatch(pattern, text string) map[string]string { func FindNamedRegexMatch(pattern, text string) map[string]string {
// error ignored because mustCompile will cause a panic // error ignored because mustCompile will cause a panic
re := getCompiledRegex(pattern) re := GetCompiledRegex(pattern)
match := re.FindStringSubmatch(text) match := re.FindStringSubmatch(text)
result := make(map[string]string) result := make(map[string]string)
if len(match) == 0 { if len(match) == 0 {
@ -49,8 +47,8 @@ func findNamedRegexMatch(pattern, text string) map[string]string {
return result return result
} }
func findAllNamedRegexMatch(pattern, text string) []map[string]string { func FindAllNamedRegexMatch(pattern, text string) []map[string]string {
re := getCompiledRegex(pattern) re := GetCompiledRegex(pattern)
match := re.FindAllStringSubmatch(text, -1) match := re.FindAllStringSubmatch(text, -1)
var results []map[string]string var results []map[string]string
if len(match) == 0 { if len(match) == 0 {
@ -70,34 +68,12 @@ func findAllNamedRegexMatch(pattern, text string) []map[string]string {
return results return results
} }
func replaceAllString(pattern, text, replaceText string) string { func ReplaceAllString(pattern, text, replaceText string) string {
re := getCompiledRegex(pattern) re := GetCompiledRegex(pattern)
return re.ReplaceAllString(text, replaceText) return re.ReplaceAllString(text, replaceText)
} }
func matchString(pattern, text string) bool { func MatchString(pattern, text string) bool {
re := getCompiledRegex(pattern) re := GetCompiledRegex(pattern)
return re.MatchString(text) return re.MatchString(text)
} }
func dirMatchesOneOf(env Environment, dir string, regexes []string) bool {
normalizedCwd := strings.ReplaceAll(dir, "\\", "/")
normalizedHomeDir := strings.ReplaceAll(env.Home(), "\\", "/")
for _, element := range regexes {
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
if strings.HasPrefix(normalizedElement, "~") {
normalizedElement = strings.Replace(normalizedElement, "~", normalizedHomeDir, 1)
}
pattern := fmt.Sprintf("^%s$", normalizedElement)
goos := env.GOOS()
if goos == windowsPlatform || goos == darwinPlatform {
pattern = "(?i)" + pattern
}
matched := matchString(pattern, normalizedCwd)
if matched {
return true
}
}
return false
}

View file

@ -1,40 +0,0 @@
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestDirMatchesOneOf(t *testing.T) {
cases := []struct {
GOOS string
HomeDir string
Dir string
Pattern string
Expected bool
}{
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill", Pattern: "/home/bill", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/foo", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/Foo", Expected: false},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~\\\\foo", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo/bar", Pattern: "~/fo.*", Expected: true},
{GOOS: linuxPlatform, HomeDir: "/home/bill", Dir: "/home/bill/foo", Pattern: "~/fo\\w", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:\\\\Users\\\\Bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "C:/Users/Bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "c:/users/bill", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill", Pattern: "~", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/Foo", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/foo", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo\\Bar", Pattern: "~/fo.*", Expected: true},
{GOOS: windowsPlatform, HomeDir: "C:\\Users\\Bill", Dir: "C:\\Users\\Bill\\Foo", Pattern: "~/fo\\w", Expected: true},
}
for _, tc := range cases {
env := new(MockedEnvironment)
env.On("GOOS").Return(tc.GOOS)
env.On("Home").Return(tc.HomeDir)
got := dirMatchesOneOf(env, tc.Dir, []string{tc.Pattern})
assert.Equal(t, tc.Expected, got)
}
}

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"strings" "strings"
) )
@ -36,7 +37,7 @@ func (s *ScmStatus) String() string {
type scm struct { type scm struct {
props Properties props Properties
env Environment env environment.Environment
} }
const ( const (
@ -48,7 +49,7 @@ const (
FullBranchPath Property = "full_branch_path" FullBranchPath Property = "full_branch_path"
) )
func (s *scm) init(props Properties, env Environment) { func (s *scm) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
} }
@ -72,7 +73,7 @@ func (s *scm) shouldIgnoreRootRepository(rootDir string) bool {
if len(excludedFolders) == 0 { if len(excludedFolders) == 0 {
return false return false
} }
return dirMatchesOneOf(s.env, rootDir, excludedFolders) return environment.DirMatchesOneOf(s.env, rootDir, excludedFolders)
} }
func (s *scm) FileContents(folder, file string) string { func (s *scm) FileContents(folder, file string) string {

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -167,15 +169,16 @@ func TestScmShouldIgnoreRootRepository(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
props := properties{ excludeFolders := []string{
ExcludeFolders: []string{
"/home/bill", "/home/bill",
"/home/gates.*", "/home/gates.*",
},
} }
env := new(MockedEnvironment) props := properties{
ExcludeFolders: excludeFolders,
}
env := new(mock.MockedEnvironment)
env.On("Home").Return("/home/bill") env.On("Home").Return("/home/bill")
env.On("GOOS").Return(windowsPlatform) env.On("GOOS").Return(environment.WindowsPlatform)
s := &scm{ s := &scm{
props: props, props: props,
env: env, env: env,

View file

@ -3,6 +3,7 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/environment"
"runtime/debug" "runtime/debug"
"time" "time"
) )
@ -24,7 +25,7 @@ type Segment struct {
writer SegmentWriter writer SegmentWriter
stringValue string stringValue string
active bool active bool
env Environment env environment.Environment
} }
// SegmentTiming holds the timing context for a segment // SegmentTiming holds the timing context for a segment
@ -51,7 +52,7 @@ type Properties interface {
type SegmentWriter interface { type SegmentWriter interface {
enabled() bool enabled() bool
template() string template() string
init(props Properties, env Environment) init(props Properties, env environment.Environment)
} }
// SegmentStyle the syle of segment, for more information, see the constants // SegmentStyle the syle of segment, for more information, see the constants
@ -200,7 +201,7 @@ func (segment *Segment) cwdIncluded() bool {
return true return true
} }
return dirMatchesOneOf(segment.env, segment.env.Pwd(), list) return environment.DirMatchesOneOf(segment.env, segment.env.Pwd(), list)
} }
func (segment *Segment) cwdExcluded() bool { func (segment *Segment) cwdExcluded() bool {
@ -209,7 +210,7 @@ func (segment *Segment) cwdExcluded() bool {
value = segment.Properties[IgnoreFolders] value = segment.Properties[IgnoreFolders]
} }
list := parseStringArray(value) list := parseStringArray(value)
return dirMatchesOneOf(segment.env, segment.env.Pwd(), list) return environment.DirMatchesOneOf(segment.env, segment.env.Pwd(), list)
} }
func (segment *Segment) getColor(templates []string, defaultColor string) string { func (segment *Segment) getColor(templates []string, defaultColor string) string {
@ -248,7 +249,7 @@ func (segment *Segment) background() string {
return segment.getColor(segment.BackgroundTemplates, segment.Background) return segment.getColor(segment.BackgroundTemplates, segment.Background)
} }
func (segment *Segment) mapSegmentWithWriter(env Environment) error { func (segment *Segment) mapSegmentWithWriter(env environment.Environment) error {
segment.env = env segment.env = env
functions := map[SegmentType]SegmentWriter{ functions := map[SegmentType]SegmentWriter{
OWM: &owm{}, OWM: &owm{},
@ -306,7 +307,7 @@ func (segment *Segment) mapSegmentWithWriter(env Environment) error {
return errors.New("unable to map writer") return errors.New("unable to map writer")
} }
func (segment *Segment) setStringValue(env Environment) { func (segment *Segment) setStringValue(env environment.Environment) {
defer func() { defer func() {
err := recover() err := recover()
if err == nil { if err == nil {

View file

@ -3,6 +3,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"oh-my-posh/environment"
) )
type angular struct { type angular struct {
@ -13,7 +14,7 @@ func (a *angular) template() string {
return languageTemplate return languageTemplate
} }
func (a *angular) init(props Properties, env Environment) { func (a *angular) init(props Properties, env environment.Environment) {
a.language = language{ a.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -2,6 +2,8 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -22,14 +24,14 @@ func TestAngularCliVersionDisplayed(t *testing.T) {
extension: "angular.json", extension: "angular.json",
} }
var env = new(MockedEnvironment) var env = new(mock.MockedEnvironment)
// mock getVersion methods // mock getVersion methods
env.On("Pwd").Return("/usr/home/dev/my-app") env.On("Pwd").Return("/usr/home/dev/my-app")
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("HasFiles", params.extension).Return(true) env.On("HasFiles", params.extension).Return(true)
env.On("HasFilesInDir", "/usr/home/dev/my-app/node_modules/@angular/core", "package.json").Return(true) env.On("HasFilesInDir", "/usr/home/dev/my-app/node_modules/@angular/core", "package.json").Return(true)
env.On("FileContent", "/usr/home/dev/my-app/node_modules/@angular/core/package.json").Return(ta.Version) env.On("FileContent", "/usr/home/dev/my-app/node_modules/@angular/core/package.json").Return(ta.Version)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
props := properties{} props := properties{}

View file

@ -2,12 +2,14 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"strings" "strings"
) )
type aws struct { type aws struct {
props Properties props Properties
env Environment env environment.Environment
Profile string Profile string
Region string Region string
} }
@ -20,7 +22,7 @@ func (a *aws) template() string {
return "{{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }}" return "{{ .Profile }}{{ if .Region }}@{{ .Region }}{{ end }}"
} }
func (a *aws) init(props Properties, env Environment) { func (a *aws) init(props Properties, env environment.Environment) {
a.props = props a.props = props
a.env = env a.env = env
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -46,7 +47,7 @@ func TestAWSSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Getenv", "AWS_VAULT").Return(tc.Vault) env.On("Getenv", "AWS_VAULT").Return(tc.Vault)
env.On("Getenv", "AWS_PROFILE").Return(tc.Profile) env.On("Getenv", "AWS_PROFILE").Return(tc.Profile)
env.On("Getenv", "AWS_REGION").Return(tc.Region) env.On("Getenv", "AWS_REGION").Return(tc.Region)

View file

@ -2,13 +2,14 @@ package main
import ( import (
"encoding/json" "encoding/json"
"oh-my-posh/environment"
"path/filepath" "path/filepath"
"strings" "strings"
) )
type az struct { type az struct {
props Properties props Properties
env Environment env environment.Environment
AzureSubscription AzureSubscription
Origin string Origin string
@ -82,7 +83,7 @@ func (a *az) template() string {
return "{{ .Name }}" return "{{ .Name }}"
} }
func (a *az) init(props Properties, env Environment) { func (a *az) init(props Properties, env environment.Environment) {
a.props = props a.props = props
a.env = env a.env = env
} }

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type azfunc struct { type azfunc struct {
language language
} }
@ -8,7 +10,7 @@ func (az *azfunc) template() string {
return languageTemplate return languageTemplate
} }
func (az *azfunc) init(props Properties, env Environment) { func (az *azfunc) init(props Properties, env environment.Environment) {
az.language = language{ az.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -2,6 +2,8 @@ package main
import ( import (
"io/ioutil" "io/ioutil"
"oh-my-posh/environment"
"oh-my-posh/mock"
"path/filepath" "path/filepath"
"testing" "testing"
@ -67,7 +69,7 @@ func TestAzSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
home := "/Users/posh" home := "/Users/posh"
env.On("Home").Return(home) env.On("Home").Return(home)
var azureProfile, azureRmContext, azureRMContext string var azureProfile, azureRmContext, azureRMContext string
@ -83,7 +85,7 @@ func TestAzSegment(t *testing.T) {
content, _ := ioutil.ReadFile("./test/AzureRmContext.json") content, _ := ioutil.ReadFile("./test/AzureRmContext.json")
azureRMContext = string(content) azureRMContext = string(content)
} }
env.On("GOOS").Return(linuxPlatform) env.On("GOOS").Return(environment.LinuxPlatform)
env.On("FileContent", filepath.Join(home, ".azure", "azureProfile.json")).Return(azureProfile) env.On("FileContent", filepath.Join(home, ".azure", "azureProfile.json")).Return(azureProfile)
env.On("FileContent", filepath.Join(home, ".Azure", "AzureRmContext.json")).Return(azureRmContext) env.On("FileContent", filepath.Join(home, ".Azure", "AzureRmContext.json")).Return(azureRmContext)
env.On("FileContent", filepath.Join(home, ".azure", "AzureRmContext.json")).Return(azureRMContext) env.On("FileContent", filepath.Join(home, ".azure", "AzureRmContext.json")).Return(azureRMContext)

View file

@ -2,13 +2,14 @@ package main
import ( import (
"math" "math"
"oh-my-posh/environment"
"github.com/distatus/battery" "github.com/distatus/battery"
) )
type batt struct { type batt struct {
props Properties props Properties
env Environment env environment.Environment
battery.Battery battery.Battery
Percentage int Percentage int
@ -66,7 +67,7 @@ func (b *batt) enabledWhileError(err error) bool {
if err == nil { if err == nil {
return true return true
} }
if _, ok := err.(*noBatteryError); ok { if _, ok := err.(*environment.NoBatteryError); ok {
return false return false
} }
displayError := b.props.getBool(DisplayError, false) displayError := b.props.getBool(DisplayError, false)
@ -103,7 +104,7 @@ func (b *batt) mapMostLogicalState(currentState, newState battery.State) battery
return newState return newState
} }
func (b *batt) init(props Properties, env Environment) { func (b *batt) init(props Properties, env environment.Environment) {
b.props = props b.props = props
b.env = env b.env = env
} }

View file

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"math" "math"
"net/http" "net/http"
"oh-my-posh/environment"
"sort" "sort"
"time" "time"
) )
@ -14,7 +15,7 @@ import (
// segment struct, makes templating easier // segment struct, makes templating easier
type brewfather struct { type brewfather struct {
props Properties props Properties
env Environment env environment.Environment
Batch Batch
TemperatureTrendIcon string TemperatureTrendIcon string
@ -324,7 +325,7 @@ func (bf *brewfather) SGToPlato(sg float64) float64 {
return math.Round(100*((135.997*sg*sg*sg)-(630.272*sg*sg)+(1111.14*sg)-616.868)) / 100 // 2 decimal places return math.Round(100*((135.997*sg*sg*sg)-(630.272*sg*sg)+(1111.14*sg)-616.868)) / 100 // 2 decimal places
} }
func (bf *brewfather) init(props Properties, env Environment) { func (bf *brewfather) init(props Properties, env environment.Environment) {
bf.props = props bf.props = props
bf.env = env bf.env = env
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/mock"
"testing" "testing"
"time" "time"
@ -136,7 +137,7 @@ func TestBrewfatherSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
props := properties{ props := properties{
CacheTimeout: tc.CacheTimeout, CacheTimeout: tc.CacheTimeout,
BFBatchID: BFFakeBatchID, BFBatchID: BFFakeBatchID,
@ -144,7 +145,7 @@ func TestBrewfatherSegment(t *testing.T) {
BFUserID: "FAKE", BFUserID: "FAKE",
} }
cache := &MockedCache{} cache := &mock.MockedCache{}
cache.On("Get", BFCacheKey).Return(nil, false) // cache testing later because cache is a little more complicated than just the single response. cache.On("Get", BFCacheKey).Return(nil, false) // cache testing later because cache is a little more complicated than just the single response.
// cache.On("Set", BFCacheKey, tc.JSONResponse, tc.CacheTimeout).Return() // cache.On("Set", BFCacheKey, tc.JSONResponse, tc.CacheTimeout).Return()

View file

@ -1,10 +1,13 @@
package main package main
import "strings" import (
"oh-my-posh/environment"
"strings"
)
type command struct { type command struct {
props Properties props Properties
env Environment env environment.Environment
Output string Output string
} }
@ -49,7 +52,7 @@ func (c *command) enabled() bool {
return c.Output != "" return c.Output != ""
} }
func (c *command) init(props Properties, env Environment) { func (c *command) init(props Properties, env environment.Environment) {
c.props = props c.props = props
c.env = env c.env = env
} }

View file

@ -1,13 +1,14 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestExecuteCommand(t *testing.T) { func TestExecuteCommand(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "echo hello").Return("hello") env.On("RunShellCommand", "bash", "echo hello").Return("hello")
props := properties{ props := properties{
@ -23,7 +24,7 @@ func TestExecuteCommand(t *testing.T) {
} }
func TestExecuteMultipleCommandsOrFirst(t *testing.T) { func TestExecuteMultipleCommandsOrFirst(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "exit 1").Return("") env.On("RunShellCommand", "bash", "exit 1").Return("")
env.On("RunShellCommand", "bash", "echo hello").Return("hello") env.On("RunShellCommand", "bash", "echo hello").Return("hello")
@ -41,7 +42,7 @@ func TestExecuteMultipleCommandsOrFirst(t *testing.T) {
} }
func TestExecuteMultipleCommandsOrSecond(t *testing.T) { func TestExecuteMultipleCommandsOrSecond(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "echo hello").Return("hello") env.On("RunShellCommand", "bash", "echo hello").Return("hello")
env.On("RunShellCommand", "bash", "echo world").Return("world") env.On("RunShellCommand", "bash", "echo world").Return("world")
@ -58,7 +59,7 @@ func TestExecuteMultipleCommandsOrSecond(t *testing.T) {
} }
func TestExecuteMultipleCommandsAnd(t *testing.T) { func TestExecuteMultipleCommandsAnd(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "echo hello").Return("hello") env.On("RunShellCommand", "bash", "echo hello").Return("hello")
env.On("RunShellCommand", "bash", "echo world").Return("world") env.On("RunShellCommand", "bash", "echo world").Return("world")
@ -75,7 +76,7 @@ func TestExecuteMultipleCommandsAnd(t *testing.T) {
} }
func TestExecuteSingleCommandEmpty(t *testing.T) { func TestExecuteSingleCommandEmpty(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "").Return("") env.On("RunShellCommand", "bash", "").Return("")
props := properties{ props := properties{
@ -90,7 +91,7 @@ func TestExecuteSingleCommandEmpty(t *testing.T) {
} }
func TestExecuteSingleCommandNoCommandProperty(t *testing.T) { func TestExecuteSingleCommandNoCommandProperty(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "echo no command specified").Return("no command specified") env.On("RunShellCommand", "bash", "echo no command specified").Return("no command specified")
var props properties var props properties
@ -104,7 +105,7 @@ func TestExecuteSingleCommandNoCommandProperty(t *testing.T) {
} }
func TestExecuteMultipleCommandsAndDisabled(t *testing.T) { func TestExecuteMultipleCommandsAndDisabled(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "echo").Return("") env.On("RunShellCommand", "bash", "echo").Return("")
props := properties{ props := properties{
@ -119,7 +120,7 @@ func TestExecuteMultipleCommandsAndDisabled(t *testing.T) {
} }
func TestExecuteMultipleCommandsOrDisabled(t *testing.T) { func TestExecuteMultipleCommandsOrDisabled(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "bash").Return(true) env.On("HasCommand", "bash").Return(true)
env.On("RunShellCommand", "bash", "echo").Return("") env.On("RunShellCommand", "bash", "echo").Return("")
env.On("RunShellCommand", "bash", "echo|| echo").Return("") env.On("RunShellCommand", "bash", "echo|| echo").Return("")

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type crystal struct { type crystal struct {
language language
} }
@ -8,7 +10,7 @@ func (c *crystal) template() string {
return languageTemplate return languageTemplate
} }
func (c *crystal) init(props Properties, env Environment) { func (c *crystal) init(props Properties, env environment.Environment) {
c.language = language{ c.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type dart struct { type dart struct {
language language
} }
@ -8,7 +10,7 @@ func (d *dart) template() string {
return languageTemplate return languageTemplate
} }
func (d *dart) init(props Properties, env Environment) { func (d *dart) init(props Properties, env environment.Environment) {
d.language = language{ d.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type dotnet struct { type dotnet struct {
language language
@ -10,7 +12,7 @@ func (d *dotnet) template() string {
return "{{ if .Unsupported }}\uf071{{ else }}{{ .Full }}{{ end }}" return "{{ if .Unsupported }}\uf071{{ else }}{{ .Full }}{{ end }}"
} }
func (d *dotnet) init(props Properties, env Environment) { func (d *dotnet) init(props Properties, env environment.Environment) {
d.language = language{ d.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -22,10 +24,10 @@ func TestDotnetSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "dotnet").Return(tc.HasCommand) env.On("HasCommand", "dotnet").Return(tc.HasCommand)
if tc.ExitCode != 0 { if tc.ExitCode != 0 {
err := &commandError{exitCode: tc.ExitCode} err := &environment.CommandError{ExitCode: tc.ExitCode}
env.On("RunCommand", "dotnet", []string{"--version"}).Return("", err) env.On("RunCommand", "dotnet", []string{"--version"}).Return("", err)
} else { } else {
env.On("RunCommand", "dotnet", []string{"--version"}).Return(tc.Version, nil) env.On("RunCommand", "dotnet", []string{"--version"}).Return(tc.Version, nil)
@ -35,7 +37,7 @@ func TestDotnetSegment(t *testing.T) {
env.On("PathSeperator").Return("") env.On("PathSeperator").Return("")
env.On("Pwd").Return("/usr/home/project") env.On("Pwd").Return("/usr/home/project")
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
props := properties{ props := properties{

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"strconv" "strconv"
lang "golang.org/x/text/language" lang "golang.org/x/text/language"
@ -10,7 +11,7 @@ import (
type executiontime struct { type executiontime struct {
props Properties props Properties
env Environment env environment.Environment
FormattedMs string FormattedMs string
Ms int64 Ms int64
@ -63,7 +64,7 @@ func (t *executiontime) template() string {
return "{{ .FormattedMs }}" return "{{ .FormattedMs }}"
} }
func (t *executiontime) init(props Properties, env Environment) { func (t *executiontime) init(props Properties, env environment.Environment) {
t.props = props t.props = props
t.env = env t.env = env
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"time" "time"
@ -8,7 +9,7 @@ import (
) )
func TestExecutionTimeWriterDefaultThresholdEnabled(t *testing.T) { func TestExecutionTimeWriterDefaultThresholdEnabled(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ExecutionTime").Return(1337) env.On("ExecutionTime").Return(1337)
executionTime := &executiontime{ executionTime := &executiontime{
env: env, env: env,
@ -18,7 +19,7 @@ func TestExecutionTimeWriterDefaultThresholdEnabled(t *testing.T) {
} }
func TestExecutionTimeWriterDefaultThresholdDisabled(t *testing.T) { func TestExecutionTimeWriterDefaultThresholdDisabled(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ExecutionTime").Return(1) env.On("ExecutionTime").Return(1)
executionTime := &executiontime{ executionTime := &executiontime{
env: env, env: env,
@ -28,7 +29,7 @@ func TestExecutionTimeWriterDefaultThresholdDisabled(t *testing.T) {
} }
func TestExecutionTimeWriterCustomThresholdEnabled(t *testing.T) { func TestExecutionTimeWriterCustomThresholdEnabled(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ExecutionTime").Return(99) env.On("ExecutionTime").Return(99)
props := properties{ props := properties{
ThresholdProperty: float64(10), ThresholdProperty: float64(10),
@ -41,7 +42,7 @@ func TestExecutionTimeWriterCustomThresholdEnabled(t *testing.T) {
} }
func TestExecutionTimeWriterCustomThresholdDisabled(t *testing.T) { func TestExecutionTimeWriterCustomThresholdDisabled(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ExecutionTime").Return(99) env.On("ExecutionTime").Return(99)
props := properties{ props := properties{
ThresholdProperty: float64(100), ThresholdProperty: float64(100),
@ -56,7 +57,7 @@ func TestExecutionTimeWriterCustomThresholdDisabled(t *testing.T) {
func TestExecutionTimeWriterDuration(t *testing.T) { func TestExecutionTimeWriterDuration(t *testing.T) {
input := 1337 input := 1337
expected := "1.337s" expected := "1.337s"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ExecutionTime").Return(input) env.On("ExecutionTime").Return(input)
executionTime := &executiontime{ executionTime := &executiontime{
env: env, env: env,
@ -69,7 +70,7 @@ func TestExecutionTimeWriterDuration(t *testing.T) {
func TestExecutionTimeWriterDuration2(t *testing.T) { func TestExecutionTimeWriterDuration2(t *testing.T) {
input := 13371337 input := 13371337
expected := "3h 42m 51.337s" expected := "3h 42m 51.337s"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ExecutionTime").Return(input) env.On("ExecutionTime").Return(input)
executionTime := &executiontime{ executionTime := &executiontime{
env: env, env: env,

View file

@ -1,10 +1,13 @@
package main package main
import "strconv" import (
"oh-my-posh/environment"
"strconv"
)
type exit struct { type exit struct {
props Properties props Properties
env Environment env environment.Environment
Text string Text string
} }
@ -21,7 +24,7 @@ func (e *exit) enabled() bool {
return e.env.ErrorCode() != 0 return e.env.ErrorCode() != 0
} }
func (e *exit) init(props Properties, env Environment) { func (e *exit) init(props Properties, env environment.Environment) {
e.props = props e.props = props
e.env = env e.env = env
} }

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -17,7 +19,7 @@ func TestExitWriterEnabled(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ErrorCode").Return(tc.ExitCode) env.On("ErrorCode").Return(tc.ExitCode)
e := &exit{ e := &exit{
env: env, env: env,
@ -74,9 +76,9 @@ func TestExitWriterTemplateString(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("ErrorCode").Return(tc.ExitCode) env.On("ErrorCode").Return(tc.ExitCode)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Code: tc.ExitCode, Code: tc.ExitCode,
}) })
e := &exit{ e := &exit{

View file

@ -2,6 +2,8 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"oh-my-posh/regex"
"strconv" "strconv"
"strings" "strings"
@ -160,7 +162,7 @@ func (g *git) shouldDisplay() bool {
// handle worktree // handle worktree
g.gitRootFolder = gitdir.Path g.gitRootFolder = gitdir.Path
dirPointer := strings.Trim(g.env.FileContent(gitdir.Path), " \r\n") dirPointer := strings.Trim(g.env.FileContent(gitdir.Path), " \r\n")
matches := findNamedRegexMatch(`^gitdir: (?P<dir>.*)$`, dirPointer) matches := regex.FindNamedRegexMatch(`^gitdir: (?P<dir>.*)$`, dirPointer)
if matches != nil && matches["dir"] != "" { if matches != nil && matches["dir"] != "" {
// if we open a worktree file in a shared wsl2 folder, we have to convert it back // if we open a worktree file in a shared wsl2 folder, we have to convert it back
// to the mounted path // to the mounted path
@ -214,7 +216,7 @@ func (g *git) setBranchStatus() {
} }
func (g *git) getUpstreamIcon() string { func (g *git) getUpstreamIcon() string {
upstream := replaceAllString("/.*", g.Upstream, "") upstream := regex.ReplaceAllString("/.*", g.Upstream, "")
g.UpstreamURL = g.getOriginURL(upstream) g.UpstreamURL = g.getOriginURL(upstream)
if strings.Contains(g.UpstreamURL, "github") { if strings.Contains(g.UpstreamURL, "github") {
return g.props.getString(GithubIcon, "\uF408 ") return g.props.getString(GithubIcon, "\uF408 ")
@ -287,7 +289,7 @@ func (g *git) getGitCommand() string {
return g.gitCommand return g.gitCommand
} }
g.gitCommand = "git" g.gitCommand = "git"
if g.env.GOOS() == windowsPlatform || g.IsWslSharedPath { if g.env.GOOS() == environment.WindowsPlatform || g.IsWslSharedPath {
g.gitCommand = "git.exe" g.gitCommand = "git.exe"
} }
return g.gitCommand return g.gitCommand
@ -353,7 +355,7 @@ func (g *git) setGitHEADContext() {
if g.hasGitFile("MERGE_MSG") { if g.hasGitFile("MERGE_MSG") {
icon := g.props.getString(MergeIcon, "\uE727 ") icon := g.props.getString(MergeIcon, "\uE727 ")
mergeContext := g.FileContents(g.gitWorkingFolder, "MERGE_MSG") mergeContext := g.FileContents(g.gitWorkingFolder, "MERGE_MSG")
matches := findNamedRegexMatch(`Merge (remote-tracking )?(?P<type>branch|commit|tag) '(?P<theirs>.*)'`, mergeContext) matches := regex.FindNamedRegexMatch(`Merge (remote-tracking )?(?P<type>branch|commit|tag) '(?P<theirs>.*)'`, mergeContext)
// head := g.getGitRefFileSymbolicName("ORIG_HEAD") // head := g.getGitRefFileSymbolicName("ORIG_HEAD")
if matches != nil && matches["theirs"] != "" { if matches != nil && matches["theirs"] != "" {
var headIcon, theirs string var headIcon, theirs string
@ -391,7 +393,7 @@ func (g *git) setGitHEADContext() {
} }
if g.hasGitFile("sequencer/todo") { if g.hasGitFile("sequencer/todo") {
todo := g.FileContents(g.gitWorkingFolder, "sequencer/todo") todo := g.FileContents(g.gitWorkingFolder, "sequencer/todo")
matches := findNamedRegexMatch(`^(?P<action>p|pick|revert)\s+(?P<sha>\S+)`, todo) matches := regex.FindNamedRegexMatch(`^(?P<action>p|pick|revert)\s+(?P<sha>\S+)`, todo)
if matches != nil && matches["sha"] != "" { if matches != nil && matches["sha"] != "" {
action := matches["action"] action := matches["action"]
sha := matches["sha"] sha := matches["sha"]

View file

@ -2,6 +2,8 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"oh-my-posh/mock"
"strings" "strings"
"testing" "testing"
@ -13,7 +15,7 @@ const (
) )
func TestEnabledGitNotFound(t *testing.T) { func TestEnabledGitNotFound(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("InWSLSharedDrive").Return(false) env.On("InWSLSharedDrive").Return(false)
env.On("HasCommand", "git").Return(false) env.On("HasCommand", "git").Return(false)
env.On("GOOS").Return("") env.On("GOOS").Return("")
@ -28,17 +30,17 @@ func TestEnabledGitNotFound(t *testing.T) {
} }
func TestEnabledInWorkingDirectory(t *testing.T) { func TestEnabledInWorkingDirectory(t *testing.T) {
fileInfo := &FileInfo{ fileInfo := &environment.FileInfo{
Path: "/dir/hello", Path: "/dir/hello",
ParentFolder: "/dir", ParentFolder: "/dir",
IsDir: true, IsDir: true,
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("InWSLSharedDrive").Return(false) env.On("InWSLSharedDrive").Return(false)
env.On("HasCommand", "git").Return(true) env.On("HasCommand", "git").Return(true)
env.On("GOOS").Return("") env.On("GOOS").Return("")
env.On("FileContent", "/dir/hello/HEAD").Return("") env.On("FileContent", "/dir/hello/HEAD").Return("")
env.mockGitCommand(fileInfo.Path, "", "describe", "--tags", "--exact-match") env.MockGitCommand(fileInfo.Path, "", "describe", "--tags", "--exact-match")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.On("HasParentFilePath", ".git").Return(fileInfo, nil) env.On("HasParentFilePath", ".git").Return(fileInfo, nil)
g := &git{ g := &git{
@ -52,18 +54,18 @@ func TestEnabledInWorkingDirectory(t *testing.T) {
} }
func TestEnabledInWorkingTree(t *testing.T) { func TestEnabledInWorkingTree(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("InWSLSharedDrive").Return(false) env.On("InWSLSharedDrive").Return(false)
env.On("HasCommand", "git").Return(true) env.On("HasCommand", "git").Return(true)
env.On("GOOS").Return("") env.On("GOOS").Return("")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
fileInfo := &FileInfo{ fileInfo := &environment.FileInfo{
Path: "/dev/folder_worktree/.git", Path: "/dev/folder_worktree/.git",
ParentFolder: "/dev/folder_worktree", ParentFolder: "/dev/folder_worktree",
IsDir: false, IsDir: false,
} }
env.On("FileContent", "/dev/real_folder/.git/worktrees/folder_worktree/HEAD").Return("") env.On("FileContent", "/dev/real_folder/.git/worktrees/folder_worktree/HEAD").Return("")
env.mockGitCommand(fileInfo.ParentFolder, "", "describe", "--tags", "--exact-match") env.MockGitCommand(fileInfo.ParentFolder, "", "describe", "--tags", "--exact-match")
env.On("HasParentFilePath", ".git").Return(fileInfo, nil) env.On("HasParentFilePath", ".git").Return(fileInfo, nil)
env.On("FileContent", "/dev/folder_worktree/.git").Return("gitdir: /dev/real_folder/.git/worktrees/folder_worktree") env.On("FileContent", "/dev/folder_worktree/.git").Return("gitdir: /dev/real_folder/.git/worktrees/folder_worktree")
env.On("FileContent", "/dev/real_folder/.git/worktrees/folder_worktree/gitdir").Return("/dev/folder_worktree.git\n") env.On("FileContent", "/dev/real_folder/.git/worktrees/folder_worktree/gitdir").Return("/dev/folder_worktree.git\n")
@ -79,18 +81,18 @@ func TestEnabledInWorkingTree(t *testing.T) {
} }
func TestEnabledInSubmodule(t *testing.T) { func TestEnabledInSubmodule(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("InWSLSharedDrive").Return(false) env.On("InWSLSharedDrive").Return(false)
env.On("HasCommand", "git").Return(true) env.On("HasCommand", "git").Return(true)
env.On("GOOS").Return("") env.On("GOOS").Return("")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
fileInfo := &FileInfo{ fileInfo := &environment.FileInfo{
Path: "/dev/parent/test-submodule/.git", Path: "/dev/parent/test-submodule/.git",
ParentFolder: "/dev/parent/test-submodule", ParentFolder: "/dev/parent/test-submodule",
IsDir: false, IsDir: false,
} }
env.On("FileContent", "/dev/parent/test-submodule/../.git/modules/test-submodule/HEAD").Return("") env.On("FileContent", "/dev/parent/test-submodule/../.git/modules/test-submodule/HEAD").Return("")
env.mockGitCommand("/dev/parent/test-submodule/../.git/modules/test-submodule", "", "describe", "--tags", "--exact-match") env.MockGitCommand("/dev/parent/test-submodule/../.git/modules/test-submodule", "", "describe", "--tags", "--exact-match")
env.On("HasParentFilePath", ".git").Return(fileInfo, nil) env.On("HasParentFilePath", ".git").Return(fileInfo, nil)
env.On("FileContent", "/dev/parent/test-submodule/.git").Return("gitdir: ../.git/modules/test-submodule") env.On("FileContent", "/dev/parent/test-submodule/.git").Return("gitdir: ../.git/modules/test-submodule")
env.On("FileContent", "/dev/parent/.git/modules/test-submodule").Return("/dev/folder_worktree.git\n") env.On("FileContent", "/dev/parent/.git/modules/test-submodule").Return("/dev/folder_worktree.git\n")
@ -110,7 +112,7 @@ func TestGetGitOutputForCommand(t *testing.T) {
args := []string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"} args := []string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}
commandArgs := []string{"symbolic-ref", "--short", "HEAD"} commandArgs := []string{"symbolic-ref", "--short", "HEAD"}
want := "je suis le output" want := "je suis le output"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.On("RunCommand", "git", append(args, commandArgs...)).Return(want, nil) env.On("RunCommand", "git", append(args, commandArgs...)).Return(want, nil)
env.On("GOOS").Return("unix") env.On("GOOS").Return("unix")
@ -124,11 +126,6 @@ func TestGetGitOutputForCommand(t *testing.T) {
assert.Equal(t, want, got) assert.Equal(t, want, got)
} }
func (m *MockedEnvironment) mockGitCommand(dir, returnValue string, args ...string) {
args = append([]string{"-C", dir, "--no-optional-locks", "-c", "core.quotepath=false", "-c", "color.status=false"}, args...)
m.On("RunCommand", "git", args).Return(returnValue, nil)
}
func TestSetGitHEADContextClean(t *testing.T) { func TestSetGitHEADContextClean(t *testing.T) {
cases := []struct { cases := []struct {
Case string Case string
@ -232,13 +229,13 @@ func TestSetGitHEADContextClean(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("InWSLSharedDrive").Return(false) env.On("InWSLSharedDrive").Return(false)
env.On("GOOS").Return("unix") env.On("GOOS").Return("unix")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.mockGitCommand("", "", "describe", "--tags", "--exact-match") env.MockGitCommand("", "", "describe", "--tags", "--exact-match")
env.mockGitCommand("", tc.Theirs, "name-rev", "--name-only", "--exclude=tags/*", tc.Theirs) env.MockGitCommand("", tc.Theirs, "name-rev", "--name-only", "--exclude=tags/*", tc.Theirs)
env.mockGitCommand("", tc.Ours, "name-rev", "--name-only", "--exclude=tags/*", tc.Ours) env.MockGitCommand("", tc.Ours, "name-rev", "--name-only", "--exclude=tags/*", tc.Ours)
// rebase merge // rebase merge
env.On("HasFolder", "/rebase-merge").Return(tc.RebaseMerge) env.On("HasFolder", "/rebase-merge").Return(tc.RebaseMerge)
env.On("FileContent", "/rebase-merge/head-name").Return(tc.Ours) env.On("FileContent", "/rebase-merge/head-name").Return(tc.Ours)
@ -300,11 +297,11 @@ func TestSetPrettyHEADName(t *testing.T) {
{Case: "no hash on commit", Expected: "commit 1234567", HEAD: "12345678910"}, {Case: "no hash on commit", Expected: "commit 1234567", HEAD: "12345678910"},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("FileContent", "/HEAD").Return(tc.HEAD) env.On("FileContent", "/HEAD").Return(tc.HEAD)
env.On("GOOS").Return("unix") env.On("GOOS").Return("unix")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.mockGitCommand("", tc.Tag, "describe", "--tags", "--exact-match") env.MockGitCommand("", tc.Tag, "describe", "--tags", "--exact-match")
g := &git{ g := &git{
scm: scm{ scm: scm{
env: env, env: env,
@ -418,10 +415,10 @@ func TestSetGitStatus(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("GOOS").Return("unix") env.On("GOOS").Return("unix")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.mockGitCommand("", strings.ReplaceAll(tc.Output, "\t", ""), "status", "-unormal", "--branch", "--porcelain=2") env.MockGitCommand("", strings.ReplaceAll(tc.Output, "\t", ""), "status", "-unormal", "--branch", "--porcelain=2")
g := &git{ g := &git{
scm: scm{ scm: scm{
env: env, env: env,
@ -454,7 +451,7 @@ func TestGetStashContextZeroEntries(t *testing.T) {
{Expected: 4, StashContent: "1\n2\n3\n4\n\n"}, {Expected: 4, StashContent: "1\n2\n3\n4\n\n"},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("FileContent", "/logs/refs/stash").Return(tc.StashContent) env.On("FileContent", "/logs/refs/stash").Return(tc.StashContent)
g := &git{ g := &git{
scm: scm{ scm: scm{
@ -481,7 +478,7 @@ func TestGitUpstream(t *testing.T) {
{Case: "Gitstash", Expected: "G", Upstream: "gitstash.com/test"}, {Case: "Gitstash", Expected: "G", Upstream: "gitstash.com/test"},
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.On("RunCommand", "git", []string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false", env.On("RunCommand", "git", []string{"-C", "", "--no-optional-locks", "-c", "core.quotepath=false",
"-c", "color.status=false", "remote", "get-url", "origin"}).Return(tc.Upstream, nil) "-c", "color.status=false", "remote", "get-url", "origin"}).Return(tc.Upstream, nil)
@ -541,39 +538,6 @@ func TestGetBranchStatus(t *testing.T) {
} }
} }
func TestShouldIgnoreRootRepository(t *testing.T) {
cases := []struct {
Case string
Dir string
Expected bool
}{
{Case: "inside excluded", Dir: "/home/bill/repo"},
{Case: "oustide excluded", Dir: "/home/melinda"},
{Case: "excluded exact match", Dir: "/home/gates", Expected: true},
{Case: "excluded inside match", Dir: "/home/gates/bill", Expected: true},
}
for _, tc := range cases {
props := properties{
ExcludeFolders: []string{
"/home/bill",
"/home/gates.*",
},
}
env := new(MockedEnvironment)
env.On("Home").Return("/home/bill")
env.On("GOOS").Return(windowsPlatform)
git := &git{
scm: scm{
props: props,
env: env,
},
}
got := git.shouldIgnoreRootRepository(tc.Dir)
assert.Equal(t, tc.Expected, got, tc.Case)
}
}
func TestGetGitCommand(t *testing.T) { func TestGetGitCommand(t *testing.T) {
cases := []struct { cases := []struct {
Case string Case string
@ -584,7 +548,7 @@ func TestGetGitCommand(t *testing.T) {
CWD string CWD string
IsWslSharedPath bool IsWslSharedPath bool
}{ }{
{Case: "On Windows", Expected: "git.exe", GOOS: windowsPlatform}, {Case: "On Windows", Expected: "git.exe", GOOS: environment.WindowsPlatform},
{Case: "Non Windows", Expected: "git"}, {Case: "Non Windows", Expected: "git"},
{Case: "Iside WSL2, non shared", IsWSL: true, Expected: "git"}, {Case: "Iside WSL2, non shared", IsWSL: true, Expected: "git"},
{Case: "Iside WSL2, shared", Expected: "git.exe", IsWSL: true, IsWslSharedPath: true, CWD: "/mnt/bill"}, {Case: "Iside WSL2, shared", Expected: "git.exe", IsWSL: true, IsWslSharedPath: true, CWD: "/mnt/bill"},
@ -592,7 +556,7 @@ func TestGetGitCommand(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("IsWsl").Return(tc.IsWSL) env.On("IsWsl").Return(tc.IsWSL)
env.On("GOOS").Return(tc.GOOS) env.On("GOOS").Return(tc.GOOS)
env.On("Pwd").Return(tc.CWD) env.On("Pwd").Return(tc.CWD)
@ -743,7 +707,7 @@ func TestGitTemplateString(t *testing.T) {
props := properties{ props := properties{
FetchStatus: true, FetchStatus: true,
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
tc.Git.env = env tc.Git.env = env
tc.Git.props = props tc.Git.props = props
assert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Git), tc.Case) assert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Git), tc.Case)

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"golang.org/x/mod/modfile" "golang.org/x/mod/modfile"
) )
@ -16,7 +18,7 @@ func (g *golang) template() string {
return languageTemplate return languageTemplate
} }
func (g *golang) init(props Properties, env Environment) { func (g *golang) init(props Properties, env environment.Environment) {
g.language = language{ g.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -4,6 +4,8 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -16,14 +18,14 @@ type mockedLanguageParams struct {
extension string extension string
} }
func getMockedLanguageEnv(params *mockedLanguageParams) (*MockedEnvironment, properties) { func getMockedLanguageEnv(params *mockedLanguageParams) (*mock.MockedEnvironment, properties) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", params.cmd).Return(true) env.On("HasCommand", params.cmd).Return(true)
env.On("RunCommand", params.cmd, []string{params.versionParam}).Return(params.versionOutput, nil) env.On("RunCommand", params.cmd, []string{params.versionParam}).Return(params.versionOutput, nil)
env.On("HasFiles", params.extension).Return(true) env.On("HasFiles", params.extension).Return(true)
env.On("Pwd").Return("/usr/home/project") env.On("Pwd").Return("/usr/home/project")
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
props := properties{ props := properties{
@ -64,7 +66,7 @@ func TestGolang(t *testing.T) {
env, props := getMockedLanguageEnv(params) env, props := getMockedLanguageEnv(params)
if tc.ParseModFile { if tc.ParseModFile {
props[ParseModFile] = tc.ParseModFile props[ParseModFile] = tc.ParseModFile
fileInfo := &FileInfo{ fileInfo := &environment.FileInfo{
Path: "./go.mod", Path: "./go.mod",
ParentFolder: "./", ParentFolder: "./",
IsDir: false, IsDir: false,

View file

@ -1,8 +1,10 @@
package main package main
import "oh-my-posh/environment"
type ipify struct { type ipify struct {
props Properties props Properties
env Environment env environment.Environment
IP string IP string
} }
@ -55,7 +57,7 @@ func (i *ipify) getResult() (string, error) {
return response, nil return response, nil
} }
func (i *ipify) init(props Properties, env Environment) { func (i *ipify) init(props Properties, env environment.Environment) {
i.props = props i.props = props
i.env = env i.env = env
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -42,7 +43,7 @@ func TestIpifySegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
props := properties{ props := properties{
CacheTimeout: 0, CacheTimeout: 0,
} }

View file

@ -1,6 +1,9 @@
package main package main
import "fmt" import (
"fmt"
"oh-my-posh/environment"
)
type java struct { type java struct {
language language
@ -10,7 +13,7 @@ func (j *java) template() string {
return languageTemplate return languageTemplate
} }
func (j *java) init(props Properties, env Environment) { func (j *java) init(props Properties, env environment.Environment) {
javaRegex := `(?: JRE)(?: \(.*\))? \((?P<version>(?P<major>[0-9]+)(?:\.(?P<minor>[0-9]+))?(?:\.(?P<patch>[0-9]+))?).*\),` javaRegex := `(?: JRE)(?: \(.*\))? \((?P<version>(?P<major>[0-9]+)(?:\.(?P<minor>[0-9]+))?(?:\.(?P<patch>[0-9]+))?).*\),`
javaCmd := &cmd{ javaCmd := &cmd{
executable: "java", executable: "java",

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -53,7 +54,7 @@ func TestJava(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "java").Return(true) env.On("HasCommand", "java").Return(true)
env.On("RunCommand", "java", []string{"-Xinternalversion"}).Return(tc.Version, nil) env.On("RunCommand", "java", []string{"-Xinternalversion"}).Return(tc.Version, nil)
env.On("HasFiles", "pom.xml").Return(true) env.On("HasFiles", "pom.xml").Return(true)

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type julia struct { type julia struct {
language language
} }
@ -8,7 +10,7 @@ func (j *julia) template() string {
return languageTemplate return languageTemplate
} }
func (j *julia) init(props Properties, env Environment) { func (j *julia) init(props Properties, env environment.Environment) {
j.language = language{ j.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/environment"
"path/filepath" "path/filepath"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@ -11,8 +12,10 @@ const ParseKubeConfig Property = "parse_kubeconfig"
type kubectl struct { type kubectl struct {
props Properties props Properties
env Environment env environment.Environment
Context string Context string
KubeContext KubeContext
} }
@ -34,7 +37,7 @@ func (k *kubectl) template() string {
return "{{ .Context }}{{ if .Namespace }} :: {{ .Namespace }}{{ end }}" return "{{ .Context }}{{ if .Namespace }} :: {{ .Namespace }}{{ end }}"
} }
func (k *kubectl) init(props Properties, env Environment) { func (k *kubectl) init(props Properties, env environment.Environment) {
k.props = props k.props = props
k.env = env k.env = env
} }

View file

@ -3,6 +3,8 @@ package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"oh-my-posh/environment"
"oh-my-posh/mock"
"path/filepath" "path/filepath"
"testing" "testing"
@ -105,7 +107,7 @@ func TestKubectlSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "kubectl").Return(tc.KubectlExists) env.On("HasCommand", "kubectl").Return(tc.KubectlExists)
var kubeconfig string var kubeconfig string
content, err := ioutil.ReadFile("./test/kubectl.yml") content, err := ioutil.ReadFile("./test/kubectl.yml")
@ -114,9 +116,9 @@ func TestKubectlSegment(t *testing.T) {
} }
var kubectlErr error var kubectlErr error
if tc.KubectlErr { if tc.KubectlErr {
kubectlErr = &commandError{ kubectlErr = &environment.CommandError{
err: "oops", Err: "oops",
exitCode: 1, ExitCode: 1,
} }
} }
env.On("RunCommand", "kubectl", []string{"config", "view", "--output", "yaml", "--minify"}).Return(kubeconfig, kubectlErr) env.On("RunCommand", "kubectl", []string{"config", "view", "--output", "yaml", "--minify"}).Return(kubeconfig, kubectlErr)

View file

@ -3,6 +3,8 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/environment"
"oh-my-posh/regex"
) )
const ( const (
@ -34,7 +36,7 @@ type cmd struct {
} }
func (c *cmd) parse(versionInfo string) (*version, error) { func (c *cmd) parse(versionInfo string) (*version, error) {
values := findNamedRegexMatch(c.regex, versionInfo) values := regex.FindNamedRegexMatch(c.regex, versionInfo)
if len(values) == 0 { if len(values) == 0 {
return nil, errors.New("cannot parse version string") return nil, errors.New("cannot parse version string")
} }
@ -52,7 +54,7 @@ func (c *cmd) parse(versionInfo string) (*version, error) {
type language struct { type language struct {
props Properties props Properties
env Environment env environment.Environment
extensions []string extensions []string
commands []*cmd commands []*cmd
versionURLTemplate string versionURLTemplate string
@ -150,8 +152,8 @@ func (l *language) setVersion() error {
continue continue
} }
versionStr, err = l.env.RunCommand(command.executable, command.args...) versionStr, err = l.env.RunCommand(command.executable, command.args...)
if exitErr, ok := err.(*commandError); ok { if exitErr, ok := err.(*environment.CommandError); ok {
l.exitCode = exitErr.exitCode l.exitCode = exitErr.ExitCode
return fmt.Errorf("err executing %s with %s", command.executable, command.args) return fmt.Errorf("err executing %s with %s", command.executable, command.args)
} }
} else { } else {

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -35,7 +37,7 @@ func (l *languageArgs) hasvalue(value string, list []string) bool {
} }
func bootStrapLanguageTest(args *languageArgs) *language { func bootStrapLanguageTest(args *languageArgs) *language {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
for _, command := range args.commands { for _, command := range args.commands {
env.On("HasCommand", command.executable).Return(args.hasvalue(command.executable, args.enabledCommands)) env.On("HasCommand", command.executable).Return(args.hasvalue(command.executable, args.enabledCommands))
env.On("RunCommand", command.executable, command.args).Return(args.version, args.expectedError) env.On("RunCommand", command.executable, command.args).Return(args.version, args.expectedError)
@ -50,7 +52,7 @@ func bootStrapLanguageTest(args *languageArgs) *language {
} }
env.On("Pwd").Return(cwd) env.On("Pwd").Return(cwd)
env.On("Home").Return(home) env.On("Home").Return(home)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
if args.properties == nil { if args.properties == nil {
@ -346,7 +348,7 @@ func TestLanguageEnabledCommandExitCode(t *testing.T) {
enabledExtensions: []string{uni, corn}, enabledExtensions: []string{uni, corn},
enabledCommands: []string{"uni"}, enabledCommands: []string{"uni"},
version: universion, version: universion,
expectedError: &commandError{exitCode: expected}, expectedError: &environment.CommandError{ExitCode: expected},
} }
lang := bootStrapLanguageTest(args) lang := bootStrapLanguageTest(args)
assert.True(t, lang.enabled()) assert.True(t, lang.enabled())

View file

@ -2,11 +2,12 @@ package main
import ( import (
"encoding/json" "encoding/json"
"oh-my-posh/environment"
) )
type nbgv struct { type nbgv struct {
props Properties props Properties
env Environment env environment.Environment
VersionInfo VersionInfo
} }
@ -43,7 +44,7 @@ func (n *nbgv) enabled() bool {
return n.VersionInfo.VersionFileFound return n.VersionInfo.VersionFileFound
} }
func (n *nbgv) init(props Properties, env Environment) { func (n *nbgv) init(props Properties, env environment.Environment) {
n.props = props n.props = props
n.env = env n.env = env
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/mock"
"testing" "testing"
"github.com/alecthomas/assert" "github.com/alecthomas/assert"
@ -57,7 +58,7 @@ func TestNbgv(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "nbgv").Return(tc.HasNbgv) env.On("HasCommand", "nbgv").Return(tc.HasNbgv)
env.On("RunCommand", "nbgv", []string{"get-version", "--format=json"}).Return(tc.Response, tc.Error) env.On("RunCommand", "nbgv", []string{"get-version", "--format=json"}).Return(tc.Response, tc.Error)
nbgv := &nbgv{ nbgv := &nbgv{

View file

@ -3,13 +3,14 @@ package main
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"oh-my-posh/environment"
"time" "time"
) )
// segment struct, makes templating easier // segment struct, makes templating easier
type nightscout struct { type nightscout struct {
props Properties props Properties
env Environment env environment.Environment
NightscoutData NightscoutData
TrendIcon string TrendIcon string
@ -137,7 +138,7 @@ func (ns *nightscout) getResult() (*NightscoutData, error) {
return data, nil return data, nil
} }
func (ns *nightscout) init(props Properties, env Environment) { func (ns *nightscout) init(props Properties, env environment.Environment) {
ns.props = props ns.props = props
ns.env = env ns.env = env
} }

View file

@ -2,6 +2,7 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -129,13 +130,13 @@ func TestNSSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
props := properties{ props := properties{
CacheTimeout: tc.CacheTimeout, CacheTimeout: tc.CacheTimeout,
URL: "FAKE", URL: "FAKE",
} }
cache := &MockedCache{} cache := &mock.MockedCache{}
cache.On("Get", FAKEAPIURL).Return(tc.JSONResponse, !tc.CacheFoundFail) cache.On("Get", FAKEAPIURL).Return(tc.JSONResponse, !tc.CacheFoundFail)
cache.On("Set", FAKEAPIURL, tc.JSONResponse, tc.CacheTimeout).Return() cache.On("Set", FAKEAPIURL, tc.JSONResponse, tc.CacheTimeout).Return()

View file

@ -1,6 +1,10 @@
package main package main
import "fmt" import (
"fmt"
"oh-my-posh/environment"
"oh-my-posh/regex"
)
type node struct { type node struct {
language language
@ -21,7 +25,7 @@ func (n *node) template() string {
return "{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}" return "{{ if .PackageManagerIcon }}{{ .PackageManagerIcon }} {{ end }}{{ .Full }}"
} }
func (n *node) init(props Properties, env Environment) { func (n *node) init(props Properties, env environment.Environment) {
n.language = language{ n.language = language{
env: env, env: env,
props: props, props: props,
@ -62,12 +66,12 @@ func (n *node) matchesVersionFile() bool {
return true return true
} }
regex := fmt.Sprintf( re := fmt.Sprintf(
`(?im)^v?%s(\.?%s)?(\.?%s)?$`, `(?im)^v?%s(\.?%s)?(\.?%s)?$`,
n.language.version.Major, n.language.version.Major,
n.language.version.Minor, n.language.version.Minor,
n.language.version.Patch, n.language.version.Patch,
) )
return matchString(regex, fileVersion) return regex.MatchString(re, fileVersion)
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/alecthomas/assert" "github.com/alecthomas/assert"
@ -29,7 +30,7 @@ func TestNodeMatchesVersionFile(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("FileContent", ".nvmrc").Return(tc.RCVersion) env.On("FileContent", ".nvmrc").Return(tc.RCVersion)
node := &node{ node := &node{
@ -60,7 +61,7 @@ func TestNodeInContext(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasFiles", "yarn.lock").Return(tc.HasYarn) env.On("HasFiles", "yarn.lock").Return(tc.HasYarn)
env.On("HasFiles", "package-lock.json").Return(tc.hasNPM) env.On("HasFiles", "package-lock.json").Return(tc.hasNPM)
env.On("HasFiles", "package.json").Return(tc.hasDefault) env.On("HasFiles", "package.json").Return(tc.hasDefault)

View file

@ -1,8 +1,10 @@
package main package main
import "oh-my-posh/environment"
type osInfo struct { type osInfo struct {
props Properties props Properties
env Environment env environment.Environment
Icon string Icon string
} }
@ -63,11 +65,11 @@ func (oi *osInfo) template() string {
func (oi *osInfo) enabled() bool { func (oi *osInfo) enabled() bool {
goos := oi.env.GOOS() goos := oi.env.GOOS()
switch goos { switch goos {
case windowsPlatform: case environment.WindowsPlatform:
oi.Icon = oi.props.getString(Windows, "\uE62A") oi.Icon = oi.props.getString(Windows, "\uE62A")
case darwinPlatform: case environment.DarwinPlatform:
oi.Icon = oi.props.getString(MacOS, "\uF179") oi.Icon = oi.props.getString(MacOS, "\uF179")
case linuxPlatform: case environment.LinuxPlatform:
platform := oi.env.Platform() platform := oi.env.Platform()
displayDistroName := oi.props.getBool(DisplayDistroName, false) displayDistroName := oi.props.getBool(DisplayDistroName, false)
if displayDistroName { if displayDistroName {
@ -125,7 +127,7 @@ func (oi *osInfo) getDistroIcon(distro string) string {
return oi.props.getString(Linux, "\uF17C") return oi.props.getString(Linux, "\uF17C")
} }
func (oi *osInfo) init(props Properties, env Environment) { func (oi *osInfo) init(props Properties, env environment.Environment) {
oi.props = props oi.props = props
oi.env = env oi.env = env
} }

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -60,10 +62,10 @@ func TestOSInfo(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("GOOS").Return(tc.GOOS) env.On("GOOS").Return(tc.GOOS)
env.On("Platform").Return(tc.Platform) env.On("Platform").Return(tc.Platform)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
WSL: tc.IsWSL, WSL: tc.IsWSL,
}) })

View file

@ -4,11 +4,13 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/environment"
) )
type owm struct { type owm struct {
props Properties props Properties
env Environment env environment.Environment
Temperature float64 Temperature float64
Weather string Weather string
URL string URL string
@ -161,7 +163,7 @@ func (d *owm) setStatus() error {
return nil return nil
} }
func (d *owm) init(props Properties, env Environment) { func (d *owm) init(props Properties, env environment.Environment) {
d.props = props d.props = props
d.env = env d.env = env
} }

View file

@ -3,6 +3,7 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -50,7 +51,7 @@ func TestOWMSegmentSingle(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
props := properties{ props := properties{
APIKey: "key", APIKey: "key",
Location: "AMSTERDAM,NL", Location: "AMSTERDAM,NL",
@ -178,7 +179,7 @@ func TestOWMSegmentIcons(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, tc.IconID) response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, tc.IconID)
expectedString := fmt.Sprintf("%s (20°C)", tc.ExpectedIconString) expectedString := fmt.Sprintf("%s (20°C)", tc.ExpectedIconString)
@ -201,7 +202,7 @@ func TestOWMSegmentIcons(t *testing.T) {
// test with hyperlink enabled // test with hyperlink enabled
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, tc.IconID) response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, tc.IconID)
expectedString := fmt.Sprintf("[%s (20°C)](http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key)", tc.ExpectedIconString) expectedString := fmt.Sprintf("[%s (20°C)](http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key)", tc.ExpectedIconString)
@ -226,8 +227,8 @@ func TestOWMSegmentFromCache(t *testing.T) {
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d") response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d")
expectedString := fmt.Sprintf("%s (20°C)", "\ufa98") expectedString := fmt.Sprintf("%s (20°C)", "\ufa98")
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
cache := &MockedCache{} cache := &mock.MockedCache{}
o := &owm{ o := &owm{
props: properties{ props: properties{
APIKey: "key", APIKey: "key",
@ -249,8 +250,8 @@ func TestOWMSegmentFromCacheWithHyperlink(t *testing.T) {
response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d") response := fmt.Sprintf(`{"weather":[{"icon":"%s"}],"main":{"temp":20}}`, "01d")
expectedString := fmt.Sprintf("[%s (20°C)](http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key)", "\ufa98") expectedString := fmt.Sprintf("[%s (20°C)](http://api.openweathermap.org/data/2.5/weather?q=AMSTERDAM,NL&units=metric&appid=key)", "\ufa98")
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
cache := &MockedCache{} cache := &mock.MockedCache{}
o := &owm{ o := &owm{
props: properties{ props: properties{

View file

@ -2,14 +2,15 @@ package main
import ( import (
"fmt" "fmt"
"path/filepath" "oh-my-posh/environment"
"oh-my-posh/regex"
"sort" "sort"
"strings" "strings"
) )
type path struct { type path struct {
props Properties props Properties
env Environment env environment.Environment
pwd string pwd string
Path string Path string
@ -95,13 +96,13 @@ func (pt *path) enabled() bool {
} }
func (pt *path) formatWindowsDrive(pwd string) string { func (pt *path) formatWindowsDrive(pwd string) string {
if pt.env.GOOS() != windowsPlatform || !strings.HasSuffix(pwd, ":") { if pt.env.GOOS() != environment.WindowsPlatform || !strings.HasSuffix(pwd, ":") {
return pwd return pwd
} }
return pwd + "\\" return pwd + "\\"
} }
func (pt *path) init(props Properties, env Environment) { func (pt *path) init(props Properties, env environment.Environment) {
pt.props = props pt.props = props
pt.env = env pt.env = env
} }
@ -141,7 +142,7 @@ func (pt *path) getAgnosterPath() string {
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon)) buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
} }
if pathDepth > 0 { if pathDepth > 0 {
buffer.WriteString(fmt.Sprintf("%s%s", separator, base(pwd, pt.env))) buffer.WriteString(fmt.Sprintf("%s%s", separator, environment.Base(pt.env, pwd)))
} }
return buffer.String() return buffer.String()
} }
@ -181,7 +182,7 @@ func (pt *path) getLetterPath() string {
} }
// check if there is at least a letter we can use // check if there is at least a letter we can use
matches := findNamedRegexMatch(`(?P<letter>[\p{L}0-9]).*`, folder) matches := regex.FindNamedRegexMatch(`(?P<letter>[\p{L}0-9]).*`, folder)
if matches == nil || matches["letter"] == "" { if matches == nil || matches["letter"] == "" {
// no letter found, keep the folder unchanged // no letter found, keep the folder unchanged
@ -241,7 +242,7 @@ func (pt *path) getFullPath() string {
func (pt *path) getFolderPath() string { func (pt *path) getFolderPath() string {
pwd := pt.getPwd() pwd := pt.getPwd()
pwd = base(pwd, pt.env) pwd = environment.Base(pt.env, pwd)
return pt.replaceFolderSeparators(pwd) return pt.replaceFolderSeparators(pwd)
} }
@ -261,7 +262,7 @@ func (pt *path) normalize(inputPath string) string {
} }
normalized = strings.ReplaceAll(normalized, "\\", "/") normalized = strings.ReplaceAll(normalized, "\\", "/")
goos := pt.env.GOOS() goos := pt.env.GOOS()
if goos == windowsPlatform || goos == darwinPlatform { if goos == environment.WindowsPlatform || goos == environment.DarwinPlatform {
normalized = strings.ToLower(normalized) normalized = strings.ToLower(normalized)
} }
return normalized return normalized
@ -343,35 +344,3 @@ func (pt *path) pathDepth(pwd string) int {
} }
return depth - 1 return depth - 1
} }
// Base returns the last element of path.
// Trailing path separators are removed before extracting the last element.
// If the path consists entirely of separators, Base returns a single separator.
func base(path string, env Environment) string {
if path == "/" {
return path
}
volumeName := filepath.VolumeName(path)
// Strip trailing slashes.
for len(path) > 0 && string(path[len(path)-1]) == env.PathSeperator() {
path = path[0 : len(path)-1]
}
if volumeName == path {
return path
}
// Throw away volume name
path = path[len(filepath.VolumeName(path)):]
// Find the last element
i := len(path) - 1
for i >= 0 && string(path[i]) != env.PathSeperator() {
i--
}
if i >= 0 {
path = path[i+1:]
}
// If empty now, it had only slashes.
if path == "" {
return env.PathSeperator()
}
return path
}

View file

@ -1,214 +1,16 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/distatus/battery"
"github.com/gookit/config/v2" "github.com/gookit/config/v2"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
) )
type MockedEnvironment struct { func renderTemplate(env *mock.MockedEnvironment, segmentTemplate string, context interface{}) string {
mock.Mock
}
func (env *MockedEnvironment) Getenv(key string) string {
args := env.Called(key)
return args.String(0)
}
func (env *MockedEnvironment) Pwd() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Home() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) HasFiles(pattern string) bool {
args := env.Called(pattern)
return args.Bool(0)
}
func (env *MockedEnvironment) HasFilesInDir(dir, pattern string) bool {
args := env.Called(dir, pattern)
return args.Bool(0)
}
func (env *MockedEnvironment) HasFolder(folder string) bool {
args := env.Called(folder)
return args.Bool(0)
}
func (env *MockedEnvironment) FileContent(file string) string {
args := env.Called(file)
return args.String(0)
}
func (env *MockedEnvironment) FolderList(path string) []string {
args := env.Called(path)
return args.Get(0).([]string)
}
func (env *MockedEnvironment) PathSeperator() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) User() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Host() (string, error) {
args := env.Called()
return args.String(0), args.Error(1)
}
func (env *MockedEnvironment) GOOS() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Platform() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) HasCommand(command string) bool {
args := env.Called(command)
return args.Bool(0)
}
func (env *MockedEnvironment) RunCommand(command string, args ...string) (string, error) {
arguments := env.Called(command, args)
return arguments.String(0), arguments.Error(1)
}
func (env *MockedEnvironment) RunShellCommand(shell, command string) string {
args := env.Called(shell, command)
return args.String(0)
}
func (env *MockedEnvironment) ErrorCode() int {
args := env.Called()
return args.Int(0)
}
func (env *MockedEnvironment) ExecutionTime() float64 {
args := env.Called()
return float64(args.Int(0))
}
func (env *MockedEnvironment) Root() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) Args() *Args {
arguments := env.Called()
return arguments.Get(0).(*Args)
}
func (env *MockedEnvironment) BatteryInfo() ([]*battery.Battery, error) {
args := env.Called()
return args.Get(0).([]*battery.Battery), args.Error(1)
}
func (env *MockedEnvironment) Shell() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) WindowTitle(imageName, windowTitleRegex string) (string, error) {
args := env.Called(imageName)
return args.String(0), args.Error(1)
}
func (env *MockedEnvironment) WindowsRegistryKeyValue(path string) (*WindowsRegistryValue, error) {
args := env.Called(path)
return args.Get(0).(*WindowsRegistryValue), args.Error(1)
}
func (env *MockedEnvironment) HTTPRequest(url string, timeout int, requestModifiers ...HTTPRequestModifier) ([]byte, error) {
args := env.Called(url)
return args.Get(0).([]byte), args.Error(1)
}
func (env *MockedEnvironment) HasParentFilePath(path string) (*FileInfo, error) {
args := env.Called(path)
return args.Get(0).(*FileInfo), args.Error(1)
}
func (env *MockedEnvironment) StackCount() int {
args := env.Called()
return args.Int(0)
}
func (env *MockedEnvironment) IsWsl() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) IsWsl2() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) TerminalWidth() (int, error) {
args := env.Called()
return args.Int(0), args.Error(1)
}
func (env *MockedEnvironment) CachePath() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) Cache() Cache {
args := env.Called()
return args.Get(0).(Cache)
}
func (env *MockedEnvironment) Close() {
_ = env.Called()
}
func (env *MockedEnvironment) Logs() string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) InWSLSharedDrive() bool {
args := env.Called()
return args.Bool(0)
}
func (env *MockedEnvironment) ConvertToWindowsPath(path string) string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) ConvertToLinuxPath(path string) string {
args := env.Called()
return args.String(0)
}
func (env *MockedEnvironment) WifiNetwork() (*WifiInfo, error) {
args := env.Called()
return args.Get(0).(*WifiInfo), args.Error(1)
}
func (env *MockedEnvironment) TemplateCache() *TemplateCache {
args := env.Called()
return args.Get(0).(*TemplateCache)
}
func renderTemplate(env *MockedEnvironment, segmentTemplate string, context interface{}) string {
found := false found := false
for _, call := range env.Mock.ExpectedCalls { for _, call := range env.Mock.ExpectedCalls {
if call.Method == "TemplateCache" { if call.Method == "TemplateCache" {
@ -217,7 +19,7 @@ func renderTemplate(env *MockedEnvironment, segmentTemplate string, context inte
} }
} }
if !found { if !found {
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
} }
@ -242,7 +44,7 @@ const (
func TestIsInHomeDirTrue(t *testing.T) { func TestIsInHomeDirTrue(t *testing.T) {
home := homeBill home := homeBill
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return(home) env.On("Home").Return(home)
path := &path{ path := &path{
env: env, env: env,
@ -257,7 +59,7 @@ func TestIsInHomeDirLevelTrue(t *testing.T) {
for i := 0; i < 99; i++ { for i := 0; i < 99; i++ {
pwd += levelDir pwd += levelDir
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return(home) env.On("Home").Return(home)
path := &path{ path := &path{
env: env, env: env,
@ -286,10 +88,10 @@ func TestRootLocationHome(t *testing.T) {
{Expected: "DRIVE:", HomePath: "/home/bill/", Pwd: "/usr/error/what", Pswd: "DRIVE:", PathSeperator: "/"}, {Expected: "DRIVE:", HomePath: "/home/bill/", Pwd: "/usr/error/what", Pswd: "DRIVE:", PathSeperator: "/"},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return(tc.HomePath) env.On("Home").Return(tc.HomePath)
env.On("Pwd").Return(tc.Pwd) env.On("Pwd").Return(tc.Pwd)
args := &Args{ args := &environment.Args{
PSWD: &tc.Pswd, PSWD: &tc.Pswd,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -309,7 +111,7 @@ func TestRootLocationHome(t *testing.T) {
func TestIsInHomeDirFalse(t *testing.T) { func TestIsInHomeDirFalse(t *testing.T) {
home := homeBill home := homeBill
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return(home) env.On("Home").Return(home)
path := &path{ path := &path{
env: env, env: env,
@ -323,7 +125,7 @@ func TestPathDepthMultipleLevelsDeep(t *testing.T) {
for i := 0; i < 99; i++ { for i := 0; i < 99; i++ {
pwd += levelDir pwd += levelDir
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("/") env.On("PathSeperator").Return("/")
env.On("getRunteGOOS").Return("") env.On("getRunteGOOS").Return("")
path := &path{ path := &path{
@ -335,7 +137,7 @@ func TestPathDepthMultipleLevelsDeep(t *testing.T) {
func TestPathDepthZeroLevelsDeep(t *testing.T) { func TestPathDepthZeroLevelsDeep(t *testing.T) {
pwd := "/usr/" pwd := "/usr/"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("/") env.On("PathSeperator").Return("/")
path := &path{ path := &path{
env: env, env: env,
@ -346,7 +148,7 @@ func TestPathDepthZeroLevelsDeep(t *testing.T) {
func TestPathDepthOneLevelDeep(t *testing.T) { func TestPathDepthOneLevelDeep(t *testing.T) {
pwd := "/usr/location" pwd := "/usr/location"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("/") env.On("PathSeperator").Return("/")
path := &path{ path := &path{
env: env, env: env,
@ -437,14 +239,14 @@ func TestAgnosterPathStyles(t *testing.T) {
{Style: Letter, Expected: "➼ s > .w > man", HomePath: "/usr/home", Pwd: "➼ something/.whatever/man", PathSeperator: "/", FolderSeparatorIcon: " > "}, {Style: Letter, Expected: "➼ s > .w > man", HomePath: "/usr/home", Pwd: "➼ something/.whatever/man", PathSeperator: "/", FolderSeparatorIcon: " > "},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return(tc.PathSeperator) env.On("PathSeperator").Return(tc.PathSeperator)
env.On("Home").Return(tc.HomePath) env.On("Home").Return(tc.HomePath)
env.On("Pwd").Return(tc.Pwd) env.On("Pwd").Return(tc.Pwd)
env.On("GOOS").Return(tc.GOOS) env.On("GOOS").Return(tc.GOOS)
env.On("StackCount").Return(0) env.On("StackCount").Return(0)
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
args := &Args{ args := &environment.Args{
PSWD: &tc.Pswd, PSWD: &tc.Pswd,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -505,8 +307,8 @@ func TestGetFullPath(t *testing.T) {
{Style: Folder, FolderSeparatorIcon: "|", Pwd: "/usr/home/abc", Expected: "abc"}, {Style: Folder, FolderSeparatorIcon: "|", Pwd: "/usr/home/abc", Expected: "abc"},
{Style: Folder, FolderSeparatorIcon: "|", Pwd: "/a/b/c/d", Expected: "d"}, {Style: Folder, FolderSeparatorIcon: "|", Pwd: "/a/b/c/d", Expected: "d"},
{Style: Folder, FolderSeparatorIcon: "\\", Pwd: "C:\\", Expected: "C:\\", PathSeparator: "\\", GOOS: windowsPlatform}, {Style: Folder, FolderSeparatorIcon: "\\", Pwd: "C:\\", Expected: "C:\\", PathSeparator: "\\", GOOS: environment.WindowsPlatform},
{Style: Full, FolderSeparatorIcon: "\\", Pwd: "C:\\Users\\Jan", Expected: "C:\\Users\\Jan", PathSeparator: "\\", GOOS: windowsPlatform}, {Style: Full, FolderSeparatorIcon: "\\", Pwd: "C:\\Users\\Jan", Expected: "C:\\Users\\Jan", PathSeparator: "\\", GOOS: environment.WindowsPlatform},
// StackCountEnabled=true and StackCount=2 // StackCountEnabled=true and StackCount=2
{Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: 2, Expected: "2 /"}, {Style: Full, FolderSeparatorIcon: "|", Pwd: "/", StackCount: 2, Expected: "2 /"},
@ -555,7 +357,7 @@ func TestGetFullPath(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
if len(tc.PathSeparator) == 0 { if len(tc.PathSeparator) == 0 {
tc.PathSeparator = "/" tc.PathSeparator = "/"
} }
@ -565,7 +367,7 @@ func TestGetFullPath(t *testing.T) {
env.On("GOOS").Return(tc.GOOS) env.On("GOOS").Return(tc.GOOS)
env.On("StackCount").Return(tc.StackCount) env.On("StackCount").Return(tc.StackCount)
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
args := &Args{ args := &environment.Args{
PSWD: &tc.Pswd, PSWD: &tc.Pswd,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -609,12 +411,12 @@ func TestGetFullPathCustomMappedLocations(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("/") env.On("PathSeperator").Return("/")
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("Pwd").Return(tc.Pwd) env.On("Pwd").Return(tc.Pwd)
env.On("GOOS").Return("") env.On("GOOS").Return("")
args := &Args{ args := &environment.Args{
PSWD: &tc.Pwd, PSWD: &tc.Pwd,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -636,18 +438,18 @@ func TestNormalizePath(t *testing.T) {
GOOS string GOOS string
Expected string Expected string
}{ }{
{Input: "C:\\Users\\Bob\\Foo", GOOS: linuxPlatform, Expected: "C:/Users/Bob/Foo"}, {Input: "C:\\Users\\Bob\\Foo", GOOS: environment.LinuxPlatform, Expected: "C:/Users/Bob/Foo"},
{Input: "C:\\Users\\Bob\\Foo", GOOS: windowsPlatform, Expected: "c:/users/bob/foo"}, {Input: "C:\\Users\\Bob\\Foo", GOOS: environment.WindowsPlatform, Expected: "c:/users/bob/foo"},
{Input: "~\\Bob\\Foo", GOOS: linuxPlatform, Expected: "/usr/home/Bob/Foo"}, {Input: "~\\Bob\\Foo", GOOS: environment.LinuxPlatform, Expected: "/usr/home/Bob/Foo"},
{Input: "~\\Bob\\Foo", GOOS: windowsPlatform, Expected: "/usr/home/bob/foo"}, {Input: "~\\Bob\\Foo", GOOS: environment.WindowsPlatform, Expected: "/usr/home/bob/foo"},
{Input: "/foo/~/bar", GOOS: linuxPlatform, Expected: "/foo/~/bar"}, {Input: "/foo/~/bar", GOOS: environment.LinuxPlatform, Expected: "/foo/~/bar"},
{Input: "/foo/~/bar", GOOS: windowsPlatform, Expected: "/foo/~/bar"}, {Input: "/foo/~/bar", GOOS: environment.WindowsPlatform, Expected: "/foo/~/bar"},
{Input: "~/baz", GOOS: linuxPlatform, Expected: "/usr/home/baz"}, {Input: "~/baz", GOOS: environment.LinuxPlatform, Expected: "/usr/home/baz"},
{Input: "~/baz", GOOS: windowsPlatform, Expected: "/usr/home/baz"}, {Input: "~/baz", GOOS: environment.WindowsPlatform, Expected: "/usr/home/baz"},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("GOOS").Return(tc.GOOS) env.On("GOOS").Return(tc.GOOS)
pt := &path{ pt := &path{
@ -660,12 +462,12 @@ func TestNormalizePath(t *testing.T) {
func TestGetFolderPathCustomMappedLocations(t *testing.T) { func TestGetFolderPathCustomMappedLocations(t *testing.T) {
pwd := "/a/b/c/d" pwd := "/a/b/c/d"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("/") env.On("PathSeperator").Return("/")
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("Pwd").Return(pwd) env.On("Pwd").Return(pwd)
env.On("GOOS").Return("") env.On("GOOS").Return("")
args := &Args{ args := &environment.Args{
PSWD: &pwd, PSWD: &pwd,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -707,12 +509,12 @@ func TestAgnosterPath(t *testing.T) { // nolint:dupl
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return(tc.Home) env.On("Home").Return(tc.Home)
env.On("PathSeperator").Return(tc.PathSeparator) env.On("PathSeperator").Return(tc.PathSeparator)
env.On("Pwd").Return(tc.PWD) env.On("Pwd").Return(tc.PWD)
env.On("GOOS").Return("") env.On("GOOS").Return("")
args := &Args{ args := &environment.Args{
PSWD: &tc.PWD, PSWD: &tc.PWD,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -755,12 +557,12 @@ func TestAgnosterLeftPath(t *testing.T) { // nolint:dupl
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Home").Return(tc.Home) env.On("Home").Return(tc.Home)
env.On("PathSeperator").Return(tc.PathSeparator) env.On("PathSeperator").Return(tc.PathSeparator)
env.On("Pwd").Return(tc.PWD) env.On("Pwd").Return(tc.PWD)
env.On("GOOS").Return("") env.On("GOOS").Return("")
args := &Args{ args := &environment.Args{
PSWD: &tc.PWD, PSWD: &tc.PWD,
} }
env.On("Args").Return(args) env.On("Args").Return(args)
@ -803,12 +605,12 @@ func TestGetPwd(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("/") env.On("PathSeperator").Return("/")
env.On("Home").Return("/usr/home") env.On("Home").Return("/usr/home")
env.On("Pwd").Return(tc.Pwd) env.On("Pwd").Return(tc.Pwd)
env.On("GOOS").Return("") env.On("GOOS").Return("")
args := &Args{ args := &environment.Args{
PSWD: &tc.Pswd, PSWD: &tc.Pswd,
} }
env.On("Args").Return(args) env.On("Args").Return(args)

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type php struct { type php struct {
language language
} }
@ -8,7 +10,7 @@ func (p *php) template() string {
return languageTemplate return languageTemplate
} }
func (p *php) init(props Properties, env Environment) { func (p *php) init(props Properties, env environment.Environment) {
p.language = language{ p.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -2,6 +2,8 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/environment"
"oh-my-posh/regex"
"strconv" "strconv"
"strings" "strings"
) )
@ -34,7 +36,7 @@ type plastic struct {
plasticWorkspaceFolder string // root folder of workspace plasticWorkspaceFolder string // root folder of workspace
} }
func (p *plastic) init(props Properties, env Environment) { func (p *plastic) init(props Properties, env environment.Environment) {
p.props = props p.props = props
p.env = env p.env = env
} }
@ -94,7 +96,7 @@ func (p *plastic) parseFilesStatus(output []string) {
continue continue
} }
p.MergePending = p.MergePending || matchString(`(?i)\smerge\s+from\s+[0-9]+\s*$`, line) p.MergePending = p.MergePending || regex.MatchString(`(?i)\smerge\s+from\s+[0-9]+\s*$`, line)
code := line[:2] code := line[:2]
p.Status.add(code) p.Status.add(code)
@ -102,7 +104,7 @@ func (p *plastic) parseFilesStatus(output []string) {
} }
func (p *plastic) parseStringPattern(output, pattern, name string) string { func (p *plastic) parseStringPattern(output, pattern, name string) string {
match := findNamedRegexMatch(pattern, output) match := regex.FindNamedRegexMatch(pattern, output)
if sValue, ok := match[name]; ok { if sValue, ok := match[name]; ok {
return sValue return sValue
} }

View file

@ -1,13 +1,15 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestPlasticEnabledNotFound(t *testing.T) { func TestPlasticEnabledNotFound(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "cm").Return(false) env.On("HasCommand", "cm").Return(false)
env.On("GOOS").Return("") env.On("GOOS").Return("")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
@ -21,12 +23,12 @@ func TestPlasticEnabledNotFound(t *testing.T) {
} }
func TestPlasticEnabledInWorkspaceDirectory(t *testing.T) { func TestPlasticEnabledInWorkspaceDirectory(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "cm").Return(true) env.On("HasCommand", "cm").Return(true)
env.On("GOOS").Return("") env.On("GOOS").Return("")
env.On("IsWsl").Return(false) env.On("IsWsl").Return(false)
env.On("FileContent", "/dir/.plastic//plastic.selector").Return("") env.On("FileContent", "/dir/.plastic//plastic.selector").Return("")
fileInfo := &FileInfo{ fileInfo := &environment.FileInfo{
Path: "/dir/hello", Path: "/dir/hello",
ParentFolder: "/dir", ParentFolder: "/dir",
IsDir: true, IsDir: true,
@ -43,7 +45,7 @@ func TestPlasticEnabledInWorkspaceDirectory(t *testing.T) {
} }
func setupCmStatusEnv(status, headStatus string) *plastic { func setupCmStatusEnv(status, headStatus string) *plastic {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("RunCommand", "cm", []string{"status", "--all", "--machinereadable"}).Return(status, nil) env.On("RunCommand", "cm", []string{"status", "--all", "--machinereadable"}).Return(status, nil)
env.On("RunCommand", "cm", []string{"status", "--head", "--machinereadable"}).Return(headStatus, nil) env.On("RunCommand", "cm", []string{"status", "--head", "--machinereadable"}).Return(headStatus, nil)
p := &plastic{ p := &plastic{
@ -329,7 +331,7 @@ func TestPlasticTemplateString(t *testing.T) {
FetchStatus: true, FetchStatus: true,
} }
tc.Plastic.props = props tc.Plastic.props = props
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
tc.Plastic.env = env tc.Plastic.env = env
assert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Plastic), tc.Case) assert.Equal(t, tc.Expected, renderTemplate(env, tc.Template, tc.Plastic), tc.Case)
} }

View file

@ -1,10 +1,13 @@
package main package main
import "strings" import (
"oh-my-posh/environment"
"strings"
)
type poshgit struct { type poshgit struct {
props Properties props Properties
env Environment env environment.Environment
Status string Status string
} }
@ -23,7 +26,7 @@ func (p *poshgit) enabled() bool {
return p.Status != "" return p.Status != ""
} }
func (p *poshgit) init(props Properties, env Environment) { func (p *poshgit) init(props Properties, env environment.Environment) {
p.props = props p.props = props
p.env = env p.env = env
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -19,7 +20,7 @@ func TestPoshGitSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Getenv", poshGitEnv).Return(tc.PoshGitPrompt) env.On("Getenv", poshGitEnv).Return(tc.PoshGitPrompt)
p := &poshgit{ p := &poshgit{
env: env, env: env,

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type python struct { type python struct {
language language
@ -15,7 +17,7 @@ func (p *python) template() string {
return languageTemplate return languageTemplate
} }
func (p *python) init(props Properties, env Environment) { func (p *python) init(props Properties, env environment.Environment) {
p.language = language{ p.language = language{
env: env, env: env,
props: props, props: props,
@ -57,7 +59,7 @@ func (p *python) loadContext() {
var venv string var venv string
for _, venvVar := range venvVars { for _, venvVar := range venvVars {
venv = p.language.env.Getenv(venvVar) venv = p.language.env.Getenv(venvVar)
name := base(venv, p.language.env) name := environment.Base(p.language.env, venv)
if p.canUseVenvName(name) { if p.canUseVenvName(name) {
p.Venv = name p.Venv = name
break break

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/alecthomas/assert" "github.com/alecthomas/assert"
@ -41,7 +43,7 @@ func TestPythonTemplate(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "python").Return(true) env.On("HasCommand", "python").Return(true)
env.On("RunCommand", "python", []string{"--version"}).Return("Python 3.8.4", nil) env.On("RunCommand", "python", []string{"--version"}).Return("Python 3.8.4", nil)
env.On("HasFiles", "*.py").Return(true) env.On("HasFiles", "*.py").Return(true)
@ -56,7 +58,7 @@ func TestPythonTemplate(t *testing.T) {
FetchVersion: tc.FetchVersion, FetchVersion: tc.FetchVersion,
DisplayMode: DisplayModeAlways, DisplayMode: DisplayModeAlways,
} }
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
python := &python{} python := &python{}
@ -76,7 +78,7 @@ func TestPythonPythonInContext(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("PathSeperator").Return("") env.On("PathSeperator").Return("")
env.On("Getenv", "VIRTUAL_ENV").Return(tc.VirtualEnvName) env.On("Getenv", "VIRTUAL_ENV").Return(tc.VirtualEnvName)
env.On("Getenv", "CONDA_ENV_PATH").Return("") env.On("Getenv", "CONDA_ENV_PATH").Return("")

View file

@ -1,8 +1,10 @@
package main package main
import "oh-my-posh/environment"
type root struct { type root struct {
props Properties props Properties
env Environment env environment.Environment
} }
func (rt *root) template() string { func (rt *root) template() string {
@ -13,7 +15,7 @@ func (rt *root) enabled() bool {
return rt.env.Root() return rt.env.Root()
} }
func (rt *root) init(props Properties, env Environment) { func (rt *root) init(props Properties, env environment.Environment) {
rt.props = props rt.props = props
rt.env = env rt.env = env
} }

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type ruby struct { type ruby struct {
language language
} }
@ -8,7 +10,7 @@ func (r *ruby) template() string {
return languageTemplate return languageTemplate
} }
func (r *ruby) init(props Properties, env Environment) { func (r *ruby) init(props Properties, env environment.Environment) {
r.language = language{ r.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -82,7 +83,7 @@ func TestRuby(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "rbenv").Return(tc.HasRbenv) env.On("HasCommand", "rbenv").Return(tc.HasRbenv)
env.On("RunCommand", "rbenv", []string{"version-name"}).Return(tc.Version, nil) env.On("RunCommand", "rbenv", []string{"version-name"}).Return(tc.Version, nil)
env.On("HasCommand", "rvm-prompt").Return(tc.HasRvmprompt) env.On("HasCommand", "rvm-prompt").Return(tc.HasRvmprompt)

View file

@ -1,5 +1,7 @@
package main package main
import "oh-my-posh/environment"
type rust struct { type rust struct {
language language
} }
@ -8,7 +10,7 @@ func (r *rust) template() string {
return languageTemplate return languageTemplate
} }
func (r *rust) init(props Properties, env Environment) { func (r *rust) init(props Properties, env environment.Environment) {
r.language = language{ r.language = language{
env: env, env: env,
props: props, props: props,

View file

@ -1,8 +1,10 @@
package main package main
import "oh-my-posh/environment"
type session struct { type session struct {
props Properties props Properties
env Environment env environment.Environment
// text string // text string
SSHSession bool SSHSession bool
@ -20,7 +22,7 @@ func (s *session) template() string {
return "{{ .UserName }}@{{ .HostName }}" return "{{ .UserName }}@{{ .HostName }}"
} }
func (s *session) init(props Properties, env Environment) { func (s *session) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
} }

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -86,7 +88,7 @@ func TestSessionSegmentTemplate(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("User").Return(tc.UserName) env.On("User").Return(tc.UserName)
env.On("GOOS").Return("burp") env.On("GOOS").Return("burp")
env.On("Host").Return(tc.ComputerName, nil) env.On("Host").Return(tc.ComputerName, nil)
@ -96,7 +98,7 @@ func TestSessionSegmentTemplate(t *testing.T) {
} }
env.On("Getenv", "SSH_CONNECTION").Return(SSHSession) env.On("Getenv", "SSH_CONNECTION").Return(SSHSession)
env.On("Getenv", "SSH_CLIENT").Return(SSHSession) env.On("Getenv", "SSH_CLIENT").Return(SSHSession)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
UserName: tc.UserName, UserName: tc.UserName,
HostName: tc.ComputerName, HostName: tc.ComputerName,
Env: map[string]string{ Env: map[string]string{

View file

@ -1,10 +1,13 @@
package main package main
import "strings" import (
"oh-my-posh/environment"
"strings"
)
type shell struct { type shell struct {
props Properties props Properties
env Environment env environment.Environment
Name string Name string
} }
@ -30,7 +33,7 @@ func (s *shell) enabled() bool {
return true return true
} }
func (s *shell) init(props Properties, env Environment) { func (s *shell) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -8,7 +9,7 @@ import (
func TestWriteCurrentShell(t *testing.T) { func TestWriteCurrentShell(t *testing.T) {
expected := "zsh" expected := "zsh"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Shell").Return(expected, nil) env.On("Shell").Return(expected, nil)
s := &shell{ s := &shell{
env: env, env: env,
@ -28,7 +29,7 @@ func TestUseMappedShellNames(t *testing.T) {
{Shell: "PWSH", Expected: "PS"}, {Shell: "PWSH", Expected: "PS"},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("Shell").Return(tc.Expected, nil) env.On("Shell").Return(tc.Expected, nil)
s := &shell{ s := &shell{
env: env, env: env,

View file

@ -1,8 +1,10 @@
package main package main
import "oh-my-posh/environment"
type spotify struct { type spotify struct {
props Properties props Properties
env Environment env environment.Environment
MusicPlayer MusicPlayer
} }
@ -43,7 +45,7 @@ func (s *spotify) resolveIcon() {
} }
} }
func (s *spotify) init(props Properties, env Environment) { func (s *spotify) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
} }

View file

@ -4,6 +4,7 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -24,7 +25,7 @@ func TestSpotifyDarwinEnabledAndSpotifyPlaying(t *testing.T) {
{Running: "true", Expected: "\uF8E3 Candlemass - Spellbreaker", Status: "paused", Artist: "Candlemass", Track: "Spellbreaker"}, {Running: "true", Expected: "\uF8E3 Candlemass - Spellbreaker", Status: "paused", Artist: "Candlemass", Track: "Spellbreaker"},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("RunCommand", "osascript", []string{"-e", "application \"Spotify\" is running"}).Return(tc.Running, tc.Error) env.On("RunCommand", "osascript", []string{"-e", "application \"Spotify\" is running"}).Return(tc.Running, tc.Error)
env.On("RunCommand", "osascript", []string{"-e", "tell application \"Spotify\" to player state as string"}).Return(tc.Status, nil) env.On("RunCommand", "osascript", []string{"-e", "tell application \"Spotify\" to player state as string"}).Return(tc.Status, nil)
env.On("RunCommand", "osascript", []string{"-e", "tell application \"Spotify\" to artist of current track as string"}).Return(tc.Artist, nil) env.On("RunCommand", "osascript", []string{"-e", "tell application \"Spotify\" to artist of current track as string"}).Return(tc.Artist, nil)

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -8,7 +9,7 @@ import (
func TestSpotifyStringPlayingSong(t *testing.T) { func TestSpotifyStringPlayingSong(t *testing.T) {
expected := "\ue602 Candlemass - Spellbreaker" expected := "\ue602 Candlemass - Spellbreaker"
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
s := &spotify{ s := &spotify{
MusicPlayer: MusicPlayer{ MusicPlayer: MusicPlayer{
Artist: "Candlemass", Artist: "Candlemass",
@ -24,7 +25,7 @@ func TestSpotifyStringPlayingSong(t *testing.T) {
func TestSpotifyStringStoppedSong(t *testing.T) { func TestSpotifyStringStoppedSong(t *testing.T) {
expected := "\uf04d " expected := "\uf04d "
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
s := &spotify{ s := &spotify{
MusicPlayer: MusicPlayer{ MusicPlayer: MusicPlayer{
Artist: "Candlemass", Artist: "Candlemass",

View file

@ -4,6 +4,7 @@ package main
import ( import (
"errors" "errors"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -15,9 +16,8 @@ type spotifyArgs struct {
} }
func bootStrapSpotifyWindowsTest(args *spotifyArgs) *spotify { func bootStrapSpotifyWindowsTest(args *spotifyArgs) *spotify {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("WindowTitle", "spotify.exe").Return(args.title, args.runError) env.On("WindowTitle", "spotify.exe").Return(args.title, args.runError)
env.onTemplate()
s := &spotify{ s := &spotify{
env: env, env: env,
props: properties{}, props: properties{},
@ -37,9 +37,14 @@ func TestSpotifyWindowsEnabledAndSpotifyPlaying(t *testing.T) {
args := &spotifyArgs{ args := &spotifyArgs{
title: "Candlemass - Spellbreaker", title: "Candlemass - Spellbreaker",
} }
s := bootStrapSpotifyWindowsTest(args) env := new(mock.MockedEnvironment)
env.On("WindowTitle", "spotify.exe").Return(args.title, args.runError)
s := &spotify{
env: env,
props: properties{},
}
assert.Equal(t, true, s.enabled()) assert.Equal(t, true, s.enabled())
assert.Equal(t, "\ue602 Candlemass - Spellbreaker", s.string()) assert.Equal(t, "\ue602 Candlemass - Spellbreaker", renderTemplate(env, s.template(), s))
} }
func TestSpotifyWindowsEnabledAndSpotifyStopped(t *testing.T) { func TestSpotifyWindowsEnabledAndSpotifyStopped(t *testing.T) {

View file

@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"testing" "testing"
"oh-my-posh/mock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -51,15 +53,14 @@ func TestSpotifyWsl(t *testing.T) {
ExecOutput: ""}, ExecOutput: ""},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("IsWsl").Return(true) env.On("IsWsl").Return(true)
env.On("RunCommand", "tasklist.exe", []string{"/V", "/FI", "Imagename eq Spotify.exe", "/FO", "CSV", "/NH"}).Return(tc.ExecOutput, nil) env.On("RunCommand", "tasklist.exe", []string{"/V", "/FI", "Imagename eq Spotify.exe", "/FO", "CSV", "/NH"}).Return(tc.ExecOutput, nil)
env.onTemplate()
s := &spotify{ s := &spotify{
env: env, env: env,
props: properties{}, props: properties{},
} }
assert.Equal(t, tc.ExpectedEnabled, s.enabled(), fmt.Sprintf("Failed in case: %s", tc.Case)) assert.Equal(t, tc.ExpectedEnabled, s.enabled(), fmt.Sprintf("Failed in case: %s", tc.Case))
assert.Equal(t, tc.ExpectedString, s.string(), fmt.Sprintf("Failed in case: %s", tc.Case)) assert.Equal(t, tc.ExpectedString, renderTemplate(env, s.template(), s), fmt.Sprintf("Failed in case: %s", tc.Case))
} }
} }

View file

@ -6,13 +6,14 @@ import (
"fmt" "fmt"
"math" "math"
"net/http" "net/http"
"oh-my-posh/environment"
"time" "time"
) )
// segment struct, makes templating easier // segment struct, makes templating easier
type strava struct { type strava struct {
props Properties props Properties
env Environment env environment.Environment
StravaData StravaData
Icon string Icon string
@ -229,7 +230,7 @@ func (s *strava) getResult() (*StravaData, error) {
return data, nil return data, nil
} }
func (s *strava) init(props Properties, env Environment) { func (s *strava) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
} }

View file

@ -3,6 +3,7 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"oh-my-posh/mock"
"testing" "testing"
"time" "time"
@ -135,13 +136,13 @@ func TestStravaSegment(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := &MockedEnvironment{} env := &mock.MockedEnvironment{}
url := "https://www.strava.com/api/v3/athlete/activities?page=1&per_page=1" url := "https://www.strava.com/api/v3/athlete/activities?page=1&per_page=1"
tokenURL := fmt.Sprintf("https://ohmyposh.dev/api/refresh?segment=strava&token=%s", tc.TokenRefreshToken) tokenURL := fmt.Sprintf("https://ohmyposh.dev/api/refresh?segment=strava&token=%s", tc.TokenRefreshToken)
var props properties = map[Property]interface{}{ var props properties = map[Property]interface{}{
CacheTimeout: tc.CacheTimeout, CacheTimeout: tc.CacheTimeout,
} }
cache := &MockedCache{} cache := &mock.MockedCache{}
cache.On("Get", url).Return(tc.JSONResponse, !tc.CacheFoundFail) cache.On("Get", url).Return(tc.JSONResponse, !tc.CacheFoundFail)
cache.On("Set", url, tc.JSONResponse, tc.CacheTimeout).Return() cache.On("Set", url, tc.JSONResponse, tc.CacheTimeout).Return()

View file

@ -1,6 +1,8 @@
package main package main
import ( import (
"oh-my-posh/environment"
cpu "github.com/shirou/gopsutil/v3/cpu" cpu "github.com/shirou/gopsutil/v3/cpu"
load "github.com/shirou/gopsutil/v3/load" load "github.com/shirou/gopsutil/v3/load"
mem "github.com/shirou/gopsutil/v3/mem" mem "github.com/shirou/gopsutil/v3/mem"
@ -8,7 +10,7 @@ import (
type sysinfo struct { type sysinfo struct {
props Properties props Properties
env Environment env environment.Environment
Precision int Precision int
// mem // mem
PhysicalTotalMemory uint64 PhysicalTotalMemory uint64
@ -42,7 +44,7 @@ func (s *sysinfo) enabled() bool {
return true return true
} }
func (s *sysinfo) init(props Properties, env Environment) { func (s *sysinfo) init(props Properties, env environment.Environment) {
s.props = props s.props = props
s.env = env s.env = env
s.Precision = s.props.getInt(Precision, 2) s.Precision = s.props.getInt(Precision, 2)

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/cpu"
@ -49,7 +50,7 @@ func TestSysInfo(t *testing.T) {
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
tc.SysInfo.env = env tc.SysInfo.env = env
tc.SysInfo.props = properties{ tc.SysInfo.props = properties{
Precision: tc.Precision, Precision: tc.Precision,

View file

@ -1,8 +1,13 @@
package main package main
import (
"oh-my-posh/environment"
)
type terraform struct { type terraform struct {
props Properties props Properties
env Environment env environment.Environment
WorkspaceName string WorkspaceName string
} }
@ -10,7 +15,7 @@ func (tf *terraform) template() string {
return "{{ .WorkspaceName }}" return "{{ .WorkspaceName }}"
} }
func (tf *terraform) init(props Properties, env Environment) { func (tf *terraform) init(props Properties, env environment.Environment) {
tf.props = props tf.props = props
tf.env = env tf.env = env
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -13,7 +14,7 @@ type terraformArgs struct {
} }
func bootStrapTerraformTest(args *terraformArgs) *terraform { func bootStrapTerraformTest(args *terraformArgs) *terraform {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("HasCommand", "terraform").Return(args.hasTfCommand) env.On("HasCommand", "terraform").Return(args.hasTfCommand)
env.On("HasFolder", "/.terraform").Return(args.hasTfFolder) env.On("HasFolder", "/.terraform").Return(args.hasTfFolder)
env.On("Pwd").Return("") env.On("Pwd").Return("")

View file

@ -2,6 +2,8 @@ package main
import ( import (
"encoding/json" "encoding/json"
"oh-my-posh/environment"
"oh-my-posh/mock"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -15,7 +17,7 @@ func TestMapSegmentWriterCanMap(t *testing.T) {
sc := &Segment{ sc := &Segment{
Type: Session, Type: Session,
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
err := sc.mapSegmentWithWriter(env) err := sc.mapSegmentWithWriter(env)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, sc.writer) assert.NotNil(t, sc.writer)
@ -25,7 +27,7 @@ func TestMapSegmentWriterCannotMap(t *testing.T) {
sc := &Segment{ sc := &Segment{
Type: "nilwriter", Type: "nilwriter",
} }
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
err := sc.mapSegmentWithWriter(env) err := sc.mapSegmentWithWriter(env)
assert.Error(t, err) assert.Error(t, err)
} }
@ -79,8 +81,8 @@ func TestShouldIncludeFolder(t *testing.T) {
{Case: "Include Mismatch / Exclude Mismatch", IncludeFolders: []string{"zProjects.*"}, ExcludeFolders: []string{"Projects/nope"}, Expected: false}, {Case: "Include Mismatch / Exclude Mismatch", IncludeFolders: []string{"zProjects.*"}, ExcludeFolders: []string{"Projects/nope"}, Expected: false},
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("GOOS").Return(linuxPlatform) env.On("GOOS").Return(environment.LinuxPlatform)
env.On("Home").Return("") env.On("Home").Return("")
env.On("Pwd").Return(cwd) env.On("Pwd").Return(cwd)
segment := &Segment{ segment := &Segment{
@ -96,8 +98,8 @@ func TestShouldIncludeFolder(t *testing.T) {
} }
func TestShouldIncludeFolderRegexInverted(t *testing.T) { func TestShouldIncludeFolderRegexInverted(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("GOOS").Return(linuxPlatform) env.On("GOOS").Return(environment.LinuxPlatform)
env.On("Home").Return("") env.On("Home").Return("")
env.On("Pwd").Return(cwd) env.On("Pwd").Return(cwd)
segment := &Segment{ segment := &Segment{
@ -117,8 +119,8 @@ func TestShouldIncludeFolderRegexInverted(t *testing.T) {
} }
func TestShouldIncludeFolderRegexInvertedNonEscaped(t *testing.T) { func TestShouldIncludeFolderRegexInvertedNonEscaped(t *testing.T) {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("GOOS").Return(linuxPlatform) env.On("GOOS").Return(environment.LinuxPlatform)
env.On("Home").Return("") env.On("Home").Return("")
env.On("Pwd").Return(cwd) env.On("Pwd").Return(cwd)
segment := &Segment{ segment := &Segment{
@ -190,8 +192,8 @@ func TestGetColors(t *testing.T) {
}, },
} }
for _, tc := range cases { for _, tc := range cases {
env := new(MockedEnvironment) env := new(mock.MockedEnvironment)
env.On("TemplateCache").Return(&TemplateCache{ env.On("TemplateCache").Return(&environment.TemplateCache{
Env: make(map[string]string), Env: make(map[string]string),
}) })
segment := &Segment{ segment := &Segment{

Some files were not shown because too many files have changed in this diff Show more