Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pkg/gui/controllers/helpers/worktree_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,11 @@ func (self *WorktreeHelper) NewWorktreeCheckout(base string, canCheckoutBase boo
self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.NewWorktreePath,
HandleConfirm: func(path string) error {
opts.Path = path
expanded, err := utils.ExpandHomeDir(path)
if err != nil {
return err
}
opts.Path = expanded

if detached {
return f()
Expand Down
37 changes: 37 additions & 0 deletions pkg/utils/path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package utils

import (
"errors"
"os"
"path/filepath"
"strings"
)

// ExpandHomeDir expands a leading "~" or "~/" in path to the user's
// home directory. Paths that do not begin with "~" are returned
// unchanged, including the empty string.
//
// We deliberately only support "~" for the current user (no
// "~user" syntax) because that is what the shells lazygit users
// expect to see lazygit honour, and the cross-platform story for
// other-user expansion is messy.
//
// If path begins with "~" but the home directory cannot be
// determined, the unexpanded path is returned along with the error.
func ExpandHomeDir(path string) (string, error) {
if path == "" || path[0] != '~' {
return path, nil
}
// Only "~" alone or "~/..." — not "~user/...".
if path != "~" && !strings.HasPrefix(path, "~"+string(filepath.Separator)) && !strings.HasPrefix(path, "~/") {
return path, errors.New("only the current user's home directory can be expanded with ~")
}
home, err := os.UserHomeDir()
if err != nil {
return path, err
}
if path == "~" {
return home, nil
}
return filepath.Join(home, path[2:]), nil
}
72 changes: 72 additions & 0 deletions pkg/utils/path_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package utils

import (
"os"
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

func TestExpandHomeDir(t *testing.T) {
home, err := os.UserHomeDir()
if err != nil {
t.Fatalf("UserHomeDir failed: %v", err)
}

scenarios := []struct {
name string
input string
expected string
wantErr bool
}{
{
name: "empty stays empty",
input: "",
expected: "",
},
{
name: "no tilde left untouched",
input: filepath.Join("path", "to", "thing"),
expected: filepath.Join("path", "to", "thing"),
},
{
name: "absolute path left untouched",
input: "/absolute/path",
expected: "/absolute/path",
},
{
name: "tilde alone expands to home",
input: "~",
expected: home,
},
{
name: "tilde slash expands to home/rest",
input: "~/foo/bar",
expected: filepath.Join(home, "foo", "bar"),
},
{
name: "tilde without separator (~user style) is rejected",
input: "~bob/foo",
expected: "~bob/foo",
wantErr: true,
},
{
name: "tilde mid-path is not expanded",
input: filepath.Join("foo", "~", "bar"),
expected: filepath.Join("foo", "~", "bar"),
},
}

for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
got, err := ExpandHomeDir(s.input)
if s.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
assert.Equal(t, s.expected, got)
})
}
}