Skip to content

Commit

Permalink
completion: complete paths with FilterList
Browse files Browse the repository at this point in the history
Make the completion filtering for paths use the standard FilterList
function. This leads to fuzzy filtering if configured, as per other
completions.

Changelog-changed: Path completion now uses the normal filtering
 mechanism, respecting case sensitivity and the fuzzy completion option.
Signed-off-by: Andrew Jeffery <[email protected]>
Acked-by: Robin Jarry <[email protected]>
  • Loading branch information
Andrew Jeffery authored and rjarry committed Oct 27, 2024
1 parent 5ccd2d0 commit 434ca29
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 22 deletions.
Empty file added commands/testdata/Foobar
Empty file.
60 changes: 46 additions & 14 deletions commands/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,36 +76,57 @@ func QuickTerm(args []string, stdin io.Reader, silent bool) (*app.Terminal, erro

// CompletePath provides filesystem completions given a starting path.
func CompletePath(path string, onlyDirs bool) []string {
return completePath(path, onlyDirs, app.SelectedAccountUiConfig().FuzzyComplete)
}

func completePath(path string, onlyDirs bool, fuzzyComplete bool) []string {
if path == ".." || strings.HasSuffix(path, "/..") {
return []string{path + "/"}
}
if path == "~" || strings.HasPrefix(path, "~/") {
if path == "~" {
path = xdg.HomeDir() + "/"
} else if strings.HasPrefix(path, "~/") {
path = xdg.HomeDir() + strings.TrimPrefix(path, "~")
}
includeHidden := path == "."
if i := strings.LastIndex(path, "/"); i != -1 && i < len(path)-1 {
includeHidden = strings.HasPrefix(path[i+1:], ".")
}

matches, err := filepath.Glob(path + "*")
if err != nil || matches == nil {
return nil
const currentDir = "."
dir, search := filepath.Split(path)
// for `file` case dir will be `` which does not work in listDir
if dir == "" {
dir = currentDir
}

results := make([]string, 0, len(matches))

for _, m := range matches {
if isDir(m) {
entries := listDir(dir, includeHidden)
filteredEntries := make([]string, 0, len(entries))
for _, m := range entries {
testM := m
if dir != currentDir {
testM = dir + m
}
if isDir(testM) {
m += "/"
} else if onlyDirs {
continue
}
if strings.HasPrefix(filepath.Base(m), ".") && !includeHidden {
continue
}
results = append(results, opt.QuoteArg(xdg.TildeHome(m)))
filteredEntries = append(filteredEntries, m)
}

results := filterList(
filteredEntries,
search,
func(s string) string {
if dir != currentDir {
s = dir + s
}
return opt.QuoteArg(xdg.TildeHome(s))
},
fuzzyComplete,
)

sort.Strings(results)

return results
Expand Down Expand Up @@ -244,13 +265,24 @@ func QuoteSpace(s string) string {
// An optional post processing function can be passed to prepend, append or
// quote each value.
func FilterList(
valid []string, search string, postProc func(string) string,
valid []string,
search string,
postProc func(string) string,
) []string {
return filterList(valid, search, postProc, app.SelectedAccountUiConfig().FuzzyComplete)
}

func filterList(
valid []string,
search string,
postProc func(string) string,
fuzzyComplete bool,
) []string {
if postProc == nil {
postProc = opt.QuoteArg
}
out := make([]string, 0, len(valid))
if app.SelectedAccountUiConfig().FuzzyComplete {
if fuzzyComplete {
for _, v := range fuzzy.RankFindFold(search, valid) {
out = append(out, postProc(v.Target))
}
Expand Down
39 changes: 31 additions & 8 deletions commands/util_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package commands_test
package commands

import (
"os"
"testing"

"git.sr.ht/~rjarry/aerc/commands"
"github.com/stretchr/testify/assert"
)

Expand All @@ -13,13 +12,14 @@ func TestCompletePath(t *testing.T) {
defer os.Chdir("..")

vectors := []struct {
arg string
onlyDirs bool
expected []string
arg string
onlyDirs bool
fuzzyComplete bool
expected []string
}{
{
arg: "",
expected: []string{"baz/", "foo.ini", "foo/"},
expected: []string{"Foobar", "baz/", "foo.ini", "foo/"},
},
{
arg: "",
Expand All @@ -32,7 +32,11 @@ func TestCompletePath(t *testing.T) {
},
{
arg: "fo",
expected: []string{"foo.ini", "foo/"},
expected: []string{"Foobar", "foo.ini", "foo/"},
},
{
arg: "Fo",
expected: []string{"Foobar"},
},
{
arg: "..",
Expand All @@ -45,6 +49,7 @@ func TestCompletePath(t *testing.T) {
{
arg: "../testdata/",
expected: []string{
"../testdata/Foobar",
"../testdata/baz/",
"../testdata/foo.ini",
"../testdata/foo/",
Expand All @@ -55,10 +60,28 @@ func TestCompletePath(t *testing.T) {
onlyDirs: true,
expected: []string{"../testdata/foo/"},
},
{
arg: "oo",
expected: []string{},
},
{
arg: "oo",
fuzzyComplete: true,
expected: []string{"Foobar", "foo.ini", "foo/"},
},
{
arg: "../testdata/oo",
expected: []string{},
},
{
arg: "../testdata/oo",
fuzzyComplete: true,
expected: []string{"../testdata/Foobar", "../testdata/foo.ini", "../testdata/foo/"},
},
}
for _, vec := range vectors {
t.Run(vec.arg, func(t *testing.T) {
res := commands.CompletePath(vec.arg, vec.onlyDirs)
res := completePath(vec.arg, vec.onlyDirs, vec.fuzzyComplete)
assert.Equal(t, vec.expected, res)
})
}
Expand Down

0 comments on commit 434ca29

Please sign in to comment.