Repository: rsteube/carapace
Pull request #832 (2023-07-21 19:12:46)

traverse: complete values attached to flags for non-optarg as well


Patch:
diff --git a/internal/pflagfork/flag.go b/internal/pflagfork/flag.go
index ae4676c..adf359e 100644
--- a/internal/pflagfork/flag.go
+++ b/internal/pflagfork/flag.go
@@ -53,10 +53,9 @@ func (f Flag) IsRepeatable() bool {
 	return false
 }
 
-func (f Flag) Split(arg string) (prefix, optarg string) {
+func (f Flag) Split(arg string) []string {
 	delimiter := string(f.OptargDelimiter())
-	splitted := strings.SplitN(arg, delimiter, 2)
-	return splitted[0] + delimiter, splitted[1]
+	return strings.SplitAfterN(arg, delimiter, 2)
 }
 
 func (f Flag) Matches(arg string, posix bool) bool {
diff --git a/traverse.go b/traverse.go
index 970a758..9c485b0 100644
--- a/traverse.go
+++ b/traverse.go
@@ -82,6 +82,8 @@ loop:
 
 			if inFlag.Flag == nil {
 				LOG.Printf("flag %#v is unknown", arg)
+			} else if splitted := inFlag.Flag.Split(arg); len(splitted) > 1 {
+				inFlag.Args = append(inFlag.Args, splitted[1])
 			}
 			continue
 
@@ -160,9 +162,9 @@ loop:
 
 	// flag
 	case !c.DisableFlagParsing && strings.HasPrefix(context.Value, "-") && (fs.IsInterspersed() || len(inPositionals) == 0):
-		if f := fs.LookupArg(context.Value); f != nil && f.IsOptarg() && strings.Contains(context.Value, string(f.OptargDelimiter())) {
+		if f := fs.LookupArg(context.Value); f != nil && strings.Contains(context.Value, string(f.OptargDelimiter())) {
 			LOG.Printf("completing optional flag argument for arg %#v\n", context.Value)
-			prefix, _ := f.Split(context.Value)
+			prefix := f.Split(context.Value)[0]
 
 			switch f.Value.Type() {
 			case "bool":


Test patch:
diff --git a/example/cmd/action_test.go b/example/cmd/action_test.go
index 83acdc6..eeed5ea 100644
--- a/example/cmd/action_test.go
+++ b/example/cmd/action_test.go
@@ -226,3 +226,49 @@ func TestPersistentFlag(t *testing.T) {
 				Usage("Help message for persistentFlag2"))
 	})
 }
+
+func TestAttached(t *testing.T) {
+	sandbox.Package(t, "github.com/rsteube/carapace/example")(func(s *sandbox.Sandbox) {
+		s.Files(
+			"dirA/file1.txt", "",
+			"dirA/file2.png", "",
+			"dirB/dirC/file3.go", "",
+			"dirB/file4.md", "",
+			"file5.go", "",
+		)
+
+		s.Run("action", "--values=").
+			Expect(carapace.ActionValues(
+				"first",
+				"second",
+				"third",
+			).Prefix("--values=").
+				Usage("ActionValues()"))
+
+		s.Run("action", "--values=f").
+			Expect(carapace.ActionValues(
+				"first",
+			).Prefix("--values=").
+				Usage("ActionValues()"))
+
+		s.Run("action", "--values=first", "").
+			Expect(carapace.ActionValues(
+				"embeddedP1",
+				"embeddedPositional1",
+			).Usage("action [pos1] [pos2] [--] [dashAny]..."))
+
+		s.Run("action", "--multiparts-nested=VALUE=").
+			Expect(carapace.ActionValues("one", "two", "three").
+				Prefix("--multiparts-nested=VALUE=").
+				NoSpace().
+				Usage("ActionMultiParts(...ActionMultiParts...)"))
+
+		s.Run("action", "--multiparts-nested=VALUE=two,DIRECTORY=").
+			Expect(carapace.ActionValues("dirA/", "dirB/").
+				Tag("directories").
+				StyleF(style.ForPath).
+				Prefix("--multiparts-nested=VALUE=two,DIRECTORY=").
+				NoSpace().
+				Usage("ActionMultiParts(...ActionMultiParts...)"))
+	})
+}