From 1458ecdcab0c03eded3151ea5ff7f4c110f16e0e Mon Sep 17 00:00:00 2001 From: TorchedSammy <38820196+TorchedSammy@users.noreply.github.com> Date: Wed, 20 Apr 2022 13:06:46 -0400 Subject: [PATCH] fix: file completions changes changed the way file completions are handed completely, which fixes #130 and makes the full name appear in the completion menu instead of it being cut off --- api.go | 2 +- complete.go | 94 +++++++++++++++++++++++++++-------------------------- rl.go | 9 ++--- 3 files changed, 54 insertions(+), 51 deletions(-) diff --git a/api.go b/api.go index 527ab43..aa141d6 100644 --- a/api.go +++ b/api.go @@ -154,7 +154,7 @@ func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return nil, err } - completions := fileComplete(query, ctx, fds) + completions, _ := fileComplete(query, ctx, fds) luaComps := rt.NewTable() for i, comp := range completions { diff --git a/complete.go b/complete.go index d23cee1..04f9095 100644 --- a/complete.go +++ b/complete.go @@ -6,21 +6,8 @@ import ( "os" ) -func fileComplete(query, ctx string, fields []string) []string { - var completions []string - - prefixes := []string{"./", "../", "/", "~/"} - for _, prefix := range prefixes { - if strings.HasPrefix(query, prefix) { - completions, _ = matchPath(strings.Replace(query, "~", curuser.HomeDir, 1), query) - } - } - - if len(completions) == 0 && len(fields) > 1 { - completions, _ = matchPath("./" + query, query) - } - - return completions +func fileComplete(query, ctx string, fields []string) ([]string, string) { + return matchPath(query) } func binaryComplete(query, ctx string, fields []string) ([]string, string) { @@ -29,17 +16,17 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) { prefixes := []string{"./", "../", "/", "~/"} for _, prefix := range prefixes { if strings.HasPrefix(query, prefix) { - fileCompletions := fileComplete(query, ctx, fields) + fileCompletions, filePref := matchPath(query) if len(fileCompletions) != 0 { for _, f := range fileCompletions { - name := strings.Replace(query + f, "~", curuser.HomeDir, 1) - if err := findExecutable(name, false, true); err != nil { + fullPath, _ := filepath.Abs(expandHome(query + strings.TrimPrefix(f, filePref))) + if err := findExecutable(fullPath, false, true); err != nil { continue } completions = append(completions, f) } } - return completions, "" + return completions, filePref } } @@ -75,37 +62,52 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) { return completions, query } -func matchPath(path, pref string) ([]string, error) { +func matchPath(query string) ([]string, string) { var entries []string - matches, err := filepath.Glob(path + "*") - if err == nil { - args := []string{ - "\"", "\\\"", - "'", "\\'", - "`", "\\`", - " ", "\\ ", - "(", "\\(", - ")", "\\)", - "[", "\\[", - "]", "\\]", - } + var baseName string - r := strings.NewReplacer(args...) - for _, match := range matches { - name := filepath.Base(match) - p := filepath.Base(pref) - if pref == "" || pref == "./" { - p = "" + path, _ := filepath.Abs(expandHome(filepath.Dir(query))) + if string(query) == "" { + // filepath base below would give us "." + // which would cause a match of only dotfiles + path, _ = filepath.Abs(".") + } else if !strings.HasSuffix(query, string(os.PathSeparator)) { + baseName = filepath.Base(query) + } + + files, _ := os.ReadDir(path) + for _, file := range files { + if strings.HasPrefix(file.Name(), baseName) { + entry := file.Name() + if file.IsDir() { + entry = entry + string(os.PathSeparator) } - name = strings.TrimPrefix(name, p) - matchFull, _ := filepath.Abs(match) - if info, err := os.Stat(matchFull); err == nil && info.IsDir() { - name = name + string(os.PathSeparator) - } - name = r.Replace(name) - entries = append(entries, name) + entry = escapeFilename(entry) + entries = append(entries, entry) } } - return entries, err + return entries, baseName +} + +func escapeFilename(fname string) string { + args := []string{ + "\"", "\\\"", + "'", "\\'", + "`", "\\`", + " ", "\\ ", + "(", "\\(", + ")", "\\)", + "[", "\\[", + "]", "\\]", + "$", "\\$", + "&", "\\&", + "*", "\\*", + ">", "\\>", + "<", "\\<", + "|", "\\|", + } + + r := strings.NewReplacer(args...) + return r.Replace(fname) } diff --git a/rl.go b/rl.go index 8975877..8093273 100644 --- a/rl.go +++ b/rl.go @@ -86,7 +86,6 @@ func newLineReader(prompt string, noHist bool) *lineReader { } rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) { ctx := string(line) - var completions []string var compGroup []*readline.CompletionGroup @@ -237,12 +236,14 @@ func newLineReader(prompt string, noHist bool) *lineReader { } if len(compGroup) == 0 { - completions = fileComplete(query, ctx, fields) - compGroup = append(compGroup, &readline.CompletionGroup{ + completions, p := fileComplete(query, ctx, fields) + fcompGroup := []*readline.CompletionGroup{{ TrimSlash: false, NoSpace: true, Suggestions: completions, - }) + }} + + return p, fcompGroup } } return "", compGroup