diff --git a/docs/src/development/vhs/doubleQuoteOpen/out/doubleQuoteOpen.zsh.ascii b/docs/src/development/vhs/doubleQuoteOpen/out/doubleQuoteOpen.zsh.ascii index cfa2153f6..c8c37893f 100644 --- a/docs/src/development/vhs/doubleQuoteOpen/out/doubleQuoteOpen.zsh.ascii +++ b/docs/src/development/vhs/doubleQuoteOpen/out/doubleQuoteOpen.zsh.ascii @@ -22,7 +22,7 @@ ──────────────────────────────────────────────────────────────────────────────── -> example action embeddedP1 "embeddedP2\ with\ space +> example action embeddedP1 "embeddedP2\ with\ space" @@ -30,7 +30,7 @@ ──────────────────────────────────────────────────────────────────────────────── -> example action embeddedP1 "embeddedP2\ with\ space +> example action embeddedP1 "embeddedP2\ with\ space" diff --git a/docs/src/development/vhs/singleQuoteOpen/out/singleQuoteOpen.zsh.ascii b/docs/src/development/vhs/singleQuoteOpen/out/singleQuoteOpen.zsh.ascii index b457ac7aa..eddcf4c0b 100644 --- a/docs/src/development/vhs/singleQuoteOpen/out/singleQuoteOpen.zsh.ascii +++ b/docs/src/development/vhs/singleQuoteOpen/out/singleQuoteOpen.zsh.ascii @@ -22,7 +22,7 @@ ──────────────────────────────────────────────────────────────────────────────── -> example action embeddedP1 'embeddedP2\ with\ space +> example action embeddedP1 'embeddedP2\ with\ space' @@ -30,7 +30,7 @@ ──────────────────────────────────────────────────────────────────────────────── -> example action embeddedP1 'embeddedP2\ with\ space +> example action embeddedP1 'embeddedP2\ with\ space' diff --git a/example/cmd/_test/zsh.sh b/example/cmd/_test/zsh.sh index b2eee982a..51d18578c 100644 --- a/example/cmd/_test/zsh.sh +++ b/example/cmd/_test/zsh.sh @@ -7,9 +7,9 @@ function _example_completion { if echo ${words}"''" | xargs echo 2>/dev/null > /dev/null; then local lines="$(echo ${words}"''" | CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs example _carapace zsh )" elif echo ${words} | sed "s/\$/'/" | xargs echo 2>/dev/null > /dev/null; then - local lines="$(echo ${words} | sed "s/\$/'/" | CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs example _carapace zsh)" + local lines="$(echo ${words} | sed "s/\$/'/" | CARAPACE_STATE=QUOTING_STATE CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs example _carapace zsh)" else - local lines="$(echo ${words} | sed 's/$/"/' | CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs example _carapace zsh)" + local lines="$(echo ${words} | sed 's/$/"/' | CARAPACE_STATE=QUOTING_ESCAPING_STATE CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs example _carapace zsh)" fi local zstyle message data diff --git a/internal/env/env.go b/internal/env/env.go index 54edee6cc..5534535a3 100644 --- a/internal/env/env.go +++ b/internal/env/env.go @@ -6,6 +6,7 @@ import ( "os" "strings" + shlex "github.com/carapace-sh/carapace-shlex" "github.com/carapace-sh/carapace/internal/common" ) @@ -18,6 +19,7 @@ const ( CARAPACE_MATCH = "CARAPACE_MATCH" // match case insensitive CARAPACE_NOSPACE = "CARAPACE_NOSPACE" // nospace suffixes CARAPACE_SANDBOX = "CARAPACE_SANDBOX" // mock context for sandbox tests + CARAPACE_STATE = "CARAPACE_STATE" // current word state CARAPACE_TOOLTIP = "CARAPACE_TOOLTIP" // enable tooltip style CARAPACE_ZSH_HASH_DIRS = "CARAPACE_ZSH_HASH_DIRS" // zsh hash directories CLICOLOR = "CLICOLOR" // disable color @@ -76,6 +78,17 @@ func Tooltip() bool { return getBool(CARAPACE_TOOLTIP) } +func State() shlex.LexerState { + switch os.Getenv(CARAPACE_STATE) { + case "QUOTING_STATE": + return shlex.QUOTING_STATE + case "QUOTING_ESCAPING_STATE": + return shlex.QUOTING_ESCAPING_STATE + default: + return shlex.START_STATE + } +} + func getBool(s string) bool { switch os.Getenv(s) { case "true", "1": diff --git a/internal/shell/zsh/action.go b/internal/shell/zsh/action.go index ff258992d..4ce3d6898 100644 --- a/internal/shell/zsh/action.go +++ b/internal/shell/zsh/action.go @@ -4,7 +4,9 @@ import ( "fmt" "strings" + shlex "github.com/carapace-sh/carapace-shlex" "github.com/carapace-sh/carapace/internal/common" + "github.com/carapace-sh/carapace/internal/env" ) var sanitizer = strings.NewReplacer( @@ -63,6 +65,16 @@ func ActionRawValues(currentWord string, meta common.Meta, values common.RawValu val.Value = quoteValue(val.Value) val.Value = strings.ReplaceAll(val.Value, `\`, `\\`) // TODO find out why `_describe` needs another backslash val.Value = strings.ReplaceAll(val.Value, `:`, `\:`) // TODO find out why `_describe` needs another backslash + + switch env.State() { + // TODO depending on state value needs to be formatted differently + // TODO backspace strings are currently an issue + case shlex.QUOTING_STATE: + val.Value = val.Value + `'` + case shlex.QUOTING_ESCAPING_STATE: + val.Value = val.Value + `"` + } + if !meta.Nospace.Matches(val.Value) { val.Value = val.Value + " " } diff --git a/internal/shell/zsh/snippet.go b/internal/shell/zsh/snippet.go index f2accd495..a116df03e 100644 --- a/internal/shell/zsh/snippet.go +++ b/internal/shell/zsh/snippet.go @@ -19,9 +19,9 @@ function _%v_completion { if echo ${words}"''" | xargs echo 2>/dev/null > /dev/null; then local lines="$(echo ${words}"''" | CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs %v _carapace zsh )" elif echo ${words} | sed "s/\$/'/" | xargs echo 2>/dev/null > /dev/null; then - local lines="$(echo ${words} | sed "s/\$/'/" | CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs %v _carapace zsh)" + local lines="$(echo ${words} | sed "s/\$/'/" | CARAPACE_STATE=QUOTING_STATE CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs %v _carapace zsh)" else - local lines="$(echo ${words} | sed 's/$/"/' | CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs %v _carapace zsh)" + local lines="$(echo ${words} | sed 's/$/"/' | CARAPACE_STATE=QUOTING_ESCAPING_STATE CARAPACE_ZSH_HASH_DIRS="$(hash -d)" xargs %v _carapace zsh)" fi local zstyle message data