Skip to content

Commit

Permalink
feat: mapped_locations_enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
tradiff authored and JanDeDobbeleer committed Dec 25, 2020
1 parent 7ff4954 commit 0e5e65d
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 135 deletions.
17 changes: 6 additions & 11 deletions docs/docs/segment-path.md
Expand Up @@ -33,17 +33,18 @@ Display the current path.
- folder_icon: `string` - the icon to use as a folder indication - defaults to `..`
- windows_registry_icon: `string` - the icon to display when in the Windows registry - defaults to `\uE0B1`
- style: `enum` - how to display the current path
- mapped_locations: `map[string]string` - custom glyph/text for specific paths(only when `style` is set to `agnoster`,
`agnoster_full`, `agnoster_short`, `short`, or `folder`)
- mapped_locations: `map[string]string` - custom glyph/text for specific paths (only when `mapped_locations_enabled`
is set to `true`)
- mapped_locations_enabled: `boolean` - replace known locations in the path with the replacements before applying the
style. defaults to `true`

## Style

Style sets the way the path is displayed. Based on previous experience and popular themes, there are 4 flavors.
Style sets the way the path is displayed. Based on previous experience and popular themes, there are 5 flavors.

- agnoster
- agnoster_full
- agnoster_short
- short
- full
- folder

Expand All @@ -61,15 +62,9 @@ Renders each folder name separated by the `folder_separator_icon`.

When more than 1 level deep, it renders one `folder_icon` followed by the name of the current folder separated by the `folder_separator_icon`.

### Short

Display `$PWD` as a string, replace `$HOME` with the `home_icon` if you're inside the `$HOME` location or
one of its children.
Specific folders can be customized using the `mapped_locations` property.

### Full

Display `$PWD` as a string
Display `$PWD` as a string.

### Folder

Expand Down
112 changes: 63 additions & 49 deletions segment_path.go
Expand Up @@ -36,6 +36,8 @@ const (
Folder string = "folder"
// MappedLocations allows overriding certain location with an icon
MappedLocations Property = "mapped_locations"
// MappedLocationsEnabled enables overriding certain locations with an icon
MappedLocationsEnabled Property = "mapped_locations_enabled"
)

func (pt *path) enabled() bool {
Expand All @@ -51,9 +53,10 @@ func (pt *path) string() string {
case AgnosterShort:
return pt.getAgnosterShortPath()
case Short:
return pt.getShortPath()
// "short" is a duplicate of "full", just here for backwards compatibility
fallthrough
case Full:
return pt.env.getcwd()
return pt.getFullPath()
case Folder:
return pt.getFolderPath()
default:
Expand All @@ -66,47 +69,9 @@ func (pt *path) init(props *properties, env environmentInfo) {
pt.env = env
}

func (pt *path) getShortPath() string {
pwd := pt.env.getcwd()
if strings.HasPrefix(pwd, "Microsoft.PowerShell.Core\\FileSystem::") {
pwd = strings.Replace(pwd, "Microsoft.PowerShell.Core\\FileSystem::", "", 1)
}

mappedLocations := map[string]string{
"HKCU:": pt.props.getString(WindowsRegistryIcon, "\uE0B1"),
"HKLM:": pt.props.getString(WindowsRegistryIcon, "\uE0B1"),
pt.env.homeDir(): pt.props.getString(HomeIcon, "~"),
}

// 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
}

func (pt *path) getAgnosterPath() string {
buffer := new(bytes.Buffer)
pwd := pt.getShortPath()
pwd := pt.getPwd()
buffer.WriteString(pt.rootLocation())
pathDepth := pt.pathDepth(pwd)
for i := 1; i < pathDepth; i++ {
Expand All @@ -119,7 +84,7 @@ func (pt *path) getAgnosterPath() string {
}

func (pt *path) getAgnosterFullPath() string {
pwd := pt.getShortPath()
pwd := pt.getPwd()
pathSeparator := pt.env.getPathSeperator()
folderSeparator := pt.props.getString(FolderSeparatorIcon, pathSeparator)
if string(pwd[0]) == pathSeparator {
Expand All @@ -133,8 +98,9 @@ func (pt *path) getAgnosterShortPath() string {
folderSeparator := pt.props.getString(FolderSeparatorIcon, pathSeparator)
folderIcon := pt.props.getString(FolderIcon, "..")
root := pt.rootLocation()
base := base(pt.env.getcwd(), pt.env)
pathDepth := pt.pathDepth(pt.getShortPath())
pwd := pt.getPwd()
base := base(pwd, pt.env)
pathDepth := pt.pathDepth(pwd)
if pathDepth <= 0 {
return root
}
Expand All @@ -144,27 +110,75 @@ func (pt *path) getAgnosterShortPath() string {
return fmt.Sprintf("%s%s%s%s%s", root, folderSeparator, folderIcon, folderSeparator, base)
}

func (pt *path) getFullPath() string {
return pt.getPwd()
}

func (pt *path) getFolderPath() string {
pwd := pt.getShortPath()
pwd := pt.getPwd()
return base(pwd, pt.env)
}

func (pt *path) getPwd() string {
pwd := pt.env.getcwd()

if pt.props.getBool(MappedLocationsEnabled, true) {
pwd = pt.replaceMappedLocations(pwd)
}

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)
}

mappedLocations := map[string]string{
"HKCU:": pt.props.getString(WindowsRegistryIcon, "\uE0B1"),
"HKLM:": pt.props.getString(WindowsRegistryIcon, "\uE0B1"),
pt.env.homeDir(): pt.props.getString(HomeIcon, "~"),
}

// 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
}

func (pt *path) inHomeDir(pwd string) bool {
return strings.HasPrefix(pwd, pt.env.homeDir())
}

func (pt *path) rootLocation() string {
pwd := pt.getShortPath()
pwd := pt.getPwd()
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 {
if pt.inHomeDir(pwd) {
pwd = strings.Replace(pwd, pt.env.homeDir(), "root", 1)
}
splitted := strings.Split(pwd, pt.env.getPathSeperator())
var validParts []string
for _, part := range splitted {
Expand Down
105 changes: 46 additions & 59 deletions segment_path_test.go
@@ -1,7 +1,6 @@
package main

import (
"math/rand"
"testing"

"github.com/distatus/battery"
Expand Down Expand Up @@ -129,7 +128,6 @@ func (env *MockedEnvironment) doGet(url string) ([]byte, error) {
}

const (
homeGates = "/home/gates"
homeBill = "/home/bill"
homeJan = "/usr/home/jan"
homeBillWindows = "C:\\Users\\Bill"
Expand All @@ -148,10 +146,9 @@ func TestIsInHomeDirTrue(t *testing.T) {
}

func TestIsInHomeDirLevelTrue(t *testing.T) {
level := rand.Intn(100)
home := homeBill
pwd := home
for i := 0; i < level; i++ {
for i := 0; i < 99; i++ {
pwd += levelDir
}
env := new(MockedEnvironment)
Expand Down Expand Up @@ -290,71 +287,23 @@ func TestIsInHomeDirFalse(t *testing.T) {
assert.False(t, got)
}

func TestPathDepthInHome(t *testing.T) {
home := homeBill
pwd := home
env := new(MockedEnvironment)
env.On("homeDir", nil).Return(home)
env.On("getPathSeperator", nil).Return("/")
path := &path{
env: env,
}
got := path.pathDepth(pwd)
assert.Equal(t, 0, got)
}

func TestPathDepthInHomeTrailing(t *testing.T) {
home := "/home/bill/"
pwd := home + "/"
env := new(MockedEnvironment)
env.On("homeDir", nil).Return(home)
env.On("getPathSeperator", nil).Return("/")
path := &path{
env: env,
}
got := path.pathDepth(pwd)
assert.Equal(t, 0, got)
}

func TestPathDepthInHomeMultipleLevelsDeep(t *testing.T) {
level := rand.Intn(100)
home := homeBill
pwd := home
for i := 0; i < level; i++ {
pwd += levelDir
}
env := new(MockedEnvironment)
env.On("homeDir", nil).Return(home)
env.On("getPathSeperator", nil).Return("/")
path := &path{
env: env,
}
got := path.pathDepth(pwd)
assert.Equal(t, level, got)
}

func TestPathDepthOutsideHomeMultipleLevelsDeep(t *testing.T) {
level := rand.Intn(100)
home := homeGates
func TestPathDepthMultipleLevelsDeep(t *testing.T) {
pwd := "/usr"
for i := 0; i < level; i++ {
for i := 0; i < 99; i++ {
pwd += levelDir
}
env := new(MockedEnvironment)
env.On("homeDir", nil).Return(home)
env.On("getPathSeperator", nil).Return("/")
path := &path{
env: env,
}
got := path.pathDepth(pwd)
assert.Equal(t, level, got)
assert.Equal(t, 99, got)
}

func TestPathDepthOutsideHomeZeroLevelsDeep(t *testing.T) {
home := homeGates
func TestPathDepthZeroLevelsDeep(t *testing.T) {
pwd := "/usr/"
env := new(MockedEnvironment)
env.On("homeDir", nil).Return(home)
env.On("getPathSeperator", nil).Return("/")
path := &path{
env: env,
Expand All @@ -363,11 +312,9 @@ func TestPathDepthOutsideHomeZeroLevelsDeep(t *testing.T) {
assert.Equal(t, 0, got)
}

func TestPathDepthOutsideHomeOneLevelDeep(t *testing.T) {
home := homeGates
func TestPathDepthOneLevelDeep(t *testing.T) {
pwd := "/usr/location"
env := new(MockedEnvironment)
env.On("homeDir", nil).Return(home)
env.On("getPathSeperator", nil).Return("/")
path := &path{
env: env,
Expand Down Expand Up @@ -624,3 +571,43 @@ func TestWritePathInfoUnixOutsideHomeOneLevels(t *testing.T) {
got := testWritePathInfo(home, "/mnt/folder/location", "/")
assert.Equal(t, want, got)
}

func TestGetPwd(t *testing.T) {
cases := []struct {
MappedLocationsEnabled bool
Pwd string
Expected string
}{
{MappedLocationsEnabled: true, Pwd: "", Expected: ""},
{MappedLocationsEnabled: true, Pwd: "/usr", Expected: "/usr"},
{MappedLocationsEnabled: true, Pwd: "/usr/home", Expected: "~"},
{MappedLocationsEnabled: true, Pwd: "/usr/home/abc", Expected: "~/abc"},
{MappedLocationsEnabled: true, Pwd: "/a/b/c/d", Expected: "#"},
{MappedLocationsEnabled: true, Pwd: "/a/b/c/d/e/f/g", Expected: "#/e/f/g"},
{MappedLocationsEnabled: true, Pwd: "/z/y/x/w", Expected: "/z/y/x/w"},

{MappedLocationsEnabled: false, Pwd: "", Expected: ""},
{MappedLocationsEnabled: false, Pwd: "/usr/home/abc", Expected: "/usr/home/abc"},
{MappedLocationsEnabled: false, Pwd: "/a/b/c/d/e/f/g", Expected: "/a/b/c/d/e/f/g"},
}

for _, tc := range cases {
env := new(MockedEnvironment)
env.On("getPathSeperator", nil).Return("/")
env.On("homeDir", nil).Return("/usr/home")
env.On("getcwd", nil).Return(tc.Pwd)
path := &path{
env: env,
props: &properties{
values: map[Property]interface{}{
MappedLocationsEnabled: tc.MappedLocationsEnabled,
MappedLocations: map[string]string{
"/a/b/c/d": "#",
},
},
},
}
got := path.getPwd()
assert.Equal(t, tc.Expected, got)
}
}
2 changes: 1 addition & 1 deletion themes/aliens.omp.json
Expand Up @@ -19,7 +19,7 @@
"foreground": "#ffffff",
"background": "#C678DD",
"properties": {
"style": "short"
"style": "full"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion themes/avit.omp.json
Expand Up @@ -10,7 +10,7 @@
"foreground": "#ffffff",
"properties": {
"prefix": "",
"style": "short"
"style": "full"
}
},
{
Expand Down

0 comments on commit 0e5e65d

Please sign in to comment.