2019-03-13 04:14:30 -07:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"path/filepath"
|
2020-11-20 10:39:07 -08:00
|
|
|
"sort"
|
2019-03-13 04:14:30 -07:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type path struct {
|
|
|
|
props *properties
|
|
|
|
env environmentInfo
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
2020-11-12 00:43:32 -08:00
|
|
|
// FolderSeparatorIcon the path which is split will be separated by this icon
|
2019-03-13 04:14:30 -07:00
|
|
|
FolderSeparatorIcon Property = "folder_separator_icon"
|
2020-11-12 00:43:32 -08:00
|
|
|
// HomeIcon indicates the $HOME location
|
2019-03-13 04:14:30 -07:00
|
|
|
HomeIcon Property = "home_icon"
|
2020-11-12 00:43:32 -08:00
|
|
|
// FolderIcon identifies one folder
|
2019-03-13 04:14:30 -07:00
|
|
|
FolderIcon Property = "folder_icon"
|
2020-11-12 00:43:32 -08:00
|
|
|
// WindowsRegistryIcon indicates the registry location on Windows
|
2019-03-13 04:14:30 -07:00
|
|
|
WindowsRegistryIcon Property = "windows_registry_icon"
|
2020-11-12 00:43:32 -08:00
|
|
|
// Agnoster displays a short path with separator icon, this the default style
|
2019-03-13 04:14:30 -07:00
|
|
|
Agnoster string = "agnoster"
|
2020-11-12 00:43:32 -08:00
|
|
|
// AgnosterFull displays all the folder names with the folder_separator_icon
|
2020-11-11 04:53:53 -08:00
|
|
|
AgnosterFull string = "agnoster_full"
|
2020-12-17 03:10:01 -08:00
|
|
|
// AgnosterShort displays the folder names with one folder_separator_icon, regardless of depth
|
|
|
|
AgnosterShort string = "agnoster_short"
|
2020-11-12 00:43:32 -08:00
|
|
|
// Short displays a shorter path
|
2019-03-13 04:14:30 -07:00
|
|
|
Short string = "short"
|
2020-11-12 00:43:32 -08:00
|
|
|
// Full displays the full path
|
2019-03-13 04:14:30 -07:00
|
|
|
Full string = "full"
|
2020-11-12 00:43:32 -08:00
|
|
|
// Folder displays the current folder
|
2019-03-13 04:14:30 -07:00
|
|
|
Folder string = "folder"
|
2021-02-09 02:57:32 -08:00
|
|
|
// Mixed like agnoster, but if the path is short it displays it
|
|
|
|
Mixed string = "mixed"
|
2021-07-13 11:15:53 -07:00
|
|
|
// Letter like agnoster, but with the first letter of each folder name
|
|
|
|
Letter string = "letter"
|
2021-02-09 02:57:32 -08:00
|
|
|
// MixedThreshold the threshold of the length of the path Mixed will display
|
|
|
|
MixedThreshold Property = "mixed_threshold"
|
2020-11-27 11:10:19 -08:00
|
|
|
// MappedLocations allows overriding certain location with an icon
|
|
|
|
MappedLocations Property = "mapped_locations"
|
2020-12-24 13:17:00 -08:00
|
|
|
// MappedLocationsEnabled enables overriding certain locations with an icon
|
|
|
|
MappedLocationsEnabled Property = "mapped_locations_enabled"
|
2021-04-12 01:58:03 -07:00
|
|
|
// StackCountEnabled enables the stack count display
|
|
|
|
StackCountEnabled Property = "stack_count_enabled"
|
2021-08-20 08:06:37 -07:00
|
|
|
// Maximum path depth to display whithout shortening
|
|
|
|
MaxDepth Property = "max_depth"
|
2019-03-13 04:14:30 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func (pt *path) enabled() bool {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *path) string() string {
|
2021-01-09 07:18:37 -08:00
|
|
|
cwd := pt.env.getcwd()
|
|
|
|
var formattedPath string
|
2019-03-13 04:14:30 -07:00
|
|
|
switch style := pt.props.getString(Style, Agnoster); style {
|
|
|
|
case Agnoster:
|
2021-01-09 07:18:37 -08:00
|
|
|
formattedPath = pt.getAgnosterPath()
|
2020-11-11 04:53:53 -08:00
|
|
|
case AgnosterFull:
|
2021-01-09 07:18:37 -08:00
|
|
|
formattedPath = pt.getAgnosterFullPath()
|
2020-12-17 03:10:01 -08:00
|
|
|
case AgnosterShort:
|
2021-01-09 07:18:37 -08:00
|
|
|
formattedPath = pt.getAgnosterShortPath()
|
2021-02-09 02:57:32 -08:00
|
|
|
case Mixed:
|
|
|
|
formattedPath = pt.getMixedPath()
|
2021-07-13 11:15:53 -07:00
|
|
|
case Letter:
|
|
|
|
formattedPath = pt.getLetterPath()
|
2019-03-13 04:14:30 -07:00
|
|
|
case Short:
|
2020-12-24 13:17:00 -08:00
|
|
|
// "short" is a duplicate of "full", just here for backwards compatibility
|
|
|
|
fallthrough
|
2019-03-13 04:14:30 -07:00
|
|
|
case Full:
|
2021-01-09 07:18:37 -08:00
|
|
|
formattedPath = pt.getFullPath()
|
2019-03-13 04:14:30 -07:00
|
|
|
case Folder:
|
2021-01-09 07:18:37 -08:00
|
|
|
formattedPath = pt.getFolderPath()
|
2019-03-13 04:14:30 -07:00
|
|
|
default:
|
|
|
|
return fmt.Sprintf("Path style: %s is not available", style)
|
|
|
|
}
|
2021-03-17 04:49:30 -07:00
|
|
|
formattedPath = pt.formatWindowsDrive(formattedPath)
|
2021-01-09 07:18:37 -08:00
|
|
|
if pt.props.getBool(EnableHyperlink, false) {
|
2021-02-15 01:31:47 -08:00
|
|
|
// wsl check
|
|
|
|
if pt.env.isWsl() {
|
|
|
|
cwd, _ = pt.env.runCommand("wslpath", "-m", cwd)
|
|
|
|
}
|
2021-01-09 07:18:37 -08:00
|
|
|
return fmt.Sprintf("[%s](file://%s)", formattedPath, cwd)
|
|
|
|
}
|
2021-04-12 01:58:03 -07:00
|
|
|
|
|
|
|
if pt.props.getBool(StackCountEnabled, false) && pt.env.stackCount() > 0 {
|
|
|
|
return fmt.Sprintf("%d %s", pt.env.stackCount(), formattedPath)
|
|
|
|
}
|
|
|
|
|
2021-01-09 07:18:37 -08:00
|
|
|
return formattedPath
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2021-03-17 04:49:30 -07:00
|
|
|
func (pt *path) formatWindowsDrive(pwd string) string {
|
|
|
|
if pt.env.getRuntimeGOOS() != windowsPlatform || !strings.HasSuffix(pwd, ":") {
|
|
|
|
return pwd
|
|
|
|
}
|
|
|
|
return pwd + "\\"
|
|
|
|
}
|
|
|
|
|
2019-03-13 04:14:30 -07:00
|
|
|
func (pt *path) init(props *properties, env environmentInfo) {
|
|
|
|
pt.props = props
|
|
|
|
pt.env = env
|
|
|
|
}
|
|
|
|
|
2021-02-09 02:57:32 -08:00
|
|
|
func (pt *path) getMixedPath() string {
|
|
|
|
var buffer strings.Builder
|
|
|
|
pwd := pt.getPwd()
|
|
|
|
splitted := strings.Split(pwd, pt.env.getPathSeperator())
|
|
|
|
threshold := int(pt.props.getFloat64(MixedThreshold, 4))
|
|
|
|
for i, part := range splitted {
|
|
|
|
if part == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
folder := part
|
|
|
|
if len(part) > threshold && i != 0 && i != len(splitted)-1 {
|
|
|
|
folder = pt.props.getString(FolderIcon, "..")
|
|
|
|
}
|
|
|
|
separator := pt.props.getString(FolderSeparatorIcon, pt.env.getPathSeperator())
|
|
|
|
if i == 0 {
|
|
|
|
separator = ""
|
|
|
|
}
|
|
|
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, folder))
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
2019-03-13 04:14:30 -07:00
|
|
|
func (pt *path) getAgnosterPath() string {
|
2021-01-05 23:52:43 -08:00
|
|
|
var buffer strings.Builder
|
2020-12-24 13:17:00 -08:00
|
|
|
pwd := pt.getPwd()
|
2020-11-17 10:22:56 -08:00
|
|
|
buffer.WriteString(pt.rootLocation())
|
2019-03-13 04:14:30 -07:00
|
|
|
pathDepth := pt.pathDepth(pwd)
|
2021-07-13 11:15:53 -07:00
|
|
|
folderIcon := pt.props.getString(FolderIcon, "..")
|
|
|
|
separator := pt.props.getString(FolderSeparatorIcon, pt.env.getPathSeperator())
|
2019-03-13 04:14:30 -07:00
|
|
|
for i := 1; i < pathDepth; i++ {
|
2021-07-13 11:15:53 -07:00
|
|
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, folderIcon))
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
if pathDepth > 0 {
|
2021-07-13 11:15:53 -07:00
|
|
|
buffer.WriteString(fmt.Sprintf("%s%s", separator, base(pwd, pt.env)))
|
|
|
|
}
|
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *path) getLetterPath() string {
|
|
|
|
var buffer strings.Builder
|
|
|
|
pwd := pt.getPwd()
|
|
|
|
splitted := strings.Split(pwd, pt.env.getPathSeperator())
|
|
|
|
separator := pt.props.getString(FolderSeparatorIcon, pt.env.getPathSeperator())
|
|
|
|
for i := 0; i < len(splitted)-1; i++ {
|
2021-08-09 11:36:26 -07:00
|
|
|
folder := splitted[i]
|
|
|
|
if len(folder) == 0 {
|
2021-07-13 11:15:53 -07:00
|
|
|
continue
|
|
|
|
}
|
2021-08-09 11:36:26 -07:00
|
|
|
var letter string
|
|
|
|
if strings.HasPrefix(folder, ".") && len(folder) > 1 {
|
|
|
|
letter = folder[0:2]
|
|
|
|
} else {
|
|
|
|
letter = folder[0:1]
|
|
|
|
}
|
|
|
|
buffer.WriteString(fmt.Sprintf("%s%s", letter, separator))
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
2021-07-13 11:15:53 -07:00
|
|
|
buffer.WriteString(splitted[len(splitted)-1])
|
2019-03-13 04:14:30 -07:00
|
|
|
return buffer.String()
|
|
|
|
}
|
|
|
|
|
2020-11-11 04:53:53 -08:00
|
|
|
func (pt *path) getAgnosterFullPath() string {
|
2020-12-24 13:17:00 -08:00
|
|
|
pwd := pt.getPwd()
|
2020-12-25 19:33:51 -08:00
|
|
|
if string(pwd[0]) == pt.env.getPathSeperator() {
|
2020-11-11 04:53:53 -08:00
|
|
|
pwd = pwd[1:]
|
|
|
|
}
|
2020-12-25 19:33:51 -08:00
|
|
|
return pt.replaceFolderSeparators(pwd)
|
2020-11-11 04:53:53 -08:00
|
|
|
}
|
|
|
|
|
2020-12-17 03:10:01 -08:00
|
|
|
func (pt *path) getAgnosterShortPath() string {
|
2021-08-20 08:06:37 -07:00
|
|
|
pwd := pt.getPwd()
|
|
|
|
pathDepth := pt.pathDepth(pwd)
|
|
|
|
maxDepth := pt.props.getInt(MaxDepth, 1)
|
|
|
|
if maxDepth < 1 {
|
|
|
|
maxDepth = 1
|
|
|
|
}
|
|
|
|
if pathDepth <= maxDepth {
|
|
|
|
return pt.getAgnosterFullPath()
|
|
|
|
}
|
2020-12-17 03:10:01 -08:00
|
|
|
pathSeparator := pt.env.getPathSeperator()
|
|
|
|
folderSeparator := pt.props.getString(FolderSeparatorIcon, pathSeparator)
|
|
|
|
folderIcon := pt.props.getString(FolderIcon, "..")
|
|
|
|
root := pt.rootLocation()
|
2021-08-20 08:06:37 -07:00
|
|
|
splitted := strings.Split(pwd, pathSeparator)
|
|
|
|
fullPathDepth := len(splitted)
|
|
|
|
splitPos := fullPathDepth - maxDepth
|
|
|
|
var buffer strings.Builder
|
|
|
|
buffer.WriteString(fmt.Sprintf("%s%s%s", root, folderSeparator, folderIcon))
|
|
|
|
for i := splitPos; i < fullPathDepth; i++ {
|
|
|
|
buffer.WriteString(fmt.Sprintf("%s%s", folderSeparator, splitted[i]))
|
2020-12-17 03:10:01 -08:00
|
|
|
}
|
2021-08-20 08:06:37 -07:00
|
|
|
return buffer.String()
|
2020-12-17 03:10:01 -08:00
|
|
|
}
|
|
|
|
|
2020-12-24 13:17:00 -08:00
|
|
|
func (pt *path) getFullPath() string {
|
2020-12-25 19:33:51 -08:00
|
|
|
pwd := pt.getPwd()
|
|
|
|
return pt.replaceFolderSeparators(pwd)
|
2020-12-24 13:17:00 -08:00
|
|
|
}
|
|
|
|
|
2020-12-24 06:19:15 -08:00
|
|
|
func (pt *path) getFolderPath() string {
|
2020-12-24 13:17:00 -08:00
|
|
|
pwd := pt.getPwd()
|
2021-01-03 08:21:17 -08:00
|
|
|
pwd = base(pwd, pt.env)
|
|
|
|
return pt.replaceFolderSeparators(pwd)
|
2020-12-24 06:19:15 -08:00
|
|
|
}
|
|
|
|
|
2020-12-24 13:17:00 -08:00
|
|
|
func (pt *path) getPwd() string {
|
2021-01-09 04:48:54 -08:00
|
|
|
pwd := *pt.env.getArgs().PSWD
|
|
|
|
if pwd == "" {
|
|
|
|
pwd = pt.env.getcwd()
|
|
|
|
}
|
2021-07-24 10:49:01 -07:00
|
|
|
pwd = pt.replaceMappedLocations(pwd)
|
2020-12-24 13:17:00 -08:00
|
|
|
return pwd
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *path) replaceMappedLocations(pwd string) string {
|
|
|
|
if strings.HasPrefix(pwd, "Microsoft.PowerShell.Core\\FileSystem::") {
|
|
|
|
pwd = strings.Replace(pwd, "Microsoft.PowerShell.Core\\FileSystem::", "", 1)
|
|
|
|
}
|
|
|
|
|
2021-07-24 10:49:01 -07:00
|
|
|
mappedLocations := map[string]string{}
|
|
|
|
if pt.props.getBool(MappedLocationsEnabled, true) {
|
|
|
|
mappedLocations["HKCU:"] = pt.props.getString(WindowsRegistryIcon, "\uF013")
|
|
|
|
mappedLocations["HKLM:"] = pt.props.getString(WindowsRegistryIcon, "\uF013")
|
|
|
|
mappedLocations[pt.env.homeDir()] = pt.props.getString(HomeIcon, "~")
|
2020-12-24 13:17:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// merge custom locations with mapped locations
|
|
|
|
// mapped locations can override predefined locations
|
|
|
|
keyValues := pt.props.getKeyValueMap(MappedLocations, make(map[string]string))
|
|
|
|
for key, val := range keyValues {
|
|
|
|
mappedLocations[key] = val
|
|
|
|
}
|
|
|
|
|
|
|
|
// sort map keys in reverse order
|
|
|
|
// fixes case when a subfoder and its parent are mapped
|
|
|
|
// ex /users/test and /users/test/dev
|
|
|
|
keys := make([]string, len(mappedLocations))
|
|
|
|
i := 0
|
|
|
|
for k := range mappedLocations {
|
|
|
|
keys[i] = k
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
sort.Sort(sort.Reverse(sort.StringSlice(keys)))
|
|
|
|
|
|
|
|
for _, value := range keys {
|
|
|
|
if strings.HasPrefix(pwd, value) {
|
|
|
|
return strings.Replace(pwd, value, mappedLocations[value], 1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pwd
|
|
|
|
}
|
|
|
|
|
2020-12-25 19:33:51 -08:00
|
|
|
func (pt *path) replaceFolderSeparators(pwd string) string {
|
|
|
|
defaultSeparator := pt.env.getPathSeperator()
|
2021-03-17 04:49:30 -07:00
|
|
|
if pwd == defaultSeparator {
|
|
|
|
return pwd
|
|
|
|
}
|
2020-12-25 19:33:51 -08:00
|
|
|
folderSeparator := pt.props.getString(FolderSeparatorIcon, defaultSeparator)
|
|
|
|
if folderSeparator == defaultSeparator {
|
|
|
|
return pwd
|
|
|
|
}
|
|
|
|
|
|
|
|
pwd = strings.ReplaceAll(pwd, defaultSeparator, folderSeparator)
|
|
|
|
return pwd
|
|
|
|
}
|
|
|
|
|
2019-03-13 04:14:30 -07:00
|
|
|
func (pt *path) inHomeDir(pwd string) bool {
|
2020-10-02 12:50:13 -07:00
|
|
|
return strings.HasPrefix(pwd, pt.env.homeDir())
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
|
2020-11-17 10:22:56 -08:00
|
|
|
func (pt *path) rootLocation() string {
|
2020-12-24 13:17:00 -08:00
|
|
|
pwd := pt.getPwd()
|
2019-03-13 04:14:30 -07:00
|
|
|
pwd = strings.TrimPrefix(pwd, pt.env.getPathSeperator())
|
|
|
|
splitted := strings.Split(pwd, pt.env.getPathSeperator())
|
|
|
|
rootLocation := splitted[0]
|
|
|
|
return rootLocation
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pt *path) pathDepth(pwd string) int {
|
|
|
|
splitted := strings.Split(pwd, pt.env.getPathSeperator())
|
2020-12-25 19:33:51 -08:00
|
|
|
depth := 0
|
2019-03-13 04:14:30 -07:00
|
|
|
for _, part := range splitted {
|
|
|
|
if part != "" {
|
2020-12-25 19:33:51 -08:00
|
|
|
depth++
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return depth - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Base returns the last element of path.
|
|
|
|
// Trailing path separators are removed before extracting the last element.
|
|
|
|
// If the path consists entirely of separators, Base returns a single separator.
|
|
|
|
func base(path string, env environmentInfo) string {
|
2021-03-17 04:49:30 -07:00
|
|
|
if path == "/" {
|
|
|
|
return path
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
2021-03-17 04:49:30 -07:00
|
|
|
volumeName := filepath.VolumeName(path)
|
2019-03-13 04:14:30 -07:00
|
|
|
// Strip trailing slashes.
|
|
|
|
for len(path) > 0 && string(path[len(path)-1]) == env.getPathSeperator() {
|
|
|
|
path = path[0 : len(path)-1]
|
|
|
|
}
|
2021-03-17 04:49:30 -07:00
|
|
|
if volumeName == path {
|
|
|
|
return path
|
|
|
|
}
|
2019-03-13 04:14:30 -07:00
|
|
|
// Throw away volume name
|
|
|
|
path = path[len(filepath.VolumeName(path)):]
|
|
|
|
// Find the last element
|
|
|
|
i := len(path) - 1
|
|
|
|
for i >= 0 && string(path[i]) != env.getPathSeperator() {
|
|
|
|
i--
|
|
|
|
}
|
|
|
|
if i >= 0 {
|
|
|
|
path = path[i+1:]
|
|
|
|
}
|
|
|
|
// If empty now, it had only slashes.
|
|
|
|
if path == "" {
|
2020-11-12 00:43:32 -08:00
|
|
|
return env.getPathSeperator()
|
2019-03-13 04:14:30 -07:00
|
|
|
}
|
|
|
|
return path
|
|
|
|
}
|