Repository: rsteube/carapace
Pull request #188 (2020-12-29 12:05:45)

skip script generation
TODO:
- [ ] fix multiparts actions
- [x] fix value with space
- [x] readd bash/oil autoinsertion when all values hav the same prefix (display value insertead instead)
- [ ] get rid of `eval`?
- [x] zsh: missing flags on `gh issue --`, `gh issue list --`


#183 


Patch:
diff --git a/action.go b/action.go
index 6a5bb31..a5b3be5 100644
--- a/action.go
+++ b/action.go
@@ -56,34 +56,6 @@ func (a ActionMap) shell(shell string) map[string]string {
 
 type CompletionCallback func(args []string) Action
 
-// finalize replaces value if a callback function is set
-func (a Action) finalize(cmd *cobra.Command, uid string) Action {
-	if a.callback != nil {
-		if a.bash == nil {
-			a.bash = func() string { return bash.Callback(cmd.Root().Name(), uid) }
-		}
-		if a.elvish == nil {
-			a.elvish = func() string { return elvish.Callback(cmd.Root().Name(), uid) }
-		}
-		if a.fish == nil {
-			a.fish = func() string { return fish.Callback(cmd.Root().Name(), uid) }
-		}
-		if a.oil == nil {
-			a.oil = func() string { return oil.Callback(cmd.Root().Name(), uid) }
-		}
-		if a.powershell == nil {
-			a.powershell = func() string { return powershell.Callback(cmd.Root().Name(), uid) }
-		}
-		if a.xonsh == nil {
-			a.xonsh = func() string { return xonsh.Callback(cmd.Root().Name(), uid) }
-		}
-		if a.zsh == nil {
-			a.zsh = func() string { return zsh.Callback(cmd.Root().Name(), uid) }
-		}
-	}
-	return a
-}
-
 func (a Action) Cache(timeout time.Duration, keys ...pkgcache.CacheKey) Action {
 	if a.callback != nil { // only relevant for callback actions
 		cachedCallback := a.callback
@@ -234,30 +206,16 @@ func ActionBool() Action {
 
 // ActionDirectories completes directories
 func ActionDirectories() Action {
-	return Action{
-		bash:       func() string { return bash.ActionDirectories() },
-		elvish:     func() string { return elvish.ActionDirectories() },
-		fish:       func() string { return fish.ActionDirectories() },
-		oil:        func() string { return oil.ActionDirectories() },
-		powershell: func() string { return powershell.ActionDirectories() },
-		xonsh:      func() string { return xonsh.ActionDirectories() },
-		zsh:        func() string { return zsh.ActionDirectories() },
-		callback:   func(args []string) Action { return actionPath("", true) },
-	}
+	return ActionCallback(func(args []string) Action {
+		return actionPath("", true).Invoke(args).ToMultiPartsA("/")
+	})
 }
 
 // ActionFiles completes files with optional suffix filtering
 func ActionFiles(suffix string) Action {
-	return Action{
-		bash:       func() string { return bash.ActionFiles(suffix) },
-		elvish:     func() string { return elvish.ActionFiles(suffix) },
-		fish:       func() string { return fish.ActionFiles(suffix) },
-		oil:        func() string { return oil.ActionFiles(suffix) },
-		powershell: func() string { return powershell.ActionFiles(suffix) },
-		xonsh:      func() string { return xonsh.ActionFiles(suffix) },
-		zsh:        func() string { return zsh.ActionFiles("*" + suffix) },
-		callback:   func(args []string) Action { return actionPath(suffix, false) },
-	}
+	return ActionCallback(func(args []string) Action {
+		return actionPath(suffix, false).Invoke(args).ToMultiPartsA("/")
+	})
 }
 
 func actionPath(fileSuffix string, dirOnly bool) Action {
@@ -331,6 +289,9 @@ var CallbackValue string
 // ActionMultiParts completes multiple parts of words separately where each part is separated by some char (CallbackValue is set to the currently completed part during invocation)
 func ActionMultiParts(divider string, callback func(args []string, parts []string) Action) Action {
 	return ActionCallback(func(args []string) Action {
+		oldValue := CallbackValue
+		defer func() { CallbackValue = oldValue }() // TODO verify this
+
 		index := strings.LastIndex(CallbackValue, string(divider))
 		prefix := ""
 		if len(divider) == 0 {
diff --git a/carapace.go b/carapace.go
index 255c3ee..6ca7055 100644
--- a/carapace.go
+++ b/carapace.go
@@ -1,4 +1,4 @@
-// Pacakge carapace provides multi-shell completion script generation for spf13/cobra
+// Package carapace provides multi-shell completion script generation for spf13/cobra
 package carapace
 
 import (
@@ -39,12 +39,12 @@ func Gen(cmd *cobra.Command) *Carapace {
 
 func (c Carapace) PositionalCompletion(action ...Action) {
 	for index, a := range action {
-		actionMap[uid.Positional(c.cmd, index+1)] = a.finalize(c.cmd, uid.Positional(c.cmd, index+1))
+		actionMap[uid.Positional(c.cmd, index+1)] = a
 	}
 }
 
 func (c Carapace) PositionalAnyCompletion(action Action) {
-	actionMap[uid.Positional(c.cmd, 0)] = action.finalize(c.cmd, uid.Positional(c.cmd, 0))
+	actionMap[uid.Positional(c.cmd, 0)] = action
 }
 
 func (c Carapace) FlagCompletion(actions ActionMap) {
@@ -52,7 +52,7 @@ func (c Carapace) FlagCompletion(actions ActionMap) {
 		if flag := c.cmd.LocalFlags().Lookup(name); flag == nil {
 			fmt.Fprintf(os.Stderr, "unknown flag: %v\n", name)
 		} else {
-			actionMap[uid.Flag(c.cmd, flag)] = action.finalize(c.cmd, uid.Flag(c.cmd, flag))
+			actionMap[uid.Flag(c.cmd, flag)] = action
 		}
 	}
 }
@@ -66,8 +66,8 @@ func (c Carapace) Standalone() {
 	c.cmd.Root().SetHelpCommand(&cobra.Command{Hidden: true})
 }
 
-func (c Carapace) Snippet(shell string, lazy bool) (string, error) {
-	var snippet func(cmd *cobra.Command, actions map[string]string, lazy bool) string
+func (c Carapace) Snippet(shell string) (string, error) {
+	var snippet func(cmd *cobra.Command, actions map[string]string) string
 
 	if shell == "" {
 		shell = determineShell()
@@ -90,7 +90,7 @@ func (c Carapace) Snippet(shell string, lazy bool) (string, error) {
 	default:
 		return "", errors.New(fmt.Sprintf("expected 'bash', 'elvish', 'fish', 'oil', 'powershell', 'xonsh' or 'zsh' [was: %v]", shell))
 	}
-	return snippet(c.cmd.Root(), actionMap.shell(shell), lazy), nil
+	return snippet(c.cmd.Root(), actionMap.shell(shell)), nil
 }
 
 func lookupFlag(cmd *cobra.Command, arg string) (flag *pflag.Flag) {
@@ -117,7 +117,7 @@ func addCompletionCommand(cmd *cobra.Command) {
 			logger.Println(os.Args) // TODO replace last with '' if empty
 
 			if len(args) == 0 {
-				if s, err := Gen(cmd).Snippet(determineShell(), true); err != nil {
+				if s, err := Gen(cmd).Snippet(determineShell()); err != nil {
 					fmt.Fprintln(io.MultiWriter(os.Stderr, logger.Writer()), err.Error())
 				} else {
 					fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), s)
@@ -130,7 +130,7 @@ func addCompletionCommand(cmd *cobra.Command) {
 							fmt.Printf("%v:\t%v\n", uid, action)
 						}
 					default:
-						if s, err := Gen(cmd).Snippet(args[0], false); err != nil {
+						if s, err := Gen(cmd).Snippet(args[0]); err != nil {
 							fmt.Fprintln(io.MultiWriter(os.Stderr, logger.Writer()), err.Error())
 						} else {
 							fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), s)
@@ -147,12 +147,12 @@ func addCompletionCommand(cmd *cobra.Command) {
 						current := os.Args[len(os.Args)-1]
 						previous := os.Args[len(os.Args)-2]
 						if strings.HasPrefix(current, "-") { // assume flag
-							if strings.Contains(current, "=") { // complate value for optarg flag
+							if strings.Contains(current, "=") { // complete value for optarg flag
 								if flag := lookupFlag(targetCmd, current); flag != nil && flag.NoOptDefVal != "" {
 									if a, ok := actionMap[uid.Flag(targetCmd, flag)]; ok {
 										CallbackValue = current // TODO verify
 										// TODO no value for oil (elvish works)
-										fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), a.Invoke(targetArgs).ToA().Value(shell))
+										fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), a.Invoke(targetArgs).Prefix(strings.SplitN(current, "=", 2)[0]+"=").ToA().Value(shell))
 									}
 								}
 							} else { // complete flagnames
@@ -164,7 +164,12 @@ func addCompletionCommand(cmd *cobra.Command) {
 								fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), a.Invoke(targetArgs).ToA().Value(shell))
 							}
 						} else if targetCmd.HasAvailableSubCommands() && len(targetArgs) <= 1 {
-							fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), actionSubcommands(targetCmd).Value(shell))
+							CallbackValue = current // TODO verify (now set multiple times, isn't this always current anyway?)
+							subcommandA := actionSubcommands(targetCmd)
+							if _, a, ok := findAction(targetCmd, targetArgs); ok {
+								subcommandA = a.Invoke(targetArgs).Merge(subcommandA.Invoke(targetArgs)).ToA()
+							}
+							fmt.Fprintln(io.MultiWriter(os.Stdout, logger.Writer()), subcommandA.Value(shell))
 						} else {
 							if _uid, action, ok := findAction(targetCmd, targetArgs); ok {
 								CallbackValue = uid.Value(targetCmd, targetArgs, _uid)
diff --git a/go.mod b/go.mod
index 27998c2..d3309ee 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/rsteube/carapace
 go 1.12
 
 require (
+	github.com/google/martian v2.1.0+incompatible
 	github.com/spf13/cobra v1.1.1
 	github.com/spf13/pflag v1.0.5
 )
diff --git a/go.sum b/go.sum
index eb058c6..cb3a672 100644
--- a/go.sum
+++ b/go.sum
@@ -57,6 +57,7 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
 github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
diff --git a/internal/bash/action.go b/internal/bash/action.go
index 0f1f2eb..9008151 100644
--- a/internal/bash/action.go
+++ b/internal/bash/action.go
@@ -2,6 +2,7 @@ package bash
 
 import (
 	"fmt"
+	"os"
 	"strings"
 
 	"github.com/rsteube/carapace/internal/common"
@@ -32,28 +33,79 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func Callback(prefix string, uid string) string {
-	return fmt.Sprintf(`eval $(_%v_callback '%v')`, prefix, uid)
+func EscapeSpace(s string) string {
+	return strings.Replace(s, " ", `\ `, -1)
 }
 
-func ActionDirectories() string {
-	return `compgen -S / -d -- "$cur"`
+func commonPrefix(a, b string) string {
+	i := 0
+	for i < len(a) && i < len(b) && a[i] == b[i] {
+		i++
+	}
+	return a[0:i]
 }
 
-func ActionFiles(suffix string) string {
-	return fmt.Sprintf(`compgen -S / -d -- "$cur"; compgen -f -X '!*%v' -- "$cur"`, suffix)
+func commonDisplayPrefix(values ...common.RawValue) (prefix string) {
+	for index, val := range values {
+		if index == 0 {
+			prefix = val.Display
+		} else {
+			prefix = commonPrefix(prefix, val.Display)
+		}
+	}
+	return
 }
 
-func ActionRawValues(values ...common.RawValue) string {
-	vals := make([]string, len(values))
+func commonValuePrefix(values ...common.RawValue) (prefix string) {
 	for index, val := range values {
-		formattedVal := strings.Replace(sanitizer.Replace(val.Value), " ", `\ `, -1)
-		if val.Description == "" {
-			vals[index] = fmt.Sprintf(`%v\t%v`, formattedVal, val.Display)
+		if index == 0 {
+			prefix = val.Value
 		} else {
-			vals[index] = fmt.Sprintf(`%v\t%v (%v)`, formattedVal, val.Display, sanitizer.Replace(val.Description))
+			prefix = commonPrefix(prefix, val.Value)
 		}
 	}
+	return
+}
 
-	return fmt.Sprintf(`compgen -W $'%v' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'`, strings.Join(vals, `\n`))
+func ActionRawValues(values ...common.RawValue) string {
+	filtered := make([]common.RawValue, 0)
+	callbackValue := os.Args[len(os.Args)-1]
+
+	for _, r := range values {
+		if strings.HasPrefix(r.Value, callbackValue) {
+			// TODO optimize
+			if wordbreaks, ok := os.LookupEnv("COMP_WORDBREAKS"); ok {
+				wordbreaks = strings.Replace(wordbreaks, " ", "", -1)
+				if index := strings.LastIndexAny(callbackValue, wordbreaks); index != -1 {
+					r.Value = strings.TrimPrefix(r.Value, callbackValue[:index+1])
+				}
+			}
+			filtered = append(filtered, r)
+		}
+	}
+
+	if len(filtered) > 1 && commonDisplayPrefix(filtered...) != "" {
+		// When all display values have the same prefix bash will insert is as partial completion (which skips prefixes/formatting).
+		if valuePrefix := commonValuePrefix(filtered...); callbackValue != valuePrefix {
+			// replace values with common value prefix (`\001` is removed in snippet and compopt nospace will be set)
+			filtered = common.RawValuesFrom(commonValuePrefix(filtered...) + "\001")
+		} else {
+			// prevent insertion of partial display values by prefixing one with space
+			filtered[0].Display = " " + filtered[0].Display
+		}
+	}
+
+	vals := make([]string, len(filtered))
+	for index, val := range filtered {
+		if len(filtered) == 1 {
+			vals[index] = EscapeSpace(sanitizer.Replace(val.Value))
+		} else {
+			if val.Description != "" {
+				vals[index] = fmt.Sprintf("%v (%v)", val.Display, sanitizer.Replace(val.Description))
+			} else {
+				vals[index] = val.Display
+			}
+		}
+	}
+	return strings.Join(vals, "\n")
 }
diff --git a/internal/bash/snippet.go b/internal/bash/snippet.go
index 7b9c48f..c5db048 100644
--- a/internal/bash/snippet.go
+++ b/internal/bash/snippet.go
@@ -2,224 +2,29 @@ package bash
 
 import (
 	"fmt"
-	"strings"
 
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
-func snippetLazy(cmd *cobra.Command) string {
-	return fmt.Sprintf(`#!/bin/bash
-_%v_completions() {
-   source <(%v _carapace bash) 
-   _%v_completions
-}
-complete -F _%v_completions %v
-`, cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), cmd.Name())
-}
-
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
-	if lazy {
-		return snippetLazy(cmd)
-	}
-
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
 	result := fmt.Sprintf(`#!/bin/bash
-_%v_callback() {
-  local compline="${COMP_LINE:0:${COMP_POINT}}"
-  # TODO
-  #if [[ $last =~ ^[\"\'] ]] && ! echo "$last" | xargs echo 2>/dev/null >/dev/null ; then
-  #    compline="${compline}${last:0:1}"
-  #    last="${last// /\\\\ }" 
-  #fi
-
-  echo "$compline" | sed -e "s/ $/ ''/" -e 's/"/\"/g' | xargs %v _carapace bash "$1"
-}
+_%v_completion() {
+  export COMP_WORDBREAKS
 
-_%v_completions() {
-  local cur prev #words cword split
-  _init_completion -n /=:.,
-  local curprefix
-  curprefix="$(echo "$cur" | sed -r 's_^(.*[:=])?.*_\1_')"
   local compline="${COMP_LINE:0:${COMP_POINT}}"
- 
-  # TODO
-  #if [[ $last =~ ^[\"\'] ]] && ! echo "$last" | xargs echo 2>/dev/null >/dev/null ; then
-  #    compline="${compline}${last:0:1}"
-  #    last="${last// /\\\\ }" 
-  #else
-  #    last="${last// /\\\ }" 
-  #fi
-
-  local state
-  state="$(echo "$compline" | sed -e "s/ \$/ ''/" -e 's/"/\"/g' | xargs %v _carapace bash state)"
-
   local IFS=$'\n'
+  mapfile -t COMPREPLY < <(echo "$compline" | sed -e "s/ \$/ ''/" -e 's/"/\"/g' | xargs %v _carapace bash "_")
+  [[ "${COMPREPLY[*]}" == "" ]] && COMPREPLY=() # fix for mapfile creating a non-empty array from empty command output
 
-  case $state in
-%v
-  esac
-
-  [[ $cur =~ ^[\"\'] ]] && COMPREPLY=("${COMPREPLY[@]//\\ /\ }")
-  
-  [[ ${#COMPREPLY[@]} -gt 1 ]] && for entry in "${COMPREPLY[@]}"; do
-    value="${entry%%	*}"
-    display="${entry#*	}"
-    if [[ "${value::1}" != "${display::1}"  ]]; then # inserted value differs from display value
-       [[ "$(printf  "%%c\n" "${COMPREPLY[@]#*	}" | uniq | wc -l)" -eq 1 ]] && COMPREPLY=("${COMPREPLY[@]}" "") # prevent insertion if all have same first character (workaround for #164)
-      break
-    fi
-  done
-
-  [[ ${#COMPREPLY[@]} -gt 1 ]] && COMPREPLY=("${COMPREPLY[@]#*	}") # show visual part (all after tab)
-  [[ ${#COMPREPLY[@]} -eq 1 ]] && COMPREPLY=( ${COMPREPLY[0]%%	*} ) # show value to insert (all before tab) https://stackoverflow.com/a/10130007
-  [[ ${COMPREPLY[0]} == *[/=@:.,] ]] && compopt -o nospace
+  [[ ${COMPREPLY[0]} == *[/=@:.,$'\001'] ]] && compopt -o nospace
+  # TODO use mapfile
+  # shellcheck disable=SC2206
+  [[ ${#COMPREPLY[@]} -eq 1 ]] && COMPREPLY=(${COMPREPLY%%$'\001'})
 }
 
-complete -F _%v_completions %v
-`, cmd.Name(), uid.Executable(), cmd.Name(), uid.Executable(), snippetFunctions(cmd, actions), cmd.Name(), cmd.Name())
+complete -F _%v_completion %v
+`, cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name())
 
 	return result
 }
-
-func snippetFunctions(cmd *cobra.Command, actions map[string]string) string {
-	function_pattern := `
-    '%v' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-%v
-          *)
-            COMPREPLY=($(%v))
-            ;;
-        esac
-      else
-        case $prev in
-%v
-          *)
-            COMPREPLY=($(%v))
-            ;;
-        esac
-      fi
-      ;;
-`
-
-	optArgflags := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
-		if !f.Hidden {
-			var s string
-			if action, ok := actions[uid.Flag(cmd, f)]; ok {
-				s = snippetFlagCompletion(f, action, true)
-			} else {
-				s = snippetFlagCompletion(f, "", true)
-			}
-			if s != "" {
-				optArgflags = append(optArgflags, s)
-			}
-		}
-	})
-
-	flags := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
-		if !f.Hidden {
-			var s string
-			if action, ok := actions[uid.Flag(cmd, f)]; ok {
-				s = snippetFlagCompletion(f, action, false)
-			} else {
-				s = snippetFlagCompletion(f, "", false)
-			}
-			if s != "" {
-				flags = append(flags, s)
-			}
-		}
-	})
-
-	var positionalAction string
-	if cmd.HasAvailableSubCommands() {
-		subcommands := make([]common.RawValue, 0)
-		for _, c := range cmd.Commands() {
-			if !c.Hidden {
-				subcommands = append(subcommands, common.RawValue{Value: c.Name(), Display: c.Name(), Description: c.Short})
-				for _, alias := range c.Aliases {
-					subcommands = append(subcommands, common.RawValue{Value: alias, Display: c.Name(), Description: c.Short})
-				}
-			}
-		}
-		positionalAction = ActionRawValues(subcommands...)
-	} else {
-		positionalAction = Callback(cmd.Root().Name(), "_")
-	}
-
-	result := make([]string, 0)
-	result = append(result, fmt.Sprintf(function_pattern, uid.Command(cmd), strings.Join(optArgflags, "\n"), snippetFlagList(cmd.LocalFlags()), strings.Join(flags, "\n"), positionalAction))
-	for _, subcmd := range cmd.Commands() {
-		if !subcmd.Hidden {
-			result = append(result, snippetFunctions(subcmd, actions))
-		}
-	}
-	return strings.Join(result, "\n")
-}
-
-func snippetFlagList(flags *pflag.FlagSet) string {
-	flagValues := make([]common.RawValue, 0)
-
-	flags.VisitAll(func(flag *pflag.Flag) {
-		if !flag.Hidden {
-			if !common.IsShorthandOnly(flag) {
-				flagValues = append(flagValues, common.RawValue{Value: "--" + flag.Name, Display: "--" + flag.Name, Description: flag.Usage})
-			}
-			if flag.Shorthand != "" {
-				flagValues = append(flagValues, common.RawValue{Value: "-" + flag.Shorthand, Display: "-" + flag.Shorthand, Description: flag.Usage})
-			}
-		}
-	})
-	if len(flagValues) > 0 {
-		return ActionRawValues(flagValues...)
-	} else {
-		return ""
-	}
-}
-
-func snippetFlagCompletion(flag *pflag.Flag, action string, optArgFlag bool) (snippet string) {
-	// TODO cleanup this mess
-	if flag.Value.Type() == "bool" {
-		return
-	}
-	if flag.NoOptDefVal != "" && !optArgFlag {
-		return
-	}
-	if flag.NoOptDefVal == "" && optArgFlag {
-		return
-	}
-
-	optArgSuffix := ""
-	if flag.NoOptDefVal != "" {
-		optArgSuffix = "=*"
-	}
-
-	var names string
-	if flag.Shorthand != "" {
-		if common.IsShorthandOnly(flag) {
-			names = fmt.Sprintf("-%v", flag.Shorthand+optArgSuffix)
-		} else {
-			names = fmt.Sprintf("-%v | --%v", flag.Shorthand+optArgSuffix, flag.Name+optArgSuffix)
-		}
-	} else {
-		names = "--" + flag.Name + optArgSuffix
-	}
-
-	if optArgFlag {
-		return fmt.Sprintf(`          %v)
-            cur=${cur#*=}
-            curprefix=${curprefix#*=}
-            COMPREPLY=($(%v))
-            ;;
-`, names, action)
-
-	} else {
-		return fmt.Sprintf(`          %v)
-            COMPREPLY=($(%v))
-            ;;
-`, names, action)
-	}
-}
diff --git a/internal/common/value.go b/internal/common/value.go
index aa8c091..570be0d 100644
--- a/internal/common/value.go
+++ b/internal/common/value.go
@@ -13,3 +13,9 @@ func RawValuesFrom(values ...string) []RawValue {
 	}
 	return rawValues
 }
+
+type ByValue []RawValue
+
+func (a ByValue) Len() int           { return len(a) }
+func (a ByValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
+func (a ByValue) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/internal/elvish/action.go b/internal/elvish/action.go
index f114df9..6508996 100644
--- a/internal/elvish/action.go
+++ b/internal/elvish/action.go
@@ -32,18 +32,6 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func Callback(prefix string, uid string) string {
-	return fmt.Sprintf(`_%v_callback '%v'`, prefix, uid)
-}
-
-func ActionDirectories() string {
-	return `edit:complete-filename $arg[-1]` // TODO
-}
-
-func ActionFiles(suffix string) string {
-	return `edit:complete-filename $arg[-1]` // TODO
-}
-
 func ActionRawValues(values ...common.RawValue) string {
 	vals := make([]string, len(values))
 	for index, val := range values {
diff --git a/internal/elvish/snippet.go b/internal/elvish/snippet.go
index 83b1283..238b6a5 100644
--- a/internal/elvish/snippet.go
+++ b/internal/elvish/snippet.go
@@ -2,12 +2,9 @@ package elvish
 
 import (
 	"fmt"
-	"strings"
-
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
+	"strings"
 )
 
 var replacer = strings.NewReplacer( // TODO
@@ -19,134 +16,12 @@ var replacer = strings.NewReplacer( // TODO
 	`'`, `\"`,
 )
 
-func snippetLazy(cmd *cobra.Command) string {
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
 	return fmt.Sprintf(`edit:completion:arg-completer[%v] = [@arg]{
-    edit:completion:arg-completer[%v] = [@arg]{}
-    eval (%v _carapace elvish | slurp)
-    $edit:completion:arg-completer[%v] $@arg
-}
-`, cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name())
-}
-
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
-	if lazy {
-		return snippetLazy(cmd)
-	}
-
-	result := fmt.Sprintf(`use str
-edit:completion:arg-completer[%v] = [@arg]{
-  fn _%v_callback [uid]{
     if (eq $arg[-1] "") {
         arg[-1] = "''"
     }
-    eval (echo (str:join "\001" $arg) | xargs --delimiter="\001" %v _carapace elvish $uid | slurp) &ns=(ns [&arg=$arg])
-  }
-
-  fn subindex [subcommand]{
-    # TODO 'edit:complete-getopt' needs the arguments shortened for subcommmands - pretty optimistic here
-    index=1
-    for x $arg { if (eq $x $subcommand) { break } else { index = (+ $index 1) } } 
-    echo $index
-  }
-  
-  state=(echo (str:join ' ' $arg) | xargs %v _carapace elvish state)
-  if (eq 1 0) {
-  } %v
+    eval (%v _carapace elvish _ (all $arg) | slurp) &ns=(ns [&arg=$arg])
 }
-`, cmd.Name(), cmd.Name(), uid.Executable(), uid.Executable(), snippetFunctions(cmd, actions))
-
-	return result
-}
-
-func snippetFunctions(cmd *cobra.Command, actions map[string]string) string {
-	function_pattern := ` elif (eq $state '%v') {
-    opt-specs = [
-%v
-    ]
-    arg-handlers = [
-%v
-    ]
-    subargs = $arg[(subindex %v):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }`
-
-	flags := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(f *pflag.Flag) {
-		if !f.Hidden {
-			var s string
-			if action, ok := actions[uid.Flag(cmd, f)]; ok {
-				s = snippetFlagCompletion(f, action)
-			} else {
-				s = snippetFlagCompletion(f, "")
-			}
-			flags = append(flags, s)
-		}
-	})
-
-	var positionals []string
-	if cmd.HasAvailableSubCommands() {
-		subcommands := make([]common.RawValue, 0)
-		for _, c := range cmd.Commands() {
-			if !c.Hidden {
-				subcommands = append(subcommands, common.RawValue{Value: c.Name(), Display: c.Name(), Description: c.Short})
-				for _, alias := range c.Aliases {
-					subcommands = append(subcommands, common.RawValue{Value: alias, Display: alias, Description: c.Short})
-				}
-			}
-		}
-		positionals = []string{"        " + snippetPositionalCompletion(ActionRawValues(subcommands...))}
-	} else {
-		pos := 1
-		for {
-			if action, ok := actions[uid.Positional(cmd, pos)]; ok {
-				positionals = append(positionals, "      "+snippetPositionalCompletion(action))
-				pos++
-			} else {
-				break // TODO only consistent entries for now
-			}
-		}
-		if action, ok := actions[uid.Positional(cmd, 0)]; ok {
-			positionals = append(positionals, "      "+snippetPositionalCompletion(action))
-			positionals = append(positionals, "      "+"...")
-		}
-		if len(positionals) == 0 {
-			if cmd.ValidArgs != nil {
-				positionals = []string{"        " + snippetPositionalCompletion(ActionRawValues(common.RawValuesFrom(cmd.ValidArgs...)...))}
-			}
-		}
-	}
-
-	result := make([]string, 0)
-	result = append(result, fmt.Sprintf(function_pattern, uid.Command(cmd), strings.Join(flags, "\n"), strings.Join(positionals, "\n"), cmd.Name()))
-	for _, subcmd := range cmd.Commands() {
-		if !subcmd.Hidden {
-			result = append(result, snippetFunctions(subcmd, actions))
-		}
-	}
-	return strings.Join(result, " ")
-}
-
-func snippetPositionalCompletion(action string) string {
-	return fmt.Sprintf(`[_]{ %v }`, action)
-}
-
-func snippetFlagCompletion(flag *pflag.Flag, action string) (snippet string) {
-	spec := []string{}
-	if !common.IsShorthandOnly(flag) {
-		spec = append(spec, fmt.Sprintf(`&long='%v'`, flag.Name))
-	}
-	if flag.Shorthand != "" {
-		spec = append(spec, fmt.Sprintf(`&short='%v'`, flag.Shorthand))
-	}
-
-	spec = append(spec, fmt.Sprintf(`&desc='%v'`, replacer.Replace(flag.Usage)))
-
-	if flag.NoOptDefVal == "" {
-		spec = append(spec, `&arg-required=$true`, fmt.Sprintf(`&completer=[_]{ %v }`, action))
-	} else {
-		spec = append(spec, `&arg-optional=$true`, fmt.Sprintf(`&completer=[_]{ %v }`, action))
-	}
-	return fmt.Sprintf(`        [%v]`, strings.Join(spec, " "))
+`, cmd.Name(), uid.Executable())
 }
diff --git a/internal/fish/action.go b/internal/fish/action.go
index f0934b5..cd3364e 100644
--- a/internal/fish/action.go
+++ b/internal/fish/action.go
@@ -26,18 +26,6 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func Callback(prefix string, uid string) string {
-	return fmt.Sprintf(`_%v_callback %v`, prefix, uid)
-}
-
-func ActionDirectories() string {
-	return `__fish_complete_directories`
-}
-
-func ActionFiles(suffix string) string {
-	return fmt.Sprintf(`__fish_complete_suffix "%v"`, suffix)
-}
-
 func ActionRawValues(values ...common.RawValue) string {
 	vals := make([]string, len(values))
 	for index, val := range values {
diff --git a/internal/fish/snippet.go b/internal/fish/snippet.go
index ecfb5bf..bb93b3f 100644
--- a/internal/fish/snippet.go
+++ b/internal/fish/snippet.go
@@ -4,10 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
 var replacer = strings.NewReplacer(
@@ -19,23 +17,8 @@ var replacer = strings.NewReplacer(
 	`'`, `\"`,
 )
 
-func snippetLazy(cmd *cobra.Command) string {
-	return fmt.Sprintf(`function _%v_completions
-   complete -c %v -e
-   %v _carapace fish | source
-   complete --do-complete=(commandline -cp)
-end
-complete --do-complete='%v ' > /dev/null
-complete -c %v -e
-complete -c %v -a '(_%v_completions)'
-`, cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), cmd.Name(), cmd.Name())
-}
-
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
-	if lazy {
-		return snippetLazy(cmd)
-	}
-	result := fmt.Sprintf(`function _%v_quote_suffix
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
+	return fmt.Sprintf(`function _%v_quote_suffix
   if not commandline -cp | xargs echo 2>/dev/null >/dev/null
     if commandline -cp | sed 's/$/"/'| xargs echo 2>/dev/null >/dev/null
       echo '"'
@@ -47,149 +30,12 @@ func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
   end
 end
 
-function _%v_state
-  set -lx CURRENT (commandline -cp)
-  if [ "$LINE" != "$CURRENT" ]
-    set -gx LINE (commandline -cp)
-    set -gx STATE (commandline -cp | sed "s/\$/"(_%v_quote_suffix)"/" | xargs %v _carapace fish state)
-  end
-
-  [ "$STATE" = "$argv" ]
-end
-
 function _%v_callback
-  set -lx CALLBACK (commandline -cp | sed "s/\$/"(_%v_quote_suffix)"/" | sed "s/ \$/ ''/" | xargs %v _carapace fish $argv )
+  set -lx CALLBACK (commandline -cp | sed "s/\$/"(_%v_quote_suffix)"/" | sed "s/ \$/ ''/" | xargs %v _carapace fish _ )
   eval "$CALLBACK"
 end
 
 complete -c %v -f
-`, cmd.Name(), cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name())
-	result += snippetFunctions(cmd, actions)
-
-	return result
-}
-
-func snippetFunctions(cmd *cobra.Command, actions map[string]string) string {
-	function_pattern := `
-%v
-`
-
-	flags := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
-		if !flag.Hidden {
-			var s string
-			if action, ok := actions[uid.Flag(cmd, flag)]; ok {
-				s = snippetFlagCompletion(cmd, flag, &action)
-			} else {
-				s = snippetFlagCompletion(cmd, flag, nil)
-			}
-
-			flags = append(flags, s)
-		}
-	})
-
-	positionals := make([]string, 0)
-	if cmd.HasAvailableSubCommands() {
-		positionals = []string{}
-		for _, subcmd := range cmd.Commands() {
-			if !subcmd.Hidden {
-				positionals = append(positionals, fmt.Sprintf(`complete -c '%v' -f -n '_%v_state %v ' -a '%v' -d '%v'`, cmd.Root().Name(), cmd.Root().Name(), uid.Command(cmd), subcmd.Name()+" "+strings.Join(subcmd.Aliases, " "), replacer.Replace(subcmd.Short)))
-			}
-		}
-	} else {
-		if len(positionals) == 0 {
-			if cmd.ValidArgs != nil {
-				//positionals = []string{"    " + snippetPositionalCompletion(1, ActionValues(cmd.ValidArgs...))}
-			}
-			positionals = append(positionals, fmt.Sprintf(`complete -c '%v' -f -n '_%v_state %v' -a '(_%v_callback _)'`, cmd.Root().Name(), cmd.Root().Name(), uid.Command(cmd), cmd.Root().Name()))
-		}
-	}
-
-	arguments := append(flags, positionals...)
-
-	result := make([]string, 0)
-	result = append(result, fmt.Sprintf(function_pattern, strings.Join(arguments, "\n")))
-	for _, subcmd := range cmd.Commands() {
-		if !subcmd.Hidden {
-			result = append(result, snippetFunctions(subcmd, actions))
-		}
-	}
-	return strings.Join(result, "\n")
-}
-
-func snippetFlagCompletion(cmd *cobra.Command, flag *pflag.Flag, action *string) (snippet string) {
-	var suffix string
-	if action == nil {
-		if flag.NoOptDefVal != "" {
-			suffix = "" // no argument required for flag
-		} else {
-			suffix = " -r" // require a value
-		}
-	} else {
-		if flag.NoOptDefVal != "" {
-			suffix = fmt.Sprintf(" -a '(%v)'", *action)
-		} else {
-			suffix = fmt.Sprintf(" -a '(%v)' -r", *action)
-		}
-	}
-
-	if flag.Shorthand == "" { // no shorthannd
-		snippet = fmt.Sprintf(`complete -c '%v' -f -n '_%v_state %v' -l '%v' -d '%v'%v`, cmd.Root().Name(), cmd.Root().Name(), uid.Command(cmd), flag.Name, replacer.Replace(flag.Usage), suffix)
-	} else if common.IsShorthandOnly(flag) {
-		snippet = fmt.Sprintf(`complete -c '%v' -f -n '_%v_state %v' -s '%v' -d '%v'%v`, cmd.Root().Name(), cmd.Root().Name(), uid.Command(cmd), flag.Shorthand, replacer.Replace(flag.Usage), suffix)
-	} else {
-		snippet = fmt.Sprintf(`complete -c '%v' -f -n '_%v_state %v' -l '%v' -s '%v' -d '%v'%v`, cmd.Root().Name(), cmd.Root().Name(), uid.Command(cmd), flag.Name, flag.Shorthand, replacer.Replace(flag.Usage), suffix)
-	}
-	return
-}
-
-func snippetPositionalCompletion(position int, action string) string {
-	return fmt.Sprintf(`"%v:: :%v"`, position, action)
-}
-
-func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool {
-	return strings.Contains(f.Value.Type(), "Slice") ||
-		strings.Contains(f.Value.Type(), "Array")
-}
-
-func snippetSubcommands(cmd *cobra.Command) string {
-	if !cmd.HasAvailableSubCommands() {
-		return ""
-	}
-	cmnds := make([]string, 0)
-	functions := make([]string, 0)
-	for _, c := range cmd.Commands() {
-		if !c.Hidden {
-			cmnds = append(cmnds, fmt.Sprintf(`        "%v:%v"`, c.Name(), c.Short))
-			functions = append(functions, fmt.Sprintf(`    %v)
-      %v
-      ;;`, c.Name(), uid.Command(c)))
-
-			for _, alias := range c.Aliases {
-				cmnds = append(cmnds, fmt.Sprintf(`        "%v:%v"`, alias, c.Short))
-				functions = append(functions, fmt.Sprintf(`    %v)
-      %v
-      ;;`, alias, uid.Command(c)))
-			}
-		}
-	}
-
-	templ := `
-
-  # shellcheck disable=SC2154
-  case $state in
-    cmnds)
-      # shellcheck disable=SC2034
-      commands=(
-%v
-      )
-      _describe "command" commands
-      ;;
-  esac
-  
-  case "${words[1]}" in
-%v
-  esac`
-
-	return fmt.Sprintf(templ, strings.Join(cmnds, "\n"), strings.Join(functions, "\n"))
+complete -c '%v' -f -a '(_%v_callback)' -r
+`, cmd.Name(), cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), cmd.Name())
 }
diff --git a/internal/oil/action.go b/internal/oil/action.go
index 33f2d50..4770020 100644
--- a/internal/oil/action.go
+++ b/internal/oil/action.go
@@ -33,28 +33,11 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func Callback(prefix string, uid string) string {
-	return ""
-}
-
-func ActionDirectories() string {
-	return ""
-}
-
-func ActionFiles(suffix string) string {
-	return ""
-}
-
 func ActionRawValues(values ...common.RawValue) string {
 	filtered := make([]common.RawValue, 0)
 
 	for _, r := range values {
 		// TODO should rather access callbackvalue (circular dependency) - seems to work though so good enough for now
-		prefix := os.Args[len(os.Args)-1]
-		if strings.HasPrefix(prefix, "-") && strings.Contains(prefix, "=") {
-			prefix = strings.SplitN(prefix, "=", 2)[0]
-			r.Value = prefix + "=" + r.Value
-		}
 		if strings.HasPrefix(r.Value, os.Args[len(os.Args)-1]) {
 			filtered = append(filtered, r)
 		}
diff --git a/internal/oil/snippet.go b/internal/oil/snippet.go
index 3b4710e..5d629e3 100644
--- a/internal/oil/snippet.go
+++ b/internal/oil/snippet.go
@@ -7,7 +7,7 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
 	result := fmt.Sprintf(`#!/bin/osh
 _%v_completion() {
   local compline="${COMP_LINE:0:${COMP_POINT}}"
diff --git a/internal/powershell/action.go b/internal/powershell/action.go
index 9035d1d..bd63f4c 100644
--- a/internal/powershell/action.go
+++ b/internal/powershell/action.go
@@ -38,18 +38,6 @@ func EscapeSpace(value string) string {
 	return strings.Replace(value, " ", "` ", -1)
 }
 
-func Callback(prefix string, uid string) string {
-	return fmt.Sprintf("_%v_callback '%v'", prefix, uid)
-}
-
-func ActionDirectories() string {
-	return `[CompletionResult]::new('', '', [CompletionResultType]::ParameterValue, '')`
-}
-
-func ActionFiles(suffix string) string {
-	return `[CompletionResult]::new('', '', [CompletionResultType]::ParameterValue, '')`
-}
-
 func ActionRawValues(values ...common.RawValue) string {
 	vals := make([]string, len(values))
 	for index, val := range values {
diff --git a/internal/powershell/snippet.go b/internal/powershell/snippet.go
index b5aaac4..fdca021 100644
--- a/internal/powershell/snippet.go
+++ b/internal/powershell/snippet.go
@@ -1,188 +1,36 @@
 package powershell
 
 import (
-	"bytes"
 	"fmt"
-	"io"
-	"strings"
 
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
-func snippetLazy(cmd *cobra.Command) string {
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
 	return fmt.Sprintf(`using namespace System.Management.Automation
 using namespace System.Management.Automation.Language
-Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock {
-    param($wordToComplete, $commandAst, $cursorPosition)
-    %v _carapace powershell | Out-String | Invoke-Expression
-    & $_%v_completer $wordToComplete $commandAst $cursorPosition
-}
-`, cmd.Name(), uid.Executable(), cmd.Name())
-}
-
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
-	if lazy {
-		return snippetLazy(cmd)
-	}
-
-	buf := new(bytes.Buffer)
-
-	var subCommandCases bytes.Buffer
-	generatePowerShellSubcommandCases(&subCommandCases, cmd, actions)
-	fmt.Fprintf(buf, powerShellCompletionTemplate, cmd.Name(), uid.Executable(), cmd.Name(), uid.Executable(), uid.Executable(), subCommandCases.String(), cmd.Name(), cmd.Name())
-
-	return buf.String()
-}
-
-var powerShellCompletionTemplate = `using namespace System.Management.Automation
-using namespace System.Management.Automation.Language
-$_%v_completer = {
+Function _%v_completer {
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", "", Scope="Function", Target="*")]
     param($wordToComplete, $commandAst) #, $cursorPosition)
     $commandElements = $commandAst.CommandElements
-    $previous = $commandElements[-1].Value
-    if ($wordToComplete) {
-        $previous = $commandElements[-2].Value
-    }
 
-    $state = %v _carapace powershell state $($commandElements| ForEach-Object {$_.Value})
 
-    Function _%v_callback {
-      [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", "", Scope="Function", Target="*")]
-      param($uid)
+    $completions = @(
       if (!$wordToComplete) {
-        %v _carapace powershell "$uid" $($commandElements| ForEach-Object {$_.Value}) '""' | Out-String | Invoke-Expression
+        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | Out-String | Invoke-Expression
       } else {
-        %v _carapace powershell "$uid" $($commandElements| ForEach-Object {$_.Value}) | Out-String | Invoke-Expression
+        %v _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | Out-String | Invoke-Expression
       }
-    }
-
-    $completions = @(switch ($state) {%s
-    })
+    )
 
     if ($completions.count -eq 0) {
       return "" # prevent default file completion
     }
 
-    $completions.Where{ ($_.CompletionText -replace '` + "`" + `','') -like "$wordToComplete*" } |
+    $completions.Where{ ($_.CompletionText -replace '`+"`"+`','') -like "$wordToComplete*" } |
         Sort-Object -Property ListItemText
 }
-Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock $_%v_completer
-`
-
-func generatePowerShellSubcommandCases(out io.Writer, cmd *cobra.Command, actions map[string]string) {
-	var cmdName = fmt.Sprintf("%v", uid.Command(cmd))
-
-	fmt.Fprintf(out, "\n        '%s' {", cmdName)
-	fmt.Fprintf(out, `
-            switch -regex ($previous) {
-%v
-                default {
-                    switch -regex ($wordToComplete) {
-%v
-
-                        default {
-%v
-                        }
-                    }
-                }
-            }
-`, snippetFlagActions(cmd, actions, false), snippetFlagActions(cmd, actions, true), snippetTODO(cmd))
-
-	for _, subCmd := range cmd.Commands() {
-		if !subCmd.Hidden {
-			generatePowerShellSubcommandCases(out, subCmd, actions)
-		}
-	}
-}
-
-func snippetFlagActions(cmd *cobra.Command, actions map[string]string, optArgFlag bool) string {
-	flagActions := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
-		// TODO cleanup this mess
-		if flag.Value.Type() == "bool" {
-			return
-		}
-		if flag.NoOptDefVal != "" && !optArgFlag {
-			return
-		}
-		if flag.NoOptDefVal == "" && optArgFlag {
-			return
-		}
-
-		optArgSuffix := ""
-		if flag.NoOptDefVal != "" {
-			optArgSuffix = "=*"
-		}
-
-		match := fmt.Sprintf(`^(--%v)$`, flag.Name+optArgSuffix)
-		if flag.Shorthand != "" {
-			match = fmt.Sprintf(`^(-%v|--%v)$`, flag.Shorthand+optArgSuffix, flag.Name+optArgSuffix)
-		} else if common.IsShorthandOnly(flag) {
-			match = fmt.Sprintf(`^(-%v)$`, flag.Shorthand+optArgSuffix)
-		}
-		var action = ""
-		if a, ok := actions[uid.Flag(cmd, flag)]; ok { // TODO cleanup
-			if strings.TrimSpace(a) != "" {
-				action = "                        " + a // TODO do the indenting below
-			}
-		}
-		if flag.NoOptDefVal != "" {
-			// add flag prefix to each CompletionResult
-			flagActions = append(flagActions, fmt.Sprintf(`                '%v' {
-                        @(
-%v
-                        ) | ForEach-Object{ [CompletionResult]::new($wordToComplete.split("=")[0] + "=" + $_.CompletionText, $_.ListItemText, $_.ResultType, $_.ToolTip) }
-                        break
-                      }`, match, strings.Replace(action, "\n", "\n                        ", -1)))
-
-		} else {
-			flagActions = append(flagActions, fmt.Sprintf(`                '%v' {
-%v
-                        break
-                      }`, match, strings.Replace(action, "\n", "\n                        ", -1)))
-		}
-	})
-	return strings.Join(flagActions, "\n")
-}
-
-func snippetTODO(cmd *cobra.Command) string {
-	result := ""
-	result += fmt.Sprint("\n            if ($wordToComplete -like \"-*\") {")
-
-	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
-		if !flag.Hidden {
-			usage := escapeStringForPowerShell(flag.Usage)
-			if len(flag.Shorthand) > 0 {
-				result += fmt.Sprintf("\n                [CompletionResult]::new('-%s ', '-%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, sanitizer.Replace(usage))
-			}
-			if !common.IsShorthandOnly(flag) {
-				result += fmt.Sprintf("\n                [CompletionResult]::new('--%s ', '--%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, sanitizer.Replace(usage))
-			}
-		}
-	})
-
-	result += fmt.Sprint("\n            } else {")
-	for _, subCmd := range cmd.Commands() {
-		if !subCmd.Hidden {
-			usage := escapeStringForPowerShell(subCmd.Short)
-			result += fmt.Sprintf("\n                [CompletionResult]::new('%s ', '%s', [CompletionResultType]::Command, '%s')", subCmd.Name(), subCmd.Name(), sanitizer.Replace(usage))
-		}
-	}
-
-	if !cmd.HasAvailableSubCommands() {
-		result += fmt.Sprintf("\n                _%v_callback '_'", cmd.Root().Name())
-	}
-	result += fmt.Sprint("\n            }")
-	result += fmt.Sprint("\n            break\n        }")
-	return result
-}
-
-func escapeStringForPowerShell(s string) string {
-	if s == "" {
-		return " " // completion fails if empty (fallback to file completion)
-	}
-	return strings.Replace(s, "'", "''", -1)
+Register-ArgumentCompleter -Native -CommandName '%v' -ScriptBlock (Get-Item "Function:_%v_completer").ScriptBlock
+`, cmd.Name(), uid.Executable(), uid.Executable(), cmd.Name(), cmd.Name())
 }
diff --git a/internal/xonsh/action.go b/internal/xonsh/action.go
index a893bbc..f2910c6 100644
--- a/internal/xonsh/action.go
+++ b/internal/xonsh/action.go
@@ -2,6 +2,7 @@ package xonsh
 
 import (
 	"fmt"
+	"os"
 	"strings"
 
 	"github.com/rsteube/carapace/internal/common"
@@ -32,23 +33,18 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func Callback(prefix string, uid string) string {
-	return fmt.Sprintf("_%v_callback('%v')", strings.Replace(prefix, "-", "__", -1), uid)
-}
-
-func ActionDirectories() string {
-	return `{ RichCompletion(f, display=pathlib.PurePath(f).name, description='', prefix_len=0) for f in complete_dir(prefix, line, begidx, endidx, ctx, True)[0]}`
-}
+func ActionRawValues(values ...common.RawValue) string {
+	filtered := make([]common.RawValue, 0)
 
-// TODO add endswith filter function
-func ActionFiles(suffix string) string {
-	return `{ RichCompletion(f, display=pathlib.PurePath(f).name, description='', prefix_len=0) for f in complete_path(prefix, line, begidx, endidx, ctx)[0]}`
-}
+	for _, r := range values {
+		if strings.HasPrefix(r.Value, os.Args[len(os.Args)-1]) {
+			filtered = append(filtered, r)
+		}
+	}
 
-func ActionRawValues(values ...common.RawValue) string {
-	vals := make([]string, len(values))
-	for index, val := range values {
-		vals[index] = fmt.Sprintf(`  RichCompletion('%v', display='%v', description='%v', prefix_len=0),`, sanitizer.Replace(val.Value), sanitizer.Replace(val.Display), sanitizer.Replace(val.Description))
+	vals := make([]string, len(filtered))
+	for index, val := range filtered {
+		vals[index] = fmt.Sprintf(`  RichCompletion('%v', display='%v', description='%v', prefix_len=0),`, strings.Replace(sanitizer.Replace(val.Value), " ", `\\ `, -1), sanitizer.Replace(val.Display), sanitizer.Replace(val.Description))
 	}
 	return fmt.Sprintf("{\n%v\n}", strings.Join(vals, "\n"))
 }
diff --git a/internal/xonsh/snippet.go b/internal/xonsh/snippet.go
index 929f576..dacb1f5 100644
--- a/internal/xonsh/snippet.go
+++ b/internal/xonsh/snippet.go
@@ -1,60 +1,20 @@
 package xonsh
 
 import (
-	"bytes"
 	"fmt"
-	"io"
 	"strings"
 
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
-func snippetLazy(cmd *cobra.Command) string {
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
 	functionName := strings.Replace(cmd.Name(), "-", "__", -1)
 	return fmt.Sprintf(`from shlex import split
 import re
 import pathlib
 import subprocess
 import xonsh
-import builtins
-from xonsh.completers._aliases import _add_one_completer
-from xonsh.completers.path import complete_dir, complete_path
-from xonsh.completers.tools import RichCompletion
-def _%v_completer(prefix, line, begidx, endidx, ctx):
-    """lazy carapace completer for %v"""
-    if not line.startswith('%v '):
-        return # not the expected command to complete
-    builtins.__xonsh__.completers = builtins.__xonsh__.completers.copy()
-    del builtins.__xonsh__.completers['%v']
-    exec(compile(subprocess.run(['%v', '_carapace', 'xonsh'], stdout=subprocess.PIPE).stdout.decode('utf-8'), "", "exec"))
-    return builtins.__xonsh__.completers['%v'](prefix, line, begidx, endidx, ctx)
-_add_one_completer('%v', _%v_completer, 'start')
-`, functionName, cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), cmd.Name(), functionName)
-}
-
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
-	if lazy {
-		return snippetLazy(cmd)
-	}
-
-	buf := new(bytes.Buffer)
-
-	var subCommandCases bytes.Buffer
-	generateXonshSubcommandCases(&subCommandCases, cmd, actions)
-	functionName := strings.Replace(cmd.Name(), "-", "__", -1)
-	fmt.Fprintf(buf, xonshCompletionTemplate, functionName, cmd.Name(), cmd.Name(), uid.Executable(), functionName, uid.Executable(), subCommandCases.String(), cmd.Name(), functionName)
-
-	return buf.String()
-}
-
-var xonshCompletionTemplate = `from shlex import split
-import re
-import pathlib
-import subprocess
-import xonsh
 from xonsh.completers._aliases import _add_one_completer
 from xonsh.completers.path import complete_dir, complete_path
 from xonsh.completers.tools import RichCompletion
@@ -74,15 +34,8 @@ def _%v_completer(prefix, line, begidx, endidx, ctx):
 
     result = {}
 
-    # TODO python retrieve state
-    state, _ = subprocess.Popen(['%v', '_carapace', 'xonsh', 'state', *words],
-                                   stdout=subprocess.PIPE,
-                                   stderr=subprocess.PIPE).communicate()
-    state = state.decode('utf-8').split('\n')[0]
-   
-    # TODO python callback function
-    def _%v_callback(uid):
-        cb, _ = subprocess.Popen(['%v', '_carapace', 'xonsh', uid, *words],
+    def _%v_callback():
+        cb, _ = subprocess.Popen(['%v', '_carapace', 'xonsh', '_', *words],
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE).communicate()
         cb = cb.decode('utf-8')
@@ -91,118 +44,14 @@ def _%v_completer(prefix, line, begidx, endidx, ctx):
         else:
             nonlocal prefix, line, begidx, endidx, ctx
             return eval(cb)
-   
-    if False:
-        pass%s
+  
+    result = _%v_callback()
 
-    result = set(filter(lambda x: x.startswith(current) and x.endswith(suffix), result))
     if len(result) == 0:
         result = {RichCompletion(current, display=current, description='', prefix_len=0)}
 
-    result = set(map(lambda x: RichCompletion(x[:len(x)-len(suffix)], display=x.display, description=x.description, prefix_len=len(current)), result))
+    result = set(map(lambda x: RichCompletion(x[:len(x)-(len(suffix)+suffix.count(' '))], display=x.display, description=x.description, prefix_len=len(current)+current.count(' ')), result))
     return result
 _add_one_completer('%v', _%v_completer, 'start')
-`
-
-func generateXonshSubcommandCases(out io.Writer, cmd *cobra.Command, actions map[string]string) {
-	var cmdName = fmt.Sprintf("%v", uid.Command(cmd))
-
-	fmt.Fprintf(out, "\n    elif state == '%s':", cmdName)
-	fmt.Fprintf(out, `
-        if False: # switch previous
-            pass
-%v
-        else:
-            if False:
-                pass
-%v
-%v
-`, snippetFlagActions(cmd, actions, false), "    "+strings.Replace(snippetFlagActions(cmd, actions, true), "\n", "\n    ", -1), snippetTODO(cmd))
-
-	for _, subCmd := range cmd.Commands() {
-		if !subCmd.Hidden {
-			generateXonshSubcommandCases(out, subCmd, actions)
-		}
-	}
-}
-
-func snippetFlagActions(cmd *cobra.Command, actions map[string]string, optArgFlag bool) string {
-	flagActions := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
-		// TODO cleanup this mess
-		if flag.Value.Type() == "bool" {
-			return
-		}
-		if flag.NoOptDefVal != "" && !optArgFlag {
-			return
-		}
-		if flag.NoOptDefVal == "" && optArgFlag {
-			return
-		}
-
-		optArgSuffix := ""
-		if flag.NoOptDefVal != "" {
-			optArgSuffix = "=.*"
-		}
-
-		match := fmt.Sprintf(`^(--%v)$`, flag.Name+optArgSuffix)
-		if flag.Shorthand != "" {
-			match = fmt.Sprintf(`^(-%v|--%v)$`, flag.Shorthand+optArgSuffix, flag.Name+optArgSuffix)
-		} else if common.IsShorthandOnly(flag) {
-			match = fmt.Sprintf(`^(-%v)$`, flag.Shorthand+optArgSuffix)
-		}
-		var action = "{}"
-		if a, ok := actions[uid.Flag(cmd, flag)]; ok { // TODO cleanup
-			action = a
-		}
-		if flag.NoOptDefVal != "" {
-			flagActions = append(flagActions, fmt.Sprintf(`        elif re.search('%v',current):
-            result = %v
-            result = set(map(lambda x: RichCompletion(current.split('=')[0]+'='+x, display=x.display, description=x.description, prefix_len=x.prefix_len), result))
-`, match, strings.Replace(action, "\n", "\n                        ", -1)))
-
-		} else {
-			flagActions = append(flagActions, fmt.Sprintf(`        elif re.search('%v',previous):
-            result = %v
-                  `, match, strings.Replace(action, "\n", "\n                        ", -1)))
-		}
-	})
-	return strings.Join(flagActions, "\n")
-}
-
-func snippetTODO(cmd *cobra.Command) string {
-	result := ""
-	result += fmt.Sprint("\n            elif re.search(\"-.*\",current):")
-	result += fmt.Sprint("\n                result = {")
-
-	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
-		if !flag.Hidden {
-			if len(flag.Shorthand) > 0 {
-				result += fmt.Sprintf("\n                    RichCompletion('-%v', display='-%v', description='%v', prefix_len=0),", flag.Shorthand, flag.Shorthand, sanitizer.Replace(flag.Usage))
-
-			}
-			if !common.IsShorthandOnly(flag) {
-				result += fmt.Sprintf("\n                    RichCompletion('--%v', display='--%v', description='%v', prefix_len=0),", flag.Name, flag.Name, sanitizer.Replace(flag.Usage))
-			}
-		}
-	})
-	result += fmt.Sprint("\n                }")
-
-	result += fmt.Sprint("\n            else:")
-	// TODO wrap in `result = {}`
-	if cmd.HasAvailableSubCommands() {
-		result += fmt.Sprint("\n                result = {")
-		for _, subCmd := range cmd.Commands() {
-			if !subCmd.Hidden {
-				result += fmt.Sprintf("\n                RichCompletion('%v', display='%v', description='%v', prefix_len=0),", subCmd.Name(), subCmd.Name(), sanitizer.Replace(subCmd.Short))
-			}
-		}
-		result += fmt.Sprint("\n                }")
-	} else {
-		if !cmd.HasAvailableSubCommands() {
-			result += fmt.Sprintf("\n                result = _%v_callback('_')", strings.Replace(cmd.Root().Name(), "-", "__", -1))
-		}
-	}
-	result += fmt.Sprint("\n")
-	return result
+`, functionName, cmd.Name(), cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), functionName)
 }
diff --git a/internal/zsh/action.go b/internal/zsh/action.go
index 1afe50d..e96c96a 100644
--- a/internal/zsh/action.go
+++ b/internal/zsh/action.go
@@ -2,8 +2,10 @@ package zsh
 
 import (
 	"fmt"
-	"github.com/rsteube/carapace/internal/common"
+	"os"
 	"strings"
+
+	"github.com/rsteube/carapace/internal/common"
 )
 
 var sanitizer = strings.NewReplacer(
@@ -34,28 +36,18 @@ func Sanitize(values ...string) []string {
 	return sanitized
 }
 
-func Callback(prefix string, cuid string) string {
-	return fmt.Sprintf(`{_%v_callback '%v'}`, prefix, cuid)
-}
-
-func ActionDirectories() string {
-	return `_files -/`
-}
+func ActionRawValues(values ...common.RawValue) string {
+	filtered := make([]common.RawValue, 0)
 
-// ActionFiles _path_files with all options except -g and -/. These options depend on file-patterns style setting. // TODO fix doc
-// [http://zsh.sourceforge.net/Doc/Release/Completion-System.html#index-_005ffiles]
-func ActionFiles(pattern string) string {
-	if pattern == "" {
-		return "_files"
-	} else {
-		return fmt.Sprintf("_files -g '%v'", pattern)
+	for _, r := range values {
+		if strings.HasPrefix(r.Value, os.Args[len(os.Args)-1]) {
+			filtered = append(filtered, r)
+		}
 	}
-}
 
-func ActionRawValues(values ...common.RawValue) string {
-	vals := make([]string, len(values))
-	displays := make([]string, len(values))
-	for index, val := range values {
+	vals := make([]string, len(filtered))
+	displays := make([]string, len(filtered))
+	for index, val := range filtered {
 		// TODO sanitize
 		vals[index] = fmt.Sprintf("'%v'", sanitizer.Replace(val.Value))
 		if strings.TrimSpace(val.Description) == "" {
@@ -64,5 +56,5 @@ func ActionRawValues(values ...common.RawValue) string {
 			displays[index] = fmt.Sprintf("'%v (%v)'", sanitizer.Replace(val.Display), sanitizer.Replace(val.Description))
 		}
 	}
-	return fmt.Sprintf("{local _comp_desc=(%v);compadd -S '' -d _comp_desc %v}", strings.Join(displays, " "), strings.Join(vals, " "))
+	return fmt.Sprintf("{local _comp_desc=(%v);compadd -S '' -d _comp_desc -- %v}", strings.Join(displays, " "), strings.Join(vals, " "))
 }
diff --git a/internal/zsh/snippet.go b/internal/zsh/snippet.go
index 7c9f53a..d6fd71e 100644
--- a/internal/zsh/snippet.go
+++ b/internal/zsh/snippet.go
@@ -4,10 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/internal/uid"
 	"github.com/spf13/cobra"
-	"github.com/spf13/pflag"
 )
 
 var replacer = strings.NewReplacer(
@@ -19,192 +17,14 @@ var replacer = strings.NewReplacer(
 	`]`, `\]`,
 )
 
-func snippetLazy(cmd *cobra.Command) string {
+func Snippet(cmd *cobra.Command, actions map[string]string) string {
 	return fmt.Sprintf(`#compdef %v
-function _%v {
-    compdef -d %v
-    unfunction _%v
-    source <(%v _carapace zsh)
-}
-
-compquote '' 2>/dev/null && _%v
-compdef _%v %v
-`, cmd.Name(), cmd.Name(), cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), cmd.Name())
-}
-
-func Snippet(cmd *cobra.Command, actions map[string]string, lazy bool) string {
-	if lazy {
-		return snippetLazy(cmd)
-	}
-
-	result := fmt.Sprintf("#compdef %v\n", cmd.Name())
-	result += fmt.Sprintf(`function _%v_callback {
+function _%v_completion {
   # shellcheck disable=SC2086
-  eval "$(%v _carapace zsh "$1" ${os_args})"
-}
-`, cmd.Name(), uid.Executable())
-	result += snippetFunctions(cmd, actions)
-
-	result += fmt.Sprintf("compquote '' 2>/dev/null && _%v\ncompdef _%v %v\n", cmd.Name(), cmd.Name(), cmd.Name())
-	return result
-}
-
-func snippetFunctions(cmd *cobra.Command, actions map[string]string) string {
-	function_pattern := `function %v {
-  %v%v  _arguments -C \
-%v%v
-}
-`
-
-	commandsVar := ""
-	if cmd.HasAvailableSubCommands() {
-		commandsVar = "local -a commands\n"
-	}
-
-	inheritedArgs := ""
-	if !cmd.HasParent() {
-		inheritedArgs = "  # shellcheck disable=SC2206\n  local -a -x os_args=(${words})\n\n"
-	}
-
-	flags := make([]string, 0)
-	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
-		if !flag.Hidden {
-			var s string
-			if action, ok := actions[uid.Flag(cmd, flag)]; ok {
-				s = "    " + snippetFlagCompletion(flag, &action)
-			} else {
-				s = "    " + snippetFlagCompletion(flag, nil)
-			}
-
-			flags = append(flags, s)
-		}
-	})
-
-	positionals := make([]string, 0)
-	if cmd.HasAvailableSubCommands() {
-		positionals = []string{`    "1: :->cmnds"`, `    "*::arg:->args"`}
-	} else {
-		pos := 1
-		for {
-			if action, ok := actions[uid.Positional(cmd, pos)]; ok {
-				positionals = append(positionals, "    "+snippetPositionalCompletion(pos, action))
-				pos++
-			} else {
-				if action, ok := actions[uid.Positional(cmd, 0)]; ok {
-					positionals = append(positionals, "    "+snippetPositionalAnyCompletion(action))
-				}
-				break // TODO only consisten entriess for now
-			}
-		}
-		if len(positionals) == 0 {
-			if cmd.ValidArgs != nil {
-				positionals = []string{"    " + snippetPositionalCompletion(1, ActionRawValues(common.RawValuesFrom(cmd.ValidArgs...)...))}
-			}
-			positionals = append(positionals, `    "*::arg:->args"`)
-		}
-	}
-
-	arguments := append(flags, positionals...)
-
-	result := make([]string, 0)
-	result = append(result, fmt.Sprintf(function_pattern, uid.Command(cmd), commandsVar, inheritedArgs, strings.Join(arguments, " \\\n"), snippetSubcommands(cmd)))
-	for _, subcmd := range cmd.Commands() {
-		if !subcmd.Hidden {
-			result = append(result, snippetFunctions(subcmd, actions))
-		}
-	}
+  eval "$(%v _carapace zsh _ ${^words//\\ / }'')"
 
-	return strings.Join(result, "\n")
 }
-
-func snippetFlagCompletion(flag *pflag.Flag, action *string) (snippet string) {
-	var suffix, multimark, multimarkEscaped string
-	if action == nil {
-		if flag.NoOptDefVal != "" {
-			suffix = "::" // no argument required for flag
-		} else {
-			suffix = ": :" // require a value
-		}
-	} else {
-		if flag.NoOptDefVal != "" {
-			suffix = fmt.Sprintf(":: :%v", *action)
-		} else {
-			suffix = fmt.Sprintf(": :%v", *action)
-		}
-	}
-
-	if zshCompFlagCouldBeSpecifiedMoreThenOnce(flag) {
-		multimark = "*"
-		multimarkEscaped = "\\*"
-	}
-
-	// TODO cleanup structure so that it can be read easier
-	optArgSuffix := ""
-	if flag.NoOptDefVal != "" {
-		optArgSuffix = "=-"
-	}
-
-	if flag.Shorthand == "" { // no shorthannd
-		snippet = fmt.Sprintf(`"%v--%v[%v]%v"`, multimark, flag.Name+optArgSuffix, replacer.Replace(flag.Usage), suffix)
-	} else if common.IsShorthandOnly(flag) {
-		snippet = fmt.Sprintf(`"%v-%v[%v]%v"`, multimark, flag.Shorthand+optArgSuffix, replacer.Replace(flag.Usage), suffix)
-	} else {
-		snippet = fmt.Sprintf(`"(%v-%v %v--%v)"{%v-%v,%v--%v}"[%v]%v"`, multimark, flag.Shorthand, multimark, flag.Name, multimarkEscaped, flag.Shorthand+optArgSuffix, multimarkEscaped, flag.Name+optArgSuffix, replacer.Replace(flag.Usage), suffix)
-	}
-	return
-}
-
-func snippetPositionalCompletion(position int, action string) string {
-	return fmt.Sprintf(`"%v: :%v"`, position, action)
-}
-
-func snippetPositionalAnyCompletion(action string) string {
-	return fmt.Sprintf(`"*: :%v"`, action)
-}
-
-func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool {
-	return strings.Contains(f.Value.Type(), "Slice") ||
-		strings.Contains(f.Value.Type(), "Array")
-}
-
-func snippetSubcommands(cmd *cobra.Command) string {
-	if !cmd.HasAvailableSubCommands() {
-		return ""
-	}
-	cmnds := make([]string, 0)
-	functions := make([]string, 0)
-	for _, c := range cmd.Commands() {
-		if !c.Hidden {
-			cmnds = append(cmnds, fmt.Sprintf(`        "%v:%v"`, c.Name(), c.Short))
-			functions = append(functions, fmt.Sprintf(`    %v)
-      %v
-      ;;`, c.Name(), uid.Command(c)))
-
-			for _, alias := range c.Aliases {
-				cmnds = append(cmnds, fmt.Sprintf(`        "%v:%v"`, alias, c.Short))
-				functions = append(functions, fmt.Sprintf(`    %v)
-      %v
-      ;;`, alias, uid.Command(c)))
-			}
-		}
-	}
-
-	templ := `
-
-  # shellcheck disable=SC2154
-  case $state in
-    cmnds)
-      # shellcheck disable=SC2034
-      commands=(
-%v
-      )
-      _describe "command" commands
-      ;;
-  esac
-  
-  case "${words[1]}" in
-%v
-  esac`
-
-	return fmt.Sprintf(templ, strings.Join(cmnds, "\n"), strings.Join(functions, "\n"))
+compquote '' 2>/dev/null && _%v_completion
+compdef _%v_completion %v
+`, cmd.Name(), cmd.Name(), uid.Executable(), cmd.Name(), cmd.Name(), cmd.Name())
 }


Test patch:
diff --git a/example/_test/invoke_bash b/example/_test/invoke_bash
index 06cfe31..f5c4889 100755
--- a/example/_test/invoke_bash
+++ b/example/_test/invoke_bash
@@ -6,5 +6,5 @@ COMP_POINT=${#1}
 COMP_WORDS=($COMP_LINE'')
 COMP_CWORD=$((${#COMP_WORDS[@]}-1))
 
-_example_completions
+_example_completion
 ( IFS=$'\n'; echo "${COMPREPLY[*]}" )
diff --git a/example/_test/invoke_elvish b/example/_test/invoke_elvish
index 2ccb93e..0d84bc9 100755
--- a/example/_test/invoke_elvish
+++ b/example/_test/invoke_elvish
@@ -2,7 +2,7 @@
 set timeout 10
 set CMDLINE [lindex $argv 0]
 log_user 0
-spawn elvish
+spawn elvish -norc
 send "eval (example _carapace elvish|slurp);echo EXPECT_START; \$edit:completion:arg-completer\[example\] $CMDLINE'' | each \[c\]{ echo \$c }; echo EXPECT_END"
 send "\r"
 expect -re "EXPECT_START\r\n(.*?)EXPECT_END"
diff --git a/example/_test/invoke_xonsh b/example/_test/invoke_xonsh
index cdd9868..46b4b63 100755
--- a/example/_test/invoke_xonsh
+++ b/example/_test/invoke_xonsh
@@ -2,7 +2,7 @@
 set timeout 10
 set CMDLINE [lindex $argv 0]
 log_user 0
-spawn xonsh -i
+spawn xonsh -i --no-rc
 send "exec(\$(example _carapace xonsh)); echo EXPECT_START; _example_completer('', '$CMDLINE ' , 0, len('$CMDLINE'), ''); echo EXPECT_END"
 send "\r"
 expect -re "EXPECT_START\r\n(.*?)EXPECT_END"
diff --git a/example/cmd/_test/bash.sh b/example/cmd/_test/bash.sh
index 04d9b9b..4bd4340 100644
--- a/example/cmd/_test/bash.sh
+++ b/example/cmd/_test/bash.sh
@@ -1,275 +1,17 @@
 #!/bin/bash
-_example_callback() {
-  local compline="${COMP_LINE:0:${COMP_POINT}}"
-  # TODO
-  #if [[ $last =~ ^[\"\'] ]] && ! echo "$last" | xargs echo 2>/dev/null >/dev/null ; then
-  #    compline="${compline}${last:0:1}"
-  #    last="${last// /\\\\ }" 
-  #fi
-
-  echo "$compline" | sed -e "s/ $/ ''/" -e 's/"/\"/g' | xargs example _carapace bash "$1"
-}
+_example_completion() {
+  export COMP_WORDBREAKS
 
-_example_completions() {
-  local cur prev #words cword split
-  _init_completion -n /=:.,
-  local curprefix
-  curprefix="$(echo "$cur" | sed -r 's_^(.*[:=])?.*_\1_')"
   local compline="${COMP_LINE:0:${COMP_POINT}}"
- 
-  # TODO
-  #if [[ $last =~ ^[\"\'] ]] && ! echo "$last" | xargs echo 2>/dev/null >/dev/null ; then
-  #    compline="${compline}${last:0:1}"
-  #    last="${last// /\\\\ }" 
-  #else
-  #    last="${last// /\\\ }" 
-  #fi
-
-  local state
-  state="$(echo "$compline" | sed -e "s/ \$/ ''/" -e 's/"/\"/g' | xargs example _carapace bash state)"
-
   local IFS=$'\n'
+  mapfile -t COMPREPLY < <(echo "$compline" | sed -e "s/ \$/ ''/" -e 's/"/\"/g' | xargs example _carapace bash "_")
+  [[ "${COMPREPLY[*]}" == "" ]] && COMPREPLY=() # fix for mapfile creating a non-empty array from empty command output
 
-  case $state in
-
-    '_example' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-          -p=* | --persistentFlag=*)
-            cur=${cur#*=}
-            curprefix=${curprefix#*=}
-            COMPREPLY=($())
-            ;;
-
-          *)
-            COMPREPLY=($(compgen -W $'--array\t--array (multiflag)\n-a\t-a (multiflag)\n--persistentFlag\t--persistentFlag (Help message for persistentFlag)\n-p\t-p (Help message for persistentFlag)\n--toggle\t--toggle (Help message for toggle)\n-t\t-t (Help message for toggle)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-        esac
-      else
-        case $prev in
-          -a | --array)
-            COMPREPLY=($())
-            ;;
-
-          *)
-            COMPREPLY=($(compgen -W $'action\taction (action example)\nalias\taction (action example)\ncallback\tcallback (callback example)\ncondition\tcondition (condition example)\nhelp\thelp (Help about any command)\ninjection\tinjection (just trying to break things)\nmultiparts\tmultiparts (multiparts example)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-        esac
-      fi
-      ;;
-
-
-    '_example__action' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-          -o=* | --optarg=*)
-            cur=${cur#*=}
-            curprefix=${curprefix#*=}
-            COMPREPLY=($(compgen -W $'blue\tblue\nred\tred\ngreen\tgreen\nyellow\tyellow' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-
-          *)
-            COMPREPLY=($(compgen -W $'--directories\t--directories (files flag)\n--files\t--files (files flag)\n-f\t-f (files flag)\n--groups\t--groups (groups flag)\n-g\t-g (groups flag)\n--kill\t--kill (kill signals)\n-k\t-k (kill signals)\n--message\t--message (message flag)\n-m\t-m (message flag)\n--net_interfaces\t--net_interfaces (net_interfaces flag)\n-n\t-n (net_interfaces flag)\n--optarg\t--optarg (optional arg with default value blue)\n-o\t-o (optional arg with default value blue)\n--usergroup\t--usergroup (user:group flag)\n--users\t--users (users flag)\n-u\t-u (users flag)\n--values\t--values (values flag)\n-v\t-v (values flag)\n--values_described\t--values_described (values with description flag)\n-d\t-d (values with description flag)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-        esac
-      else
-        case $prev in
-          --directories)
-            COMPREPLY=($(compgen -S / -d -- "$cur"))
-            ;;
-
-          -f | --files)
-            COMPREPLY=($(compgen -S / -d -- "$cur"; compgen -f -X '!*.go' -- "$cur"))
-            ;;
-
-          -g | --groups)
-            COMPREPLY=($(eval $(_example_callback '_example__action##groups')))
-            ;;
-
-          -k | --kill)
-            COMPREPLY=($(compgen -W $'ABRT\tABRT (Abnormal termination)\nALRM\tALRM (Virtual alarm clock)\nBUS\tBUS (BUS error)\nCHLD\tCHLD (Child status has changed)\nCONT\tCONT (Continue stopped process)\nFPE\tFPE (Floating-point exception)\nHUP\tHUP (Hangup detected on controlling terminal)\nILL\tILL (Illegal instruction)\nINT\tINT (Interrupt from keyboard)\nKILL\tKILL (Kill, unblockable)\nPIPE\tPIPE (Broken pipe)\nPOLL\tPOLL (Pollable event occurred)\nPROF\tPROF (Profiling alarm clock timer expired)\nPWR\tPWR (Power failure restart)\nQUIT\tQUIT (Quit from keyboard)\nSEGV\tSEGV (Segmentation violation)\nSTKFLT\tSTKFLT (Stack fault on coprocessor)\nSTOP\tSTOP (Stop process, unblockable)\nSYS\tSYS (Bad system call)\nTERM\tTERM (Termination request)\nTRAP\tTRAP (Trace/breakpoint trap)\nTSTP\tTSTP (Stop typed at keyboard)\nTTIN\tTTIN (Background read from tty)\nTTOU\tTTOU (Background write to tty)\nURG\tURG (Urgent condition on socket)\nUSR1\tUSR1 (User-defined signal 1)\nUSR2\tUSR2 (User-defined signal 2)\nVTALRM\tVTALRM (Virtual alarm clock)\nWINCH\tWINCH (Window size change)\nXCPU\tXCPU (CPU time limit exceeded)\nXFSZ\tXFSZ (File size limit exceeded)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-
-          -m | --message)
-            COMPREPLY=($(compgen -W $'_\t_\nERR\tERR (message example)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-
-          -n | --net_interfaces)
-            COMPREPLY=($(eval $(_example_callback '_example__action##net_interfaces')))
-            ;;
-
-          --usergroup)
-            COMPREPLY=($(eval $(_example_callback '_example__action##usergroup')))
-            ;;
-
-          -u | --users)
-            COMPREPLY=($(eval $(_example_callback '_example__action##users')))
-            ;;
-
-          -v | --values)
-            COMPREPLY=($(compgen -W $'values\tvalues\nexample\texample' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-
-          -d | --values_described)
-            COMPREPLY=($(compgen -W $'values\tvalues (valueDescription)\nexample\texample (exampleDescription)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-
-          *)
-            COMPREPLY=($(eval $(_example_callback '_')))
-            ;;
-        esac
-      fi
-      ;;
-
-
-    '_example__callback' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-
-          *)
-            COMPREPLY=($(compgen -W $'--callback\t--callback (Help message for callback)\n-c\t-c (Help message for callback)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-        esac
-      else
-        case $prev in
-          -c | --callback)
-            COMPREPLY=($(eval $(_example_callback '_example__callback##callback')))
-            ;;
-
-          *)
-            COMPREPLY=($(eval $(_example_callback '_')))
-            ;;
-        esac
-      fi
-      ;;
-
-
-    '_example__condition' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-
-          *)
-            COMPREPLY=($(compgen -W $'--required\t--required (required flag)\n-r\t-r (required flag)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-        esac
-      else
-        case $prev in
-          -r | --required)
-            COMPREPLY=($(compgen -W $'valid\tvalid\ninvalid\tinvalid' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-
-          *)
-            COMPREPLY=($(eval $(_example_callback '_')))
-            ;;
-        esac
-      fi
-      ;;
-
-
-    '_example__help' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-
-          *)
-            COMPREPLY=($())
-            ;;
-        esac
-      else
-        case $prev in
-
-          *)
-            COMPREPLY=($(eval $(_example_callback '_')))
-            ;;
-        esac
-      fi
-      ;;
-
-
-    '_example__injection' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-
-          *)
-            COMPREPLY=($())
-            ;;
-        esac
-      else
-        case $prev in
-
-          *)
-            COMPREPLY=($(eval $(_example_callback '_')))
-            ;;
-        esac
-      fi
-      ;;
-
-
-    '_example__multiparts' )
-      if [[ $cur == -* ]]; then
-        case $cur in
-
-          *)
-            COMPREPLY=($(compgen -W $'--at\t--at (multiparts with @ as divider)\n--colon\t--colon (multiparts with : as divider )\n--comma\t--comma (multiparts with , as divider)\n--dot\t--dot (multiparts with . as divider)\n--dotdotdot\t--dotdotdot (multiparts with ... as divider)\n--equals\t--equals (multiparts with = as divider)\n--none\t--none (multiparts without divider)\n--slash\t--slash (multiparts with / as divider)' -- "${cur//\\ / }" | sed "s"$'\001'"^${curprefix//\\ / }"$'\001'$'\001'))
-            ;;
-        esac
-      else
-        case $prev in
-          --at)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##at')))
-            ;;
-
-          --colon)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##colon')))
-            ;;
-
-          --comma)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##comma')))
-            ;;
-
-          --dot)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##dot')))
-            ;;
-
-          --dotdotdot)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##dotdotdot')))
-            ;;
-
-          --equals)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##equals')))
-            ;;
-
-          --none)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##none')))
-            ;;
-
-          --slash)
-            COMPREPLY=($(eval $(_example_callback '_example__multiparts##slash')))
-            ;;
-
-          *)
-            COMPREPLY=($(eval $(_example_callback '_')))
-            ;;
-        esac
-      fi
-      ;;
-
-  esac
-
-  [[ $cur =~ ^[\"\'] ]] && COMPREPLY=("${COMPREPLY[@]//\\ /\ }")
-  
-  [[ ${#COMPREPLY[@]} -gt 1 ]] && for entry in "${COMPREPLY[@]}"; do
-    value="${entry%	*}"
-    display="${entry#*	}"
-    if [[ "${value::1}" != "${display::1}"  ]]; then # inserted value differs from display value
-       [[ "$(printf  "%c\n" "${COMPREPLY[@]#*	}" | uniq | wc -l)" -eq 1 ]] && COMPREPLY=("${COMPREPLY[@]}" "") # prevent insertion if all have same first character (workaround for #164)
-      break
-    fi
-  done
-
-  [[ ${#COMPREPLY[@]} -gt 1 ]] && COMPREPLY=("${COMPREPLY[@]#*	}") # show visual part (all after tab)
-  [[ ${#COMPREPLY[@]} -eq 1 ]] && COMPREPLY=( ${COMPREPLY[0]%	*} ) # show value to insert (all before tab) https://stackoverflow.com/a/10130007
-  [[ ${COMPREPLY[0]} == *[/=@:.,] ]] && compopt -o nospace
+  [[ ${COMPREPLY[0]} == *[/=@:.,$'\001'] ]] && compopt -o nospace
+  # TODO use mapfile
+  # shellcheck disable=SC2206
+  [[ ${#COMPREPLY[@]} -eq 1 ]] && COMPREPLY=(${COMPREPLY%$'\001'})
 }
 
-complete -F _example_completions example
+complete -F _example_completion example
 
diff --git a/example/cmd/_test/elvish.elv b/example/cmd/_test/elvish.elv
index 0803c99..1b18f2c 100644
--- a/example/cmd/_test/elvish.elv
+++ b/example/cmd/_test/elvish.elv
@@ -1,175 +1,7 @@
-use str
 edit:completion:arg-completer[example] = [@arg]{
-  fn _example_callback [uid]{
     if (eq $arg[-1] "") {
         arg[-1] = "''"
     }
-    eval (echo (str:join "\001" $arg) | xargs --delimiter="\001" example _carapace elvish $uid | slurp) &ns=(ns [&arg=$arg])
-  }
-
-  fn subindex [subcommand]{
-    # TODO 'edit:complete-getopt' needs the arguments shortened for subcommmands - pretty optimistic here
-    index=1
-    for x $arg { if (eq $x $subcommand) { break } else { index = (+ $index 1) } } 
-    echo $index
-  }
-  
-  state=(echo (str:join ' ' $arg) | xargs example _carapace elvish state)
-  if (eq 1 0) {
-  }  elif (eq $state '_example') {
-    opt-specs = [
-        [&long='array' &short='a' &desc='multiflag' &arg-required=$true &completer=[_]{  }]
-        [&long='persistentFlag' &short='p' &desc='Help message for persistentFlag' &arg-optional=$true &completer=[_]{  }]
-        [&long='toggle' &short='t' &desc='Help message for toggle' &arg-optional=$true &completer=[_]{ edit:complex-candidate 'true' &display='true'
-edit:complex-candidate 'false' &display='false' }]
-    ]
-    arg-handlers = [
-        [_]{ edit:complex-candidate 'action' &display='action (action example)'
-edit:complex-candidate 'alias' &display='alias (action example)'
-edit:complex-candidate 'callback' &display='callback (callback example)'
-edit:complex-candidate 'condition' &display='condition (condition example)'
-edit:complex-candidate 'help' &display='help (Help about any command)'
-edit:complex-candidate 'injection' &display='injection (just trying to break things)'
-edit:complex-candidate 'multiparts' &display='multiparts (multiparts example)' }
-    ]
-    subargs = $arg[(subindex example):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }  elif (eq $state '_example__action') {
-    opt-specs = [
-        [&long='directories' &desc='files flag' &arg-required=$true &completer=[_]{ edit:complete-filename $arg[-1] }]
-        [&long='files' &short='f' &desc='files flag' &arg-required=$true &completer=[_]{ edit:complete-filename $arg[-1] }]
-        [&long='groups' &short='g' &desc='groups flag' &arg-required=$true &completer=[_]{ _example_callback '_example__action##groups' }]
-        [&long='kill' &short='k' &desc='kill signals' &arg-required=$true &completer=[_]{ edit:complex-candidate 'ABRT' &display='ABRT (Abnormal termination)'
-edit:complex-candidate 'ALRM' &display='ALRM (Virtual alarm clock)'
-edit:complex-candidate 'BUS' &display='BUS (BUS error)'
-edit:complex-candidate 'CHLD' &display='CHLD (Child status has changed)'
-edit:complex-candidate 'CONT' &display='CONT (Continue stopped process)'
-edit:complex-candidate 'FPE' &display='FPE (Floating-point exception)'
-edit:complex-candidate 'HUP' &display='HUP (Hangup detected on controlling terminal)'
-edit:complex-candidate 'ILL' &display='ILL (Illegal instruction)'
-edit:complex-candidate 'INT' &display='INT (Interrupt from keyboard)'
-edit:complex-candidate 'KILL' &display='KILL (Kill, unblockable)'
-edit:complex-candidate 'PIPE' &display='PIPE (Broken pipe)'
-edit:complex-candidate 'POLL' &display='POLL (Pollable event occurred)'
-edit:complex-candidate 'PROF' &display='PROF (Profiling alarm clock timer expired)'
-edit:complex-candidate 'PWR' &display='PWR (Power failure restart)'
-edit:complex-candidate 'QUIT' &display='QUIT (Quit from keyboard)'
-edit:complex-candidate 'SEGV' &display='SEGV (Segmentation violation)'
-edit:complex-candidate 'STKFLT' &display='STKFLT (Stack fault on coprocessor)'
-edit:complex-candidate 'STOP' &display='STOP (Stop process, unblockable)'
-edit:complex-candidate 'SYS' &display='SYS (Bad system call)'
-edit:complex-candidate 'TERM' &display='TERM (Termination request)'
-edit:complex-candidate 'TRAP' &display='TRAP (Trace/breakpoint trap)'
-edit:complex-candidate 'TSTP' &display='TSTP (Stop typed at keyboard)'
-edit:complex-candidate 'TTIN' &display='TTIN (Background read from tty)'
-edit:complex-candidate 'TTOU' &display='TTOU (Background write to tty)'
-edit:complex-candidate 'URG' &display='URG (Urgent condition on socket)'
-edit:complex-candidate 'USR1' &display='USR1 (User-defined signal 1)'
-edit:complex-candidate 'USR2' &display='USR2 (User-defined signal 2)'
-edit:complex-candidate 'VTALRM' &display='VTALRM (Virtual alarm clock)'
-edit:complex-candidate 'WINCH' &display='WINCH (Window size change)'
-edit:complex-candidate 'XCPU' &display='XCPU (CPU time limit exceeded)'
-edit:complex-candidate 'XFSZ' &display='XFSZ (File size limit exceeded)' }]
-        [&long='message' &short='m' &desc='message flag' &arg-required=$true &completer=[_]{ edit:complex-candidate '_' &display='_'
-edit:complex-candidate 'ERR' &display='ERR (message example)' }]
-        [&long='net_interfaces' &short='n' &desc='net_interfaces flag' &arg-required=$true &completer=[_]{ _example_callback '_example__action##net_interfaces' }]
-        [&long='optarg' &short='o' &desc='optional arg with default value blue' &arg-optional=$true &completer=[_]{ edit:complex-candidate 'blue' &display='blue'
-edit:complex-candidate 'red' &display='red'
-edit:complex-candidate 'green' &display='green'
-edit:complex-candidate 'yellow' &display='yellow' }]
-        [&long='usergroup' &desc='user\:group flag' &arg-required=$true &completer=[_]{ _example_callback '_example__action##usergroup' }]
-        [&long='users' &short='u' &desc='users flag' &arg-required=$true &completer=[_]{ _example_callback '_example__action##users' }]
-        [&long='values' &short='v' &desc='values flag' &arg-required=$true &completer=[_]{ edit:complex-candidate 'values' &display='values'
-edit:complex-candidate 'example' &display='example' }]
-        [&long='values_described' &short='d' &desc='values with description flag' &arg-required=$true &completer=[_]{ edit:complex-candidate 'values' &display='values (valueDescription)'
-edit:complex-candidate 'example' &display='example (exampleDescription)' }]
-    ]
-    arg-handlers = [
-      [_]{ edit:complex-candidate 'positional1' &display='positional1'
-edit:complex-candidate 'p1' &display='p1' }
-      [_]{ edit:complex-candidate 'positional2' &display='positional2'
-edit:complex-candidate 'p2' &display='p2' }
-    ]
-    subargs = $arg[(subindex action):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }  elif (eq $state '_example__callback') {
-    opt-specs = [
-        [&long='callback' &short='c' &desc='Help message for callback' &arg-required=$true &completer=[_]{ _example_callback '_example__callback##callback' }]
-    ]
-    arg-handlers = [
-      [_]{ _example_callback '_example__callback#1' }
-      [_]{ _example_callback '_example__callback#2' }
-      [_]{ _example_callback '_example__callback#0' }
-      ...
-    ]
-    subargs = $arg[(subindex callback):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }  elif (eq $state '_example__condition') {
-    opt-specs = [
-        [&long='required' &short='r' &desc='required flag' &arg-required=$true &completer=[_]{ edit:complex-candidate 'valid' &display='valid'
-edit:complex-candidate 'invalid' &display='invalid' }]
-    ]
-    arg-handlers = [
-      [_]{ _example_callback '_example__condition#1' }
-    ]
-    subargs = $arg[(subindex condition):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }  elif (eq $state '_example__help') {
-    opt-specs = [
-
-    ]
-    arg-handlers = [
-
-    ]
-    subargs = $arg[(subindex help):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }  elif (eq $state '_example__injection') {
-    opt-specs = [
-
-    ]
-    arg-handlers = [
-      [_]{ edit:complex-candidate 'echo fail' &display='echo fail' }
-      [_]{ edit:complex-candidate 'echo fail' &display='echo fail' }
-      [_]{ edit:complex-candidate 'echo fail' &display='echo fail' }
-      [_]{ edit:complex-candidate ' echo fail ' &display=' echo fail ' }
-      [_]{ edit:complex-candidate ' echo fail ' &display=' echo fail ' }
-      [_]{ edit:complex-candidate ' echo fail ' &display=' echo fail ' }
-      [_]{ edit:complex-candidate 'echo fail' &display='echo fail' }
-      [_]{ edit:complex-candidate '' &display='' }
-      [_]{ edit:complex-candidate 'LAST POSITIONAL VALUE' &display='LAST POSITIONAL VALUE' }
-    ]
-    subargs = $arg[(subindex injection):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }  elif (eq $state '_example__multiparts') {
-    opt-specs = [
-        [&long='at' &desc='multiparts with @ as divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##at' }]
-        [&long='colon' &desc='multiparts with \: as divider ' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##colon' }]
-        [&long='comma' &desc='multiparts with , as divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##comma' }]
-        [&long='dot' &desc='multiparts with . as divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##dot' }]
-        [&long='dotdotdot' &desc='multiparts with ... as divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##dotdotdot' }]
-        [&long='equals' &desc='multiparts with = as divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##equals' }]
-        [&long='none' &desc='multiparts without divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##none' }]
-        [&long='slash' &desc='multiparts with / as divider' &arg-required=$true &completer=[_]{ _example_callback '_example__multiparts##slash' }]
-    ]
-    arg-handlers = [
-      [_]{ _example_callback '_example__multiparts#1' }
-    ]
-    subargs = $arg[(subindex multiparts):] 
-    if (> (count $subargs) 0) {
-      edit:complete-getopt $subargs $opt-specs $arg-handlers
-    }
-  }
+    eval (example _carapace elvish _ (all $arg) | slurp) &ns=(ns [&arg=$arg])
 }
 
diff --git a/example/cmd/_test/fish.fish b/example/cmd/_test/fish.fish
index 1a1fbbe..5128f9c 100644
--- a/example/cmd/_test/fish.fish
+++ b/example/cmd/_test/fish.fish
@@ -10,69 +10,11 @@ function _example_quote_suffix
   end
 end
 
-function _example_state
-  set -lx CURRENT (commandline -cp)
-  if [ "$LINE" != "$CURRENT" ]
-    set -gx LINE (commandline -cp)
-    set -gx STATE (commandline -cp | sed "s/\$/"(_example_quote_suffix)"/" | xargs example _carapace fish state)
-  end
-
-  [ "$STATE" = "$argv" ]
-end
-
 function _example_callback
-  set -lx CALLBACK (commandline -cp | sed "s/\$/"(_example_quote_suffix)"/" | sed "s/ \$/ ''/" | xargs example _carapace fish $argv )
+  set -lx CALLBACK (commandline -cp | sed "s/\$/"(_example_quote_suffix)"/" | sed "s/ \$/ ''/" | xargs example _carapace fish _ )
   eval "$CALLBACK"
 end
 
 complete -c example -f
-
-complete -c 'example' -f -n '_example_state _example' -l 'array' -s 'a' -d 'multiflag' -r
-complete -c 'example' -f -n '_example_state _example' -l 'persistentFlag' -s 'p' -d 'Help message for persistentFlag'
-complete -c 'example' -f -n '_example_state _example' -l 'toggle' -s 't' -d 'Help message for toggle' -a '(echo -e "true	\nfalse	")'
-complete -c 'example' -f -n '_example_state _example ' -a 'action alias' -d 'action example'
-complete -c 'example' -f -n '_example_state _example ' -a 'callback ' -d 'callback example'
-complete -c 'example' -f -n '_example_state _example ' -a 'condition ' -d 'condition example'
-complete -c 'example' -f -n '_example_state _example ' -a 'help ' -d 'Help about any command'
-complete -c 'example' -f -n '_example_state _example ' -a 'injection ' -d 'just trying to break things'
-complete -c 'example' -f -n '_example_state _example ' -a 'multiparts ' -d 'multiparts example'
-
-
-complete -c 'example' -f -n '_example_state _example__action' -l 'directories' -d 'files flag' -a '(__fish_complete_directories)' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'files' -s 'f' -d 'files flag' -a '(__fish_complete_suffix ".go")' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'groups' -s 'g' -d 'groups flag' -a '(_example_callback _example__action##groups)' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'kill' -s 'k' -d 'kill signals' -a '(echo -e "ABRT	Abnormal termination\nALRM	Virtual alarm clock\nBUS	BUS error\nCHLD	Child status has changed\nCONT	Continue stopped process\nFPE	Floating-point exception\nHUP	Hangup detected on controlling terminal\nILL	Illegal instruction\nINT	Interrupt from keyboard\nKILL	Kill, unblockable\nPIPE	Broken pipe\nPOLL	Pollable event occurred\nPROF	Profiling alarm clock timer expired\nPWR	Power failure restart\nQUIT	Quit from keyboard\nSEGV	Segmentation violation\nSTKFLT	Stack fault on coprocessor\nSTOP	Stop process, unblockable\nSYS	Bad system call\nTERM	Termination request\nTRAP	Trace/breakpoint trap\nTSTP	Stop typed at keyboard\nTTIN	Background read from tty\nTTOU	Background write to tty\nURG	Urgent condition on socket\nUSR1	User-defined signal 1\nUSR2	User-defined signal 2\nVTALRM	Virtual alarm clock\nWINCH	Window size change\nXCPU	CPU time limit exceeded\nXFSZ	File size limit exceeded")' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'message' -s 'm' -d 'message flag' -a '(echo -e "_	\nERR	message example")' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'net_interfaces' -s 'n' -d 'net_interfaces flag' -a '(_example_callback _example__action##net_interfaces)' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'optarg' -s 'o' -d 'optional arg with default value blue' -a '(echo -e "blue	\nred	\ngreen	\nyellow	")'
-complete -c 'example' -f -n '_example_state _example__action' -l 'usergroup' -d 'user\:group flag' -a '(_example_callback _example__action##usergroup)' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'users' -s 'u' -d 'users flag' -a '(_example_callback _example__action##users)' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'values' -s 'v' -d 'values flag' -a '(echo -e "values	\nexample	")' -r
-complete -c 'example' -f -n '_example_state _example__action' -l 'values_described' -s 'd' -d 'values with description flag' -a '(echo -e "values	valueDescription\nexample	exampleDescription")' -r
-complete -c 'example' -f -n '_example_state _example__action' -a '(_example_callback _)'
-
-
-complete -c 'example' -f -n '_example_state _example__callback' -l 'callback' -s 'c' -d 'Help message for callback' -a '(_example_callback _example__callback##callback)' -r
-complete -c 'example' -f -n '_example_state _example__callback' -a '(_example_callback _)'
-
-
-complete -c 'example' -f -n '_example_state _example__condition' -l 'required' -s 'r' -d 'required flag' -a '(echo -e "valid	\ninvalid	")' -r
-complete -c 'example' -f -n '_example_state _example__condition' -a '(_example_callback _)'
-
-
-complete -c 'example' -f -n '_example_state _example__help' -a '(_example_callback _)'
-
-
-complete -c 'example' -f -n '_example_state _example__injection' -a '(_example_callback _)'
-
-
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'at' -d 'multiparts with @ as divider' -a '(_example_callback _example__multiparts##at)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'colon' -d 'multiparts with \: as divider ' -a '(_example_callback _example__multiparts##colon)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'comma' -d 'multiparts with , as divider' -a '(_example_callback _example__multiparts##comma)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'dot' -d 'multiparts with . as divider' -a '(_example_callback _example__multiparts##dot)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'dotdotdot' -d 'multiparts with ... as divider' -a '(_example_callback _example__multiparts##dotdotdot)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'equals' -d 'multiparts with = as divider' -a '(_example_callback _example__multiparts##equals)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'none' -d 'multiparts without divider' -a '(_example_callback _example__multiparts##none)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -l 'slash' -d 'multiparts with / as divider' -a '(_example_callback _example__multiparts##slash)' -r
-complete -c 'example' -f -n '_example_state _example__multiparts' -a '(_example_callback _)'
+complete -c 'example' -f -a '(_example_callback)' -r
 
diff --git a/example/cmd/_test/powershell.ps1 b/example/cmd/_test/powershell.ps1
index 484793a..6395e64 100644
--- a/example/cmd/_test/powershell.ps1
+++ b/example/cmd/_test/powershell.ps1
@@ -1,336 +1,18 @@
 using namespace System.Management.Automation
 using namespace System.Management.Automation.Language
-$_example_completer = {
+Function _example_completer {
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", "", Scope="Function", Target="*")]
     param($wordToComplete, $commandAst) #, $cursorPosition)
     $commandElements = $commandAst.CommandElements
-    $previous = $commandElements[-1].Value
-    if ($wordToComplete) {
-        $previous = $commandElements[-2].Value
-    }
 
-    $state = example _carapace powershell state $($commandElements| ForEach-Object {$_.Value})
 
-    Function _example_callback {
-      [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingInvokeExpression", "", Scope="Function", Target="*")]
-      param($uid)
+    $completions = @(
       if (!$wordToComplete) {
-        example _carapace powershell "$uid" $($commandElements| ForEach-Object {$_.Value}) '""' | Out-String | Invoke-Expression
+        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) '""' | Out-String | Invoke-Expression
       } else {
-        example _carapace powershell "$uid" $($commandElements| ForEach-Object {$_.Value}) | Out-String | Invoke-Expression
+        example _carapace powershell _ $($commandElements| ForEach-Object {$_.Extent}) | Out-String | Invoke-Expression
       }
-    }
-
-    $completions = @(switch ($state) {
-        '_example' {
-            switch -regex ($previous) {
-                '^(-a|--array)$' {
-
-                        break
-                      }
-                default {
-                    switch -regex ($wordToComplete) {
-                '^(-p=*|--persistentFlag=*)$' {
-                        @(
-
-                        ) | ForEach-Object{ [CompletionResult]::new($wordToComplete.split("=")[0] + "=" + $_.CompletionText, $_.ListItemText, $_.ResultType, $_.ToolTip) }
-                        break
-                      }
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-                [CompletionResult]::new('-a ', '-a', [CompletionResultType]::ParameterName, 'multiflag')
-                [CompletionResult]::new('--array ', '--array', [CompletionResultType]::ParameterName, 'multiflag')
-                [CompletionResult]::new('-p ', '-p', [CompletionResultType]::ParameterName, 'Help message for persistentFlag')
-                [CompletionResult]::new('--persistentFlag ', '--persistentFlag', [CompletionResultType]::ParameterName, 'Help message for persistentFlag')
-                [CompletionResult]::new('-t ', '-t', [CompletionResultType]::ParameterName, 'Help message for toggle')
-                [CompletionResult]::new('--toggle ', '--toggle', [CompletionResultType]::ParameterName, 'Help message for toggle')
-            } else {
-                [CompletionResult]::new('action ', 'action', [CompletionResultType]::Command, 'action example')
-                [CompletionResult]::new('callback ', 'callback', [CompletionResultType]::Command, 'callback example')
-                [CompletionResult]::new('condition ', 'condition', [CompletionResultType]::Command, 'condition example')
-                [CompletionResult]::new('help ', 'help', [CompletionResultType]::Command, 'Help about any command')
-                [CompletionResult]::new('injection ', 'injection', [CompletionResultType]::Command, 'just trying to break things')
-                [CompletionResult]::new('multiparts ', 'multiparts', [CompletionResultType]::Command, 'multiparts example')
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-        '_example__action' {
-            switch -regex ($previous) {
-                '^(--directories)$' {
-                        [CompletionResult]::new('', '', [CompletionResultType]::ParameterValue, '')
-                        break
-                      }
-                '^(-f|--files)$' {
-                        [CompletionResult]::new('', '', [CompletionResultType]::ParameterValue, '')
-                        break
-                      }
-                '^(-g|--groups)$' {
-                        _example_callback '_example__action##groups'
-                        break
-                      }
-                '^(-k|--kill)$' {
-                        [CompletionResult]::new('ABRT', 'ABRT ', [CompletionResultType]::ParameterValue, 'Abnormal termination ')
-                        [CompletionResult]::new('ALRM', 'ALRM ', [CompletionResultType]::ParameterValue, 'Virtual alarm clock ')
-                        [CompletionResult]::new('BUS', 'BUS ', [CompletionResultType]::ParameterValue, 'BUS error ')
-                        [CompletionResult]::new('CHLD', 'CHLD ', [CompletionResultType]::ParameterValue, 'Child status has changed ')
-                        [CompletionResult]::new('CONT', 'CONT ', [CompletionResultType]::ParameterValue, 'Continue stopped process ')
-                        [CompletionResult]::new('FPE', 'FPE ', [CompletionResultType]::ParameterValue, 'Floating-point exception ')
-                        [CompletionResult]::new('HUP', 'HUP ', [CompletionResultType]::ParameterValue, 'Hangup detected on controlling terminal ')
-                        [CompletionResult]::new('ILL', 'ILL ', [CompletionResultType]::ParameterValue, 'Illegal instruction ')
-                        [CompletionResult]::new('INT', 'INT ', [CompletionResultType]::ParameterValue, 'Interrupt from keyboard ')
-                        [CompletionResult]::new('KILL', 'KILL ', [CompletionResultType]::ParameterValue, 'Kill`, unblockable ')
-                        [CompletionResult]::new('PIPE', 'PIPE ', [CompletionResultType]::ParameterValue, 'Broken pipe ')
-                        [CompletionResult]::new('POLL', 'POLL ', [CompletionResultType]::ParameterValue, 'Pollable event occurred ')
-                        [CompletionResult]::new('PROF', 'PROF ', [CompletionResultType]::ParameterValue, 'Profiling alarm clock timer expired ')
-                        [CompletionResult]::new('PWR', 'PWR ', [CompletionResultType]::ParameterValue, 'Power failure restart ')
-                        [CompletionResult]::new('QUIT', 'QUIT ', [CompletionResultType]::ParameterValue, 'Quit from keyboard ')
-                        [CompletionResult]::new('SEGV', 'SEGV ', [CompletionResultType]::ParameterValue, 'Segmentation violation ')
-                        [CompletionResult]::new('STKFLT', 'STKFLT ', [CompletionResultType]::ParameterValue, 'Stack fault on coprocessor ')
-                        [CompletionResult]::new('STOP', 'STOP ', [CompletionResultType]::ParameterValue, 'Stop process`, unblockable ')
-                        [CompletionResult]::new('SYS', 'SYS ', [CompletionResultType]::ParameterValue, 'Bad system call ')
-                        [CompletionResult]::new('TERM', 'TERM ', [CompletionResultType]::ParameterValue, 'Termination request ')
-                        [CompletionResult]::new('TRAP', 'TRAP ', [CompletionResultType]::ParameterValue, 'Trace/breakpoint trap ')
-                        [CompletionResult]::new('TSTP', 'TSTP ', [CompletionResultType]::ParameterValue, 'Stop typed at keyboard ')
-                        [CompletionResult]::new('TTIN', 'TTIN ', [CompletionResultType]::ParameterValue, 'Background read from tty ')
-                        [CompletionResult]::new('TTOU', 'TTOU ', [CompletionResultType]::ParameterValue, 'Background write to tty ')
-                        [CompletionResult]::new('URG', 'URG ', [CompletionResultType]::ParameterValue, 'Urgent condition on socket ')
-                        [CompletionResult]::new('USR1', 'USR1 ', [CompletionResultType]::ParameterValue, 'User-defined signal 1 ')
-                        [CompletionResult]::new('USR2', 'USR2 ', [CompletionResultType]::ParameterValue, 'User-defined signal 2 ')
-                        [CompletionResult]::new('VTALRM', 'VTALRM ', [CompletionResultType]::ParameterValue, 'Virtual alarm clock ')
-                        [CompletionResult]::new('WINCH', 'WINCH ', [CompletionResultType]::ParameterValue, 'Window size change ')
-                        [CompletionResult]::new('XCPU', 'XCPU ', [CompletionResultType]::ParameterValue, 'CPU time limit exceeded ')
-                        [CompletionResult]::new('XFSZ', 'XFSZ ', [CompletionResultType]::ParameterValue, 'File size limit exceeded ')
-                        break
-                      }
-                '^(-m|--message)$' {
-                        [CompletionResult]::new('_', '_ ', [CompletionResultType]::ParameterValue, ' ')
-                        [CompletionResult]::new('ERR', 'ERR ', [CompletionResultType]::ParameterValue, 'message example ')
-                        break
-                      }
-                '^(-n|--net_interfaces)$' {
-                        _example_callback '_example__action##net_interfaces'
-                        break
-                      }
-                '^(--usergroup)$' {
-                        _example_callback '_example__action##usergroup'
-                        break
-                      }
-                '^(-u|--users)$' {
-                        _example_callback '_example__action##users'
-                        break
-                      }
-                '^(-v|--values)$' {
-                        [CompletionResult]::new('values', 'values ', [CompletionResultType]::ParameterValue, ' ')
-                        [CompletionResult]::new('example', 'example ', [CompletionResultType]::ParameterValue, ' ')
-                        break
-                      }
-                '^(-d|--values_described)$' {
-                        [CompletionResult]::new('values', 'values ', [CompletionResultType]::ParameterValue, 'valueDescription ')
-                        [CompletionResult]::new('example', 'example ', [CompletionResultType]::ParameterValue, 'exampleDescription ')
-                        break
-                      }
-                default {
-                    switch -regex ($wordToComplete) {
-                '^(-o=*|--optarg=*)$' {
-                        @(
-                        [CompletionResult]::new('blue', 'blue ', [CompletionResultType]::ParameterValue, ' ')
-                        [CompletionResult]::new('red', 'red ', [CompletionResultType]::ParameterValue, ' ')
-                        [CompletionResult]::new('green', 'green ', [CompletionResultType]::ParameterValue, ' ')
-                        [CompletionResult]::new('yellow', 'yellow ', [CompletionResultType]::ParameterValue, ' ')
-                        ) | ForEach-Object{ [CompletionResult]::new($wordToComplete.split("=")[0] + "=" + $_.CompletionText, $_.ListItemText, $_.ResultType, $_.ToolTip) }
-                        break
-                      }
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-                [CompletionResult]::new('--directories ', '--directories', [CompletionResultType]::ParameterName, 'files flag')
-                [CompletionResult]::new('-f ', '-f', [CompletionResultType]::ParameterName, 'files flag')
-                [CompletionResult]::new('--files ', '--files', [CompletionResultType]::ParameterName, 'files flag')
-                [CompletionResult]::new('-g ', '-g', [CompletionResultType]::ParameterName, 'groups flag')
-                [CompletionResult]::new('--groups ', '--groups', [CompletionResultType]::ParameterName, 'groups flag')
-                [CompletionResult]::new('-k ', '-k', [CompletionResultType]::ParameterName, 'kill signals')
-                [CompletionResult]::new('--kill ', '--kill', [CompletionResultType]::ParameterName, 'kill signals')
-                [CompletionResult]::new('-m ', '-m', [CompletionResultType]::ParameterName, 'message flag')
-                [CompletionResult]::new('--message ', '--message', [CompletionResultType]::ParameterName, 'message flag')
-                [CompletionResult]::new('-n ', '-n', [CompletionResultType]::ParameterName, 'net_interfaces flag')
-                [CompletionResult]::new('--net_interfaces ', '--net_interfaces', [CompletionResultType]::ParameterName, 'net_interfaces flag')
-                [CompletionResult]::new('-o ', '-o', [CompletionResultType]::ParameterName, 'optional arg with default value blue')
-                [CompletionResult]::new('--optarg ', '--optarg', [CompletionResultType]::ParameterName, 'optional arg with default value blue')
-                [CompletionResult]::new('--usergroup ', '--usergroup', [CompletionResultType]::ParameterName, 'user:group flag')
-                [CompletionResult]::new('-u ', '-u', [CompletionResultType]::ParameterName, 'users flag')
-                [CompletionResult]::new('--users ', '--users', [CompletionResultType]::ParameterName, 'users flag')
-                [CompletionResult]::new('-v ', '-v', [CompletionResultType]::ParameterName, 'values flag')
-                [CompletionResult]::new('--values ', '--values', [CompletionResultType]::ParameterName, 'values flag')
-                [CompletionResult]::new('-d ', '-d', [CompletionResultType]::ParameterName, 'values with description flag')
-                [CompletionResult]::new('--values_described ', '--values_described', [CompletionResultType]::ParameterName, 'values with description flag')
-            } else {
-                _example_callback '_'
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-        '_example__callback' {
-            switch -regex ($previous) {
-                '^(-c|--callback)$' {
-                        _example_callback '_example__callback##callback'
-                        break
-                      }
-                default {
-                    switch -regex ($wordToComplete) {
-
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-                [CompletionResult]::new('-c ', '-c', [CompletionResultType]::ParameterName, 'Help message for callback')
-                [CompletionResult]::new('--callback ', '--callback', [CompletionResultType]::ParameterName, 'Help message for callback')
-            } else {
-                _example_callback '_'
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-        '_example__condition' {
-            switch -regex ($previous) {
-                '^(-r|--required)$' {
-                        [CompletionResult]::new('valid', 'valid ', [CompletionResultType]::ParameterValue, ' ')
-                        [CompletionResult]::new('invalid', 'invalid ', [CompletionResultType]::ParameterValue, ' ')
-                        break
-                      }
-                default {
-                    switch -regex ($wordToComplete) {
-
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-                [CompletionResult]::new('-r ', '-r', [CompletionResultType]::ParameterName, 'required flag')
-                [CompletionResult]::new('--required ', '--required', [CompletionResultType]::ParameterName, 'required flag')
-            } else {
-                _example_callback '_'
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-        '_example__help' {
-            switch -regex ($previous) {
-
-                default {
-                    switch -regex ($wordToComplete) {
-
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-            } else {
-                _example_callback '_'
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-        '_example__injection' {
-            switch -regex ($previous) {
-
-                default {
-                    switch -regex ($wordToComplete) {
-
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-            } else {
-                _example_callback '_'
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-        '_example__multiparts' {
-            switch -regex ($previous) {
-                '^(--at)$' {
-                        _example_callback '_example__multiparts##at'
-                        break
-                      }
-                '^(--colon)$' {
-                        _example_callback '_example__multiparts##colon'
-                        break
-                      }
-                '^(--comma)$' {
-                        _example_callback '_example__multiparts##comma'
-                        break
-                      }
-                '^(--dot)$' {
-                        _example_callback '_example__multiparts##dot'
-                        break
-                      }
-                '^(--dotdotdot)$' {
-                        _example_callback '_example__multiparts##dotdotdot'
-                        break
-                      }
-                '^(--equals)$' {
-                        _example_callback '_example__multiparts##equals'
-                        break
-                      }
-                '^(--none)$' {
-                        _example_callback '_example__multiparts##none'
-                        break
-                      }
-                '^(--slash)$' {
-                        _example_callback '_example__multiparts##slash'
-                        break
-                      }
-                default {
-                    switch -regex ($wordToComplete) {
-
-
-                        default {
-
-            if ($wordToComplete -like "-*") {
-                [CompletionResult]::new('--at ', '--at', [CompletionResultType]::ParameterName, 'multiparts with @ as divider')
-                [CompletionResult]::new('--colon ', '--colon', [CompletionResultType]::ParameterName, 'multiparts with : as divider ')
-                [CompletionResult]::new('--comma ', '--comma', [CompletionResultType]::ParameterName, 'multiparts with `, as divider')
-                [CompletionResult]::new('--dot ', '--dot', [CompletionResultType]::ParameterName, 'multiparts with . as divider')
-                [CompletionResult]::new('--dotdotdot ', '--dotdotdot', [CompletionResultType]::ParameterName, 'multiparts with ... as divider')
-                [CompletionResult]::new('--equals ', '--equals', [CompletionResultType]::ParameterName, 'multiparts with = as divider')
-                [CompletionResult]::new('--none ', '--none', [CompletionResultType]::ParameterName, 'multiparts without divider')
-                [CompletionResult]::new('--slash ', '--slash', [CompletionResultType]::ParameterName, 'multiparts with / as divider')
-            } else {
-                _example_callback '_'
-            }
-            break
-        }
-                        }
-                    }
-                }
-            }
-
-    })
+    )
 
     if ($completions.count -eq 0) {
       return "" # prevent default file completion
@@ -339,5 +21,5 @@ $_example_completer = {
     $completions.Where{ ($_.CompletionText -replace '`','') -like "$wordToComplete*" } |
         Sort-Object -Property ListItemText
 }
-Register-ArgumentCompleter -Native -CommandName 'example' -ScriptBlock $_example_completer
+Register-ArgumentCompleter -Native -CommandName 'example' -ScriptBlock (Get-Item "Function:_example_completer").ScriptBlock
 
diff --git a/example/cmd/_test/xonsh.py b/example/cmd/_test/xonsh.py
index 7ab4927..328d4d8 100644
--- a/example/cmd/_test/xonsh.py
+++ b/example/cmd/_test/xonsh.py
@@ -22,15 +22,8 @@ def _example_completer(prefix, line, begidx, endidx, ctx):
 
     result = {}
 
-    # TODO python retrieve state
-    state, _ = subprocess.Popen(['example', '_carapace', 'xonsh', 'state', *words],
-                                   stdout=subprocess.PIPE,
-                                   stderr=subprocess.PIPE).communicate()
-    state = state.decode('utf-8').split('\n')[0]
-   
-    # TODO python callback function
-    def _example_callback(uid):
-        cb, _ = subprocess.Popen(['example', '_carapace', 'xonsh', uid, *words],
+    def _example_callback():
+        cb, _ = subprocess.Popen(['example', '_carapace', 'xonsh', '_', *words],
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.PIPE).communicate()
         cb = cb.decode('utf-8')
@@ -39,285 +32,13 @@ def _example_completer(prefix, line, begidx, endidx, ctx):
         else:
             nonlocal prefix, line, begidx, endidx, ctx
             return eval(cb)
-   
-    if False:
-        pass
-    elif state == '_example':
-        if False: # switch previous
-            pass
-        elif re.search('^(-a|--array)$',previous):
-            result = {}
-                  
-        else:
-            if False:
-                pass
-            elif re.search('^(-p=.*|--persistentFlag=.*)$',current):
-                result = {}
-                result = set(map(lambda x: RichCompletion(current.split('=')[0]+'='+x, display=x.display, description=x.description, prefix_len=x.prefix_len), result))
-    
-
-            elif re.search("-.*",current):
-                result = {
-                    RichCompletion('-a', display='-a', description='multiflag', prefix_len=0),
-                    RichCompletion('--array', display='--array', description='multiflag', prefix_len=0),
-                    RichCompletion('-p', display='-p', description='Help message for persistentFlag', prefix_len=0),
-                    RichCompletion('--persistentFlag', display='--persistentFlag', description='Help message for persistentFlag', prefix_len=0),
-                    RichCompletion('-t', display='-t', description='Help message for toggle', prefix_len=0),
-                    RichCompletion('--toggle', display='--toggle', description='Help message for toggle', prefix_len=0),
-                }
-            else:
-                result = {
-                RichCompletion('action', display='action', description='action example', prefix_len=0),
-                RichCompletion('callback', display='callback', description='callback example', prefix_len=0),
-                RichCompletion('condition', display='condition', description='condition example', prefix_len=0),
-                RichCompletion('help', display='help', description='Help about any command', prefix_len=0),
-                RichCompletion('injection', display='injection', description='just trying to break things', prefix_len=0),
-                RichCompletion('multiparts', display='multiparts', description='multiparts example', prefix_len=0),
-                }
-
-
-    elif state == '_example__action':
-        if False: # switch previous
-            pass
-        elif re.search('^(--directories)$',previous):
-            result = { RichCompletion(f, display=pathlib.PurePath(f).name, description='', prefix_len=0) for f in complete_dir(prefix, line, begidx, endidx, ctx, True)[0]}
-                  
-        elif re.search('^(-f|--files)$',previous):
-            result = { RichCompletion(f, display=pathlib.PurePath(f).name, description='', prefix_len=0) for f in complete_path(prefix, line, begidx, endidx, ctx)[0]}
-                  
-        elif re.search('^(-g|--groups)$',previous):
-            result = _example_callback('_example__action##groups')
-                  
-        elif re.search('^(-k|--kill)$',previous):
-            result = {
-                          RichCompletion('ABRT', display='ABRT', description='Abnormal termination', prefix_len=0),
-                          RichCompletion('ALRM', display='ALRM', description='Virtual alarm clock', prefix_len=0),
-                          RichCompletion('BUS', display='BUS', description='BUS error', prefix_len=0),
-                          RichCompletion('CHLD', display='CHLD', description='Child status has changed', prefix_len=0),
-                          RichCompletion('CONT', display='CONT', description='Continue stopped process', prefix_len=0),
-                          RichCompletion('FPE', display='FPE', description='Floating-point exception', prefix_len=0),
-                          RichCompletion('HUP', display='HUP', description='Hangup detected on controlling terminal', prefix_len=0),
-                          RichCompletion('ILL', display='ILL', description='Illegal instruction', prefix_len=0),
-                          RichCompletion('INT', display='INT', description='Interrupt from keyboard', prefix_len=0),
-                          RichCompletion('KILL', display='KILL', description='Kill, unblockable', prefix_len=0),
-                          RichCompletion('PIPE', display='PIPE', description='Broken pipe', prefix_len=0),
-                          RichCompletion('POLL', display='POLL', description='Pollable event occurred', prefix_len=0),
-                          RichCompletion('PROF', display='PROF', description='Profiling alarm clock timer expired', prefix_len=0),
-                          RichCompletion('PWR', display='PWR', description='Power failure restart', prefix_len=0),
-                          RichCompletion('QUIT', display='QUIT', description='Quit from keyboard', prefix_len=0),
-                          RichCompletion('SEGV', display='SEGV', description='Segmentation violation', prefix_len=0),
-                          RichCompletion('STKFLT', display='STKFLT', description='Stack fault on coprocessor', prefix_len=0),
-                          RichCompletion('STOP', display='STOP', description='Stop process, unblockable', prefix_len=0),
-                          RichCompletion('SYS', display='SYS', description='Bad system call', prefix_len=0),
-                          RichCompletion('TERM', display='TERM', description='Termination request', prefix_len=0),
-                          RichCompletion('TRAP', display='TRAP', description='Trace/breakpoint trap', prefix_len=0),
-                          RichCompletion('TSTP', display='TSTP', description='Stop typed at keyboard', prefix_len=0),
-                          RichCompletion('TTIN', display='TTIN', description='Background read from tty', prefix_len=0),
-                          RichCompletion('TTOU', display='TTOU', description='Background write to tty', prefix_len=0),
-                          RichCompletion('URG', display='URG', description='Urgent condition on socket', prefix_len=0),
-                          RichCompletion('USR1', display='USR1', description='User-defined signal 1', prefix_len=0),
-                          RichCompletion('USR2', display='USR2', description='User-defined signal 2', prefix_len=0),
-                          RichCompletion('VTALRM', display='VTALRM', description='Virtual alarm clock', prefix_len=0),
-                          RichCompletion('WINCH', display='WINCH', description='Window size change', prefix_len=0),
-                          RichCompletion('XCPU', display='XCPU', description='CPU time limit exceeded', prefix_len=0),
-                          RichCompletion('XFSZ', display='XFSZ', description='File size limit exceeded', prefix_len=0),
-                        }
-                  
-        elif re.search('^(-m|--message)$',previous):
-            result = {
-                          RichCompletion('_', display='_', description='', prefix_len=0),
-                          RichCompletion('ERR', display='ERR', description='message example', prefix_len=0),
-                        }
-                  
-        elif re.search('^(-n|--net_interfaces)$',previous):
-            result = _example_callback('_example__action##net_interfaces')
-                  
-        elif re.search('^(--usergroup)$',previous):
-            result = _example_callback('_example__action##usergroup')
-                  
-        elif re.search('^(-u|--users)$',previous):
-            result = _example_callback('_example__action##users')
-                  
-        elif re.search('^(-v|--values)$',previous):
-            result = {
-                          RichCompletion('values', display='values', description='', prefix_len=0),
-                          RichCompletion('example', display='example', description='', prefix_len=0),
-                        }
-                  
-        elif re.search('^(-d|--values_described)$',previous):
-            result = {
-                          RichCompletion('values', display='values', description='valueDescription', prefix_len=0),
-                          RichCompletion('example', display='example', description='exampleDescription', prefix_len=0),
-                        }
-                  
-        else:
-            if False:
-                pass
-            elif re.search('^(-o=.*|--optarg=.*)$',current):
-                result = {
-                              RichCompletion('blue', display='blue', description='', prefix_len=0),
-                              RichCompletion('red', display='red', description='', prefix_len=0),
-                              RichCompletion('green', display='green', description='', prefix_len=0),
-                              RichCompletion('yellow', display='yellow', description='', prefix_len=0),
-                            }
-                result = set(map(lambda x: RichCompletion(current.split('=')[0]+'='+x, display=x.display, description=x.description, prefix_len=x.prefix_len), result))
-    
-
-            elif re.search("-.*",current):
-                result = {
-                    RichCompletion('--directories', display='--directories', description='files flag', prefix_len=0),
-                    RichCompletion('-f', display='-f', description='files flag', prefix_len=0),
-                    RichCompletion('--files', display='--files', description='files flag', prefix_len=0),
-                    RichCompletion('-g', display='-g', description='groups flag', prefix_len=0),
-                    RichCompletion('--groups', display='--groups', description='groups flag', prefix_len=0),
-                    RichCompletion('-k', display='-k', description='kill signals', prefix_len=0),
-                    RichCompletion('--kill', display='--kill', description='kill signals', prefix_len=0),
-                    RichCompletion('-m', display='-m', description='message flag', prefix_len=0),
-                    RichCompletion('--message', display='--message', description='message flag', prefix_len=0),
-                    RichCompletion('-n', display='-n', description='net_interfaces flag', prefix_len=0),
-                    RichCompletion('--net_interfaces', display='--net_interfaces', description='net_interfaces flag', prefix_len=0),
-                    RichCompletion('-o', display='-o', description='optional arg with default value blue', prefix_len=0),
-                    RichCompletion('--optarg', display='--optarg', description='optional arg with default value blue', prefix_len=0),
-                    RichCompletion('--usergroup', display='--usergroup', description='user:group flag', prefix_len=0),
-                    RichCompletion('-u', display='-u', description='users flag', prefix_len=0),
-                    RichCompletion('--users', display='--users', description='users flag', prefix_len=0),
-                    RichCompletion('-v', display='-v', description='values flag', prefix_len=0),
-                    RichCompletion('--values', display='--values', description='values flag', prefix_len=0),
-                    RichCompletion('-d', display='-d', description='values with description flag', prefix_len=0),
-                    RichCompletion('--values_described', display='--values_described', description='values with description flag', prefix_len=0),
-                }
-            else:
-                result = _example_callback('_')
-
-
-    elif state == '_example__callback':
-        if False: # switch previous
-            pass
-        elif re.search('^(-c|--callback)$',previous):
-            result = _example_callback('_example__callback##callback')
-                  
-        else:
-            if False:
-                pass
-    
-
-            elif re.search("-.*",current):
-                result = {
-                    RichCompletion('-c', display='-c', description='Help message for callback', prefix_len=0),
-                    RichCompletion('--callback', display='--callback', description='Help message for callback', prefix_len=0),
-                }
-            else:
-                result = _example_callback('_')
-
-
-    elif state == '_example__condition':
-        if False: # switch previous
-            pass
-        elif re.search('^(-r|--required)$',previous):
-            result = {
-                          RichCompletion('valid', display='valid', description='', prefix_len=0),
-                          RichCompletion('invalid', display='invalid', description='', prefix_len=0),
-                        }
-                  
-        else:
-            if False:
-                pass
-    
-
-            elif re.search("-.*",current):
-                result = {
-                    RichCompletion('-r', display='-r', description='required flag', prefix_len=0),
-                    RichCompletion('--required', display='--required', description='required flag', prefix_len=0),
-                }
-            else:
-                result = _example_callback('_')
-
-
-    elif state == '_example__help':
-        if False: # switch previous
-            pass
-
-        else:
-            if False:
-                pass
-    
-
-            elif re.search("-.*",current):
-                result = {
-                }
-            else:
-                result = _example_callback('_')
-
-
-    elif state == '_example__injection':
-        if False: # switch previous
-            pass
-
-        else:
-            if False:
-                pass
-    
-
-            elif re.search("-.*",current):
-                result = {
-                }
-            else:
-                result = _example_callback('_')
-
-
-    elif state == '_example__multiparts':
-        if False: # switch previous
-            pass
-        elif re.search('^(--at)$',previous):
-            result = _example_callback('_example__multiparts##at')
-                  
-        elif re.search('^(--colon)$',previous):
-            result = _example_callback('_example__multiparts##colon')
-                  
-        elif re.search('^(--comma)$',previous):
-            result = _example_callback('_example__multiparts##comma')
-                  
-        elif re.search('^(--dot)$',previous):
-            result = _example_callback('_example__multiparts##dot')
-                  
-        elif re.search('^(--dotdotdot)$',previous):
-            result = _example_callback('_example__multiparts##dotdotdot')
-                  
-        elif re.search('^(--equals)$',previous):
-            result = _example_callback('_example__multiparts##equals')
-                  
-        elif re.search('^(--none)$',previous):
-            result = _example_callback('_example__multiparts##none')
-                  
-        elif re.search('^(--slash)$',previous):
-            result = _example_callback('_example__multiparts##slash')
-                  
-        else:
-            if False:
-                pass
-    
-
-            elif re.search("-.*",current):
-                result = {
-                    RichCompletion('--at', display='--at', description='multiparts with @ as divider', prefix_len=0),
-                    RichCompletion('--colon', display='--colon', description='multiparts with : as divider ', prefix_len=0),
-                    RichCompletion('--comma', display='--comma', description='multiparts with , as divider', prefix_len=0),
-                    RichCompletion('--dot', display='--dot', description='multiparts with . as divider', prefix_len=0),
-                    RichCompletion('--dotdotdot', display='--dotdotdot', description='multiparts with ... as divider', prefix_len=0),
-                    RichCompletion('--equals', display='--equals', description='multiparts with = as divider', prefix_len=0),
-                    RichCompletion('--none', display='--none', description='multiparts without divider', prefix_len=0),
-                    RichCompletion('--slash', display='--slash', description='multiparts with / as divider', prefix_len=0),
-                }
-            else:
-                result = _example_callback('_')
-
-
+  
+    result = _example_callback()
 
-    result = set(filter(lambda x: x.startswith(current) and x.endswith(suffix), result))
     if len(result) == 0:
         result = {RichCompletion(current, display=current, description='', prefix_len=0)}
 
-    result = set(map(lambda x: RichCompletion(x[:len(x)-len(suffix)], display=x.display, description=x.description, prefix_len=len(current)), result))
+    result = set(map(lambda x: RichCompletion(x[:len(x)-(len(suffix)+suffix.count(' '))], display=x.display, description=x.description, prefix_len=len(current)+current.count(' ')), result))
     return result
 _add_one_completer('example', _example_completer, 'start')
 
diff --git a/example/cmd/_test/zsh.sh b/example/cmd/_test/zsh.sh
index 0ead05a..1e12b21 100644
--- a/example/cmd/_test/zsh.sh
+++ b/example/cmd/_test/zsh.sh
@@ -1,123 +1,9 @@
 #compdef example
-function _example_callback {
+function _example_completion {
   # shellcheck disable=SC2086
-  eval "$(example _carapace zsh "$1" ${os_args})"
-}
-function _example {
-  local -a commands
-  # shellcheck disable=SC2206
-  local -a -x os_args=(${words})
-
-  _arguments -C \
-    "(*-a *--array)"{\*-a,\*--array}"[multiflag]: :" \
-    "(-p --persistentFlag)"{-p=-,--persistentFlag=-}"[Help message for persistentFlag]::" \
-    "(-t --toggle)"{-t=-,--toggle=-}"[Help message for toggle]:: :{local _comp_desc=('true' 'false');compadd -S '' -d _comp_desc 'true' 'false'}" \
-    "1: :->cmnds" \
-    "*::arg:->args"
-
-  # shellcheck disable=SC2154
-  case $state in
-    cmnds)
-      # shellcheck disable=SC2034
-      commands=(
-        "action:action example"
-        "alias:action example"
-        "callback:callback example"
-        "condition:condition example"
-        "help:Help about any command"
-        "injection:just trying to break things"
-        "multiparts:multiparts example"
-      )
-      _describe "command" commands
-      ;;
-  esac
-  
-  case "${words[1]}" in
-    action)
-      _example__action
-      ;;
-    alias)
-      _example__action
-      ;;
-    callback)
-      _example__callback
-      ;;
-    condition)
-      _example__condition
-      ;;
-    help)
-      _example__help
-      ;;
-    injection)
-      _example__injection
-      ;;
-    multiparts)
-      _example__multiparts
-      ;;
-  esac
-}
-
-function _example__action {
-    _arguments -C \
-    "--directories[files flag]: :_files -/" \
-    "(-f --files)"{-f,--files}"[files flag]: :_files -g '*.go'" \
-    "(-g --groups)"{-g,--groups}"[groups flag]: :{_example_callback '_example__action##groups'}" \
-    "(-k --kill)"{-k,--kill}"[kill signals]: :{local _comp_desc=('ABRT (Abnormal termination)' 'ALRM (Virtual alarm clock)' 'BUS (BUS error)' 'CHLD (Child status has changed)' 'CONT (Continue stopped process)' 'FPE (Floating-point exception)' 'HUP (Hangup detected on controlling terminal)' 'ILL (Illegal instruction)' 'INT (Interrupt from keyboard)' 'KILL (Kill, unblockable)' 'PIPE (Broken pipe)' 'POLL (Pollable event occurred)' 'PROF (Profiling alarm clock timer expired)' 'PWR (Power failure restart)' 'QUIT (Quit from keyboard)' 'SEGV (Segmentation violation)' 'STKFLT (Stack fault on coprocessor)' 'STOP (Stop process, unblockable)' 'SYS (Bad system call)' 'TERM (Termination request)' 'TRAP (Trace/breakpoint trap)' 'TSTP (Stop typed at keyboard)' 'TTIN (Background read from tty)' 'TTOU (Background write to tty)' 'URG (Urgent condition on socket)' 'USR1 (User-defined signal 1)' 'USR2 (User-defined signal 2)' 'VTALRM (Virtual alarm clock)' 'WINCH (Window size change)' 'XCPU (CPU time limit exceeded)' 'XFSZ (File size limit exceeded)');compadd -S '' -d _comp_desc 'ABRT' 'ALRM' 'BUS' 'CHLD' 'CONT' 'FPE' 'HUP' 'ILL' 'INT' 'KILL' 'PIPE' 'POLL' 'PROF' 'PWR' 'QUIT' 'SEGV' 'STKFLT' 'STOP' 'SYS' 'TERM' 'TRAP' 'TSTP' 'TTIN' 'TTOU' 'URG' 'USR1' 'USR2' 'VTALRM' 'WINCH' 'XCPU' 'XFSZ'}" \
-    "(-m --message)"{-m,--message}"[message flag]: :{local _comp_desc=('_' 'ERR (message example)');compadd -S '' -d _comp_desc '_' 'ERR'}" \
-    "(-n --net_interfaces)"{-n,--net_interfaces}"[net_interfaces flag]: :{_example_callback '_example__action##net_interfaces'}" \
-    "(-o --optarg)"{-o=-,--optarg=-}"[optional arg with default value blue]:: :{local _comp_desc=('blue' 'red' 'green' 'yellow');compadd -S '' -d _comp_desc 'blue' 'red' 'green' 'yellow'}" \
-    "--usergroup[user\:group flag]: :{_example_callback '_example__action##usergroup'}" \
-    "(-u --users)"{-u,--users}"[users flag]: :{_example_callback '_example__action##users'}" \
-    "(-v --values)"{-v,--values}"[values flag]: :{local _comp_desc=('values' 'example');compadd -S '' -d _comp_desc 'values' 'example'}" \
-    "(-d --values_described)"{-d,--values_described}"[values with description flag]: :{local _comp_desc=('values (valueDescription)' 'example (exampleDescription)');compadd -S '' -d _comp_desc 'values' 'example'}" \
-    "1: :{local _comp_desc=('positional1' 'p1');compadd -S '' -d _comp_desc 'positional1' 'p1'}" \
-    "2: :{local _comp_desc=('positional2' 'p2');compadd -S '' -d _comp_desc 'positional2' 'p2'}"
-}
-
-function _example__callback {
-    _arguments -C \
-    "(-c --callback)"{-c,--callback}"[Help message for callback]: :{_example_callback '_example__callback##callback'}" \
-    "1: :{_example_callback '_example__callback#1'}" \
-    "2: :{_example_callback '_example__callback#2'}" \
-    "*: :{_example_callback '_example__callback#0'}"
-}
-
-function _example__condition {
-    _arguments -C \
-    "(-r --required)"{-r,--required}"[required flag]: :{local _comp_desc=('valid' 'invalid');compadd -S '' -d _comp_desc 'valid' 'invalid'}" \
-    "1: :{_example_callback '_example__condition#1'}"
-}
-
-function _example__help {
-    _arguments -C \
-    "*::arg:->args"
-}
-
-function _example__injection {
-    _arguments -C \
-    "1: :{local _comp_desc=('echo fail');compadd -S '' -d _comp_desc 'echo fail'}" \
-    "2: :{local _comp_desc=('echo fail');compadd -S '' -d _comp_desc 'echo fail'}" \
-    "3: :{local _comp_desc=('echo fail');compadd -S '' -d _comp_desc 'echo fail'}" \
-    "4: :{local _comp_desc=(' echo fail ');compadd -S '' -d _comp_desc ' echo fail '}" \
-    "5: :{local _comp_desc=(' echo fail ');compadd -S '' -d _comp_desc ' echo fail '}" \
-    "6: :{local _comp_desc=(' echo fail ');compadd -S '' -d _comp_desc ' echo fail '}" \
-    "7: :{local _comp_desc=('echo fail');compadd -S '' -d _comp_desc 'echo fail'}" \
-    "8: :{local _comp_desc=('');compadd -S '' -d _comp_desc ''}" \
-    "9: :{local _comp_desc=('LAST POSITIONAL VALUE');compadd -S '' -d _comp_desc 'LAST POSITIONAL VALUE'}"
-}
+  eval "$(example _carapace zsh _ ${^words//\\ / }'')"
 
-function _example__multiparts {
-    _arguments -C \
-    "--at[multiparts with @ as divider]: :{_example_callback '_example__multiparts##at'}" \
-    "--colon[multiparts with \: as divider ]: :{_example_callback '_example__multiparts##colon'}" \
-    "--comma[multiparts with , as divider]: :{_example_callback '_example__multiparts##comma'}" \
-    "--dot[multiparts with . as divider]: :{_example_callback '_example__multiparts##dot'}" \
-    "--dotdotdot[multiparts with ... as divider]: :{_example_callback '_example__multiparts##dotdotdot'}" \
-    "--equals[multiparts with = as divider]: :{_example_callback '_example__multiparts##equals'}" \
-    "--none[multiparts without divider]: :{_example_callback '_example__multiparts##none'}" \
-    "--slash[multiparts with / as divider]: :{_example_callback '_example__multiparts##slash'}" \
-    "1: :{_example_callback '_example__multiparts#1'}"
 }
-compquote '' 2>/dev/null && _example
-compdef _example example
+compquote '' 2>/dev/null && _example_completion
+compdef _example_completion example
 
diff --git a/example/cmd/root_test.go b/example/cmd/root_test.go
index ffdf49f..42b3143 100644
--- a/example/cmd/root_test.go
+++ b/example/cmd/root_test.go
@@ -13,7 +13,7 @@ func testScript(t *testing.T, shell string, file string) {
 		t.Fatal("failed to read fixture file")
 	} else {
 		rootCmd.InitDefaultHelpCmd()
-		s, _ := carapace.Gen(rootCmd).Snippet(shell, false)
+		s, _ := carapace.Gen(rootCmd).Snippet(shell)
 		assert.Equal(t, string(content), s+"\n")
 	}
 }
diff --git a/example/main_test.go b/example/main_test.go
index 3797333..1667150 100644
--- a/example/main_test.go
+++ b/example/main_test.go
@@ -16,13 +16,20 @@ func doComplete(t *testing.T, shell string, cmdline string, contained ...string)
 		case "bash":
 			cmd = exec.Command("./_test/invoke_bash", cmdline)
 		case "elvish":
-			cmd = exec.Command("./_test/invoke_elvish", cmdline)
+			replacer := strings.NewReplacer(
+				`\ `, "' '", // TODO simple escape fix
+			)
+			cmd = exec.Command("./_test/invoke_elvish", replacer.Replace(cmdline))
 		case "fish":
 			cmd = exec.Command("./_test/invoke_fish", cmdline)
 		case "oil":
 			cmd = exec.Command("./_test/invoke_oil", cmdline)
 		case "powershell":
-			cmd = exec.Command("./_test/invoke_powershell", strings.Replace(cmdline, ",", "`,", -1))
+			replacer := strings.NewReplacer(
+				",", "`,",
+				`\ `, "` ", // TODO simple escape fix
+			)
+			cmd = exec.Command("./_test/invoke_powershell", replacer.Replace(cmdline))
 		case "xonsh":
 			cmd = exec.Command("./_test/invoke_xonsh", cmdline)
 		case "zsh":
@@ -45,21 +52,49 @@ func doComplete(t *testing.T, shell string, cmdline string, contained ...string)
 }
 
 var tests = map[string]string{
-	`example action `:                         "positional1",
-	`example action --`:                       "--values_described",
-	`example action --optarg `:                "positional1",
-	`example action --optarg`:                 "--optarg",
-	`example action --optarg=`:                "blue",
-	`example condition `:                      "ERR",
-	`example condition --required `:           "valid",
-	`example condition --required invalid `:   "ERR",
-	`example condition --required valid `:     "fulfilled",
-	`example callback `:                       "callback1",
-	`example callback --callback `:            "cb1",
-	`example multiparts `:                     "VALUE",
-	`example multiparts VALUE=`:               "one",
-	`example multiparts VALUE=one,`:           "DIRECTORY",
-	`example multiparts VALUE=one,DIRECTORY=`: "/",
+	`example action `:                                              "p",
+	`example action positional`:                                    "positional1",
+	`example action --`:                                            "--values_described",
+	`example action --optarg `:                                     "p",
+	`example action --optarg positional`:                           "positional1",
+	`example action --optarg`:                                      "--optarg",
+	`example action --optarg=`:                                     "blue",
+	`example condition `:                                           "ERR",
+	`example condition --required `:                                "valid",
+	`example condition --required invalid `:                        "ERR",
+	`example condition --required valid `:                          "fulfilled",
+	`example callback `:                                            "callback",
+	`example callback callback`:                                    "callback1",
+	`example callback --callback `:                                 "cb",
+	`example callback --callback cb`:                               "cb1",
+	`example multiparts `:                                          "VALUE",
+	`example multiparts --at `:                                     "first",
+	`example multiparts --at first@`:                               "second",
+	`example multiparts --at first@third\ with\ space@`:            "second",
+	`example multiparts --colon `:                                  "first",
+	`example multiparts --colon first:`:                            "second",
+	`example multiparts --colon first:third\ with\ space:`:         "second",
+	`example multiparts --comma `:                                  "first",
+	`example multiparts --comma first,`:                            "second",
+	`example multiparts --comma first,third\ with\ space,`:         "second", // TODO escape space correctly for each shell
+	`example multiparts --dot `:                                    "first",
+	`example multiparts --dot first.`:                              "second",
+	`example multiparts --dot first.third\ with\ space.`:           "second",
+	`example multiparts --dotdotdot `:                              "first",
+	`example multiparts --dotdotdot first...`:                      "second",
+	`example multiparts --dotdotdot first...third\ with\ space...`: "second",
+	`example multiparts --equals `:                                 "first",
+	`example multiparts --equals first=`:                           "second",
+	`example multiparts --equals first=third\ with\ space=`:        "second",
+	`example multiparts --slash `:                                  "first",
+	`example multiparts --slash first/`:                            "second",
+	`example multiparts --slash first/third\ with\ space/`:         "second",
+	`example multiparts --none `:                                   "a",
+	`example multiparts --none a`:                                  "b",
+	`example multiparts --none ab`:                                 "c",
+	`example multiparts VALUE=`:                                    "one",
+	`example multiparts VALUE=one,`:                                "DIRECTORY",
+	`example multiparts VALUE=one,DIRECTORY=`:                      "/",
 }
 
 func TestBash(t *testing.T) {