Coder Social home page Coder Social logo

zsh-fzf-history-search's Introduction

zsh/fzf History Search

zsh-fzf-history-search plugin screenshot

A simple zsh plugin to replace Ctrl-r with an fzf-driven, searchable list of history.

Pull requests always appreciated!

Requirements

Installation

zinit

Add this to ~/.zshrc:

# zsh-fzf-history-search
zinit ice lucid wait'0'
zinit light joshskidmore/zsh-fzf-history-search

oh-my-zsh

Clone the repository inside your oh-my-zsh repo:

git clone https://github.com/joshskidmore/zsh-fzf-history-search ${ZSH_CUSTOM:=~/.oh-my-zsh/custom}/plugins/zsh-fzf-history-search

Enable it in your .zshrc by adding it to your plugin list:

plugins=(… zsh-fzf-history-search)

Add joshskidmore/zsh-fzf-history-search to your .zshrc file in the same function you're doing your other zgenom load calls in.

Zgenom will automatically clone the plugin repositories for you when you do a zgenom save.

Configuration Variables

Variable Default Description
ZSH_FZF_HISTORY_SEARCH_BIND '^r' Keybind to trigger fzf reverse search
ZSH_FZF_HISTORY_SEARCH_FZF_ARGS '+s +m -x -e --preview-window=hidden' Arguments for fzf (might be updated, not recommended to override)
ZSH_FZF_HISTORY_SEARCH_FZF_EXTRA_ARGS '' Extra arguments for fzf
ZSH_FZF_HISTORY_SEARCH_FZF_QUERY_PREFIX '' Query prefix for fzf when $BUFFER is not empty. Set it to '^' to query history lines begin with $BUFFER
ZSH_FZF_HISTORY_SEARCH_END_OF_LINE '' Put the cursor on at the end of the line after completion, empty=false
ZSH_FZF_HISTORY_SEARCH_EVENT_NUMBERS 1 Include event numbers in search. Set to 0 to remove event numbers from the search.
ZSH_FZF_HISTORY_SEARCH_DATES_IN_SEARCH 1 Include ISO8601 timestamps in search. Set to 0 to remove them from the search.
ZSH_FZF_HISTORY_SEARCH_REMOVE_DUPLICATES '' Remove duplicate entries from search. Only makes sense with EVENT_NUMBERS and DATE_INSEARCH 0 (false).

TODO

  • use fzf's keybindings for additional functionality (remove specific history item, clear history, etc) while keeping plugin's simplicity in mind (issue)
  • better documentation (issue)

zsh-fzf-history-search's People

Contributors

freed-wu avatar haxibami avatar hojerst avatar javimerino avatar joshskidmore avatar kassadin avatar mamoruds avatar mosauter avatar ofirgall avatar unixorn avatar zebolino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

zsh-fzf-history-search's Issues

Feature: multi-line support

I managed to add support for multi-line blocks, and I want to share it.

What I did was to retrieve the number event of the selected command in fzf, and then use history expansion zle expand-or-complete with that number so zsh gets the correct block of code.

function fzf_history_search() {
  # get event number
  e_num=$(fc -l 0 | fzf --tac | awk '{print $1}')
  
  # HISTORY EXPANSION
  BUFFER="!$e_num"
  zle vi-fetch-history -n $BUFFER
  zle expand-or-complete
}

I modified the script to my needs, didn't include some stuff, but maybe you like some of what i changed, here I leave it:

# do nothing if fzf is not installed
(( ! $+commands[fzf] )) && return

# Bind for fzf history search
(( ! ${+ZSH_FZF_HISTORY_SEARCH_BIND} )) &&
typeset -g ZSH_FZF_HISTORY_SEARCH_BIND='^r'

# Cursor to end-of-line
(( ! ${+ZSH_FZF_HISTORY_SEARCH_END_OF_LINE} )) &&
typeset -g ZSH_FZF_HISTORY_SEARCH_END_OF_LINE=''

# Include event numbers
(( ! ${+ZSH_FZF_HISTORY_SEARCH_EVENT_NUMBERS} )) &&
typeset -g ZSH_FZF_HISTORY_SEARCH_EVENT_NUMBERS=1

# Include full date timestamps in ISO8601 `yyyy-mm-dd hh:mm' format
(( ! ${+ZSH_FZF_HISTORY_SEARCH_DATES_IN_SEARCH} )) &&
typeset -g ZSH_FZF_HISTORY_SEARCH_DATES_IN_SEARCH=1

# Remove duplicate entries in history
(( ! ${+ZSH_FZF_HISTORY_SEARCH_REMOVE_DUPLICATES} )) &&
typeset -g ZSH_FZF_HISTORY_SEARCH_REMOVE_DUPLICATES=''

function fzf_history_search() {
	local cmd_col=1
	local fc_args=

	# SETUP DATES
	if [ -n "${ZSH_FZF_HISTORY_SEARCH_DATES_IN_SEARCH}" ]; then
		cmd_col=3
		fc_args+=' -i'
	fi

	local his_out=$(fc ${=fc_args} -l 0)

	# REMOVE DUPLICATES
	if [ -n "${ZSH_FZF_HISTORY_SEARCH_REMOVE_DUPLICATES}" ]; then
		his_out=$(printf '%s\n' "$his_out" | sort -k $((cmd_col+1)) | tac | uniq -f $((cmd_col)) | sort)
	fi

	# REMOVE NUMBER COLUMNS
	if ! [ -n "${ZSH_FZF_HISTORY_SEARCH_EVENT_NUMBERS}" ]; then
		his_out=$(printf '%s\n' "$his_out" | sed 's/^[[:blank:]]*[[:digit:]]*//')
	fi

	local e_num=$(printf '%s\n' "$his_out" | fzf --tac -q "$BUFFER" | awk '{print $1}')
	if [ -n "$e_num" ]; then
		BUFFER="!$e_num"
		zle vi-fetch-history -n $BUFFER
		zle expand-or-complete
		if [ -n "$ZSH_FZF_HISTORY_SEARCH_END_OF_LINE" ]; then
			zle end-of-buffer-or-history
		fi
	fi
	#zle reset-prompt
}
autoload fzf_history_search
zle -N fzf_history_search
bindkey $ZSH_FZF_HISTORY_SEARCH_BIND fzf_history_search

invalid directive when trying to fetch commands with %T and similar strings

This issue started when I moved to a new computer (MacBook Pro Apple M2).
When trying to fetch from the history command like:
kcat -b broker -t topic -C -Z -o beginning -f ' %k:%s\n'
I get the following error:
fzf_history_search:printf:35: %k: invalid directive
and only left with part of the string in the terminal line:
kcat -b broker -t topic -C -Z -o beginning -f '

The reason is that printf interprets the %k as a format specifier.

I am not sure why it only started now when I switched to a new computer, but though it will be a good idea to post about it here

Thanks

[bug] any history contained '1969' cannot be searched

One solution is

diff --git a/zsh-fzf-history-search.zsh b/zsh-fzf-history-search.zsh
index 3a83aeb..8167033 100644
--- a/zsh-fzf-history-search.zsh
+++ b/zsh-fzf-history-search.zsh
@@ -1,9 +1,9 @@
 fzf_history_seach() {
-  BUFFER=$(history -t '%Y-%m-%d %H:%M:%S' 0 | grep -v 1969 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
+  BUFFER=$(history -t '%Y-%m-%d %H:%M:%S' 0 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
   zle end-of-line
 }

Make it compatible with Antigen

I used antigen to install the package and it's downloaded properly, but it's not sourced. Manually sourcing works fine though. Looks like a great addition to my setup, thanks!

main file should be ending in *.plugin.zsh

Hi! Thanks for the nice plugin.

As I just tried to use your repository with my scripts, I ran into a small problem, which resulted the plugin first not being picked up... Your plugin breaks with the convention, that there is exactly one *.plugin.zsh file per plugin which means to be sourced. Would it be possible to rename the main file?

Plugin appears nonfunctioning

MacOS Ventura 13.4

Package versions:

❯ zsh --version
zsh 5.9 (x86_64-apple-darwin22.0)
❯ fzf --version
0.41.1 (brew)

Cloned your master branch today and tested it with the following plugin configurations in .zshrc:

plugins=(
  git
  macos
  z
  zsh-autocomplete
  zsh-autosuggestions
  zsh-fzf-history-search
  zsh-syntax-highlighting
)
plugins=(
  git
  macos
  z
  zsh-autocomplete
  zsh-autosuggestions
  zsh-syntax-highlighting
  zsh-fzf-history-search
)

With the above settings, fzf's CTRL-R output remained in the default format, with the command counter/ID instead of with date and time as described in your README:

 1965  zsh --version
 1966  fzf --version
2/1000 +S -----------------------------------------------------------------------------------------------------------
> ^zsh | ^fzf --version$

Let me know if you're un/able to reproduce.

[Question or Feature] Keep the search term if none of the history results is selected

Thanks for this great plugin. I have the following usage question, potentially a feature request:

Case: you search for foo and the only history item you have is bar.
Desired outcome: you are able to keep foo after exiting this plugin. Or, additionally, able to execute foo directly from the plugin, without exiting it.
Current outcome: you are forced to exit the plugin and lose the entered search term foo - the longer foo is, the worse the outcome.

Is the Desired outcome achievable, either by this plugin or by [fzf] itself?

  • None of the options in man fzf seem applicable.
  • An issue in fzf repo uses the term "search buffer". It seems that the fzf author's reply implies the Desired outcome isn't currently achievable? If so, then feel free to close this issue.

If this is not achievable, but could be within this plugin, please consider this a feature request.

Doesn't respect fzf environment variables

It has been raised elsewhere (#31) that this plugin is not sourced properly by Oh My Zsh. So users must manually source zsh-fzf-history-search.zsh for it to have any effect.

However, once sourced, it overrides (or probably more accurately, just doesn't use) fzf's own FZF_CTRL_R_OPTS variable which users can use to customize the look and feel.

Updating the plugin to respect fzf's variables would be a major improvement.

history search jumping to bottom of terminal

When I push CTRL-R, the history window appears at the bottom of the terminal and the prompt disappears. I don't believe this was the behavior in my previous installation(lost).

image

After c-r

image

I would prefer that it act like fzf-tab ... am I missing something?
image

TODO: Better documentation

Dropping this issue as a TODO.

  • screenshot
  • better documentation in general
  • documentation for usage in various zsh plugin management systems

[bug] cannot support multi-lines

# let us input two lines, we have binded '^J' to self-insert, so we can input a line-feedecho 1
echo 1
1
1
# after press <C-R> and search 'echo 1'echo 1\necho 1

this will work:

 fzf_history_seach() {
-  BUFFER=$(history -t '%Y-%m-%d %H:%M:%S' 0 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
+  print -v BUFFER $(history -t '%Y-%m-%d %H:%M:%S' 0 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
   zle end-of-line
 }

because print will convert '\n', '\t', etc.

Another problem is the position of cursor, because zle end-of-line, it will be

echo 1▏
echo 1

if you change it to

 fzf_history_seach() {
-  BUFFER=$(history -t '%Y-%m-%d %H:%M:%S' 0 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
-  zle end-of-line
+  print -v BUFFER $(history -t '%Y-%m-%d %H:%M:%S' 0 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
+  zle end-of-buffer-or-history
 }

the position of cursor will be

echo 1
echo 1▏

i think it will be better.

the last problem is awk: it is no necessary. according to
https://github.com/zdharma/Zsh-100-Commits-Club/blob/master/Zsh-Native-Scripting-Handbook.adoc#skipping-awk
we can skip awk:

+setopt extendedglob
 fzf_history_seach() {
-  BUFFER=$(history -t '%Y-%m-%d %H:%M:%S' 0 | fzf +s +m -x --tac -e -q "$BUFFER" | awk '{print substr($0, index($0, $4))}')
-  zle end-of-line
+  candidates=(${(f)"$(history -t '%Y-%m-%d %H:%M:%S' 0| fzf +s +m -x --tac -e -q "$BUFFER")"})
+  print -v BUFFER "${candidates[@]/(#m)*/${${(As: :)MATCH}[4,-1]}}"
+  zle end-of-buffer-or-history
 }

however it need setopt extendedglob, i don't know if anyone all want it. if
not, they must setopt noextendedglob after load this plugin.

not copying the whole line after '%' character for some commands

so if i try to chose some command that has the "%" character, anything after that will be cut for some reason.
some of those commands are

ffmpeg -f alsa -i default -flush_packets 1 $(date '+%d-%m-%y-%H_%M_%S').ogg
echo %hello%

if there is a command such as echo %%foo%%bar%% i'll get echo %foo%bar%

Feature: Use fzf keybindings to add additional functionality to history

Using fzf keybindings, allow for specific history items to be removed from history list in the same manner they're selected from fzf.

Example:

  • tap C-r
  • use up/down/C-k/C-j to select a history entry
  • use something like M-d to use fzf's execute-silent() to call a function which will delete the selected history item from the current zsh session as well as $HISTFILE
  • use fzf's abort() + execute() to automatically reload updated history (with removed history item removed)

This is something I will try to tackle, but need to refresh myself on advanced zsh syntax.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.