Repository: junegunn/fzf (language: go)

Issue:
0.56.1/2 breaks my `FZF_COMPLETION_TRIGGER`
### Checklist

- [X] I have read through the manual page (`man fzf`)
- [X] I have searched through the existing issues
- [X] For bug reports, I have checked if the bug is reproducible in the latest version of fzf

### Output of `fzf --version`

0.56.2

### OS

- [ ] Linux
- [X] macOS
- [ ] Windows
- [ ] Etc.

### Shell

- [ ] bash
- [X] zsh
- [ ] fish

### Problem / Steps to reproduce

Thank you for the great work!

In my `.zshrc`, I set ``FZF_COMPLETION_TRIGGER='`'``. With up to 0.56.0 installed, this works well (and has for years). 

Starting in 0.56.1 and still existing in 0.56.2, this no longer works. When I type for example `` cd `<TAB> ``, nothing happens. If I set the env var to nearly anything else, it works again.

If I downgrade to 0.56.0, it works again.

The fzf portion of my `.zshrc`: https://github.com/jefferickson/dotfiles/blob/d552e8eae75edd1ce4d14b11ae960a9aeccb370a/.zshrc#L96-L106


Discussion / hints:

Fix patch:
diff --git a/shell/completion.zsh b/shell/completion.zsh
index 171a1b2b7ed..39e29a03a75 100644
--- a/shell/completion.zsh
+++ b/shell/completion.zsh
@@ -123,10 +123,10 @@ __fzf_comprun() {
 # Extract the name of the command. e.g. ls; foo=1 ssh **<tab>
 __fzf_extract_command() {
   setopt localoptions noksh_arrays
-  # Control completion with the "compstate" parameter, insert and list noting
+  # Control completion with the "compstate" parameter, insert and list nothing
   compstate[insert]=
   compstate[list]=
-  cmd_word="${words[1]}"
+  cmd_word="${(Q)words[1]}"
 }
 
 __fzf_generic_path_completion() {
@@ -303,8 +303,9 @@ _fzf_complete_kill_post() {
 }
 
 fzf-completion() {
+  typeset -g cmd_word
   trap 'unset cmd_word' EXIT
-  local tokens prefix trigger tail matches lbuf d_cmds
+  local tokens prefix trigger tail matches lbuf d_cmds cursor_pos
   setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
 
   # Check if at least one completion system (old or new) is active
@@ -323,7 +324,7 @@ fzf-completion() {
 
   # Explicitly allow for empty trigger.
   trigger=${FZF_COMPLETION_TRIGGER-'**'}
-  [ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("")
+  [[ -z $trigger && ${LBUFFER[-1]} == ' ' ]] && tokens+=("")
 
   # When the trigger starts with ';', it becomes a separate token
   if [[ ${LBUFFER} = *"${tokens[-2]-}${tokens[-1]}" ]]; then
@@ -338,9 +339,16 @@ fzf-completion() {
   if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
     d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS-cd pushd rmdir})
 
-    # Make the 'cmd_word' global
-    zle __fzf_extract_command || :
-    [[ -z "$cmd_word" ]] && return
+    cursor_pos=$CURSOR
+    {
+      # Move the cursor before the trigger to preserve word array elements when
+      # trigger chars like ';' or '`' would otherwise reset the 'words' array.
+      CURSOR=$((cursor_pos - ${#trigger} - 1))
+      # Assign the extracted command to the global variable 'cmd_word'
+      zle __fzf_extract_command
+    } always {
+      CURSOR=$cursor_pos
+    }
 
     [ -z "$trigger"      ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
     if [[ $prefix = *'$('* ]] || [[ $prefix = *'<('* ]] || [[ $prefix = *'>('* ]] || [[ $prefix = *':='* ]] || [[ $prefix = *'`'* ]]; then
@@ -348,7 +356,7 @@ fzf-completion() {
     fi
     [ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}}
 
-    if eval "type _fzf_complete_${cmd_word} > /dev/null"; then
+    if eval "noglob type _fzf_complete_${cmd_word} >/dev/null"; then
       prefix="$prefix" eval _fzf_complete_${cmd_word} ${(q)lbuf}
       zle reset-prompt
     elif [ ${d_cmds[(i)$cmd_word]} -le ${#d_cmds} ]; then


Test patch: