Repository: rsteube/carapace
Pull request #476 (2022-04-06 15:58:42)

zsh: fix fzf-tab compability


Patch:
diff --git a/internal/shell/zsh/action.go b/internal/shell/zsh/action.go
index 89ad329..8ae8248 100644
--- a/internal/shell/zsh/action.go
+++ b/internal/shell/zsh/action.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/rsteube/carapace/internal/common"
 	"github.com/rsteube/carapace/pkg/style"
+	"github.com/rsteube/carapace/third_party/github.com/elves/elvish/pkg/ui"
 )
 
 var sanitizer = strings.NewReplacer(
@@ -30,6 +31,16 @@ func ActionRawValues(currentWord string, nospace bool, values common.RawValues)
 		}
 	}
 
+	valueStyle := "default"
+	if s := style.Carapace.Value; s != "" && ui.ParseStyling(s) != nil {
+		valueStyle = s
+	}
+
+	descriptionStyle := "default"
+	if s := style.Carapace.Description; s != "" && ui.ParseStyling(s) != nil {
+		descriptionStyle = s
+	}
+
 	zstyles := make([]string, 0)
 	vals := make([]string, len(filtered))
 	for index, val := range filtered {
@@ -40,34 +51,38 @@ func ActionRawValues(currentWord string, nospace bool, values common.RawValues)
 		val.Display = sanitizer.Replace(val.Display)
 		val.Description = sanitizer.Replace(val.Description)
 
-		if zstyle := formatZstyle(val.Display, val.Style); zstyle != "" {
-			zstyles = append(zstyles, zstyle)
+		if val.Style == "" || ui.ParseStyling(val.Style) == nil {
+			val.Style = valueStyle
 		}
 
 		if strings.TrimSpace(val.Description) == "" {
-			if hasDescriptions {
-				vals[index] = fmt.Sprintf("%v\t%v\002", val.Value, val.Display)
-			} else {
-				vals[index] = fmt.Sprintf("%v\t%v", val.Value, val.Display)
-			}
+			vals[index] = fmt.Sprintf("%v\t%v", val.Value, val.Display)
+			zstyles = append(zstyles, formatZstyle(fmt.Sprintf("(%v)()", zstyleQuoter.Replace(val.Display)), val.Style, descriptionStyle))
 		} else {
-			vals[index] = fmt.Sprintf("%v\t%v\002 %v-- %v", val.Value, val.Display, strings.Repeat(" ", maxLength-len(val.Display)), val.TrimmedDescription())
+			vals[index] = fmt.Sprintf("%v\t%v %v-- %v", val.Value, val.Display, strings.Repeat(" ", maxLength-len(val.Display)), val.TrimmedDescription())
+			zstyles = append(zstyles, formatZstyle(fmt.Sprintf("(%v)[ ]*-- (%v)", zstyleQuoter.Replace(val.Display), zstyleQuoter.Replace(val.TrimmedDescription())), val.Style, descriptionStyle))
 		}
 	}
 
 	if len(zstyles) > 1000 { // TODO disable styling for large amount of values (bad performance)
 		zstyles = make([]string, 0)
 	}
-	zstyles = append(zstyles, fmt.Sprintf("=(#b)(*)(\002*)=0=%v=%v", style.SGR(style.Carapace.Value), style.SGR(style.Carapace.Description)))
-	return fmt.Sprintf("%v\n%v", strings.Join(zstyles, ":"), strings.Join(vals, "\n"))
+	return fmt.Sprintf(":%v\n%v", strings.Join(zstyles, ":"), strings.Join(vals, "\n"))
 }
 
+var zstyleQuoter = strings.NewReplacer(
+	"#", `\#`,
+	"*", `\*`,
+	"(", `\(`,
+	")", `\)`,
+	"~", `\~`,
+	"[", `\[`,
+	"]", `\]`,
+)
+
 // formatZstyle creates a zstyle matcher for given display stings.
 // `compadd -l` (one per line) accepts ansi escape sequences in display value but it seems in tabular view these are removed.
 // To ease matching in list mode, the display values have a hidden `\002` suffix.
-func formatZstyle(s, _style string) string {
-	if sgr := style.SGR(_style); sgr != "" {
-		return fmt.Sprintf("=(#b)(%v)(\002*|)=0=%v=%v", strings.Replace(s, "#", `\#`, -1), sgr, style.SGR(style.Carapace.Description))
-	}
-	return ""
+func formatZstyle(s, _styleValue, _styleDescription string) string {
+	return fmt.Sprintf("=(#b)%v=0=%v=%v", s, style.SGR(_styleValue), style.SGR(_styleDescription))
 }
diff --git a/internal/shell/zsh/snippet.go b/internal/shell/zsh/snippet.go
index 5ad022b..b9ce303 100644
--- a/internal/shell/zsh/snippet.go
+++ b/internal/shell/zsh/snippet.go
@@ -27,6 +27,7 @@ function _%v_completion {
   fi
 
   export ZLS_COLOURS="${lines[1]}"
+  # TODO for ${curcontext}: zstyle ':completion:*' list-colors "${lines[1]}"
   
   # shellcheck disable=SC2034,2206
   lines=(${lines[@]:1})
@@ -41,13 +42,7 @@ function _%v_completion {
   # shellcheck disable=SC2034,2206
   vals=(${vals%%%%$'\001'*})
 
-  if [[ ${displays[*]} == *$'\002'" "* ]]; then # with descriptions
-      compadd -l -S "${suffix}" -d displays -a -- vals
-  else
-      # shellcheck disable=SC2034,2206
-      displays=(${displays%%%%$'\002'*})
-      compadd -S "${suffix}" -d displays -a -- vals
-  fi
+  compadd -S "${suffix}" -d displays -a -- vals
 }
 compquote '' 2>/dev/null && _%v_completion
 compdef _%v_completion %v


Test patch:
diff --git a/example/cmd/_test/zsh.sh b/example/cmd/_test/zsh.sh
index 05eebe5..7dd2ce9 100644
--- a/example/cmd/_test/zsh.sh
+++ b/example/cmd/_test/zsh.sh
@@ -15,6 +15,7 @@ function _example_completion {
   fi
 
   export ZLS_COLOURS="${lines[1]}"
+  # TODO for ${curcontext}: zstyle ':completion:*' list-colors "${lines[1]}"
   
   # shellcheck disable=SC2034,2206
   lines=(${lines[@]:1})
@@ -29,13 +30,7 @@ function _example_completion {
   # shellcheck disable=SC2034,2206
   vals=(${vals%%$'\001'*})
 
-  if [[ ${displays[*]} == *$'\002'" "* ]]; then # with descriptions
-      compadd -l -S "${suffix}" -d displays -a -- vals
-  else
-      # shellcheck disable=SC2034,2206
-      displays=(${displays%%$'\002'*})
-      compadd -S "${suffix}" -d displays -a -- vals
-  fi
+  compadd -S "${suffix}" -d displays -a -- vals
 }
 compquote '' 2>/dev/null && _example_completion
 compdef _example_completion example