Repository: junegunn/fzf
File: shell/key-bindings.zsh (Shell)

Code before:
  # lines, are set. Also, make sure Perl is installed for multi-line output.
  if zmodload -F zsh/parameter p:{commands,history} 2>/dev/null && (( ${+commands[perl]} )); then
    selected="$(printf '%s\t%s\000' "${(kv)history[@]}" |
      perl -0 -ne 'if (!$seen{(/^\s*[0-9]+\**\t(.*)/s, $1)}++) { s/\n/\n\t/g; print; }' |
      FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '\t↳ ' --highlight-line -m ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} --read0") \
      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
      extracted_with_perl=1
  else
    selected="$(fc -rl 1 | __fzf_exec_awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
      FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '\t↳ ' --highlight-line -m ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER}") \
      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
  fi
  local ret=$?
  local -a cmds
  # Avoid leaking auto assigned values when using backreferences '(#b)'
  local -a mbegin mend match
  if [ -n "$selected" ]; then
    # Heuristic to check if the selected value is from history or a custom query
    if [[ $selected == [[:blank:]]#<->[[:blank:]]* ]]; then
      # Split at newlines
      for line in ${(ps:\n:)selected}; do
        if (( extracted_with_perl )); then
          [[ $line == (#b)(<->)(#B)$'\t'* ]] && cmds+=("${history[${match[1]}]}")
        elif [[ $line == [[:blank:]]#(#b)(<->)(#B)[[:blank:]]* ]]; then
          if zmodload -F zsh/parameter p:history 2>/dev/null && (( ${+history[${match[1]}]} )); then
            cmds+=("${history[${match[1]}]}")
          else
            cmds+=("${(g::)"$(fc -ln ${match[1]} ${match[1]})"}")
          fi
        fi
      done
      LBUFFER="${(pj:\n:)${(@)cmds%%$'\n'##}}"
    else # selected is a custom query, not from history
      LBUFFER="$selected"
    fi
  fi
  zle reset-prompt
  return $ret
}
if [[ ${FZF_CTRL_R_COMMAND-x} != "" ]]; then
  if [[ -n ${FZF_CTRL_R_COMMAND-} ]]; then
    echo "warning: FZF_CTRL_R_COMMAND is set to a custom command, but custom commands are not yet supported for CTRL-R" >&2
  fi
  zle     -N            fzf-history-widget
  bindkey -M emacs '^R' fzf-history-widget
  bindkey -M vicmd '^R' fzf-history-widget
  bindkey -M viins '^R' fzf-history-widget
fi
fi

} always {

Review comment (security):
❌❌❌ This is the part I’m concerned about: the history number here was created
with the `fc` builtin.

In the past, we’ve stumbled over foreign commands (the ones with a `*`) not
appearing in the `history` array:
- Ref: https://github.com/junegunn/fzf/issues/4061
- Ref: https://zsh.org/mla/users/2024/msg00692.html

What the user selects via fzf and what is actually delivered to them may differ;
this was partially alleviated by using `(( ${+history[${match[1]}]} ))`, but it
can still lead to issues for users. Even though I can't provide a good example,
at the moment.

Another problem with `"${(g::)"$(fc -ln ${match[1]} ${match[1]})"}"` is that it
treats every escape sequence the same, whereas retrieving from `history`
preserves the command exactly as it was entered.

For example, consider this demo command:

```bash
{
  seq 5
  echo '\n'
} | wc -l
```

✅ Using the `"${history[${match[1]}]}"` array to retrieve the command yields the
same command the user entered:

```bash
{
  seq 5
  echo '\n'
} | wc -l
```

❌ Using `"${(g::)"$(fc -ln ${match[1]} ${match[1]})"}"` causes `'\n'` to be
expanded:

```bash
{
  seq 5
  echo '
'
} | wc -l
```

---

SUMMARY: As long as the user has Perl and uses the `history` array, there
shouldn’t be an issue. The `fc` builtin and `history` array crossover is a
potenial issue.


Code after:
  # lines, are set. Also, make sure Perl is installed for multi-line output.
  if zmodload -F zsh/parameter p:{commands,history} 2>/dev/null && (( ${+commands[perl]} )); then
    selected="$(printf '%s\t%s\000' "${(kv)history[@]}" |
      perl -0 -ne 'if (!$seen{(/^\s*[0-9]+\**\t(.*)/s, $1)}++) { s/\n/\n\t/g; print; }' |
      FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '\t↳ ' --highlight-line --multi ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} --read0") \
      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
      extracted_with_perl=1
  else
    selected="$(fc -rl 1 | __fzf_exec_awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
      FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,alt-r:toggle-raw --wrap-sign '\t↳ ' --highlight-line --multi ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER}") \
      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
  fi
  local ret=$?
  local -a cmds
  # Avoid leaking auto assigned values when using backreferences '(#b)'
  local -a mbegin mend match
  if [ -n "$selected" ]; then
    # Heuristic to check if the selected value is from history or a custom query
    if ((( extracted_with_perl )) && [[ $selected == <->$'\t'* ]]) ||
    ((( ! extracted_with_perl )) && [[ $selected == [[:blank:]]#<->(  |\* )* ]]); then
      # Split at newlines
      for line in ${(ps:\n:)selected}; do
        if (( extracted_with_perl )); then
          if [[ $line == (#b)(<->)(#B)$'\t'* ]]; then
            (( ${+history[${match[1]}]} )) && cmds+=("${history[${match[1]}]}")
          fi
        elif [[ $line == [[:blank:]]#(#b)(<->)(#B)(  |\* )* ]]; then
          # Avoid $history array: lags behind 'fc' on foreign commands (*)
          # https://zsh.org/mla/users/2024/msg00692.html
          # Push BUFFER onto stack; fetch and save history entry from BUFFER; restore
          zle .push-line
          zle vi-fetch-history -n ${match[1]}
          (( ${#BUFFER} )) && cmds+=("${BUFFER}")
          BUFFER=""
          zle .get-line
        fi
      done
      if (( ${#cmds[@]} )); then
        # Join by newline after stripping trailing newlines from each command
        BUFFER="${(pj:\n:)${(@)cmds%%$'\n'#}}"
        CURSOR=${#BUFFER}
      fi
    else # selected is a custom query, not from history
      LBUFFER="$selected"
    fi
  fi
  zle reset-prompt
  return $ret
}
if [[ ${FZF_CTRL_R_COMMAND-x} != "" ]]; then
  if [[ -n ${FZF_CTRL_R_COMMAND-} ]]; then