mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-02-02 05:41:10 -08:00
fix(path): improve path cleaning, normalization and parsing
This commit is contained in:
parent
476bfd1fff
commit
abd6676c5b
|
@ -171,7 +171,7 @@ func (e *Engine) getTitleTemplateText() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
|
func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
|
||||||
defer e.patchPowerShellBleed()
|
defer e.applyPowerShellBleedPatch()
|
||||||
|
|
||||||
// This is deprecated but we leave it in to not break configs
|
// This is deprecated but we leave it in to not break configs
|
||||||
// It is encouraged to use "newline": true on block level
|
// It is encouraged to use "newline": true on block level
|
||||||
|
@ -267,7 +267,7 @@ func (e *Engine) renderBlock(block *config.Block, cancelNewline bool) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) patchPowerShellBleed() {
|
func (e *Engine) applyPowerShellBleedPatch() {
|
||||||
// when in PowerShell, we need to clear the line after the prompt
|
// when in PowerShell, we need to clear the line after the prompt
|
||||||
// to avoid the background being printed on the next line
|
// to avoid the background being printed on the next line
|
||||||
// when at the end of the buffer.
|
// when at the end of the buffer.
|
||||||
|
@ -514,10 +514,6 @@ func New(flags *runtime.Flags) *Engine {
|
||||||
env.Init()
|
env.Init()
|
||||||
cfg := config.Load(env)
|
cfg := config.Load(env)
|
||||||
|
|
||||||
if cfg.PatchPwshBleed {
|
|
||||||
patchPowerShellBleed(env.Shell(), flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
env.Var = cfg.Var
|
env.Var = cfg.Var
|
||||||
flags.HasTransient = cfg.TransientPrompt != nil
|
flags.HasTransient = cfg.TransientPrompt != nil
|
||||||
|
|
||||||
|
@ -532,10 +528,16 @@ func New(flags *runtime.Flags) *Engine {
|
||||||
Plain: flags.Plain,
|
Plain: flags.Plain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.PatchPwshBleed {
|
||||||
|
eng.patchPowerShellBleed()
|
||||||
|
}
|
||||||
|
|
||||||
return eng
|
return eng
|
||||||
}
|
}
|
||||||
|
|
||||||
func patchPowerShellBleed(sh string, flags *runtime.Flags) {
|
func (e *Engine) patchPowerShellBleed() {
|
||||||
|
sh := e.Env.Shell()
|
||||||
|
|
||||||
// when in PowerShell, and force patching the bleed bug
|
// when in PowerShell, and force patching the bleed bug
|
||||||
// we need to reduce the terminal width by 1 so the last
|
// we need to reduce the terminal width by 1 so the last
|
||||||
// character isn't cut off by the ANSI escape sequences
|
// character isn't cut off by the ANSI escape sequences
|
||||||
|
@ -544,10 +546,12 @@ func patchPowerShellBleed(sh string, flags *runtime.Flags) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// only do this when relevant
|
// Since the terminal width may not be given by the CLI flag, we should always call this here.
|
||||||
if flags.TerminalWidth <= 0 {
|
_, err := e.Env.TerminalWidth()
|
||||||
|
if err != nil {
|
||||||
|
// Skip when we're unable to determine the terminal width.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
flags.TerminalWidth--
|
e.Env.Flags().TerminalWidth--
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,25 +173,20 @@ func (term *Terminal) Pwd() string {
|
||||||
if term.cwd != "" {
|
if term.cwd != "" {
|
||||||
return term.cwd
|
return term.cwd
|
||||||
}
|
}
|
||||||
correctPath := func(pwd string) string {
|
|
||||||
if term.GOOS() != WINDOWS {
|
|
||||||
return pwd
|
|
||||||
}
|
|
||||||
// on Windows, and being case sensitive and not consistent and all, this gives silly issues
|
|
||||||
driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
|
|
||||||
return driveLetter.ReplaceAllStringFunc(pwd, strings.ToUpper)
|
|
||||||
}
|
|
||||||
if term.CmdFlags != nil && term.CmdFlags.PWD != "" {
|
if term.CmdFlags != nil && term.CmdFlags.PWD != "" {
|
||||||
term.cwd = correctPath(term.CmdFlags.PWD)
|
term.cwd = CleanPath(term, term.CmdFlags.PWD)
|
||||||
term.Debug(term.cwd)
|
term.Debug(term.cwd)
|
||||||
return term.cwd
|
return term.cwd
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, err := os.Getwd()
|
dir, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
term.Error(err)
|
term.Error(err)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
term.cwd = correctPath(dir)
|
|
||||||
|
term.cwd = CleanPath(term, dir)
|
||||||
term.Debug(term.cwd)
|
term.Debug(term.cwd)
|
||||||
return term.cwd
|
return term.cwd
|
||||||
}
|
}
|
||||||
|
@ -321,7 +316,10 @@ func (term *Terminal) LsDir(path string) []fs.DirEntry {
|
||||||
|
|
||||||
func (term *Terminal) PathSeparator() string {
|
func (term *Terminal) PathSeparator() string {
|
||||||
defer term.Trace(time.Now())
|
defer term.Trace(time.Now())
|
||||||
return string(os.PathSeparator)
|
if term.GOOS() == WINDOWS {
|
||||||
|
return `\`
|
||||||
|
}
|
||||||
|
return "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (term *Terminal) User() string {
|
func (term *Terminal) User() string {
|
||||||
|
@ -882,6 +880,54 @@ func Base(env Environment, path string) string {
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CleanPath(env Environment, path string) string {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
cleaned := path
|
||||||
|
separator := env.PathSeparator()
|
||||||
|
|
||||||
|
// The prefix can be empty for a relative path.
|
||||||
|
var prefix string
|
||||||
|
if IsPathSeparator(env, cleaned[0]) {
|
||||||
|
prefix = separator
|
||||||
|
}
|
||||||
|
|
||||||
|
if env.GOOS() == WINDOWS {
|
||||||
|
// Normalize (forward) slashes to backslashes on Windows.
|
||||||
|
cleaned = strings.ReplaceAll(cleaned, "/", `\`)
|
||||||
|
|
||||||
|
// Clean the prefix for a UNC path, if any.
|
||||||
|
if regex.MatchString(`^\\{2}[^\\]+`, cleaned) {
|
||||||
|
cleaned = strings.TrimPrefix(cleaned, `\\.\UNC\`)
|
||||||
|
if len(cleaned) == 0 {
|
||||||
|
return cleaned
|
||||||
|
}
|
||||||
|
prefix = `\\`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always use an uppercase drive letter on Windows.
|
||||||
|
driveLetter := regex.GetCompiledRegex(`^[a-z]:`)
|
||||||
|
cleaned = driveLetter.ReplaceAllStringFunc(cleaned, strings.ToUpper)
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := new(strings.Builder)
|
||||||
|
sb.WriteString(prefix)
|
||||||
|
|
||||||
|
// Clean slashes.
|
||||||
|
matches := regex.FindAllNamedRegexMatch(fmt.Sprintf(`(?P<element>[^\%s]+)`, separator), cleaned)
|
||||||
|
n := len(matches) - 1
|
||||||
|
for i, m := range matches {
|
||||||
|
sb.WriteString(m["element"])
|
||||||
|
if i != n {
|
||||||
|
sb.WriteString(separator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
func ReplaceTildePrefixWithHomeDir(env Environment, path string) string {
|
func ReplaceTildePrefixWithHomeDir(env Environment, path string) string {
|
||||||
if !strings.HasPrefix(path, "~") {
|
if !strings.HasPrefix(path, "~") {
|
||||||
return path
|
return path
|
||||||
|
|
|
@ -13,23 +13,44 @@ import (
|
||||||
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
"github.com/jandedobbeleer/oh-my-posh/src/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Folder struct {
|
||||||
|
Name string
|
||||||
|
Display bool
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Folders []*Folder
|
||||||
|
|
||||||
|
func (f Folders) List() []string {
|
||||||
|
var list []string
|
||||||
|
|
||||||
|
for _, folder := range f {
|
||||||
|
list = append(list, folder.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
type Path struct {
|
type Path struct {
|
||||||
props properties.Properties
|
props properties.Properties
|
||||||
env runtime.Environment
|
env runtime.Environment
|
||||||
|
|
||||||
root string
|
pwd string
|
||||||
relative string
|
root string
|
||||||
pwd string
|
relative string
|
||||||
cygPath bool
|
folders Folders
|
||||||
windowsPath bool
|
// After `setPaths` is called, the above 4 fields should remain unchanged to preserve the original path info.
|
||||||
pathSeparator string
|
|
||||||
|
cygPath bool
|
||||||
|
windowsPath bool
|
||||||
|
pathSeparator string
|
||||||
|
mappedLocations map[string]string
|
||||||
|
|
||||||
Path string
|
Path string
|
||||||
StackCount int
|
StackCount int
|
||||||
Location string
|
Location string
|
||||||
Writable bool
|
Writable bool
|
||||||
RootDir bool
|
RootDir bool
|
||||||
Folders Folders
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -121,7 +142,7 @@ func (pt *Path) Enabled() bool {
|
||||||
|
|
||||||
func (pt *Path) setPaths() {
|
func (pt *Path) setPaths() {
|
||||||
defer func() {
|
defer func() {
|
||||||
pt.Folders = pt.splitPath()
|
pt.folders = pt.splitPath()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
displayCygpath := func() bool {
|
displayCygpath := func() bool {
|
||||||
|
@ -147,33 +168,33 @@ func (pt *Path) setPaths() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure a clean path
|
// ensure a clean path
|
||||||
pt.root, pt.relative = pt.replaceMappedLocations()
|
pt.root, pt.relative = pt.replaceMappedLocations(pt.pwd)
|
||||||
|
pt.pwd = pt.join(pt.root, pt.relative)
|
||||||
// this is a full replacement of the parent
|
|
||||||
if len(pt.root) == 0 {
|
|
||||||
pt.pwd = pt.relative
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasSuffix(pt.root, pt.pathSeparator) && len(pt.relative) > 0 {
|
|
||||||
pt.pwd = pt.root + pt.pathSeparator + pt.relative
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pt.pwd = pt.root + pt.relative
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) Parent() string {
|
func (pt *Path) Parent() string {
|
||||||
if len(pt.pwd) == 0 {
|
if len(pt.pwd) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if len(pt.relative) == 0 {
|
|
||||||
// a root path has no parent
|
folders := pt.folders.List()
|
||||||
|
if len(folders) == 0 {
|
||||||
|
// No parent.
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
base := runtime.Base(pt.env, pt.pwd)
|
|
||||||
path := pt.replaceFolderSeparators(pt.pwd[:len(pt.pwd)-len(base)])
|
sb := new(strings.Builder)
|
||||||
return path
|
folderSeparator := pt.getFolderSeparator()
|
||||||
|
|
||||||
|
sb.WriteString(pt.root)
|
||||||
|
if !pt.endWithSeparator(pt.root) {
|
||||||
|
sb.WriteString(folderSeparator)
|
||||||
|
}
|
||||||
|
for _, folder := range folders[:len(folders)-1] {
|
||||||
|
sb.WriteString(folder)
|
||||||
|
sb.WriteString(folderSeparator)
|
||||||
|
}
|
||||||
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) Init(props properties.Properties, env runtime.Environment) {
|
func (pt *Path) Init(props properties.Properties, env runtime.Environment) {
|
||||||
|
@ -183,12 +204,14 @@ func (pt *Path) Init(props properties.Properties, env runtime.Environment) {
|
||||||
|
|
||||||
func (pt *Path) setStyle() {
|
func (pt *Path) setStyle() {
|
||||||
if len(pt.relative) == 0 {
|
if len(pt.relative) == 0 {
|
||||||
|
root := pt.root
|
||||||
|
|
||||||
// Only append a separator to a non-filesystem PSDrive root or a Windows drive root.
|
// Only append a separator to a non-filesystem PSDrive root or a Windows drive root.
|
||||||
if (len(pt.env.Flags().PSWD) != 0 || pt.windowsPath) && strings.HasSuffix(pt.root, ":") {
|
if (len(pt.env.Flags().PSWD) != 0 || pt.windowsPath) && strings.HasSuffix(root, ":") {
|
||||||
pt.root += pt.getFolderSeparator()
|
root += pt.getFolderSeparator()
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.Path = pt.colorizePath(pt.root, nil)
|
pt.Path = pt.colorizePath(root, nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,75 +299,77 @@ func (pt *Path) getFolderSeparator() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getMixedPath() string {
|
func (pt *Path) getMixedPath() string {
|
||||||
|
root := pt.root
|
||||||
|
folders := pt.folders
|
||||||
threshold := int(pt.props.GetFloat64(MixedThreshold, 4))
|
threshold := int(pt.props.GetFloat64(MixedThreshold, 4))
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
|
|
||||||
if pt.root == pt.pathSeparator {
|
if pt.isRootFS(root) {
|
||||||
pt.root = pt.Folders[0].Name
|
root = folders[0].Name
|
||||||
pt.Folders = pt.Folders[1:]
|
folders = folders[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
var folders []string
|
var elements []string
|
||||||
|
|
||||||
for i, n := 0, len(pt.Folders); i < n; i++ {
|
for i, n := 0, len(folders); i < n; i++ {
|
||||||
folder := pt.Folders[i].Name
|
folderName := folders[i].Name
|
||||||
if len(folder) > threshold && i != n-1 && !pt.Folders[i].Display {
|
if len(folderName) > threshold && i != n-1 && !folders[i].Display {
|
||||||
folder = folderIcon
|
elements = append(elements, folderIcon)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
folders = append(folders, folder)
|
|
||||||
|
elements = append(elements, folderName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pt.colorizePath(pt.root, folders)
|
return pt.colorizePath(root, elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterPath() string {
|
func (pt *Path) getAgnosterPath() string {
|
||||||
|
root := pt.root
|
||||||
|
folders := pt.folders
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
|
|
||||||
if pt.root == pt.pathSeparator {
|
if pt.isRootFS(root) {
|
||||||
pt.root = pt.Folders[0].Name
|
root = folders[0].Name
|
||||||
pt.Folders = pt.Folders[1:]
|
folders = folders[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
var elements []string
|
var elements []string
|
||||||
n := len(pt.Folders)
|
|
||||||
for i := 0; i < n-1; i++ {
|
|
||||||
name := folderIcon
|
|
||||||
|
|
||||||
if pt.Folders[i].Display {
|
for i, n := 0, len(folders); i < n; i++ {
|
||||||
name = pt.Folders[i].Name
|
if folders[i].Display || i == n-1 {
|
||||||
}
|
elements = append(elements, folders[i].Name)
|
||||||
|
|
||||||
elements = append(elements, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(pt.Folders) > 0 {
|
|
||||||
elements = append(elements, pt.Folders[n-1].Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pt.colorizePath(pt.root, elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pt *Path) getAgnosterLeftPath() string {
|
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
|
||||||
|
|
||||||
if pt.root == pt.pathSeparator {
|
|
||||||
pt.root = pt.Folders[0].Name
|
|
||||||
pt.Folders = pt.Folders[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
var elements []string
|
|
||||||
n := len(pt.Folders)
|
|
||||||
elements = append(elements, pt.Folders[0].Name)
|
|
||||||
for i := 1; i < n; i++ {
|
|
||||||
if pt.Folders[i].Display {
|
|
||||||
elements = append(elements, pt.Folders[i].Name)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
elements = append(elements, folderIcon)
|
elements = append(elements, folderIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pt.colorizePath(pt.root, elements)
|
return pt.colorizePath(root, elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *Path) getAgnosterLeftPath() string {
|
||||||
|
root := pt.root
|
||||||
|
folders := pt.folders
|
||||||
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
|
|
||||||
|
if pt.isRootFS(root) {
|
||||||
|
root = folders[0].Name
|
||||||
|
folders = folders[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
var elements []string
|
||||||
|
elements = append(elements, folders[0].Name)
|
||||||
|
for i, n := 1, len(folders); i < n; i++ {
|
||||||
|
if folders[i].Display {
|
||||||
|
elements = append(elements, folders[i].Name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
elements = append(elements, folderIcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pt.colorizePath(root, elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getRelevantLetter(folder *Folder) string {
|
func (pt *Path) getRelevantLetter(folder *Folder) string {
|
||||||
|
@ -365,62 +390,78 @@ func (pt *Path) getRelevantLetter(folder *Folder) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getLetterPath() string {
|
func (pt *Path) getLetterPath() string {
|
||||||
if pt.root == pt.pathSeparator {
|
root := pt.root
|
||||||
pt.root = pt.Folders[0].Name
|
folders := pt.folders
|
||||||
pt.Folders = pt.Folders[1:]
|
|
||||||
|
if pt.isRootFS(root) {
|
||||||
|
root = folders[0].Name
|
||||||
|
folders = folders[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.root = pt.getRelevantLetter(&Folder{Name: pt.root})
|
root = pt.getRelevantLetter(&Folder{Name: root})
|
||||||
|
|
||||||
var elements []string
|
var elements []string
|
||||||
n := len(pt.Folders)
|
for i, n := 0, len(folders); i < n; i++ {
|
||||||
for i := 0; i < n-1; i++ {
|
if folders[i].Display || i == n-1 {
|
||||||
if pt.Folders[i].Display {
|
elements = append(elements, folders[i].Name)
|
||||||
elements = append(elements, pt.Folders[i].Name)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
letter := pt.getRelevantLetter(pt.Folders[i])
|
letter := pt.getRelevantLetter(folders[i])
|
||||||
elements = append(elements, letter)
|
elements = append(elements, letter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pt.Folders) > 0 {
|
return pt.colorizePath(root, elements)
|
||||||
elements = append(elements, pt.Folders[n-1].Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pt.colorizePath(pt.root, elements)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getUniqueLettersPath(maxWidth int) string {
|
func (pt *Path) getUniqueLettersPath(maxWidth int) string {
|
||||||
|
root := pt.root
|
||||||
|
folders := pt.folders
|
||||||
separator := pt.getFolderSeparator()
|
separator := pt.getFolderSeparator()
|
||||||
|
|
||||||
if pt.root == pt.pathSeparator {
|
if pt.isRootFS(root) {
|
||||||
pt.root = pt.Folders[0].Name
|
root = folders[0].Name
|
||||||
pt.Folders = pt.Folders[1:]
|
folders = folders[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
folderNames := folders.List()
|
||||||
|
|
||||||
|
usePowerlevelStyle := func(root, relative string) bool {
|
||||||
|
length := len(root) + len(relative)
|
||||||
|
if !pt.endWithSeparator(root) {
|
||||||
|
length += len(separator)
|
||||||
|
}
|
||||||
|
return length <= maxWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
if maxWidth > 0 {
|
if maxWidth > 0 {
|
||||||
path := strings.Join(pt.Folders.List(), separator)
|
relative := strings.Join(folderNames, separator)
|
||||||
if len(path) <= maxWidth {
|
if usePowerlevelStyle(root, relative) {
|
||||||
return pt.colorizePath(pt.root, pt.Folders.List())
|
return pt.colorizePath(root, folderNames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pt.root = pt.getRelevantLetter(&Folder{Name: pt.root})
|
root = pt.getRelevantLetter(&Folder{Name: root})
|
||||||
|
|
||||||
var elements []string
|
var elements []string
|
||||||
n := len(pt.Folders)
|
|
||||||
letters := make(map[string]bool)
|
letters := make(map[string]bool)
|
||||||
letters[pt.root] = true
|
letters[root] = true
|
||||||
for i := 0; i < n-1; i++ {
|
|
||||||
folder := pt.Folders[i].Name
|
for i, n := 0, len(folders); i < n; i++ {
|
||||||
letter := pt.getRelevantLetter(pt.Folders[i])
|
folderName := folderNames[i]
|
||||||
|
|
||||||
|
if i == n-1 {
|
||||||
|
elements = append(elements, folderName)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
letter := pt.getRelevantLetter(folders[i])
|
||||||
|
|
||||||
for letters[letter] {
|
for letters[letter] {
|
||||||
if letter == folder {
|
if letter == folderName {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
letter += folder[len(letter) : len(letter)+1]
|
letter += folderName[len(letter) : len(letter)+1]
|
||||||
}
|
}
|
||||||
|
|
||||||
letters[letter] = true
|
letters[letter] = true
|
||||||
|
@ -429,87 +470,95 @@ func (pt *Path) getUniqueLettersPath(maxWidth int) string {
|
||||||
// only return early on maxWidth > 0
|
// only return early on maxWidth > 0
|
||||||
// this enables the powerlevel10k behavior
|
// this enables the powerlevel10k behavior
|
||||||
if maxWidth > 0 {
|
if maxWidth > 0 {
|
||||||
list := pt.Folders[i+1:].List()
|
list := elements
|
||||||
list = append(list, elements...)
|
list = append(list, folderNames[i+1:]...)
|
||||||
current := strings.Join(list, separator)
|
relative := strings.Join(list, separator)
|
||||||
leftover := maxWidth - len(current) - len(pt.root) - len(separator)
|
if usePowerlevelStyle(root, relative) {
|
||||||
if leftover >= 0 {
|
return pt.colorizePath(root, list)
|
||||||
elements = append(elements, strings.Join(pt.Folders[i+1:].List(), separator))
|
|
||||||
return pt.colorizePath(pt.root, elements)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pt.Folders) > 0 {
|
return pt.colorizePath(root, elements)
|
||||||
elements = append(elements, pt.Folders[n-1].Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pt.colorizePath(pt.root, elements)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterFullPath() string {
|
func (pt *Path) getAgnosterFullPath() string {
|
||||||
if pt.root == pt.pathSeparator {
|
root := pt.root
|
||||||
pt.root = pt.Folders[0].Name
|
folders := pt.folders
|
||||||
pt.Folders = pt.Folders[1:]
|
|
||||||
|
if pt.isRootFS(root) {
|
||||||
|
root = folders[0].Name
|
||||||
|
folders = folders[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return pt.colorizePath(pt.root, pt.Folders.List())
|
return pt.colorizePath(root, folders.List())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getAgnosterShortPath() string {
|
func (pt *Path) getAgnosterShortPath() string {
|
||||||
pathDepth := len(pt.Folders)
|
root := pt.root
|
||||||
|
folders := pt.folders
|
||||||
|
|
||||||
|
if pt.isRootFS(root) {
|
||||||
|
root = folders[0].Name
|
||||||
|
folders = folders[1:]
|
||||||
|
}
|
||||||
|
|
||||||
maxDepth := pt.props.GetInt(MaxDepth, 1)
|
maxDepth := pt.props.GetInt(MaxDepth, 1)
|
||||||
if maxDepth < 1 {
|
if maxDepth < 1 {
|
||||||
maxDepth = 1
|
maxDepth = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
folderIcon := pt.props.GetString(FolderIcon, "..")
|
pathDepth := len(folders)
|
||||||
hideRootLocation := pt.props.GetBool(HideRootLocation, false)
|
hideRootLocation := pt.props.GetBool(HideRootLocation, false)
|
||||||
|
folderIcon := pt.props.GetString(FolderIcon, "..")
|
||||||
|
|
||||||
if pathDepth <= maxDepth {
|
// No need to shorten.
|
||||||
if hideRootLocation {
|
if pathDepth < maxDepth || (pathDepth == maxDepth && !hideRootLocation) {
|
||||||
pt.root = folderIcon
|
|
||||||
}
|
|
||||||
return pt.getAgnosterFullPath()
|
return pt.getAgnosterFullPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
splitPos := pathDepth - maxDepth
|
elements := []string{folderIcon}
|
||||||
|
|
||||||
var folders []string
|
for i := pathDepth - maxDepth; i < pathDepth; i++ {
|
||||||
// unix root, needs to be replaced with the folder we're in at root level
|
elements = append(elements, folders[i].Name)
|
||||||
root := pt.root
|
|
||||||
room := pathDepth - maxDepth
|
|
||||||
if root == pt.pathSeparator {
|
|
||||||
root = pt.Folders[0].Name
|
|
||||||
room--
|
|
||||||
}
|
|
||||||
|
|
||||||
if hideRootLocation || room > 0 {
|
|
||||||
folders = append(folders, folderIcon)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if hideRootLocation {
|
if hideRootLocation {
|
||||||
root = ""
|
return pt.colorizePath(elements[0], elements[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := splitPos; i < pathDepth; i++ {
|
return pt.colorizePath(root, elements)
|
||||||
folders = append(folders, pt.Folders[i].Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pt.colorizePath(root, folders)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getFullPath() string {
|
func (pt *Path) getFullPath() string {
|
||||||
return pt.colorizePath(pt.root, pt.Folders.List())
|
return pt.colorizePath(pt.root, pt.folders.List())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) getFolderPath() string {
|
func (pt *Path) getFolderPath() string {
|
||||||
return pt.colorizePath(runtime.Base(pt.env, pt.pwd), nil)
|
folderName := pt.folders[len(pt.folders)-1].Name
|
||||||
|
return pt.colorizePath(folderName, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) replaceMappedLocations() (string, string) {
|
func (pt *Path) join(root, relative string) string {
|
||||||
mappedLocations := map[string]string{}
|
// this is a full replacement of the parent
|
||||||
|
if len(root) == 0 {
|
||||||
|
return relative
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pt.endWithSeparator(root) && len(relative) > 0 {
|
||||||
|
return root + pt.pathSeparator + relative
|
||||||
|
}
|
||||||
|
|
||||||
|
return root + relative
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *Path) setMappedLocations() {
|
||||||
|
if pt.mappedLocations != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mappedLocations := make(map[string]string)
|
||||||
|
|
||||||
// predefined mapped locations, can be disabled
|
// predefined mapped locations, can be disabled
|
||||||
if pt.props.GetBool(MappedLocationsEnabled, true) {
|
if pt.props.GetBool(MappedLocationsEnabled, true) {
|
||||||
mappedLocations["hkcu:"] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
|
mappedLocations["hkcu:"] = pt.props.GetString(WindowsRegistryIcon, "\uF013")
|
||||||
|
@ -520,7 +569,7 @@ func (pt *Path) replaceMappedLocations() (string, string) {
|
||||||
// merge custom locations with mapped locations
|
// merge custom locations with mapped locations
|
||||||
// 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, value := range keyValues {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -540,89 +589,86 @@ func (pt *Path) replaceMappedLocations() (string, string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
mappedLocations[pt.normalize(path)] = val
|
// When two templates resolve to the same key, the values are compared in ascending order and the latter is taken.
|
||||||
|
if v, exist := mappedLocations[pt.normalize(path)]; exist && value <= v {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
mappedLocations[pt.normalize(path)] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.mappedLocations = mappedLocations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *Path) replaceMappedLocations(inputPath string) (string, string) {
|
||||||
|
root, relative := pt.parsePath(inputPath)
|
||||||
|
if len(relative) == 0 {
|
||||||
|
pt.RootDir = true
|
||||||
|
}
|
||||||
|
|
||||||
|
pt.setMappedLocations()
|
||||||
|
if len(pt.mappedLocations) == 0 {
|
||||||
|
return root, relative
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, 0, len(mappedLocations))
|
keys := make([]string, 0, len(pt.mappedLocations))
|
||||||
for k := range mappedLocations {
|
for k := range pt.mappedLocations {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
|
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
|
||||||
|
|
||||||
root, relative := pt.parsePath(pt.pwd)
|
|
||||||
if len(relative) == 0 {
|
|
||||||
pt.RootDir = true
|
|
||||||
}
|
|
||||||
|
|
||||||
rootN := pt.normalize(root)
|
rootN := pt.normalize(root)
|
||||||
relativeN := pt.normalize(relative)
|
relativeN := pt.normalize(relative)
|
||||||
|
|
||||||
|
escape := func(path string) string {
|
||||||
|
// Escape chevron characters to avoid applying unexpected text styles.
|
||||||
|
return strings.NewReplacer("<", "<<>", ">", "<>>").Replace(path)
|
||||||
|
}
|
||||||
|
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
keyRoot, keyRelative := pt.parsePath(key)
|
keyRoot, keyRelative := pt.parsePath(key)
|
||||||
matchSubFolders := strings.HasSuffix(keyRelative, "*")
|
matchSubFolders := strings.HasSuffix(keyRelative, pt.pathSeparator+"*")
|
||||||
|
|
||||||
if matchSubFolders && len(keyRelative) > 1 {
|
if matchSubFolders {
|
||||||
keyRelative = keyRelative[0 : len(keyRelative)-1] // remove trailing /* or \*
|
// Remove the trailing wildcard (*).
|
||||||
|
keyRelative = keyRelative[:len(keyRelative)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyRoot != rootN || !strings.HasPrefix(relativeN, keyRelative) {
|
if keyRoot != rootN || !strings.HasPrefix(relativeN, keyRelative) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
value := mappedLocations[key]
|
value := pt.mappedLocations[key]
|
||||||
overflow := relative[len(keyRelative):]
|
overflow := relative[len(keyRelative):]
|
||||||
|
|
||||||
|
// exactly match the full path
|
||||||
if len(overflow) == 0 {
|
if len(overflow) == 0 {
|
||||||
// exactly match the full path
|
|
||||||
return value, ""
|
return value, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only match the root
|
||||||
if len(keyRelative) == 0 {
|
if len(keyRelative) == 0 {
|
||||||
// only match the root
|
return value, strings.Trim(escape(relative), pt.pathSeparator)
|
||||||
return value, strings.Trim(relative, pt.pathSeparator)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// match several prefix elements
|
// match several prefix elements
|
||||||
if matchSubFolders || overflow[0:1] == pt.pathSeparator {
|
if matchSubFolders || overflow[:1] == pt.pathSeparator {
|
||||||
return value, strings.Trim(overflow, pt.pathSeparator)
|
return value, strings.Trim(escape(overflow), pt.pathSeparator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return root, strings.Trim(relative, pt.pathSeparator)
|
return escape(root), strings.Trim(escape(relative), pt.pathSeparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) normalizePath(path string) string {
|
// parsePath parses a clean input path into a root and a relative.
|
||||||
if pt.env.GOOS() != runtime.WINDOWS || pt.cygPath {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
var clean []rune
|
|
||||||
for _, char := range path {
|
|
||||||
var lastChar rune
|
|
||||||
if len(clean) > 0 {
|
|
||||||
lastChar = clean[len(clean)-1:][0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if char == '/' && lastChar != 60 { // 60 == <, this is done to avoid replacing color codes
|
|
||||||
clean = append(clean, 92) // 92 == \
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
clean = append(clean, char)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(clean)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParsePath parses an input path and returns a clean root and a clean path.
|
|
||||||
func (pt *Path) parsePath(inputPath string) (string, string) {
|
func (pt *Path) parsePath(inputPath string) (string, string) {
|
||||||
var root, path string
|
var root, relative string
|
||||||
|
|
||||||
if len(inputPath) == 0 {
|
if len(inputPath) == 0 {
|
||||||
return root, path
|
return root, relative
|
||||||
}
|
}
|
||||||
|
|
||||||
if pt.cygPath {
|
if pt.cygPath {
|
||||||
|
@ -638,76 +684,58 @@ func (pt *Path) parsePath(inputPath string) (string, string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clean := func(path string) string {
|
if pt.env.GOOS() == runtime.WINDOWS {
|
||||||
matches := regex.FindAllNamedRegexMatch(fmt.Sprintf(`(?P<element>[^\%s]+)`, pt.pathSeparator), path)
|
// Handle a UNC path, if any.
|
||||||
n := len(matches) - 1
|
pattern := fmt.Sprintf(`^\%[1]s{2}(?P<hostname>[^\%[1]s]+)\%[1]s(?P<sharename>[^\%[1]s]+)(\%[1]s(?P<path>[\s\S]*))?$`, pt.pathSeparator)
|
||||||
s := new(strings.Builder)
|
matches := regex.FindNamedRegexMatch(pattern, inputPath)
|
||||||
for i, m := range matches {
|
|
||||||
s.WriteString(m["element"])
|
|
||||||
if i != n {
|
|
||||||
s.WriteString(pt.pathSeparator)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if pt.windowsPath {
|
|
||||||
inputPath = pt.normalizePath(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 {
|
if len(matches) > 0 {
|
||||||
root = `\\` + matches["hostname"] + `\` + matches["sharename"]
|
root = fmt.Sprintf(`%[1]s%[1]s%[2]s%[1]s%[3]s`, pt.pathSeparator, matches["hostname"], matches["sharename"])
|
||||||
path = clean(matches["path"])
|
relative = matches["path"]
|
||||||
return root, path
|
return root, relative
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strings.SplitAfterN(inputPath, pt.pathSeparator, 2)
|
s := strings.SplitAfterN(inputPath, pt.pathSeparator, 2)
|
||||||
root = s[0]
|
root = s[0]
|
||||||
|
|
||||||
if pt.windowsPath {
|
|
||||||
root = strings.TrimSuffix(root, pt.pathSeparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(s) == 2 {
|
if len(s) == 2 {
|
||||||
path = clean(s[1])
|
if len(root) > 1 {
|
||||||
|
root = root[:len(root)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
relative = s[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
return root, path
|
return root, relative
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *Path) isRootFS(path string) bool {
|
||||||
|
return len(path) == 1 && runtime.IsPathSeparator(pt.env, path[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pt *Path) endWithSeparator(path string) bool {
|
||||||
|
if len(path) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return runtime.IsPathSeparator(pt.env, path[len(path)-1])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) normalize(inputPath string) string {
|
func (pt *Path) normalize(inputPath string) string {
|
||||||
normalized := inputPath
|
normalized := inputPath
|
||||||
|
|
||||||
if strings.HasPrefix(normalized, "~") && (len(normalized) == 1 || runtime.IsPathSeparator(pt.env, normalized[1])) {
|
if strings.HasPrefix(normalized, "~") && (len(normalized) == 1 || runtime.IsPathSeparator(pt.env, normalized[1])) {
|
||||||
normalized = pt.env.Home() + normalized[1:]
|
normalized = pt.env.Home() + normalized[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if pt.cygPath {
|
normalized = runtime.CleanPath(pt.env, normalized)
|
||||||
return normalized
|
|
||||||
}
|
|
||||||
|
|
||||||
switch pt.env.GOOS() {
|
if pt.env.GOOS() == runtime.WINDOWS || pt.env.GOOS() == runtime.DARWIN {
|
||||||
case runtime.WINDOWS:
|
|
||||||
normalized = pt.normalizePath(normalized)
|
|
||||||
fallthrough
|
|
||||||
case runtime.DARWIN:
|
|
||||||
normalized = strings.ToLower(normalized)
|
normalized = strings.ToLower(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalized
|
return normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) replaceFolderSeparators(pwd string) string {
|
|
||||||
defaultSeparator := pt.pathSeparator
|
|
||||||
folderSeparator := pt.getFolderSeparator()
|
|
||||||
if folderSeparator == defaultSeparator {
|
|
||||||
return pwd
|
|
||||||
}
|
|
||||||
|
|
||||||
pwd = strings.ReplaceAll(pwd, defaultSeparator, folderSeparator)
|
|
||||||
return pwd
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pt *Path) colorizePath(root string, elements []string) string {
|
func (pt *Path) colorizePath(root string, elements []string) string {
|
||||||
cycle := pt.props.GetStringArray(Cycle, []string{})
|
cycle := pt.props.GetStringArray(Cycle, []string{})
|
||||||
skipColorize := len(cycle) == 0
|
skipColorize := len(cycle) == 0
|
||||||
|
@ -730,8 +758,8 @@ func (pt *Path) colorizePath(root string, elements []string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(elements) == 0 {
|
if len(elements) == 0 {
|
||||||
root = fmt.Sprintf(leftFormat, root)
|
formattedRoot := fmt.Sprintf(leftFormat, root)
|
||||||
return colorizeElement(root)
|
return colorizeElement(formattedRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
colorizeSeparator := func() string {
|
colorizeSeparator := func() string {
|
||||||
|
@ -741,13 +769,13 @@ func (pt *Path) colorizePath(root string, elements []string) string {
|
||||||
return fmt.Sprintf("<%s>%s</>", cycle[0], folderSeparator)
|
return fmt.Sprintf("<%s>%s</>", cycle[0], folderSeparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
var builder strings.Builder
|
sb := new(strings.Builder)
|
||||||
|
|
||||||
formattedRoot := fmt.Sprintf(leftFormat, root)
|
formattedRoot := fmt.Sprintf(leftFormat, root)
|
||||||
builder.WriteString(colorizeElement(formattedRoot))
|
sb.WriteString(colorizeElement(formattedRoot))
|
||||||
|
|
||||||
if root != pt.pathSeparator && len(root) != 0 {
|
if !pt.endWithSeparator(root) {
|
||||||
builder.WriteString(colorizeSeparator())
|
sb.WriteString(colorizeSeparator())
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, element := range elements {
|
for i, element := range elements {
|
||||||
|
@ -760,76 +788,49 @@ func (pt *Path) colorizePath(root string, elements []string) string {
|
||||||
format = rightFormat
|
format = rightFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
element = fmt.Sprintf(format, element)
|
formattedElement := fmt.Sprintf(format, element)
|
||||||
builder.WriteString(colorizeElement(element))
|
sb.WriteString(colorizeElement(formattedElement))
|
||||||
if i != len(elements)-1 {
|
if i != len(elements)-1 {
|
||||||
builder.WriteString(colorizeSeparator())
|
sb.WriteString(colorizeSeparator())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.String()
|
return sb.String()
|
||||||
}
|
|
||||||
|
|
||||||
type Folder struct {
|
|
||||||
Name string
|
|
||||||
Display bool
|
|
||||||
Path string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Folders []*Folder
|
|
||||||
|
|
||||||
func (f Folders) List() []string {
|
|
||||||
var list []string
|
|
||||||
|
|
||||||
for _, folder := range f {
|
|
||||||
list = append(list, folder.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return list
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) splitPath() Folders {
|
func (pt *Path) splitPath() Folders {
|
||||||
result := Folders{}
|
folders := Folders{}
|
||||||
folders := []string{}
|
|
||||||
|
|
||||||
if len(pt.relative) != 0 {
|
if len(pt.relative) == 0 {
|
||||||
folders = strings.Split(pt.relative, pt.pathSeparator)
|
return folders
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elements := strings.Split(pt.relative, pt.pathSeparator)
|
||||||
folderFormatMap := pt.makeFolderFormatMap()
|
folderFormatMap := pt.makeFolderFormatMap()
|
||||||
|
currentPath := pt.root
|
||||||
|
|
||||||
getCurrentPath := func() string {
|
if !pt.endWithSeparator(pt.root) {
|
||||||
if pt.root == "~" {
|
currentPath += pt.pathSeparator
|
||||||
return pt.env.Home() + pt.pathSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
if pt.windowsPath {
|
|
||||||
return pt.root + pt.pathSeparator
|
|
||||||
}
|
|
||||||
|
|
||||||
return pt.root
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPath := getCurrentPath()
|
|
||||||
|
|
||||||
var display bool
|
var display bool
|
||||||
|
|
||||||
for _, folder := range folders {
|
for _, element := range elements {
|
||||||
currentPath += folder
|
currentPath += element
|
||||||
|
|
||||||
if format := folderFormatMap[currentPath]; len(format) != 0 {
|
if format := folderFormatMap[currentPath]; len(format) != 0 {
|
||||||
folder = fmt.Sprintf(format, folder)
|
element = fmt.Sprintf(format, element)
|
||||||
display = true
|
display = true
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, &Folder{Name: folder, Path: currentPath, Display: display})
|
folders = append(folders, &Folder{Name: element, Path: currentPath, Display: display})
|
||||||
|
|
||||||
currentPath += pt.pathSeparator
|
currentPath += pt.pathSeparator
|
||||||
|
|
||||||
display = false
|
display = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return folders
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pt *Path) makeFolderFormatMap() map[string]string {
|
func (pt *Path) makeFolderFormatMap() map[string]string {
|
||||||
|
@ -838,7 +839,9 @@ func (pt *Path) makeFolderFormatMap() map[string]string {
|
||||||
if gitDirFormat := pt.props.GetString(GitDirFormat, ""); len(gitDirFormat) != 0 {
|
if gitDirFormat := pt.props.GetString(GitDirFormat, ""); len(gitDirFormat) != 0 {
|
||||||
dir, err := pt.env.HasParentFilePath(".git", false)
|
dir, err := pt.env.HasParentFilePath(".git", false)
|
||||||
if err == nil && dir.IsDir {
|
if err == nil && dir.IsDir {
|
||||||
folderFormatMap[dir.ParentFolder] = gitDirFormat
|
// Make it consistent with the modified path.
|
||||||
|
path := pt.join(pt.replaceMappedLocations(dir.ParentFolder))
|
||||||
|
folderFormatMap[path] = gitDirFormat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterFull,
|
Style: AgnosterFull,
|
||||||
Expected: "PSDRIVE:/ | src",
|
Expected: "PSDRIVE: | src",
|
||||||
HomePath: homeDir,
|
HomePath: homeDir,
|
||||||
Pwd: "/foo",
|
Pwd: "/foo",
|
||||||
Pswd: "PSDRIVE:/src",
|
Pswd: "PSDRIVE:/src",
|
||||||
|
@ -489,7 +489,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterShort,
|
Style: AgnosterShort,
|
||||||
Expected: ".. | src",
|
Expected: "PSDRIVE: | src",
|
||||||
HomePath: homeDir,
|
HomePath: homeDir,
|
||||||
Pwd: "/foo",
|
Pwd: "/foo",
|
||||||
Pswd: "PSDRIVE:/src",
|
Pswd: "PSDRIVE:/src",
|
||||||
|
@ -591,7 +591,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterShort,
|
Style: AgnosterShort,
|
||||||
Expected: "PSDRIVE:/ | .. | init",
|
Expected: "PSDRIVE: | .. | init",
|
||||||
HomePath: homeDir,
|
HomePath: homeDir,
|
||||||
Pwd: "/foo",
|
Pwd: "/foo",
|
||||||
Pswd: "PSDRIVE:/src/init",
|
Pswd: "PSDRIVE:/src/init",
|
||||||
|
@ -630,7 +630,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterShort,
|
Style: AgnosterShort,
|
||||||
Expected: ".. > foo",
|
Expected: "~ > foo",
|
||||||
HomePath: homeDir,
|
HomePath: homeDir,
|
||||||
Pwd: homeDir + "/foo",
|
Pwd: homeDir + "/foo",
|
||||||
PathSeparator: "/",
|
PathSeparator: "/",
|
||||||
|
@ -640,7 +640,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterShort,
|
Style: AgnosterShort,
|
||||||
Expected: ".. > foo > bar",
|
Expected: "~ > foo > bar",
|
||||||
HomePath: homeDir,
|
HomePath: homeDir,
|
||||||
Pwd: homeDir + "/foo/bar",
|
Pwd: homeDir + "/foo/bar",
|
||||||
PathSeparator: "/",
|
PathSeparator: "/",
|
||||||
|
@ -661,7 +661,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterShort,
|
Style: AgnosterShort,
|
||||||
Expected: ".. | space foo",
|
Expected: "~ | space foo",
|
||||||
HomePath: homeDir,
|
HomePath: homeDir,
|
||||||
Pwd: homeDir + "/space foo",
|
Pwd: homeDir + "/space foo",
|
||||||
PathSeparator: "/",
|
PathSeparator: "/",
|
||||||
|
@ -752,7 +752,7 @@ func TestAgnosterPathStyles(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Style: AgnosterShort,
|
Style: AgnosterShort,
|
||||||
Expected: ".. > foo",
|
Expected: "~ > foo",
|
||||||
HomePath: homeDirWindows,
|
HomePath: homeDirWindows,
|
||||||
Pwd: homeDirWindows + "\\foo",
|
Pwd: homeDirWindows + "\\foo",
|
||||||
GOOS: runtime.WINDOWS,
|
GOOS: runtime.WINDOWS,
|
||||||
|
@ -848,6 +848,7 @@ func TestFullAndFolderPath(t *testing.T) {
|
||||||
|
|
||||||
// for Windows paths
|
// for Windows paths
|
||||||
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: "C:\\", Expected: "C:\\", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: "C:\\", Expected: "C:\\", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||||
|
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: "\\\\localhost\\d$", Expected: "\\\\localhost\\d$", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||||
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: homeDirWindows, Expected: "~", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
{Style: FolderType, FolderSeparatorIcon: "\\", Pwd: homeDirWindows, Expected: "~", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||||
{Style: Full, FolderSeparatorIcon: "\\", Pwd: homeDirWindows, Expected: "~", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
{Style: Full, FolderSeparatorIcon: "\\", Pwd: homeDirWindows, Expected: "~", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||||
{Style: Full, FolderSeparatorIcon: "\\", Pwd: homeDirWindows + "\\abc", Expected: "~\\abc", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
{Style: Full, FolderSeparatorIcon: "\\", Pwd: homeDirWindows + "\\abc", Expected: "~\\abc", PathSeparator: "\\", GOOS: runtime.WINDOWS},
|
||||||
|
@ -1001,41 +1002,6 @@ func TestFullPathCustomMappedLocations(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPowerlevelMappedLocations(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Pwd string
|
|
||||||
MappedLocations map[string]string
|
|
||||||
Expected string
|
|
||||||
}{
|
|
||||||
{Pwd: "/Users/michal/Applications", MappedLocations: map[string]string{"~": "#"}, Expected: "#/Applications"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
env := new(mock.Environment)
|
|
||||||
env.On("Home").Return("/Users/michal")
|
|
||||||
env.On("Pwd").Return(tc.Pwd)
|
|
||||||
env.On("GOOS").Return(runtime.DARWIN)
|
|
||||||
env.On("PathSeparator").Return("/")
|
|
||||||
env.On("Shell").Return(shell.GENERIC)
|
|
||||||
env.On("DebugF", testify_.Anything, testify_.Anything).Return(nil)
|
|
||||||
env.On("Flags").Return(&runtime.Flags{})
|
|
||||||
|
|
||||||
path := &Path{
|
|
||||||
env: env,
|
|
||||||
props: properties.Map{
|
|
||||||
properties.Style: Powerlevel,
|
|
||||||
MappedLocations: tc.MappedLocations,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
path.setPaths()
|
|
||||||
path.setStyle()
|
|
||||||
|
|
||||||
got := renderTemplateNoTrimSpace(env, "{{ .Path }}", path)
|
|
||||||
assert.Equal(t, tc.Expected, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFolderPathCustomMappedLocations(t *testing.T) {
|
func TestFolderPathCustomMappedLocations(t *testing.T) {
|
||||||
pwd := abcd
|
pwd := abcd
|
||||||
env := new(mock.Environment)
|
env := new(mock.Environment)
|
||||||
|
@ -1501,46 +1467,155 @@ func TestGetFolderSeparator(t *testing.T) {
|
||||||
|
|
||||||
func TestNormalizePath(t *testing.T) {
|
func TestNormalizePath(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Input string
|
Case string
|
||||||
HomeDir string
|
Input string
|
||||||
GOOS string
|
HomeDir string
|
||||||
Expected string
|
GOOS string
|
||||||
|
PathSeparator string
|
||||||
|
Expected string
|
||||||
}{
|
}{
|
||||||
{Input: "/foo/~/bar", HomeDir: homeDirWindows, GOOS: runtime.WINDOWS, Expected: "\\foo\\~\\bar"},
|
{
|
||||||
{Input: homeDirWindows + "\\Foo", HomeDir: homeDirWindows, GOOS: runtime.WINDOWS, Expected: "c:\\users\\someone\\foo"},
|
Case: "Windows: absolute w/o drive letter, forward slash included",
|
||||||
{Input: "~/Bob\\Foo", HomeDir: homeDir, GOOS: runtime.LINUX, Expected: homeDir + "/Bob\\Foo"},
|
Input: "/foo/~/bar",
|
||||||
{Input: "~/Bob\\Foo", HomeDir: homeDir, GOOS: runtime.DARWIN, Expected: homeDir + "/bob\\foo"},
|
HomeDir: homeDirWindows,
|
||||||
{Input: "~\\Bob\\Foo", HomeDir: homeDirWindows, GOOS: runtime.WINDOWS, Expected: "c:\\users\\someone\\bob\\foo"},
|
GOOS: runtime.WINDOWS,
|
||||||
{Input: "/foo/~/bar", HomeDir: homeDir, GOOS: runtime.LINUX, Expected: "/foo/~/bar"},
|
PathSeparator: `\`,
|
||||||
{Input: "~/baz", HomeDir: homeDir, GOOS: runtime.LINUX, Expected: homeDir + "/baz"},
|
Expected: "\\foo\\~\\bar",
|
||||||
{Input: "~/baz", HomeDir: homeDirWindows, GOOS: runtime.WINDOWS, Expected: "c:\\users\\someone\\baz"},
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: absolute",
|
||||||
|
Input: homeDirWindows + "\\Foo",
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "c:\\users\\someone\\foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Linux: home prefix, backslash included",
|
||||||
|
Input: "~/Bob\\Foo",
|
||||||
|
HomeDir: homeDir,
|
||||||
|
GOOS: runtime.LINUX,
|
||||||
|
Expected: homeDir + "/Bob\\Foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "macOS: home prefix, backslash included",
|
||||||
|
Input: "~/Bob\\Foo",
|
||||||
|
HomeDir: homeDir,
|
||||||
|
GOOS: runtime.DARWIN,
|
||||||
|
Expected: homeDir + "/bob\\foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: home prefix",
|
||||||
|
Input: "~\\Bob\\Foo",
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "c:\\users\\someone\\bob\\foo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Linux: absolute",
|
||||||
|
Input: "/foo/~/bar",
|
||||||
|
HomeDir: homeDir,
|
||||||
|
GOOS: runtime.LINUX,
|
||||||
|
Expected: "/foo/~/bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Linux: home prefix",
|
||||||
|
Input: "~/baz",
|
||||||
|
HomeDir: homeDir,
|
||||||
|
GOOS: runtime.LINUX,
|
||||||
|
Expected: homeDir + "/baz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: home prefix",
|
||||||
|
Input: "~/baz",
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "c:\\users\\someone\\baz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: UNC root w/ prefix",
|
||||||
|
Input: `\\.\UNC\localhost\c$`,
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "\\\\localhost\\c$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: UNC root w/ prefix, forward slash included",
|
||||||
|
Input: "//./UNC/localhost/c$",
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "\\\\localhost\\c$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: UNC root",
|
||||||
|
Input: `\\localhost\c$\`,
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "\\\\localhost\\c$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: UNC root, forward slash included",
|
||||||
|
Input: "//localhost/c$",
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "\\\\localhost\\c$",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: UNC",
|
||||||
|
Input: `\\localhost\c$\some`,
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "\\\\localhost\\c$\\some",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Case: "Windows: UNC, forward slash included",
|
||||||
|
Input: "//localhost/c$/some",
|
||||||
|
HomeDir: homeDirWindows,
|
||||||
|
GOOS: runtime.WINDOWS,
|
||||||
|
PathSeparator: `\`,
|
||||||
|
Expected: "\\\\localhost\\c$\\some",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := new(mock.Environment)
|
env := new(mock.Environment)
|
||||||
env.On("Home").Return(tc.HomeDir)
|
env.On("Home").Return(tc.HomeDir)
|
||||||
env.On("GOOS").Return(tc.GOOS)
|
env.On("GOOS").Return(tc.GOOS)
|
||||||
pt := &Path{
|
|
||||||
env: env,
|
if len(tc.PathSeparator) == 0 {
|
||||||
|
tc.PathSeparator = "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
env.On("PathSeparator").Return(tc.PathSeparator)
|
||||||
|
pt := &Path{env: env}
|
||||||
got := pt.normalize(tc.Input)
|
got := pt.normalize(tc.Input)
|
||||||
assert.Equal(t, tc.Expected, got)
|
assert.Equal(t, tc.Expected, got, tc.Case)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestReplaceMappedLocations(t *testing.T) {
|
func TestReplaceMappedLocations(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Case string
|
Case string
|
||||||
Pwd string
|
Pwd string
|
||||||
Expected string
|
MappedLocationsEnabled bool
|
||||||
|
Expected string
|
||||||
}{
|
}{
|
||||||
{Pwd: "/c/l/k/f", Expected: "f"},
|
{Pwd: "/c/l/k/f", Expected: "f"},
|
||||||
{Pwd: "/f/g/h", Expected: "/f/g/h"},
|
{Pwd: "/f/g/h", Expected: "/f/g/h"},
|
||||||
{Pwd: "/f/g/h/e", Expected: "^/e"},
|
{Pwd: "/f/g/h/e", Expected: "^/e"},
|
||||||
{Pwd: abcd, Expected: "#"},
|
{Pwd: abcd, Expected: "#"},
|
||||||
{Pwd: "/a/b/c/d/e", Expected: "#/e"},
|
{Pwd: "/a/b/c/d/e", Expected: "#/e"},
|
||||||
{Pwd: "/a/b/c/d/e", Expected: "#/e"},
|
{Pwd: "/a/b/c/D/e", Expected: "#/e"},
|
||||||
{Pwd: "/a/b/k/j/e", Expected: "e"},
|
{Pwd: "/a/b/k/j/e", Expected: "e"},
|
||||||
|
{Pwd: "/a/b/k/l", Expected: "@/l"},
|
||||||
|
{Pwd: "/a/b/k/l", MappedLocationsEnabled: true, Expected: "~/l"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
|
@ -1556,11 +1631,12 @@ func TestReplaceMappedLocations(t *testing.T) {
|
||||||
path := &Path{
|
path := &Path{
|
||||||
env: env,
|
env: env,
|
||||||
props: properties.Map{
|
props: properties.Map{
|
||||||
MappedLocationsEnabled: false,
|
MappedLocationsEnabled: tc.MappedLocationsEnabled,
|
||||||
MappedLocations: map[string]string{
|
MappedLocations: map[string]string{
|
||||||
abcd: "#",
|
abcd: "#",
|
||||||
"/f/g/h/*": "^",
|
"/f/g/h/*": "^",
|
||||||
"/c/l/k/*": "",
|
"/c/l/k/*": "",
|
||||||
|
"~": "@",
|
||||||
"~/j/*": "",
|
"~/j/*": "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1600,8 +1676,8 @@ func TestSplitPath(t *testing.T) {
|
||||||
GitDir: &runtime.FileInfo{IsDir: true, ParentFolder: "/a/b/c"},
|
GitDir: &runtime.FileInfo{IsDir: true, ParentFolder: "/a/b/c"},
|
||||||
GitDirFormat: "<b>%s</b>",
|
GitDirFormat: "<b>%s</b>",
|
||||||
Expected: Folders{
|
Expected: Folders{
|
||||||
{Name: "<b>c</b>", Path: "/a/b/c", Display: true},
|
{Name: "<b>c</b>", Path: "~/c", Display: true},
|
||||||
{Name: "d", Path: "/a/b/c/d"},
|
{Name: "d", Path: "~/c/d"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1622,6 +1698,7 @@ func TestSplitPath(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
env := new(mock.Environment)
|
env := new(mock.Environment)
|
||||||
|
env.On("PathSeparator").Return("/")
|
||||||
env.On("Home").Return("/a/b")
|
env.On("Home").Return("/a/b")
|
||||||
env.On("HasParentFilePath", ".git", false).Return(tc.GitDir, nil)
|
env.On("HasParentFilePath", ".git", false).Return(tc.GitDir, nil)
|
||||||
env.On("GOOS").Return(tc.GOOS)
|
env.On("GOOS").Return(tc.GOOS)
|
||||||
|
|
|
@ -86,6 +86,8 @@ const (
|
||||||
hyperLinkText = "<TEXT>"
|
hyperLinkText = "<TEXT>"
|
||||||
hyperLinkTextEnd = "</TEXT>"
|
hyperLinkTextEnd = "</TEXT>"
|
||||||
|
|
||||||
|
empty = "<>"
|
||||||
|
|
||||||
startProgress = "\x1b]9;4;3;0\x07"
|
startProgress = "\x1b]9;4;3;0\x07"
|
||||||
endProgress = "\x1b]9;4;0;0\x07"
|
endProgress = "\x1b]9;4;0;0\x07"
|
||||||
|
|
||||||
|
@ -160,10 +162,6 @@ func Pwd(pwdType, userName, hostName, pwd string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(pwd, ":") {
|
|
||||||
pwd += `/`
|
|
||||||
}
|
|
||||||
|
|
||||||
switch pwdType {
|
switch pwdType {
|
||||||
case OSC7:
|
case OSC7:
|
||||||
return fmt.Sprintf(formats.Osc7, hostName, pwd)
|
return fmt.Sprintf(formats.Osc7, hostName, pwd)
|
||||||
|
@ -346,6 +344,9 @@ func Write(background, foreground color.Ansi, text string) {
|
||||||
i += len([]rune(match[ANCHOR])) - 1
|
i += len([]rune(match[ANCHOR])) - 1
|
||||||
builder.WriteString(formats.HyperlinkEnd)
|
builder.WriteString(formats.HyperlinkEnd)
|
||||||
continue
|
continue
|
||||||
|
case empty:
|
||||||
|
i += len([]rune(match[ANCHOR])) - 1
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
i = writeArchorOverride(match, background, i)
|
i = writeArchorOverride(match, background, i)
|
||||||
|
|
|
@ -77,7 +77,9 @@ For example, to swap out `C:\Users\Leet\GitHub` with a GitHub icon, you can do t
|
||||||
- To make mapped locations work cross-platform, use `/` as the path separator, Oh My Posh will
|
- To make mapped locations work cross-platform, use `/` as the path separator, Oh My Posh will
|
||||||
automatically match effective separators based on the running operating system.
|
automatically match effective separators based on the running operating system.
|
||||||
- If you want to match all child directories, you can use `*` as a wildcard, for example:
|
- If you want to match all child directories, you can use `*` as a wildcard, for example:
|
||||||
`"C:/Users/Bill/*": "$"` will turn `C:/Users/Bill/Downloads` into `$/Downloads`.
|
`"C:/Users/Bill/*": "$"` will turn `C:/Users/Bill/Downloads` into `$/Downloads` but leave `C:/Users/Bill` unchanged.
|
||||||
|
- To prevent mangling path elements, if you use any text style tags (e.g., `<lightGreen>...</>`) in replacement values,
|
||||||
|
you should avoid using a chevron character (`<`/`>`) in the `folder_separator_icon` property, and vice versa.
|
||||||
- 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. This means that for
|
- The match is case-insensitive on Windows and macOS, but case-sensitive on other operating systems. This means that for
|
||||||
user Bill, who has a user account `Bill` on Windows and `bill` on Linux, `~/Foo` might match
|
user Bill, who has a user account `Bill` on Windows and `bill` on Linux, `~/Foo` might match
|
||||||
|
|
Loading…
Reference in a new issue