mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-02-21 02:55:37 -08:00
fix(path): parse path correctly
This commit is contained in:
parent
049f9d4f94
commit
5b6a3470d1
|
@ -22,7 +22,7 @@ const (
|
||||||
Prompt BlockType = "prompt"
|
Prompt BlockType = "prompt"
|
||||||
// LineBreak creates a line break in the prompt
|
// LineBreak creates a line break in the prompt
|
||||||
LineBreak BlockType = "newline"
|
LineBreak BlockType = "newline"
|
||||||
// RPrompt a right aligned prompt in ZSH and Powershell
|
// RPrompt is a right aligned prompt
|
||||||
RPrompt BlockType = "rprompt"
|
RPrompt BlockType = "rprompt"
|
||||||
// Left aligns left
|
// Left aligns left
|
||||||
Left BlockAlignment = "left"
|
Left BlockAlignment = "left"
|
||||||
|
|
|
@ -130,7 +130,7 @@ func (e *Engine) shouldFill(block *Block, length int) (string, bool) {
|
||||||
|
|
||||||
func (e *Engine) renderBlock(block *Block) {
|
func (e *Engine) renderBlock(block *Block) {
|
||||||
defer func() {
|
defer func() {
|
||||||
// Due to a bug in Powershell, the end of the line needs to be cleared.
|
// Due to a bug in PowerShell, the end of the line needs to be cleared.
|
||||||
// If this doesn't happen, the portion after the prompt gets colored in the background
|
// If this doesn't happen, the portion after the prompt gets colored in the background
|
||||||
// color of the line above the new input line. Clearing the line fixes this,
|
// color of the line above the new input line. Clearing the line fixes this,
|
||||||
// but can hopefully one day be removed when this is resolved natively.
|
// but can hopefully one day be removed when this is resolved natively.
|
||||||
|
|
|
@ -337,11 +337,16 @@ func (env *ShellEnvironment) 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 := regex.GetCompiledRegex(`^[a-z]:`)
|
if env.GOOS() == WINDOWS {
|
||||||
return driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper)
|
driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
|
||||||
|
return driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper)
|
||||||
|
}
|
||||||
|
return pwd
|
||||||
}
|
}
|
||||||
if env.CmdFlags != nil && env.CmdFlags.PWD != "" {
|
if env.CmdFlags != nil && env.CmdFlags.PWD != "" {
|
||||||
env.cwd = correctPath(env.CmdFlags.PWD)
|
// ensure a clean path
|
||||||
|
root, path := ParsePath(env, correctPath(env.CmdFlags.PWD))
|
||||||
|
env.cwd = root + path
|
||||||
return env.cwd
|
return env.cwd
|
||||||
}
|
}
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
|
@ -735,6 +740,9 @@ func (env *ShellEnvironment) TemplateCache() *TemplateCache {
|
||||||
pwd := env.Pwd()
|
pwd := env.Pwd()
|
||||||
tmplCache.PWD = ReplaceHomeDirPrefixWithTilde(env, pwd)
|
tmplCache.PWD = ReplaceHomeDirPrefixWithTilde(env, pwd)
|
||||||
tmplCache.Folder = Base(env, pwd)
|
tmplCache.Folder = Base(env, pwd)
|
||||||
|
if env.GOOS() == WINDOWS && strings.HasSuffix(tmplCache.Folder, ":") {
|
||||||
|
tmplCache.Folder += `\`
|
||||||
|
}
|
||||||
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
|
||||||
|
@ -766,19 +774,21 @@ func (env *ShellEnvironment) DirMatchesOneOf(dir string, regexes []string) (matc
|
||||||
}
|
}
|
||||||
|
|
||||||
func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
|
func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
|
||||||
normalizedCwd := strings.ReplaceAll(dir, "\\", "/")
|
if goos == WINDOWS {
|
||||||
normalizedHomeDir := strings.ReplaceAll(home, "\\", "/")
|
dir = strings.ReplaceAll(dir, "\\", "/")
|
||||||
|
home = strings.ReplaceAll(home, "\\", "/")
|
||||||
|
}
|
||||||
|
|
||||||
for _, element := range regexes {
|
for _, element := range regexes {
|
||||||
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
|
normalizedElement := strings.ReplaceAll(element, "\\\\", "/")
|
||||||
if strings.HasPrefix(normalizedElement, "~") {
|
if strings.HasPrefix(normalizedElement, "~") {
|
||||||
normalizedElement = strings.Replace(normalizedElement, "~", normalizedHomeDir, 1)
|
normalizedElement = strings.Replace(normalizedElement, "~", home, 1)
|
||||||
}
|
}
|
||||||
pattern := fmt.Sprintf("^%s$", normalizedElement)
|
pattern := fmt.Sprintf("^%s$", normalizedElement)
|
||||||
if goos == WINDOWS || goos == DARWIN {
|
if goos == WINDOWS || goos == DARWIN {
|
||||||
pattern = "(?i)" + pattern
|
pattern = "(?i)" + pattern
|
||||||
}
|
}
|
||||||
matched := regex.MatchString(pattern, normalizedCwd)
|
matched := regex.MatchString(pattern, dir)
|
||||||
if matched {
|
if matched {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -786,7 +796,7 @@ func dirMatchesOneOf(dir, home, goos string, regexes []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func isPathSeparator(env Environment, c uint8) bool {
|
func IsPathSeparator(env Environment, c uint8) bool {
|
||||||
if c == '/' {
|
if c == '/' {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -800,14 +810,14 @@ func isPathSeparator(env Environment, c uint8) bool {
|
||||||
// Trailing path separators are removed before extracting the last element.
|
// Trailing path separators are removed before extracting the last element.
|
||||||
// If the path consists entirely of separators, Base returns a single separator.
|
// If the path consists entirely of separators, Base returns a single separator.
|
||||||
func Base(env Environment, path string) string {
|
func Base(env Environment, path string) string {
|
||||||
if path == "/" {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
volumeName := filepath.VolumeName(path)
|
volumeName := filepath.VolumeName(path)
|
||||||
// Strip trailing slashes.
|
// Strip trailing slashes.
|
||||||
for len(path) > 0 && isPathSeparator(env, path[len(path)-1]) {
|
for len(path) > 0 && IsPathSeparator(env, path[len(path)-1]) {
|
||||||
path = path[0 : len(path)-1]
|
path = path[0 : len(path)-1]
|
||||||
}
|
}
|
||||||
|
if len(path) == 0 {
|
||||||
|
return env.PathSeparator()
|
||||||
|
}
|
||||||
if volumeName == path {
|
if volumeName == path {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
@ -815,22 +825,69 @@ func Base(env Environment, path string) string {
|
||||||
path = path[len(filepath.VolumeName(path)):]
|
path = path[len(filepath.VolumeName(path)):]
|
||||||
// Find the last element
|
// Find the last element
|
||||||
i := len(path) - 1
|
i := len(path) - 1
|
||||||
for i >= 0 && !isPathSeparator(env, path[i]) {
|
for i >= 0 && !IsPathSeparator(env, path[i]) {
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
path = path[i+1:]
|
path = path[i+1:]
|
||||||
}
|
}
|
||||||
// If empty now, it had only slashes.
|
// If empty now, it had only slashes.
|
||||||
if path == "" {
|
if len(path) == 0 {
|
||||||
return env.PathSeparator()
|
return env.PathSeparator()
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParsePath parses an input path and returns a clean root and a clean path.
|
||||||
|
func ParsePath(env Environment, inputPath string) (root, path string) {
|
||||||
|
if len(inputPath) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
separator := env.PathSeparator()
|
||||||
|
clean := func(path string) string {
|
||||||
|
matches := regex.FindAllNamedRegexMatch(fmt.Sprintf(`(?P<element>[^\%s]+)`, separator), path)
|
||||||
|
n := len(matches) - 1
|
||||||
|
s := new(strings.Builder)
|
||||||
|
for i, m := range matches {
|
||||||
|
s.WriteString(m["element"])
|
||||||
|
if i != n {
|
||||||
|
s.WriteString(separator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if env.GOOS() == WINDOWS {
|
||||||
|
inputPath = strings.ReplaceAll(inputPath, "/", `\`)
|
||||||
|
// for a UNC path, extract \\hostname\sharename as the root
|
||||||
|
matches := regex.FindNamedRegexMatch(`^\\\\(?P<hostname>[^\\]+)\\+(?P<sharename>[^\\]+)\\*(?P<path>[\s\S]*)$`, inputPath)
|
||||||
|
if len(matches) > 0 {
|
||||||
|
root = `\\` + matches["hostname"] + `\` + matches["sharename"] + `\`
|
||||||
|
path = clean(matches["path"])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s := strings.SplitAfterN(inputPath, separator, 2)
|
||||||
|
root = s[0]
|
||||||
|
if !strings.HasSuffix(root, separator) {
|
||||||
|
// a root should end with a separator
|
||||||
|
root += separator
|
||||||
|
}
|
||||||
|
if len(s) == 2 {
|
||||||
|
path = clean(s[1])
|
||||||
|
}
|
||||||
|
return root, path
|
||||||
|
}
|
||||||
|
|
||||||
func ReplaceHomeDirPrefixWithTilde(env Environment, path string) string {
|
func ReplaceHomeDirPrefixWithTilde(env Environment, path string) string {
|
||||||
if strings.HasPrefix(path, env.Home()) {
|
home := env.Home()
|
||||||
return strings.Replace(path, env.Home(), "~", 1)
|
// match Home directory exactly
|
||||||
|
if !strings.HasPrefix(path, home) {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
rem := path[len(home):]
|
||||||
|
if len(rem) == 0 || IsPathSeparator(env, rem[0]) {
|
||||||
|
return "~" + rem
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,29 +22,6 @@ func TestHostNameWithLan(t *testing.T) {
|
||||||
assert.Equal(t, "hello", cleanHostName)
|
assert.Equal(t, "hello", cleanHostName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWindowsPathWithDriveLetter(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Case string
|
|
||||||
CWD string
|
|
||||||
Expected string
|
|
||||||
}{
|
|
||||||
{Case: "C drive", CWD: `C:\Windows\`, Expected: `C:\Windows\`},
|
|
||||||
{Case: "C drive lower case", CWD: `c:\Windows\`, Expected: `C:\Windows\`},
|
|
||||||
{Case: "P drive lower case", CWD: `p:\some\`, Expected: `P:\some\`},
|
|
||||||
{Case: "some drive lower case", CWD: `some:\some\`, Expected: `some:\some\`},
|
|
||||||
{Case: "drive ending in c:", CWD: `src:\source\`, Expected: `src:\source\`},
|
|
||||||
{Case: "registry drive", CWD: `HKLM:\SOFTWARE\magnetic:test\`, Expected: `HKLM:\SOFTWARE\magnetic:test\`},
|
|
||||||
}
|
|
||||||
for _, tc := range cases {
|
|
||||||
env := &ShellEnvironment{
|
|
||||||
CmdFlags: &Flags{
|
|
||||||
PWD: tc.CWD,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
assert.Equal(t, env.Pwd(), tc.Expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDirMatchesOneOf(t *testing.T) {
|
func TestDirMatchesOneOf(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
GOOS string
|
GOOS string
|
||||||
|
|
|
@ -5,8 +5,8 @@ import (
|
||||||
"oh-my-posh/environment"
|
"oh-my-posh/environment"
|
||||||
"oh-my-posh/properties"
|
"oh-my-posh/properties"
|
||||||
"oh-my-posh/regex"
|
"oh-my-posh/regex"
|
||||||
|
"oh-my-posh/shell"
|
||||||
"oh-my-posh/template"
|
"oh-my-posh/template"
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -45,7 +45,7 @@ const (
|
||||||
Full string = "full"
|
Full string = "full"
|
||||||
// Folder displays the current folder
|
// Folder displays the current folder
|
||||||
Folder string = "folder"
|
Folder string = "folder"
|
||||||
// Mixed like agnoster, but if the path is short it displays it
|
// Mixed like agnoster, but if a folder name is short enough, it is displayed as-is
|
||||||
Mixed string = "mixed"
|
Mixed string = "mixed"
|
||||||
// Letter like agnoster, but with the first letter of each folder name
|
// Letter like agnoster, but with the first letter of each folder name
|
||||||
Letter string = "letter"
|
Letter string = "letter"
|
||||||
|
@ -70,64 +70,33 @@ func (pt *Path) Template() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) Enabled() bool {
|
func (pt *Path) Enabled() bool {
|
||||||
pt.pwd = pt.env.Pwd()
|
pt.setPath()
|
||||||
switch style := pt.props.GetString(properties.Style, Agnoster); style {
|
|
||||||
case Agnoster:
|
|
||||||
pt.Path = pt.getAgnosterPath()
|
|
||||||
case AgnosterFull:
|
|
||||||
pt.Path = pt.getAgnosterFullPath()
|
|
||||||
case AgnosterShort:
|
|
||||||
pt.Path = pt.getAgnosterShortPath()
|
|
||||||
case Mixed:
|
|
||||||
pt.Path = pt.getMixedPath()
|
|
||||||
case Letter:
|
|
||||||
pt.Path = pt.getLetterPath()
|
|
||||||
case Unique:
|
|
||||||
pt.Path = pt.getUniqueLettersPath()
|
|
||||||
case AgnosterLeft:
|
|
||||||
pt.Path = pt.getAgnosterLeftPath()
|
|
||||||
case Short:
|
|
||||||
// "short" is a duplicate of "full", just here for backwards compatibility
|
|
||||||
fallthrough
|
|
||||||
case Full:
|
|
||||||
pt.Path = pt.getFullPath()
|
|
||||||
case Folder:
|
|
||||||
pt.Path = pt.getFolderPath()
|
|
||||||
default:
|
|
||||||
pt.Path = fmt.Sprintf("Path style: %s is not available", style)
|
|
||||||
}
|
|
||||||
pt.Path = pt.formatWindowsDrive(pt.Path)
|
|
||||||
if pt.env.IsWsl() {
|
if pt.env.IsWsl() {
|
||||||
pt.Location, _ = pt.env.RunCommand("wslpath", "-m", pt.pwd)
|
pt.Location, _ = pt.env.RunCommand("wslpath", "-m", pt.pwd)
|
||||||
} else {
|
} else {
|
||||||
pt.Location = pt.pwd
|
pt.Location = pt.pwd
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.StackCount = pt.env.StackCount()
|
pt.StackCount = pt.env.StackCount()
|
||||||
pt.Writable = pt.env.DirIsWritable(pt.pwd)
|
pt.Writable = pt.env.DirIsWritable(pt.pwd)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) Parent() string {
|
func (pt *Path) Parent() string {
|
||||||
if pt.pwd == pt.env.Home() {
|
pwd := pt.getPwd()
|
||||||
|
if len(pwd) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
parent := filepath.Dir(pt.pwd)
|
root, path := environment.ParsePath(pt.env, pwd)
|
||||||
if pt.pwd == parent {
|
if len(path) == 0 {
|
||||||
|
// a root path has no parent
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
separator := pt.env.PathSeparator()
|
base := environment.Base(pt.env, path)
|
||||||
if parent == pt.rootLocation() || parent == separator {
|
path = pt.replaceFolderSeparators(path[:len(path)-len(base)])
|
||||||
separator = ""
|
if root != pt.env.PathSeparator() {
|
||||||
|
root = root[:len(root)-1] + pt.getFolderSeparator()
|
||||||
}
|
}
|
||||||
return pt.replaceMappedLocations(parent) + separator
|
return root + path
|
||||||
}
|
|
||||||
|
|
||||||
func (pt *Path) formatWindowsDrive(pwd string) string {
|
|
||||||
if pt.env.GOOS() != environment.WINDOWS || !strings.HasSuffix(pwd, ":") {
|
|
||||||
return pwd
|
|
||||||
}
|
|
||||||
return pwd + "\\"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) Init(props properties.Properties, env environment.Environment) {
|
func (pt *Path) Init(props properties.Properties, env environment.Environment) {
|
||||||
|
@ -135,10 +104,52 @@ func (pt *Path) Init(props properties.Properties, env environment.Environment) {
|
||||||
pt.env = env
|
pt.env = env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pt *Path) setPath() {
|
||||||
|
pwd := pt.getPwd()
|
||||||
|
if len(pwd) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
root, path := environment.ParsePath(pt.env, pwd)
|
||||||
|
if len(path) == 0 {
|
||||||
|
pt.Path = pt.formatRoot(root)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch style := pt.props.GetString(properties.Style, Agnoster); style {
|
||||||
|
case Agnoster:
|
||||||
|
pt.Path = pt.getAgnosterPath(root, path)
|
||||||
|
case AgnosterFull:
|
||||||
|
pt.Path = pt.getAgnosterFullPath(root, path)
|
||||||
|
case AgnosterShort:
|
||||||
|
pt.Path = pt.getAgnosterShortPath(root, path)
|
||||||
|
case Mixed:
|
||||||
|
pt.Path = pt.getMixedPath(root, path)
|
||||||
|
case Letter:
|
||||||
|
pt.Path = pt.getLetterPath(root, path)
|
||||||
|
case Unique:
|
||||||
|
pt.Path = pt.getUniqueLettersPath(root, path)
|
||||||
|
case AgnosterLeft:
|
||||||
|
pt.Path = pt.getAgnosterLeftPath(root, path)
|
||||||
|
case Short:
|
||||||
|
// "short" is a duplicate of "full", just here for backwards compatibility
|
||||||
|
fallthrough
|
||||||
|
case Full:
|
||||||
|
pt.Path = pt.getFullPath(root, path)
|
||||||
|
case Folder:
|
||||||
|
pt.Path = pt.getFolderPath(path)
|
||||||
|
default:
|
||||||
|
pt.Path = fmt.Sprintf("Path style: %s is not available", style)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (pt *Path) getFolderSeparator() string {
|
func (pt *Path) getFolderSeparator() string {
|
||||||
separatorTemplate := pt.props.GetString(FolderSeparatorTemplate, "")
|
separatorTemplate := pt.props.GetString(FolderSeparatorTemplate, "")
|
||||||
if len(separatorTemplate) == 0 {
|
if len(separatorTemplate) == 0 {
|
||||||
return pt.props.GetString(FolderSeparatorIcon, pt.env.PathSeparator())
|
separator := pt.props.GetString(FolderSeparatorIcon, pt.env.PathSeparator())
|
||||||
|
// if empty, use the default separator
|
||||||
|
if len(separator) == 0 {
|
||||||
|
return pt.env.PathSeparator()
|
||||||
|
}
|
||||||
|
return separator
|
||||||
}
|
}
|
||||||
tmpl := &template.Text{
|
tmpl := &template.Text{
|
||||||
Template: separatorTemplate,
|
Template: separatorTemplate,
|
||||||
|
@ -149,67 +160,66 @@ func (pt *Path) getFolderSeparator() string {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pt.env.Log(environment.Error, "getFolderSeparator", err.Error())
|
pt.env.Log(environment.Error, "getFolderSeparator", err.Error())
|
||||||
}
|
}
|
||||||
|
if len(text) == 0 {
|
||||||
|
return pt.env.PathSeparator()
|
||||||
|
}
|
||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getMixedPath() string {
|
func (pt *Path) getMixedPath(root, path string) string {
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
pwd := pt.getPwd()
|
|
||||||
splitted := strings.Split(pwd, pt.env.PathSeparator())
|
|
||||||
threshold := int(pt.props.GetFloat64(MixedThreshold, 4))
|
threshold := int(pt.props.GetFloat64(MixedThreshold, 4))
|
||||||
for i, part := range splitted {
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
if part == "" {
|
separator := pt.getFolderSeparator()
|
||||||
continue
|
elements := strings.Split(path, pt.env.PathSeparator())
|
||||||
}
|
if root != pt.env.PathSeparator() {
|
||||||
|
elements = append([]string{root[:len(root)-1]}, elements...)
|
||||||
folder := part
|
}
|
||||||
if len(part) > threshold && i != 0 && i != len(splitted)-1 {
|
n := len(elements)
|
||||||
folder = pt.props.GetString(FolderIcon, "..")
|
buffer.WriteString(elements[0])
|
||||||
}
|
for i := 1; i < n; i++ {
|
||||||
separator := pt.getFolderSeparator()
|
folder := elements[i]
|
||||||
if i == 0 {
|
if len(folder) > threshold && i != n-1 {
|
||||||
separator = ""
|
folder = folderIcon
|
||||||
}
|
}
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", separator, folder))
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, folder))
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterPath() string {
|
func (pt *Path) getAgnosterPath(root, path string) string {
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
pwd := pt.getPwd()
|
|
||||||
buffer.WriteString(pt.rootLocation())
|
|
||||||
pathDepth := pt.pathDepth(pwd)
|
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
separator := pt.getFolderSeparator()
|
separator := pt.getFolderSeparator()
|
||||||
for i := 1; i < pathDepth; i++ {
|
elements := strings.Split(path, pt.env.PathSeparator())
|
||||||
|
if root != pt.env.PathSeparator() {
|
||||||
|
elements = append([]string{root[:len(root)-1]}, elements...)
|
||||||
|
}
|
||||||
|
n := len(elements)
|
||||||
|
buffer.WriteString(elements[0])
|
||||||
|
for i := 2; i < n; i++ {
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
|
||||||
}
|
}
|
||||||
if pathDepth > 0 {
|
if n > 1 {
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", separator, environment.Base(pt.env, pwd)))
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, elements[n-1]))
|
||||||
}
|
}
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterLeftPath() string {
|
func (pt *Path) getAgnosterLeftPath(root, path string) string {
|
||||||
pwd := pt.getPwd()
|
|
||||||
separator := pt.env.PathSeparator()
|
|
||||||
pwd = strings.Trim(pwd, separator)
|
|
||||||
splitted := strings.Split(pwd, separator)
|
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
|
||||||
separator = pt.getFolderSeparator()
|
|
||||||
switch len(splitted) {
|
|
||||||
case 0:
|
|
||||||
return ""
|
|
||||||
case 1:
|
|
||||||
return splitted[0]
|
|
||||||
case 2:
|
|
||||||
return fmt.Sprintf("%s%s%s", splitted[0], separator, splitted[1])
|
|
||||||
}
|
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s%s", splitted[0], separator, splitted[1]))
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
for i := 2; i < len(splitted); i++ {
|
separator := pt.getFolderSeparator()
|
||||||
|
elements := strings.Split(path, pt.env.PathSeparator())
|
||||||
|
if root != pt.env.PathSeparator() {
|
||||||
|
elements = append([]string{root[:len(root)-1]}, elements...)
|
||||||
|
}
|
||||||
|
n := len(elements)
|
||||||
|
buffer.WriteString(elements[0])
|
||||||
|
if n > 1 {
|
||||||
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, elements[1]))
|
||||||
|
}
|
||||||
|
for i := 2; i < n; i++ {
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
|
||||||
}
|
}
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
|
@ -218,7 +228,7 @@ func (pt *Path) getAgnosterLeftPath() string {
|
||||||
func (pt *Path) getRelevantLetter(folder string) string {
|
func (pt *Path) getRelevantLetter(folder string) string {
|
||||||
// check if there is at least a letter we can use
|
// check if there is at least a letter we can use
|
||||||
matches := regex.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 || len(matches["letter"]) == 0 {
|
||||||
// no letter found, keep the folder unchanged
|
// no letter found, keep the folder unchanged
|
||||||
return folder
|
return folder
|
||||||
}
|
}
|
||||||
|
@ -228,36 +238,36 @@ func (pt *Path) getRelevantLetter(folder string) string {
|
||||||
return letter
|
return letter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getLetterPath() string {
|
func (pt *Path) getLetterPath(root, path string) string {
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
pwd := pt.getPwd()
|
|
||||||
splitted := strings.Split(pwd, pt.env.PathSeparator())
|
|
||||||
separator := pt.getFolderSeparator()
|
separator := pt.getFolderSeparator()
|
||||||
for i := 0; i < len(splitted)-1; i++ {
|
elements := strings.Split(path, pt.env.PathSeparator())
|
||||||
folder := splitted[i]
|
if root != pt.env.PathSeparator() {
|
||||||
if len(folder) == 0 {
|
elements = append([]string{root[:len(root)-1]}, elements...)
|
||||||
continue
|
}
|
||||||
|
n := len(elements)
|
||||||
|
for i := 0; i < n-1; i++ {
|
||||||
|
letter := pt.getRelevantLetter(elements[i])
|
||||||
|
if i != 0 {
|
||||||
|
buffer.WriteString(separator)
|
||||||
}
|
}
|
||||||
letter := pt.getRelevantLetter(folder)
|
buffer.WriteString(letter)
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", letter, separator))
|
|
||||||
}
|
|
||||||
if len(splitted) > 0 {
|
|
||||||
buffer.WriteString(splitted[len(splitted)-1])
|
|
||||||
}
|
}
|
||||||
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, elements[n-1]))
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getUniqueLettersPath() string {
|
func (pt *Path) getUniqueLettersPath(root, path string) string {
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
pwd := pt.getPwd()
|
|
||||||
splitted := strings.Split(pwd, pt.env.PathSeparator())
|
|
||||||
separator := pt.getFolderSeparator()
|
separator := pt.getFolderSeparator()
|
||||||
letters := make(map[string]bool, len(splitted))
|
elements := strings.Split(path, pt.env.PathSeparator())
|
||||||
for i := 0; i < len(splitted)-1; i++ {
|
if root != pt.env.PathSeparator() {
|
||||||
folder := splitted[i]
|
elements = append([]string{root[:len(root)-1]}, elements...)
|
||||||
if len(folder) == 0 {
|
}
|
||||||
continue
|
n := len(elements)
|
||||||
}
|
letters := make(map[string]bool)
|
||||||
|
for i := 0; i < n-1; i++ {
|
||||||
|
folder := elements[i]
|
||||||
letter := pt.getRelevantLetter(folder)
|
letter := pt.getRelevantLetter(folder)
|
||||||
for letters[letter] {
|
for letters[letter] {
|
||||||
if letter == folder {
|
if letter == folder {
|
||||||
|
@ -266,102 +276,126 @@ func (pt *Path) getUniqueLettersPath() string {
|
||||||
letter += folder[len(letter) : len(letter)+1]
|
letter += folder[len(letter) : len(letter)+1]
|
||||||
}
|
}
|
||||||
letters[letter] = true
|
letters[letter] = true
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", letter, separator))
|
if i != 0 {
|
||||||
}
|
buffer.WriteString(separator)
|
||||||
if len(splitted) > 0 {
|
}
|
||||||
buffer.WriteString(splitted[len(splitted)-1])
|
buffer.WriteString(letter)
|
||||||
}
|
}
|
||||||
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, elements[n-1]))
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterFullPath() string {
|
func (pt *Path) getAgnosterFullPath(root, path string) string {
|
||||||
pwd := pt.getPwd()
|
path = pt.replaceFolderSeparators(path)
|
||||||
for len(pwd) > 1 && string(pwd[0]) == pt.env.PathSeparator() {
|
if root == pt.env.PathSeparator() {
|
||||||
pwd = pwd[1:]
|
return path
|
||||||
}
|
}
|
||||||
return pt.replaceFolderSeparators(pwd)
|
root = root[:len(root)-1] + pt.getFolderSeparator()
|
||||||
|
return root + path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterShortPath() string {
|
func (pt *Path) getAgnosterShortPath(root, path string) string {
|
||||||
pwd := pt.getPwd()
|
elements := strings.Split(path, pt.env.PathSeparator())
|
||||||
pathDepth := pt.pathDepth(pwd)
|
if root != pt.env.PathSeparator() {
|
||||||
|
elements = append([]string{root[:len(root)-1]}, elements...)
|
||||||
|
}
|
||||||
|
depth := len(elements)
|
||||||
maxDepth := pt.props.GetInt(MaxDepth, 1)
|
maxDepth := pt.props.GetInt(MaxDepth, 1)
|
||||||
if maxDepth < 1 {
|
if maxDepth < 1 {
|
||||||
maxDepth = 1
|
maxDepth = 1
|
||||||
}
|
}
|
||||||
hideRootLocation := pt.props.GetBool(HideRootLocation, false)
|
hideRootLocation := pt.props.GetBool(HideRootLocation, false)
|
||||||
if hideRootLocation {
|
if !hideRootLocation {
|
||||||
// 1-indexing to avoid showing the root location when exceeding the max depth
|
maxDepth++
|
||||||
pathDepth++
|
|
||||||
}
|
}
|
||||||
if pathDepth <= maxDepth {
|
if depth <= maxDepth {
|
||||||
return pt.getAgnosterFullPath()
|
return pt.getAgnosterFullPath(root, path)
|
||||||
}
|
}
|
||||||
folderSeparator := pt.getFolderSeparator()
|
separator := pt.getFolderSeparator()
|
||||||
pathSeparator := pt.env.PathSeparator()
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
splitted := strings.Split(pwd, pathSeparator)
|
|
||||||
fullPathDepth := len(splitted)
|
|
||||||
splitPos := fullPathDepth - maxDepth
|
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
if hideRootLocation {
|
if !hideRootLocation {
|
||||||
buffer.WriteString(splitted[splitPos])
|
buffer.WriteString(fmt.Sprintf("%s%s", elements[0], separator))
|
||||||
splitPos++
|
maxDepth--
|
||||||
} else {
|
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
|
||||||
root := pt.rootLocation()
|
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s%s", root, folderSeparator, folderIcon))
|
|
||||||
}
|
}
|
||||||
for i := splitPos; i < fullPathDepth; i++ {
|
splitPos := depth - maxDepth
|
||||||
buffer.WriteString(fmt.Sprintf("%s%s", folderSeparator, splitted[i]))
|
if splitPos != 1 {
|
||||||
|
buffer.WriteString(fmt.Sprintf("%s%s", folderIcon, separator))
|
||||||
|
}
|
||||||
|
for i := splitPos; i < depth; i++ {
|
||||||
|
buffer.WriteString(elements[i])
|
||||||
|
if i != depth-1 {
|
||||||
|
buffer.WriteString(separator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getFullPath() string {
|
func (pt *Path) getFullPath(root, path string) string {
|
||||||
pwd := pt.getPwd()
|
if root != pt.env.PathSeparator() {
|
||||||
return pt.replaceFolderSeparators(pwd)
|
root = root[:len(root)-1] + pt.getFolderSeparator()
|
||||||
|
}
|
||||||
|
path = pt.replaceFolderSeparators(path)
|
||||||
|
return root + path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getFolderPath() string {
|
func (pt *Path) getFolderPath(path string) string {
|
||||||
pwd := pt.getPwd()
|
return environment.Base(pt.env, path)
|
||||||
pwd = environment.Base(pt.env, pwd)
|
}
|
||||||
return pt.replaceFolderSeparators(pwd)
|
|
||||||
|
func (pt *Path) setPwd() {
|
||||||
|
if len(pt.pwd) > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if pt.env.Shell() == shell.PWSH || pt.env.Shell() == shell.PWSH5 {
|
||||||
|
pt.pwd = pt.env.Flags().PSWD
|
||||||
|
}
|
||||||
|
if len(pt.pwd) == 0 {
|
||||||
|
pt.pwd = pt.env.Pwd()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ensure a clean path
|
||||||
|
root, path := environment.ParsePath(pt.env, pt.pwd)
|
||||||
|
pt.pwd = root + path
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getPwd() string {
|
func (pt *Path) getPwd() string {
|
||||||
pwd := pt.env.Flags().PSWD
|
pt.setPwd()
|
||||||
if pwd == "" {
|
return pt.replaceMappedLocations(pt.pwd)
|
||||||
pwd = pt.env.Pwd()
|
}
|
||||||
|
|
||||||
|
func (pt *Path) formatRoot(root string) string {
|
||||||
|
n := len(root)
|
||||||
|
// trim the trailing separator first
|
||||||
|
root = root[:n-1]
|
||||||
|
// only preserve the trailing separator for a Unix/Windows/PSDrive root
|
||||||
|
if len(root) == 0 || (strings.HasPrefix(pt.pwd, root) && strings.HasSuffix(root, ":")) {
|
||||||
|
return root + pt.env.PathSeparator()
|
||||||
}
|
}
|
||||||
pwd = pt.replaceMappedLocations(pwd)
|
return root
|
||||||
return pwd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) normalize(inputPath string) string {
|
func (pt *Path) normalize(inputPath string) string {
|
||||||
normalized := inputPath
|
normalized := inputPath
|
||||||
if strings.HasPrefix(inputPath, "~") {
|
if strings.HasPrefix(normalized, "~") && (len(normalized) == 1 || environment.IsPathSeparator(pt.env, normalized[1])) {
|
||||||
normalized = pt.env.Home() + normalized[1:]
|
normalized = pt.env.Home() + normalized[1:]
|
||||||
}
|
}
|
||||||
normalized = strings.ReplaceAll(normalized, "\\", "/")
|
switch pt.env.GOOS() {
|
||||||
goos := pt.env.GOOS()
|
case environment.WINDOWS:
|
||||||
if goos == environment.WINDOWS || goos == environment.DARWIN {
|
normalized = strings.ReplaceAll(normalized, "/", `\`)
|
||||||
|
fallthrough
|
||||||
|
case environment.DARWIN:
|
||||||
normalized = strings.ToLower(normalized)
|
normalized = strings.ToLower(normalized)
|
||||||
}
|
}
|
||||||
if !strings.HasSuffix(normalized, "/") {
|
|
||||||
normalized += "/"
|
|
||||||
}
|
|
||||||
return normalized
|
return normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) replaceMappedLocations(pwd string) string {
|
func (pt *Path) replaceMappedLocations(pwd string) string {
|
||||||
if strings.HasPrefix(pwd, "Microsoft.PowerShell.Core\\FileSystem::") {
|
|
||||||
pwd = strings.Replace(pwd, "Microsoft.PowerShell.Core\\FileSystem::", "", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
mappedLocations := map[string]string{}
|
mappedLocations := map[string]string{}
|
||||||
|
// predefined mapped locations, can be disabled
|
||||||
if pt.props.GetBool(MappedLocationsEnabled, true) {
|
if pt.props.GetBool(MappedLocationsEnabled, true) {
|
||||||
mappedLocations[pt.normalize("hkcu:")] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
|
mappedLocations["hkcu:"] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
|
||||||
mappedLocations[pt.normalize("hklm:")] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
|
mappedLocations["hklm:"] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
|
||||||
mappedLocations[pt.normalize(pt.env.Home())] = pt.props.GetString(HomeIcon, "~")
|
mappedLocations[pt.normalize(pt.env.Home())] = pt.props.GetString(HomeIcon, "~")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,37 +403,48 @@ func (pt *Path) replaceMappedLocations(pwd string) string {
|
||||||
// mapped locations can override predefined locations
|
// mapped locations can override predefined locations
|
||||||
keyValues := pt.props.GetKeyValueMap(MappedLocations, make(map[string]string))
|
keyValues := pt.props.GetKeyValueMap(MappedLocations, make(map[string]string))
|
||||||
for key, val := range keyValues {
|
for key, val := range keyValues {
|
||||||
mappedLocations[pt.normalize(key)] = val
|
if key != "" {
|
||||||
|
mappedLocations[pt.normalize(key)] = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort map keys in reverse order
|
// sort map keys in reverse order
|
||||||
// fixes case when a subfoder and its parent are mapped
|
// fixes case when a subfoder and its parent are mapped
|
||||||
// ex /users/test and /users/test/dev
|
// ex /users/test and /users/test/dev
|
||||||
keys := make([]string, len(mappedLocations))
|
keys := make([]string, 0, len(mappedLocations))
|
||||||
i := 0
|
|
||||||
for k := range mappedLocations {
|
for k := range mappedLocations {
|
||||||
keys[i] = k
|
keys = append(keys, k)
|
||||||
i++
|
|
||||||
}
|
}
|
||||||
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
|
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
|
||||||
|
|
||||||
normalizedPwd := pt.normalize(pwd)
|
cleanPwdRoot, cleanPwdPath := environment.ParsePath(pt.env, pwd)
|
||||||
|
pwdRoot := pt.normalize(cleanPwdRoot)
|
||||||
|
pwdPath := pt.normalize(cleanPwdPath)
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if strings.HasPrefix(normalizedPwd, key) {
|
keyRoot, keyPath := environment.ParsePath(pt.env, key)
|
||||||
replacement := mappedLocations[key]
|
if keyRoot != pwdRoot || !strings.HasPrefix(pwdPath, keyPath) {
|
||||||
// -1 as we want to ignore the trailing slash
|
continue
|
||||||
// set by the normalize function
|
}
|
||||||
return replacement + pwd[len(key)-1:]
|
value := mappedLocations[key]
|
||||||
|
rem := cleanPwdPath[len(keyPath):]
|
||||||
|
if len(rem) == 0 {
|
||||||
|
// exactly match the full path
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if len(keyPath) == 0 {
|
||||||
|
// only match the root
|
||||||
|
return value + pt.env.PathSeparator() + cleanPwdPath
|
||||||
|
}
|
||||||
|
// match several prefix elements
|
||||||
|
if rem[0:1] == pt.env.PathSeparator() {
|
||||||
|
return value + rem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pwd
|
return cleanPwdRoot + cleanPwdPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) replaceFolderSeparators(pwd string) string {
|
func (pt *Path) replaceFolderSeparators(pwd string) string {
|
||||||
defaultSeparator := pt.env.PathSeparator()
|
defaultSeparator := pt.env.PathSeparator()
|
||||||
if pwd == defaultSeparator {
|
|
||||||
return pwd
|
|
||||||
}
|
|
||||||
folderSeparator := pt.getFolderSeparator()
|
folderSeparator := pt.getFolderSeparator()
|
||||||
if folderSeparator == defaultSeparator {
|
if folderSeparator == defaultSeparator {
|
||||||
return pwd
|
return pwd
|
||||||
|
@ -408,22 +453,3 @@ func (pt *Path) replaceFolderSeparators(pwd string) string {
|
||||||
pwd = strings.ReplaceAll(pwd, defaultSeparator, folderSeparator)
|
pwd = strings.ReplaceAll(pwd, defaultSeparator, folderSeparator)
|
||||||
return pwd
|
return pwd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) rootLocation() string {
|
|
||||||
pwd := pt.getPwd()
|
|
||||||
pwd = strings.TrimPrefix(pwd, pt.env.PathSeparator())
|
|
||||||
splitted := strings.Split(pwd, pt.env.PathSeparator())
|
|
||||||
rootLocation := splitted[0]
|
|
||||||
return rootLocation
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pt *Path) pathDepth(pwd string) int {
|
|
||||||
splitted := strings.Split(pwd, pt.env.PathSeparator())
|
|
||||||
depth := 0
|
|
||||||
for _, part := range splitted {
|
|
||||||
if part != "" {
|
|
||||||
depth++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return depth - 1
|
|
||||||
}
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -100,22 +100,22 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
|
||||||
|
|
||||||
function Set-PoshContext {}
|
function Set-PoshContext {}
|
||||||
|
|
||||||
function Get-PoshContext {
|
function Get-CleanPSWD {
|
||||||
$cleanPWD = $PWD.ProviderPath
|
$pswd = $PWD.ToString()
|
||||||
$cleanPSWD = $PWD.ToString()
|
if ($pswd -ne '/') {
|
||||||
$cleanPWD = $cleanPWD.TrimEnd('\')
|
return $pswd.TrimEnd('\') -replace '^Microsoft\.PowerShell\.Core\\FileSystem::', ''
|
||||||
$cleanPSWD = $cleanPSWD.TrimEnd('\')
|
}
|
||||||
return $cleanPWD, $cleanPSWD
|
return $pswd
|
||||||
}
|
}
|
||||||
|
|
||||||
if (("::TOOLTIPS::" -eq "true") -and ($ExecutionContext.SessionState.LanguageMode -ne "ConstrainedLanguage")) {
|
if (("::TOOLTIPS::" -eq "true") -and ($ExecutionContext.SessionState.LanguageMode -ne "ConstrainedLanguage")) {
|
||||||
Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock {
|
Set-PSReadLineKeyHandler -Key Spacebar -BriefDescription 'OhMyPoshSpaceKeyHandler' -ScriptBlock {
|
||||||
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')
|
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(' ')
|
||||||
$position = $host.UI.RawUI.CursorPosition
|
$position = $host.UI.RawUI.CursorPosition
|
||||||
$cleanPWD, $cleanPSWD = Get-PoshContext
|
$cleanPSWD = Get-CleanPSWD
|
||||||
$command = $null
|
$command = $null
|
||||||
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
|
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$command, [ref]$null)
|
||||||
$standardOut = @(Start-Utf8Process $script:OMPExecutable @("print", "tooltip", "--error=$script:ErrorCode", "--pwd=$cleanPWD", "--shell=$script:ShellName", "--pswd=$cleanPSWD", "--config=$env:POSH_THEME", "--command=$command", "--shell-version=$script:PSVersion"))
|
$standardOut = @(Start-Utf8Process $script:OMPExecutable @("print", "tooltip", "--error=$script:ErrorCode", "--shell=$script:ShellName", "--pswd=$cleanPSWD", "--config=$env:POSH_THEME", "--command=$command", "--shell-version=$script:PSVersion"))
|
||||||
Write-Host $standardOut -NoNewline
|
Write-Host $standardOut -NoNewline
|
||||||
$host.UI.RawUI.CursorPosition = $position
|
$host.UI.RawUI.CursorPosition = $position
|
||||||
# we need this workaround to prevent the text after cursor from disappearing when the tooltip is rendered
|
# we need this workaround to prevent the text after cursor from disappearing when the tooltip is rendered
|
||||||
|
@ -259,9 +259,10 @@ New-Module -Name "oh-my-posh-core" -ScriptBlock {
|
||||||
if ($List -eq $true) {
|
if ($List -eq $true) {
|
||||||
$themes | Select-Object @{ Name = 'hyperlink'; Expression = { Get-FileHyperlink -uri $_.FullName } } | Format-Table -HideTableHeaders
|
$themes | Select-Object @{ Name = 'hyperlink'; Expression = { Get-FileHyperlink -uri $_.FullName } } | Format-Table -HideTableHeaders
|
||||||
} else {
|
} else {
|
||||||
|
$cleanPSWD = Get-CleanPSWD
|
||||||
$themes | ForEach-Object -Process {
|
$themes | ForEach-Object -Process {
|
||||||
Write-Host "Theme: $(Get-FileHyperlink -uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n"
|
Write-Host "Theme: $(Get-FileHyperlink -uri $_.FullName -Name ($_.BaseName -replace '\.omp$', ''))`n"
|
||||||
@(Start-Utf8Process $script:OMPExecutable @("print", "primary", "--config=$($_.FullName)", "--pwd=$PWD", "--shell=$script:ShellName"))
|
@(Start-Utf8Process $script:OMPExecutable @("print", "primary", "--config=$($_.FullName)", "--pswd=$cleanPSWD", "--shell=$script:ShellName"))
|
||||||
Write-Host "`n"
|
Write-Host "`n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,7 +332,7 @@ Example:
|
||||||
if ($script:PromptType -ne 'transient') {
|
if ($script:PromptType -ne 'transient') {
|
||||||
Update-PoshErrorCode
|
Update-PoshErrorCode
|
||||||
}
|
}
|
||||||
$cleanPWD, $cleanPSWD = Get-PoshContext
|
$cleanPSWD = Get-CleanPSWD
|
||||||
$stackCount = global:Get-PoshStackCount
|
$stackCount = global:Get-PoshStackCount
|
||||||
Set-PoshContext
|
Set-PoshContext
|
||||||
$terminalWidth = $Host.UI.RawUI.WindowSize.Width
|
$terminalWidth = $Host.UI.RawUI.WindowSize.Width
|
||||||
|
@ -339,7 +340,7 @@ Example:
|
||||||
if (-not $terminalWidth) {
|
if (-not $terminalWidth) {
|
||||||
$terminalWidth = 0
|
$terminalWidth = 0
|
||||||
}
|
}
|
||||||
$standardOut = @(Start-Utf8Process $script:OMPExecutable @("print", $script:PromptType, "--error=$script:ErrorCode", "--pwd=$cleanPWD", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--shell-version=$script:PSVersion", "--terminal-width=$terminalWidth", "--shell=$script:ShellName"))
|
$standardOut = @(Start-Utf8Process $script:OMPExecutable @("print", $script:PromptType, "--error=$script:ErrorCode", "--pswd=$cleanPSWD", "--execution-time=$script:ExecutionTime", "--stack-count=$stackCount", "--config=$env:POSH_THEME", "--shell-version=$script:PSVersion", "--terminal-width=$terminalWidth", "--shell=$script:ShellName"))
|
||||||
# make sure PSReadLine knows if we have a multiline prompt
|
# make sure PSReadLine knows if we have a multiline prompt
|
||||||
Set-PSReadLineOption -ExtraPromptLineCount (($standardOut | Measure-Object -Line).Lines - 1)
|
Set-PSReadLineOption -ExtraPromptLineCount (($standardOut | Measure-Object -Line).Lines - 1)
|
||||||
# the output can be multiline, joining these ensures proper rendering by adding line breaks with `n
|
# the output can be multiline, joining these ensures proper rendering by adding line breaks with `n
|
||||||
|
|
|
@ -42,9 +42,9 @@ Display the current path.
|
||||||
|
|
||||||
## Mapped Locations
|
## Mapped Locations
|
||||||
|
|
||||||
Allows you to override a location with an icon. It validates if the current path **starts with** the value and replaces
|
Allows you to override a location with an icon/string.
|
||||||
it with the icon if there's a match. To avoid issues with nested overrides, Oh My Posh will sort the list of mapped
|
It validates if the current path **starts with the specific elements** and replaces it with the icon/string if there's a match.
|
||||||
locations before doing a replacement.
|
To avoid issues with nested overrides, Oh My Posh will sort the list of mapped locations before doing a replacement.
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| -------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
|
| -------------------------- | --------- | -------------------------------------------------------------------------------------------------------- |
|
||||||
|
@ -63,8 +63,8 @@ For example, to swap out `C:\Users\Leet\GitHub` with a GitHub icon, you can do t
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- Oh My Posh will accept both `/` and `\` as path separators for a mapped location and will match regardless of which
|
- To make mapped Locations work cross-platform, you should use `/` as the path separator, Oh My Posh will
|
||||||
is used by the current operating system.
|
automatically match effective separators based on the running operating system.
|
||||||
- The character `~` at the start of a mapped location will match the user's home directory.
|
- The character `~` at the start of a mapped location will match the user's home directory.
|
||||||
- The match is case-insensitive on Windows and macOS, but case-sensitive on other operating systems.
|
- The match is case-insensitive on Windows and macOS, but case-sensitive on other operating systems.
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ Style sets the way the path is displayed. Based on previous experience and popul
|
||||||
|
|
||||||
### Agnoster
|
### Agnoster
|
||||||
|
|
||||||
Renders each folder as the `folder_icon` separated by the `folder_separator_icon`.
|
Renders each intermediate folder as the `folder_icon` separated by the `folder_separator_icon`.
|
||||||
Only the current folder name is displayed at the end.
|
The first and the last (current) folder name are always displayed as-is.
|
||||||
|
|
||||||
### Agnoster Full
|
### Agnoster Full
|
||||||
|
|
||||||
|
@ -96,17 +96,18 @@ Renders each folder name separated by the `folder_separator_icon`.
|
||||||
|
|
||||||
### Agnoster Short
|
### Agnoster Short
|
||||||
|
|
||||||
When more than `max_depth` levels deep, it renders one `folder_icon` (if `hide_root_location` is `false`) followed by
|
When more than `max_depth` levels deep, it renders one `folder_icon` (if `hide_root_location` is `false`,
|
||||||
the names of the last `max_depth` folders, separated by the `folder_separator_icon`.
|
which means the root folder does not count for depth) followed by the names of the last `max_depth` folders,
|
||||||
|
separated by the `folder_separator_icon`.
|
||||||
|
|
||||||
### Agnoster Left
|
### Agnoster Left
|
||||||
|
|
||||||
Renders each folder as the `folder_icon` separated by the `folder_separator_icon`.
|
Renders each folder as the `folder_icon` separated by the `folder_separator_icon`.
|
||||||
Only the root folder name and it's child are displayed in full.
|
Only the first folder name and its child are displayed in full.
|
||||||
|
|
||||||
### Full
|
### Full
|
||||||
|
|
||||||
Display `$PWD` as a string.
|
Display the current working directory as a full string with each folder separated by the `folder_separator_icon`.
|
||||||
|
|
||||||
### Folder
|
### Folder
|
||||||
|
|
||||||
|
@ -114,13 +115,13 @@ Display the name of the current folder.
|
||||||
|
|
||||||
### Mixed
|
### Mixed
|
||||||
|
|
||||||
Works like `Agnoster Full`, but for any middle folder short enough it will display its name instead. The maximum length
|
Works like `Agnoster`, but for any intermediate folder name that is short enough, it will be displayed as-is.
|
||||||
for the folders to display is governed by the `mixed_threshold` property.
|
The maximum length for the folders to display is governed by the `mixed_threshold` property.
|
||||||
|
|
||||||
### Letter
|
### Letter
|
||||||
|
|
||||||
Works like `Full`, but will write every subfolder name using the first letter only, except when the folder name
|
Works like `Agnoster Full`, but will write every folder name using the first letter only, except when the folder name
|
||||||
starts with a symbol or icon.
|
starts with a symbol or icon. Specially, the last (current) folder name is always displayed in full.
|
||||||
|
|
||||||
- `folder` will be shortened to `f`
|
- `folder` will be shortened to `f`
|
||||||
- `.config` will be shortened to `.c`
|
- `.config` will be shortened to `.c`
|
||||||
|
@ -132,9 +133,9 @@ starts with a symbol or icon.
|
||||||
Works like `Letter`, but will make sure every folder name is the shortest unique value.
|
Works like `Letter`, but will make sure every folder name is the shortest unique value.
|
||||||
|
|
||||||
The uniqueness refers to the displayed path, so `C:\dev\dev\dev\development` will be displayed as
|
The uniqueness refers to the displayed path, so `C:\dev\dev\dev\development` will be displayed as
|
||||||
`C:\d\de\dev\development` (instead of `C:\d\d\d\development` for `Letter`). Uniqueness does _not_ refer to other
|
`C\d\de\dev\development` (instead of `C\d\d\d\development` for `Letter`). Uniqueness does **not** refer to other
|
||||||
folders at the same level, so if `C:\projectA\dev` and `C:\projectB\dev` exist, then both will be displayed as
|
folders at the same level, so if `C:\projectA\dev` and `C:\projectB\dev` exist, then both will be displayed as
|
||||||
`C:\p\dev`.
|
`C\p\dev`.
|
||||||
|
|
||||||
## Template ([info][templates])
|
## Template ([info][templates])
|
||||||
|
|
||||||
|
@ -148,12 +149,12 @@ folders at the same level, so if `C:\projectA\dev` and `C:\projectB\dev` exist,
|
||||||
|
|
||||||
### Properties
|
### Properties
|
||||||
|
|
||||||
| Name | Type | Description |
|
| Name | Type | Description |
|
||||||
| ------------- | --------- | ---------------------------------------------------------------------------- |
|
| ------------- | --------- | ---------------------------------------------------------------------------- |
|
||||||
| `.Path` | `string` | the current directory (based on the `style` property) |
|
| `.Path` | `string` | the current directory (based on the `style` property) |
|
||||||
| `.Parent` | `string` | the current directory's parent folder (designed for use with style `folder`) |
|
| `.Parent` | `string` | the current directory's parent folder which ends with a path separator (designed for use with style `folder`, it is empty if `.Path` contains only one single element) |
|
||||||
| `.Location` | `string` | the current directory (raw value) |
|
| `.Location` | `string` | the current directory (raw value) |
|
||||||
| `.StackCount` | `int` | the stack count |
|
| `.StackCount` | `int` | the stack count |
|
||||||
| `.Writable` | `boolean` | is the current directory writable by the user or not |
|
| `.Writable` | `boolean` | is the current directory writable by the user or not |
|
||||||
|
|
||||||
[templates]: /docs/configuration/templates
|
[templates]: /docs/configuration/templates
|
||||||
|
|
Loading…
Reference in a new issue