junegunn / fzf

:cherry_blossom: A command-line fuzzy finder
https://junegunn.github.io/fzf/
MIT License
61.81k stars 2.35k forks source link

[zsh] Prevent glob expansion in history widget #3855

Closed udf closed 3 weeks ago

udf commented 3 weeks ago

I have some lines in my history that break the new multiline history widget, when pressing ctrl+r I get

zsh: no matches found: cd \M-cÂ\M-+クシ\M-c~ィ\M-c\nイズ

and no prompt is shown, the issue is with the expansion of the history array, since when I run echo "${(vk)history[@]}", I get the same error.

zsh is trying to expand the (improperly) encoded line for some reason, which can be fixed by setting the noglob option.

I am not sure if any of the other widgets would need this option too, or if the issue only arises from zsh's metafied format for history files.

junegunn commented 3 weeks ago

Thanks!

LangLangBart commented 3 weeks ago

I have some lines in my history that break the new multiline history widget, when pressing ctrl+r I get

Can you share a minimal version of your .zsh_history file and your zsh version? I'm just curious to try and reproduce it on my machine as well, and learn from it.

If I use a glob, zsh encloses it in quotes when retrieving the value from the associative history array.

# start a new zsh session without reading your config files and xtrace enabled
 zsh -fx

# glob 
@*
zsh: no matches found: @*

printf '%s\t%s\n' "${(vk)history[@]}" 
+zsh:2> printf '%s\t%s\n' 1 '@*'
1   @*
udf commented 3 weeks ago

@LangLangBart

% zsh --version
zsh 5.9 (x86_64-pc-linux-gnu)

I'm not sure if you can reproduce this normally, I think what happened is I renamed my .bash_history file when I switched to zsh, so my .zsh_history contained lines that were not encoded the way zsh expected them to be. You can reproduce it by having a .zsh_history file containing this line:

echo 'メカクシティデイズ'

If you actually run that command from zsh, the resulting history line will be encoded as echo 'ャ\ufffd\ufffdカクシャ\ufffd\ufffdィャ\ufffd\ufffdイズ', which doesn't result in zsh trying to perform a glob. So you have to edit the history file manually to get it to happen. I suspect it might be a zsh bug, because expanding an associative array shouldn't try to glob, but I didn't investigate further.

LangLangBart commented 3 weeks ago

Thanks for sharing. I can now reproduce it as well. I narrowed it down to one letter:

Character Name Unicode
KATAKANA LETTER DE U+30C7
# Ensure that these options are enabled to get the error
setopt nomatch glob
# 'fc -p': pushes entries from the temporary file onto a stack and uses this history
# '=(<<<arg)' is a shortcut for creating a temporary file with the passed argument
fc -p =(<<<デ)

printf "%s\n" "${history[@]}"
zsh: no matches found: \M-c\n

# The precommand modifier 'noglob', similar to 'command' or 'builtin',
# disables globbing on the command, and 'bat' is used to show non-printable characters
noglob printf "%s\n" "${history[@]}" | bat -pA
\xE3␊

# 'V' flag makes special characters in the resulting words visible.
noglob printf "%s\n" "${(V)history[@]}"
\M-c\n

I suspect it might be a zsh bug, because expanding an associative array shouldn't try to glob, but I didn't investigate further.

I will update you if I find anything. For now, your solution to disable globbing seems effective in preventing the error. However, as you mentioned, one needs to manipulate the history file to encounter this issue.

LangLangBart commented 2 weeks ago

The issue was eventually posted on the Zsh Mailing List Archive, where a user provided a compelling reason to cease pursuing it further. @udf had tentatively hinted in this direction.

Mikael Magnusson: History files are stored in metafied form, this character probably happens to correspond to the metafied form of the internal token for some glob symbol.

Source: Re: Unexpected globbing when expanding history