Repository: junegunn/fzf (language: go)

Issue:
0.56.1 broke fzf-history-widget completion in zsh 5.9 when share_history is enabled
### 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 (brew)

### OS

- [ ] Linux
- [X] macOS
- [ ] Windows
- [ ] Etc.

### Shell

- [ ] bash
- [X] zsh
- [ ] fish

### Problem / Steps to reproduce

This seems related to #4061:

I am using default `source <(fzf --zsh)` from macOS Homebrew with zsh 5.9 (x86_64-apple-darwin23.0) with `setopt share_history` enabled, but as of fzf version [0.56.1](https://github.com/junegunn/fzf/releases/tag/v0.56.1) the history completion with `^R` bound to `fzf-history-widget` is broken (last working version was 0.56.0). Previous behaviour in zsh was that `foo^r^m` would return fzf’s default matching result for `foo` (e.g. `found-history`) but now it returns my original input string `foo`. In the simplest case of `^r^m` the widget simply returns nothing (previously, it would have returned the fzf’s default selected item). Intermittently it does return a result, but rarely. Despite having `share_history` enabled, I do not have a second shell using the history file; this issue is reproducible with a single shell on its own. (And unlike https://github.com/junegunn/fzf/issues/4088 I’m not using `FZF_COMPLETION_TRIGGER`.) If I downgrade to 0.56.0 or disable `share_history` the previous expected behaviour is restored.




Discussion / hints:
> 0.56.2 (brew)

> but as of fzf version 0.56.1 the history completion

Just to confirm, you also tested `0.56.2` and the issue remains?

Please share your options.
```bash
unsetopt KSH_OPTION_PRINT
print -r -- $(setopt)
```

---

Could you give me some guidance on the individual steps I need to take to see the issue? 

A minimal zsh version with a couple of steps ...
```zsh
command env -i HOME=$HOME TERM=$TERM USER=$USER PATH=$PATH zsh -f -o sharehistory
source <(fzf --zsh)
# press 'Control-R'
# ?
```

I am experiencing this issue too.

* Latest iTerm, MacOS, fzf.
* Using Zsh.

```
% fzf --version
0.56.2 (brew)

% unsetopt KSH_OPTION_PRINT
% print -r -- $(setopt)
combiningchars extendedhistory histignorealldups histreduceblanks interactive login promptsubst sharehistory shinstdin
```

in .zshrc
```
# history
HISTFILE=~/.zsh_history
HISTSIZE=10000
SAVEHIST=10000
setopt EXTENDED_HISTORY          # write the history file in the ":start:elapsed;command" format.
setopt HIST_REDUCE_BLANKS        # remove superfluous blanks before recording entry.
setopt SHARE_HISTORY             # share history between all sessions.
setopt HIST_IGNORE_ALL_DUPS      # delete old recorded entry if new entry is a duplicate.

source <(fzf --zsh)
```

1. press 'Control-R' - history appears and searches great
2. After selecting the desired history command, fzf closes and nothing is written to the prompt


After commenting out the `setopt SHARE_HISTORY` option, fzf works again.


@ryanwi, does the issue disappear if you do the following:

1. Press <kbd>⏎ Enter</kbd> before opening the `fzf-history`.
2. Open the fzf-history-widget with your assigned key (default <kbd>⌃ Control</kbd> + <kbd>R</kbd>).
3. Make your selection. Was the desired item successfully retrieved?

In the meantime, this workaround will remove the `fc -RI` call, which likely
causes the mischief, but you'll still encounter the original issue[^1] it was
intended to solve.

```bash
source <(fzf --zsh | sed 's/fc -RI/true/')
```
[^1]: [ctrl+r no longer pulling from shared history until a command is run succesfully ¬∑ Issue #4061 ¬∑ junegunn/fzf ¬∑ GitHub](https://github.com/junegunn/fzf/issues/4061)
Thanks very much @LangLangBart and @ryanwi. For me: pressing <kbd>⏎ Enter</kbd> doesn’t help, but removing `fc -RI` does! Without `fc -RI` the history and indexes shown in fzf are correct (matching the shell session), but with `fc -RI` the history list and indexes shown in fzf are wildly wrong when HISTFILE is non-empty. 
Thanks for the confirmation, could you test an earlier version of the
keybinding[^1], before the `fc -RI` call was moved inside the command
substitution `$(…)`?


https://github.com/junegunn/fzf/blob/d938fdc496ccecfe5d747500927b675d31e1835a/shell/key-bindings.zsh#L116-L118

Just run:

```bash
source <(curl -fsSL https://raw.githubusercontent.com/junegunn/fzf/d938fdc/shell/key-bindings.zsh) 
```
[^1]: [fix(zsh): history loading with shared option by LangLangBart · Pull Request #4071 · junegunn/fzf · GitHub](https://github.com/junegunn/fzf/pull/4071)
Yes, d938fdc “works” (selected item appears on the zsh line) but has the problematic side-effect of heavily mutating the shell history every time fzf is used: changes the order and numbers of items in the history, and up-arrow takes me to the wrong (out of order) history lines.
Thanks again for testing. I might propose reverting `fc -RI` and reopening #4061.

We could move `sharehistory` into the `if…` block so that `fc -…` with `awk`
handles the history. However, this isn't a good solution, as some users would be
confused about why they need to disable `sharehistory` to see multiline `fzf`
history, right?

https://github.com/junegunn/fzf/blob/215ab48222ac5fa8855c1e5bbf56742276b57324/shell/key-bindings.zsh#L113-L130
Hmm yeah, revert and re-open seems fair, given that it minimises the unresolved corner case and retains the overall functionality until a cleaner solution is found. 

Fix patch:
diff --git a/shell/key-bindings.zsh b/shell/key-bindings.zsh
index 368811859ad..3c17401cd7a 100644
--- a/shell/key-bindings.zsh
+++ b/shell/key-bindings.zsh
@@ -112,16 +112,10 @@ fzf-history-widget() {
   # as the associative 'history' array, which maps event numbers to full history
   # 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
-    # Import commands from other shells if SHARE_HISTORY is enabled, as the
-    # 'history' array only updates after executing a non-empty command.
-    selected="$(
-      if [[ -o sharehistory ]]; then
-        fc -RI
-      fi
-      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 --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \
-        FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
+    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 --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \
+      FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
   else
     selected="$(fc -rl 1 | 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 --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m") \


Test patch: