Skip to content

Commit

Permalink
bash: fix path containing space with ~ prefix
Browse files Browse the repository at this point in the history
Path was only partially quoted for homedir expansion to work.
But seems bash doesn't like this so we need to use escaping.
  • Loading branch information
rsteube committed Feb 20, 2025
1 parent 546cbd9 commit d0a0896
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 14 deletions.
1 change: 1 addition & 0 deletions complete.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func complete(cmd *cobra.Command, args []string) (string, error) {
case "bash": // TODO what about oil and such?
LOG.Printf("COMP_LINE is %#v", os.Getenv("COMP_LINE"))
LOG.Printf("COMP_POINT is %#v", os.Getenv("COMP_POINT"))
LOG.Printf("COMP_WORDBREAKS is %#v", os.Getenv("COMP_WORDBREAKS"))
var err error
args, err = bash.Patch(args) // handle redirects
LOG.Printf("patching args to %#v", args)
Expand Down
44 changes: 30 additions & 14 deletions internal/shell/bash/action.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,36 @@ var sanitizer = strings.NewReplacer(
"\t", ``,
)

var valueReplacer = strings.NewReplacer(
var escapingQuotedReplacer = strings.NewReplacer(
`\`, `\\`,
`"`, `\"`,
`$`, `\$`,
"`", "\\`",
)

var escapingReplacer = strings.NewReplacer(
`\`, `\\`,
`&`, `\&`,
`<`, `\<`,
`>`, `\>`,
"`", "\\`",
`'`, `\'`,
`"`, `\"`,
`{`, `\{`,
`}`, `\}`,
`$`, `\$`,
`#`, `\#`,
`|`, `\|`,
`?`, `\?`,
`(`, `\(`,
`)`, `\)`,
`;`, `\;`,
` `, `\ `,
`[`, `\[`,
`]`, `\]`,
`*`, `\*`,
)

var displayReplacer = strings.NewReplacer(
`${`, `\\\${`,
)
Expand Down Expand Up @@ -81,19 +104,11 @@ func ActionRawValues(currentWord string, meta common.Meta, values common.RawValu
nospace = nospace || meta.Nospace.Matches(val.Value)

vals[index] = sanitizer.Replace(val.Value)
if requiresQuoting(vals[index]) {
vals[index] = valueReplacer.Replace(vals[index])
switch {
case strings.HasPrefix(vals[index], "~"): // assume homedir expansion
if splitted := strings.SplitAfterN(vals[index], "/", 2); len(splitted) == 2 {
vals[index] = fmt.Sprintf(`%v"%v"`, splitted[0], splitted[1])
} else {
// TODO homedir expansion won't work this way, but shouldn't reach this point anyway.
vals[index] = fmt.Sprintf(`~"%v"`, strings.TrimPrefix(vals[index], "~"))
}
default:
vals[index] = fmt.Sprintf(`"%v"`, vals[index])
}
switch {
case strings.HasPrefix(vals[index], "~"): // assume homedir expansion
vals[index] = escapingReplacer.Replace(vals[index])
case requiresQuoting(vals[index]):
vals[index] = fmt.Sprintf(`"%v"`, escapingQuotedReplacer.Replace(vals[index]))
}
} else {
nospace = true
Expand All @@ -111,6 +126,7 @@ func ActionRawValues(currentWord string, meta common.Meta, values common.RawValu

func requiresQuoting(s string) bool {
chars := " \t\r\n`" + `[]{}()<>;|$&:*#`
chars += `'"`
chars += os.Getenv("COMP_WORDBREAKS")
chars += `\`
return strings.ContainsAny(s, chars)
Expand Down

0 comments on commit d0a0896

Please sign in to comment.