diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c55d487..a3271162 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,15 @@ CHANGELOG - Added `--preview-wrap-sign` to set a different wrap indicator for the preview window - Added `alt-gutter` color option (#4602) (@hedgieinsocks) +- Added `$FZF_WRAP` environment variable to child processes (`char` or `word` + when wrapping is enabled) (#4672) (@bitraid) +- fish: Improved command history (CTRL-R) (#4672) (@bitraid) + - Enabled syntax highlighting in the list on fish 4.3.3+ + - Added syntax-highlighted preview window that auto-shows for long or + multi-line commands + - Added `ALT-ENTER` to reformat and insert selected commands + - Improved handling of bulk deletion of selected history entries + (`SHIFT-DELETE`) - Added fish completion support (#4605) (@lalvarezt) - zsh: Handle multi-line history selection (#4595) (@LangLangBart) - Bug fixes diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 03a40c01..d438b7a3 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -1390,6 +1390,8 @@ fzf exports the following environment variables to its child processes. .br .BR FZF_POS " Vertical position of the cursor in the list starting from 1" .br +.BR FZF_WRAP " The line wrapping mode (char, word) when enabled" +.br .BR FZF_QUERY " Current query string" .br .BR FZF_INPUT_STATE " Current input state (enabled, disabled, hidden)" diff --git a/shell/key-bindings.fish b/shell/key-bindings.fish index ed0219b7..e6fd471a 100644 --- a/shell/key-bindings.fish +++ b/shell/key-bindings.fish @@ -21,8 +21,8 @@ function fzf_key_bindings # Check fish version - set -l fish_ver (string match -r '^(\d+).(\d+)' $version 2> /dev/null; or echo 0\n0\n0) - if test \( "$fish_ver[2]" -lt 3 \) -o \( "$fish_ver[2]" -eq 3 -a "$fish_ver[3]" -lt 1 \) + if set -l -- fish_ver (string match -r '^(\d+)\.(\d+)' $version 2>/dev/null) + and test "$fish_ver[2]" -lt 3 -o "$fish_ver[2]" -eq 3 -a "$fish_ver[3]" -lt 1 echo "This script requires fish version 3.1b1 or newer." >&2 return 1 else if not type -q fzf @@ -182,24 +182,46 @@ function fzf_key_bindings set -l -- total_lines (count $command_line) set -l -- fzf_query (string escape -- $command_line[$current_line]) - set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \ - '--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \ - '--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \ + set -lx -- FZF_DEFAULT_OPTS (__fzf_defaults '' \ + '--nth=2..,.. --scheme=history --multi --no-multi-line --no-wrap --wrap-sign="\t\t\t↳ " --preview-wrap-sign="↳ "' \ + '--bind=\'shift-delete:execute-silent(for i in (string split0 -- <{+f}); eval builtin history delete --exact --case-sensitive -- (string escape -n -- $i | string replace -r "^\d*\\\\\\t" ""); end)+reload(eval $FZF_DEFAULT_COMMAND)\'' \ + '--bind="alt-enter:become(string join0 -- (string collect -- {+2..} | fish_indent -i))"' \ "--bind=ctrl-r:toggle-sort,alt-r:toggle-raw --highlight-line $FZF_CTRL_R_OPTS" \ - '--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c) + '--accept-nth=2.. --delimiter="\t" --tabstop=4 --read0 --print0 --with-shell='(status fish-path)\\ -c) + + # Add dynamic preview options if preview command isn't already set by user + if string match -qvr -- '--preview[= ]' "$FZF_DEFAULT_OPTS" + # Convert the highlighted timestamp using the date command if available + set -l -- date_cmd '{1}' + if type -q date + if date -d @0 '+%s' 2>/dev/null | string match -q 0 + # GNU date + set -- date_cmd '(date -d @{1} \\"+%F %a %T\\")' + else if date -r 0 '+%s' 2>/dev/null | string match -q 0 + # BSD date + set -- date_cmd '(date -r {1} \\"+%F %a %T\\")' + end + end + + # Prepend the options to allow user customizations + set -p -- FZF_DEFAULT_OPTS \ + '--bind="focus,resize:bg-transform:if test \\"$FZF_COLUMNS\\" -gt 100 -a \\\\( \\"$FZF_SELECT_COUNT\\" -gt 0 -o \\\\( -z \\"$FZF_WRAP\\" -a (string length -- {}) -gt (math $FZF_COLUMNS - 4) \\\\) -o (string collect -- {2..} | fish_indent | count) -gt 1 \\\\); echo show-preview; else echo hide-preview; end"' \ + '--preview="string collect -- (test \\"$FZF_SELECT_COUNT\\" -gt 0; and string collect -- {+2..}) \\"\\n# \\"'$date_cmd' {2..} | fish_indent --ansi"' \ + '--preview-window="right,50%,wrap-word,follow,info,hidden"' + end set -lx FZF_DEFAULT_OPTS_FILE - set -lx FZF_DEFAULT_COMMAND - if type -q perl - set -a FZF_DEFAULT_OPTS '--tac' - set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\'' - else - set FZF_DEFAULT_COMMAND \ - 'set -l h (builtin history -z --reverse | string split0);' \ - 'for i in (seq (count $h) -1 1);' \ - 'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \ - 'end' + set -lx -- FZF_DEFAULT_COMMAND 'builtin history -z --show-time="%s%t"' + + # Enable syntax highlighting colors on fish v4.3.3 and newer + if set -l -- v (string match -r -- '^(\d+)\.(\d+)(?:\.(\d+))?' $version) + and test "$v[2]" -gt 4 -o "$v[2]" -eq 4 -a \ + \( "$v[3]" -gt 3 -o "$v[3]" -eq 3 -a \ + \( -n "$v[4]" -a "$v[4]" -ge 3 \) \) + + set -a -- FZF_DEFAULT_OPTS '--ansi' + set -a -- FZF_DEFAULT_COMMAND '--color=always' end # Merge history from other sessions before searching @@ -207,11 +229,11 @@ function fzf_key_bindings if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0) if test "$total_lines" -eq 1 - commandline -- (string replace -a -- \n\t \n $result) + commandline -- $result else set -l a (math $current_line - 1) set -l b (math $current_line + 1) - commandline -- $command_line[1..$a] (string replace -a -- \n\t \n $result) + commandline -- $command_line[1..$a] $result commandline -a -- '' $command_line[$b..-1] end end diff --git a/src/terminal.go b/src/terminal.go index 6c30ee9b..d761dd77 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1356,6 +1356,13 @@ func (t *Terminal) environImpl(forPreview bool) []string { } else if t.paused { inputState = "disabled" } + if t.wrap { + if t.wrapWord { + env = append(env, "FZF_WRAP=word") + } else { + env = append(env, "FZF_WRAP=char") + } + } env = append(env, "FZF_INPUT_STATE="+inputState) env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", t.count)) env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.resultMerger.Length())) diff --git a/test/lib/common.rb b/test/lib/common.rb index ef4dd915..e731a788 100644 --- a/test/lib/common.rb +++ b/test/lib/common.rb @@ -163,6 +163,7 @@ class Tmux self.until(true) do |lines| message = "Prepare[#{tries}]" send_keys ' ', 'C-u', :Enter, message, :Left, :Right + sleep(0.15) lines[-1] == message end rescue Minitest::Assertion diff --git a/test/test_shell_integration.rb b/test/test_shell_integration.rb index f51d7195..b67f307a 100644 --- a/test/test_shell_integration.rb +++ b/test/test_shell_integration.rb @@ -138,7 +138,7 @@ module TestShell tmux.send_keys 'C-r' tmux.until { |lines| assert_equal '>', lines[-1] } tmux.send_keys 'foo bar' - tmux.until { |lines| assert_includes lines[-4], '"foo' } unless shell == :zsh + tmux.until { |lines| assert_includes lines[-4], '"foo' } if shell == :bash tmux.until { |lines| assert lines[-3]&.match?(/bar"␊?/) } tmux.send_keys :Enter tmux.until { |lines| assert lines[-1]&.match?(/bar"␊?/) } @@ -1020,15 +1020,23 @@ class TestFish < TestBase tmux.send_keys 'echo "bar', :Enter, 'foo"', :Enter tmux.prepare tmux.send_keys 'C-l', 'C-r' + offset = -6 block = <<~BLOCK echo "foo bar" echo "bar foo" BLOCK + if shell == :fish + offset = -4 + block = <<~FISH + echo "foo␊bar" + echo "bar␊foo" + FISH + end tmux.until do |lines| block.lines.each_with_index do |line, idx| - assert_includes lines[-6 + idx], line.chomp + assert_includes lines[idx + offset], line.chomp end end tmux.send_keys :BTab, :BTab