mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-05 14:42:11 -07:00
Compare commits
1 Commits
v0.65.1
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
8843cfad71 |
48
CHANGELOG.md
48
CHANGELOG.md
@@ -1,54 +1,6 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.65.1
|
||||
------
|
||||
- Fixed incorrect `$FZF_CLICK_HEADER_WORD` and `$FZF_CLICK_FOOTER_WORD` when the header or footer contains ANSI escape sequences and tab characters.
|
||||
- Fixed a bug where you cannot unset the default `--nth` using `change-nth` action.
|
||||
- Fixed a highlighting bug when using `--color fg:dim,nth:regular` pattern over ANSI-colored items.
|
||||
|
||||
0.65.0
|
||||
------
|
||||
- Added `click-footer` event that is triggered when the footer section is clicked. When the event is triggered, the following environment variables are set:
|
||||
- `$FZF_CLICK_FOOTER_COLUMN` - clicked column (1-based)
|
||||
- `$FZF_CLICK_FOOTER_LINE` - clicked line (1-based)
|
||||
- `$FZF_CLICK_FOOTER_WORD` - the word under the cursor
|
||||
```sh
|
||||
fzf --footer $'[Edit] [View]\n[Copy to clipboard]' \
|
||||
--with-shell 'bash -c' \
|
||||
--bind 'click-footer:transform:
|
||||
[[ $FZF_CLICK_FOOTER_WORD =~ Edit ]] && echo "execute:vim \{}"
|
||||
[[ $FZF_CLICK_FOOTER_WORD =~ View ]] && echo "execute:view \{}"
|
||||
(( FZF_CLICK_FOOTER_LINE == 2 )) && (( FZF_CLICK_FOOTER_COLUMN < 20 )) &&
|
||||
echo "execute-silent(echo -n \{} | pbcopy)+bell"
|
||||
'
|
||||
```
|
||||
- Added `trigger(...)` action that triggers events bound to another key or event.
|
||||
```sh
|
||||
# You can click on each key name to trigger the actions bound to that key
|
||||
fzf --footer 'Ctrl-E: Edit / Ctrl-V: View / Ctrl-Y: Copy to clipboard' \
|
||||
--with-shell 'bash -c' \
|
||||
--bind 'ctrl-e:execute:vim {}' \
|
||||
--bind 'ctrl-v:execute:view {}' \
|
||||
--bind 'ctrl-y:execute-silent(echo -n {} | pbcopy)+bell' \
|
||||
--bind 'click-footer:transform:
|
||||
[[ $FZF_CLICK_FOOTER_WORD =~ Ctrl ]] && echo "trigger(${FZF_CLICK_FOOTER_WORD%:})"
|
||||
'
|
||||
```
|
||||
- You can specify a series of keys and events
|
||||
```sh
|
||||
fzf --bind 'a:up,b:trigger(a,a,a)'
|
||||
```
|
||||
- Added support for `{*n}` and `{*nf}` placeholder.
|
||||
- `{*n}` evaluates to the zero-based ordinal index of all matched items.
|
||||
- `{*nf}` evaluates to the temporary file containing that.
|
||||
- Bug fixes and improvements
|
||||
- [neovim] Fixed margin background color when `&winborder` is used (#4453)
|
||||
- Fixed rendering error when hiding a preview window without border (#4465)
|
||||
- fix(shell): check for mawk existence before version check (#4468)
|
||||
- Thanks to @LangLangBart and @akinomyoga
|
||||
- Fixed `--no-header-lines-border` behavior (08027e7a)
|
||||
|
||||
0.64.0
|
||||
------
|
||||
- Added `multi` event that is triggered when the multi-selection has changed.
|
||||
|
4
go.mod
4
go.mod
@@ -6,7 +6,7 @@ require (
|
||||
github.com/junegunn/go-shellwords v0.0.0-20250127100254-2aa3b3277741
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/rivo/uniseg v0.4.7
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/sys v0.34.0
|
||||
golang.org/x/term v0.29.0
|
||||
)
|
||||
|
||||
@@ -17,4 +17,4 @@ require (
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
)
|
||||
|
||||
go 1.20
|
||||
go 1.23.0
|
||||
|
4
go.sum
4
go.sum
@@ -55,8 +55,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
2
install
2
install
@@ -2,7 +2,7 @@
|
||||
|
||||
set -u
|
||||
|
||||
version=0.65.1
|
||||
version=0.64.0
|
||||
auto_completion=
|
||||
key_bindings=
|
||||
update_config=2
|
||||
|
@@ -1,4 +1,4 @@
|
||||
$version="0.65.1"
|
||||
$version="0.64.0"
|
||||
|
||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
|
||||
|
2
main.go
2
main.go
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/junegunn/fzf/src/protector"
|
||||
)
|
||||
|
||||
var version = "0.65"
|
||||
var version = "0.64"
|
||||
var revision = "devel"
|
||||
|
||||
//go:embed shell/key-bindings.bash
|
||||
|
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf\-tmux 1 "Aug 2025" "fzf 0.65.1" "fzf\-tmux - open fzf in tmux split pane"
|
||||
.TH fzf\-tmux 1 "Jul 2025" "fzf 0.64.0" "fzf\-tmux - open fzf in tmux split pane"
|
||||
|
||||
.SH NAME
|
||||
fzf\-tmux - open fzf in tmux split pane
|
||||
|
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf 1 "Aug 2025" "fzf 0.65.1" "fzf - a command-line fuzzy finder"
|
||||
.TH fzf 1 "Jul 2025" "fzf 0.64.0" "fzf - a command-line fuzzy finder"
|
||||
|
||||
.SH NAME
|
||||
fzf - a command-line fuzzy finder
|
||||
@@ -1682,14 +1682,6 @@ e.g.
|
||||
)'\fR
|
||||
.RE
|
||||
|
||||
\fIclick\-footer\fR
|
||||
.RS
|
||||
Triggered when a mouse click occurs within the footer. Sets
|
||||
\fBFZF_CLICK_FOOTER_LINE\fR and \fBFZF_CLICK_FOOTER_COLUMN\fR environment
|
||||
variables starting from 1. It optionally sets \fBFZF_CLICK_FOOTER_WORD\fR
|
||||
if clicked on a word.
|
||||
.RE
|
||||
|
||||
.SS AVAILABLE ACTIONS:
|
||||
A key or an event can be bound to one or more of the following actions.
|
||||
|
||||
@@ -1817,7 +1809,6 @@ A key or an event can be bound to one or more of the following actions.
|
||||
\fBtransform\-prompt(...)\fR (transform prompt string using an external command)
|
||||
\fBtransform\-query(...)\fR (transform query string using an external command)
|
||||
\fBtransform\-search(...)\fR (trigger fzf search with the output of an external command)
|
||||
\fBtrigger(...)\fR (trigger actions bound to a comma-separated list of keys and events)
|
||||
\fBunbind(...)\fR (unbind bindings)
|
||||
\fBunix\-line\-discard\fR \fIctrl\-u\fR
|
||||
\fBunix\-word\-rubout\fR \fIctrl\-w\fR
|
||||
|
@@ -1027,23 +1027,8 @@ if has('nvim')
|
||||
let buf = nvim_create_buf(v:false, v:true)
|
||||
let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
|
||||
let win = nvim_open_win(buf, v:true, opts)
|
||||
silent! call setwinvar(win, '&winhighlight', 'Pmenu:,Normal:Normal')
|
||||
call setwinvar(win, '&colorcolumn', '')
|
||||
|
||||
" Colors
|
||||
try
|
||||
call setwinvar(win, '&winhighlight', 'Pmenu:,Normal:Normal')
|
||||
let rules = get(g:, 'fzf_colors', {})
|
||||
if has_key(rules, 'bg')
|
||||
let color = call('s:get_color', rules.bg)
|
||||
if len(color)
|
||||
let ns = nvim_create_namespace('fzf_popup')
|
||||
let hl = nvim_set_hl(ns, 'Normal',
|
||||
\ &termguicolors ? { 'bg': color } : { 'ctermbg': str2nr(color) })
|
||||
call nvim_win_set_hl_ns(win, ns)
|
||||
endif
|
||||
endif
|
||||
catch
|
||||
endtry
|
||||
return buf
|
||||
endfunction
|
||||
else
|
||||
|
@@ -22,11 +22,11 @@ __fzf_exec_awk() {
|
||||
# modern point of view. To use a standard-conforming version in Solaris,
|
||||
# one needs to explicitly use /usr/xpg4/bin/awk.
|
||||
__fzf_awk=/usr/xpg4/bin/awk
|
||||
elif command -v mawk >/dev/null 2>&1; then
|
||||
else
|
||||
# choose the faster mawk if: it's installed && build date >= 20230322 &&
|
||||
# version >= 1.3.4
|
||||
local n x y z d
|
||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
||||
fi
|
||||
fi
|
||||
|
@@ -47,9 +47,9 @@ __fzf_exec_awk() {
|
||||
__fzf_awk=awk
|
||||
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
|
||||
__fzf_awk=/usr/xpg4/bin/awk
|
||||
elif command -v mawk >/dev/null 2>&1; then
|
||||
else
|
||||
local n x y z d
|
||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
||||
fi
|
||||
fi
|
||||
@@ -524,7 +524,7 @@ if ! declare -F __fzf_list_hosts > /dev/null; then
|
||||
if ($i != "0.0.0.0")
|
||||
print $i
|
||||
}
|
||||
' /etc/hosts 2> /dev/null
|
||||
' /etc/hosts 2> /dev/null
|
||||
)
|
||||
}
|
||||
fi
|
||||
|
@@ -112,9 +112,9 @@ __fzf_exec_awk() {
|
||||
__fzf_awk=awk
|
||||
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
|
||||
__fzf_awk=/usr/xpg4/bin/awk
|
||||
elif command -v mawk >/dev/null 2>&1; then
|
||||
else
|
||||
local n x y z d
|
||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
||||
fi
|
||||
fi
|
||||
|
@@ -33,9 +33,9 @@ __fzf_exec_awk() {
|
||||
__fzf_awk=awk
|
||||
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
|
||||
__fzf_awk=/usr/xpg4/bin/awk
|
||||
elif command -v mawk >/dev/null 2>&1; then
|
||||
else
|
||||
local n x y z d
|
||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
||||
fi
|
||||
fi
|
||||
|
@@ -54,9 +54,9 @@ __fzf_exec_awk() {
|
||||
__fzf_awk=awk
|
||||
if [[ $OSTYPE == solaris* && -x /usr/xpg4/bin/awk ]]; then
|
||||
__fzf_awk=/usr/xpg4/bin/awk
|
||||
elif command -v mawk >/dev/null 2>&1; then
|
||||
else
|
||||
local n x y z d
|
||||
IFS=' .' read -r n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
|
||||
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
|
||||
fi
|
||||
fi
|
||||
|
@@ -113,66 +113,65 @@ func _() {
|
||||
_ = x[actTransformPrompt-102]
|
||||
_ = x[actTransformQuery-103]
|
||||
_ = x[actTransformSearch-104]
|
||||
_ = x[actTrigger-105]
|
||||
_ = x[actBgTransform-106]
|
||||
_ = x[actBgTransformBorderLabel-107]
|
||||
_ = x[actBgTransformGhost-108]
|
||||
_ = x[actBgTransformHeader-109]
|
||||
_ = x[actBgTransformFooter-110]
|
||||
_ = x[actBgTransformHeaderLabel-111]
|
||||
_ = x[actBgTransformFooterLabel-112]
|
||||
_ = x[actBgTransformInputLabel-113]
|
||||
_ = x[actBgTransformListLabel-114]
|
||||
_ = x[actBgTransformNth-115]
|
||||
_ = x[actBgTransformPointer-116]
|
||||
_ = x[actBgTransformPreviewLabel-117]
|
||||
_ = x[actBgTransformPrompt-118]
|
||||
_ = x[actBgTransformQuery-119]
|
||||
_ = x[actBgTransformSearch-120]
|
||||
_ = x[actBgCancel-121]
|
||||
_ = x[actSearch-122]
|
||||
_ = x[actPreview-123]
|
||||
_ = x[actPreviewTop-124]
|
||||
_ = x[actPreviewBottom-125]
|
||||
_ = x[actPreviewUp-126]
|
||||
_ = x[actPreviewDown-127]
|
||||
_ = x[actPreviewPageUp-128]
|
||||
_ = x[actPreviewPageDown-129]
|
||||
_ = x[actPreviewHalfPageUp-130]
|
||||
_ = x[actPreviewHalfPageDown-131]
|
||||
_ = x[actPrevHistory-132]
|
||||
_ = x[actPrevSelected-133]
|
||||
_ = x[actPrint-134]
|
||||
_ = x[actPut-135]
|
||||
_ = x[actNextHistory-136]
|
||||
_ = x[actNextSelected-137]
|
||||
_ = x[actExecute-138]
|
||||
_ = x[actExecuteSilent-139]
|
||||
_ = x[actExecuteMulti-140]
|
||||
_ = x[actSigStop-141]
|
||||
_ = x[actFirst-142]
|
||||
_ = x[actLast-143]
|
||||
_ = x[actReload-144]
|
||||
_ = x[actReloadSync-145]
|
||||
_ = x[actDisableSearch-146]
|
||||
_ = x[actEnableSearch-147]
|
||||
_ = x[actSelect-148]
|
||||
_ = x[actDeselect-149]
|
||||
_ = x[actUnbind-150]
|
||||
_ = x[actRebind-151]
|
||||
_ = x[actToggleBind-152]
|
||||
_ = x[actBecome-153]
|
||||
_ = x[actShowHeader-154]
|
||||
_ = x[actHideHeader-155]
|
||||
_ = x[actBell-156]
|
||||
_ = x[actExclude-157]
|
||||
_ = x[actExcludeMulti-158]
|
||||
_ = x[actAsync-159]
|
||||
_ = x[actBgTransform-105]
|
||||
_ = x[actBgTransformBorderLabel-106]
|
||||
_ = x[actBgTransformGhost-107]
|
||||
_ = x[actBgTransformHeader-108]
|
||||
_ = x[actBgTransformFooter-109]
|
||||
_ = x[actBgTransformHeaderLabel-110]
|
||||
_ = x[actBgTransformFooterLabel-111]
|
||||
_ = x[actBgTransformInputLabel-112]
|
||||
_ = x[actBgTransformListLabel-113]
|
||||
_ = x[actBgTransformNth-114]
|
||||
_ = x[actBgTransformPointer-115]
|
||||
_ = x[actBgTransformPreviewLabel-116]
|
||||
_ = x[actBgTransformPrompt-117]
|
||||
_ = x[actBgTransformQuery-118]
|
||||
_ = x[actBgTransformSearch-119]
|
||||
_ = x[actBgCancel-120]
|
||||
_ = x[actSearch-121]
|
||||
_ = x[actPreview-122]
|
||||
_ = x[actPreviewTop-123]
|
||||
_ = x[actPreviewBottom-124]
|
||||
_ = x[actPreviewUp-125]
|
||||
_ = x[actPreviewDown-126]
|
||||
_ = x[actPreviewPageUp-127]
|
||||
_ = x[actPreviewPageDown-128]
|
||||
_ = x[actPreviewHalfPageUp-129]
|
||||
_ = x[actPreviewHalfPageDown-130]
|
||||
_ = x[actPrevHistory-131]
|
||||
_ = x[actPrevSelected-132]
|
||||
_ = x[actPrint-133]
|
||||
_ = x[actPut-134]
|
||||
_ = x[actNextHistory-135]
|
||||
_ = x[actNextSelected-136]
|
||||
_ = x[actExecute-137]
|
||||
_ = x[actExecuteSilent-138]
|
||||
_ = x[actExecuteMulti-139]
|
||||
_ = x[actSigStop-140]
|
||||
_ = x[actFirst-141]
|
||||
_ = x[actLast-142]
|
||||
_ = x[actReload-143]
|
||||
_ = x[actReloadSync-144]
|
||||
_ = x[actDisableSearch-145]
|
||||
_ = x[actEnableSearch-146]
|
||||
_ = x[actSelect-147]
|
||||
_ = x[actDeselect-148]
|
||||
_ = x[actUnbind-149]
|
||||
_ = x[actRebind-150]
|
||||
_ = x[actToggleBind-151]
|
||||
_ = x[actBecome-152]
|
||||
_ = x[actShowHeader-153]
|
||||
_ = x[actHideHeader-154]
|
||||
_ = x[actBell-155]
|
||||
_ = x[actExclude-156]
|
||||
_ = x[actExcludeMulti-157]
|
||||
_ = x[actAsync-158]
|
||||
}
|
||||
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1558, 1572, 1597, 1616, 1636, 1656, 1681, 1706, 1730, 1753, 1770, 1791, 1817, 1837, 1856, 1876, 1887, 1896, 1906, 1919, 1935, 1947, 1961, 1977, 1995, 2015, 2037, 2051, 2066, 2074, 2080, 2094, 2109, 2119, 2135, 2150, 2160, 2168, 2175, 2184, 2197, 2213, 2228, 2237, 2248, 2257, 2266, 2279, 2288, 2301, 2314, 2321, 2331, 2346, 2354}
|
||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 283, 298, 313, 333, 353, 372, 390, 404, 416, 432, 448, 469, 491, 506, 520, 534, 547, 564, 572, 585, 601, 613, 621, 635, 649, 660, 671, 689, 706, 713, 732, 744, 758, 767, 782, 794, 807, 818, 829, 841, 855, 876, 891, 904, 922, 938, 953, 967, 979, 991, 1008, 1015, 1020, 1029, 1040, 1051, 1064, 1079, 1090, 1103, 1118, 1125, 1138, 1151, 1168, 1183, 1196, 1210, 1224, 1240, 1260, 1272, 1295, 1312, 1330, 1348, 1371, 1394, 1416, 1437, 1452, 1471, 1495, 1513, 1530, 1548, 1562, 1587, 1606, 1626, 1646, 1671, 1696, 1720, 1743, 1760, 1781, 1807, 1827, 1846, 1866, 1877, 1886, 1896, 1909, 1925, 1937, 1951, 1967, 1985, 2005, 2027, 2041, 2056, 2064, 2070, 2084, 2099, 2109, 2125, 2140, 2150, 2158, 2165, 2174, 2187, 2203, 2218, 2227, 2238, 2247, 2256, 2269, 2278, 2291, 2304, 2311, 2321, 2336, 2344}
|
||||
|
||||
func (i actionType) String() string {
|
||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||
|
@@ -932,12 +932,15 @@ func parseBorder(str string, optional bool) (tui.BorderShape, error) {
|
||||
return tui.BorderNone, errors.New("invalid border style (expected: rounded|sharp|bold|block|thinblock|double|horizontal|vertical|top|bottom|left|right|none)")
|
||||
}
|
||||
|
||||
func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Event, error) {
|
||||
func parseKeyChords(str string, message string) (map[tui.Event]string, error) {
|
||||
return parseKeyChordsImpl(str, message)
|
||||
}
|
||||
|
||||
func parseKeyChordsImpl(str string, message string) (map[tui.Event]string, error) {
|
||||
if len(str) == 0 {
|
||||
return nil, nil, errors.New(message)
|
||||
return nil, errors.New(message)
|
||||
}
|
||||
|
||||
list := []tui.Event{}
|
||||
str = regexp.MustCompile("(?i)(alt-),").ReplaceAllString(str, "$1"+string([]rune{escapedComma}))
|
||||
tokens := strings.Split(str, ",")
|
||||
if str == "," || strings.HasPrefix(str, ",,") || strings.HasSuffix(str, ",,") || strings.Contains(str, ",,,") {
|
||||
@@ -953,7 +956,6 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
|
||||
lkey := strings.ToLower(key)
|
||||
add := func(e tui.EventType) {
|
||||
chords[e.AsEvent()] = key
|
||||
list = append(list, e.AsEvent())
|
||||
}
|
||||
switch lkey {
|
||||
case "up":
|
||||
@@ -967,9 +969,7 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
|
||||
case "enter", "return":
|
||||
add(tui.Enter)
|
||||
case "space":
|
||||
evt := tui.Key(' ')
|
||||
chords[evt] = key
|
||||
list = append(list, evt)
|
||||
chords[tui.Key(' ')] = key
|
||||
case "backspace", "bspace", "bs":
|
||||
add(tui.Backspace)
|
||||
case "ctrl-space":
|
||||
@@ -1008,18 +1008,12 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
|
||||
add(tui.JumpCancel)
|
||||
case "click-header":
|
||||
add(tui.ClickHeader)
|
||||
case "click-footer":
|
||||
add(tui.ClickFooter)
|
||||
case "multi":
|
||||
add(tui.Multi)
|
||||
case "alt-enter", "alt-return":
|
||||
evt := tui.CtrlAltKey('m')
|
||||
chords[evt] = key
|
||||
list = append(list, evt)
|
||||
chords[tui.CtrlAltKey('m')] = key
|
||||
case "alt-space":
|
||||
evt := tui.AltKey(' ')
|
||||
chords[evt] = key
|
||||
list = append(list, evt)
|
||||
chords[tui.AltKey(' ')] = key
|
||||
case "alt-bs", "alt-bspace", "alt-backspace":
|
||||
add(tui.AltBackspace)
|
||||
case "alt-up":
|
||||
@@ -1097,9 +1091,7 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
|
||||
default:
|
||||
runes := []rune(key)
|
||||
if len(key) == 10 && strings.HasPrefix(lkey, "ctrl-alt-") && isAlphabet(lkey[9]) {
|
||||
evt := tui.CtrlAltKey(rune(key[9]))
|
||||
chords[evt] = key
|
||||
list = append(list, evt)
|
||||
chords[tui.CtrlAltKey(rune(key[9]))] = key
|
||||
} else if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
||||
add(tui.EventType(tui.CtrlA.Int() + int(lkey[5]) - 'a'))
|
||||
} else if len(runes) == 5 && strings.HasPrefix(lkey, "alt-") {
|
||||
@@ -1112,21 +1104,17 @@ func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Eve
|
||||
case escapedPlus:
|
||||
r = '+'
|
||||
}
|
||||
evt := tui.AltKey(r)
|
||||
chords[evt] = key
|
||||
list = append(list, evt)
|
||||
chords[tui.AltKey(r)] = key
|
||||
} else if len(key) == 2 && strings.HasPrefix(lkey, "f") && key[1] >= '1' && key[1] <= '9' {
|
||||
add(tui.EventType(tui.F1.Int() + int(key[1]) - '1'))
|
||||
} else if len(runes) == 1 {
|
||||
evt := tui.Key(runes[0])
|
||||
chords[evt] = key
|
||||
list = append(list, evt)
|
||||
chords[tui.Key(runes[0])] = key
|
||||
} else {
|
||||
return nil, list, errors.New("unsupported key: " + key)
|
||||
return nil, errors.New("unsupported key: " + key)
|
||||
}
|
||||
}
|
||||
}
|
||||
return chords, list, nil
|
||||
return chords, nil
|
||||
}
|
||||
|
||||
func parseScheme(str string) (string, []criterion, error) {
|
||||
@@ -1449,7 +1437,7 @@ const (
|
||||
|
||||
func init() {
|
||||
executeRegexp = regexp.MustCompile(
|
||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|bg-transform|transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|bg-transform|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search|trigger)`)
|
||||
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|bg-transform|transform)-(?:query|prompt|(?:border|list|preview|input|header|footer)-label|header|footer|search|nth|pointer|ghost)|bg-transform|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`)
|
||||
splitRegexp = regexp.MustCompile("[,:]+")
|
||||
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
||||
}
|
||||
@@ -1746,7 +1734,7 @@ func parseActionList(masked string, original string, prevActions []*action, putA
|
||||
}
|
||||
switch t {
|
||||
case actUnbind, actRebind, actToggleBind:
|
||||
if _, _, err := parseKeyChords(actionArg, spec[0:offset]+" target required"); err != nil {
|
||||
if _, err := parseKeyChordsImpl(actionArg, spec[0:offset]+" target required"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case actChangePreviewWindow:
|
||||
@@ -1791,7 +1779,7 @@ func parseKeymap(keymap map[tui.Event][]*action, str string) error {
|
||||
} else if len(keyName) == 1 && keyName[0] == escapedPlus {
|
||||
key = tui.Key('+')
|
||||
} else {
|
||||
keys, _, err := parseKeyChords(keyName, "key name required")
|
||||
keys, err := parseKeyChordsImpl(keyName, "key name required")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1938,8 +1926,6 @@ func isExecuteAction(str string) actionType {
|
||||
return actBgTransformQuery
|
||||
case "bg-transform-search":
|
||||
return actBgTransformSearch
|
||||
case "trigger":
|
||||
return actTrigger
|
||||
case "search":
|
||||
return actSearch
|
||||
}
|
||||
@@ -1947,7 +1933,7 @@ func isExecuteAction(str string) actionType {
|
||||
}
|
||||
|
||||
func parseToggleSort(keymap map[tui.Event][]*action, str string) error {
|
||||
keys, _, err := parseKeyChords(str, "key name required")
|
||||
keys, err := parseKeyChords(str, "key name required")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2486,7 +2472,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chords, _, err := parseKeyChords(str, "key names required")
|
||||
chords, err := parseKeyChords(str, "key names required")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -2938,7 +2924,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
||||
return err
|
||||
}
|
||||
case "--no-header-lines-border":
|
||||
opts.HeaderLinesShape = tui.BorderUndefined
|
||||
opts.HeaderLinesShape = tui.BorderNone
|
||||
case "--header-lines-border":
|
||||
hasArg, arg := optionalNextString()
|
||||
if opts.HeaderLinesShape, err = parseBorder(arg, !hasArg); err != nil {
|
||||
|
@@ -142,7 +142,7 @@ func TestIrrelevantNth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseKeys(t *testing.T) {
|
||||
pairs, _, _ := parseKeyChords("ctrl-z,alt-z,f2,@,Alt-a,!,ctrl-G,J,g,ctrl-alt-a,ALT-enter,alt-SPACE", "")
|
||||
pairs, _ := parseKeyChords("ctrl-z,alt-z,f2,@,Alt-a,!,ctrl-G,J,g,ctrl-alt-a,ALT-enter,alt-SPACE", "")
|
||||
checkEvent := func(e tui.Event, s string) {
|
||||
if pairs[e] != s {
|
||||
t.Errorf("%s != %s", pairs[e], s)
|
||||
@@ -168,7 +168,7 @@ func TestParseKeys(t *testing.T) {
|
||||
checkEvent(tui.AltKey(' '), "alt-SPACE")
|
||||
|
||||
// Synonyms
|
||||
pairs, _, _ = parseKeyChords("enter,Return,space,tab,btab,esc,up,down,left,right", "")
|
||||
pairs, _ = parseKeyChords("enter,Return,space,tab,btab,esc,up,down,left,right", "")
|
||||
if len(pairs) != 9 {
|
||||
t.Error(9)
|
||||
}
|
||||
@@ -182,7 +182,7 @@ func TestParseKeys(t *testing.T) {
|
||||
check(tui.Left, "left")
|
||||
check(tui.Right, "right")
|
||||
|
||||
pairs, _, _ = parseKeyChords("Tab,Ctrl-I,PgUp,page-up,pgdn,Page-Down,Home,End,Alt-BS,Alt-BSpace,shift-left,shift-right,btab,shift-tab,return,Enter,bspace", "")
|
||||
pairs, _ = parseKeyChords("Tab,Ctrl-I,PgUp,page-up,pgdn,Page-Down,Home,End,Alt-BS,Alt-BSpace,shift-left,shift-right,btab,shift-tab,return,Enter,bspace", "")
|
||||
if len(pairs) != 11 {
|
||||
t.Error(11)
|
||||
}
|
||||
@@ -211,40 +211,40 @@ func TestParseKeysWithComma(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
pairs, _, _ := parseKeyChords(",", "")
|
||||
pairs, _ := parseKeyChords(",", "")
|
||||
checkN(len(pairs), 1)
|
||||
check(pairs, tui.Key(','), ",")
|
||||
|
||||
pairs, _, _ = parseKeyChords(",,a,b", "")
|
||||
pairs, _ = parseKeyChords(",,a,b", "")
|
||||
checkN(len(pairs), 3)
|
||||
check(pairs, tui.Key('a'), "a")
|
||||
check(pairs, tui.Key('b'), "b")
|
||||
check(pairs, tui.Key(','), ",")
|
||||
|
||||
pairs, _, _ = parseKeyChords("a,b,,", "")
|
||||
pairs, _ = parseKeyChords("a,b,,", "")
|
||||
checkN(len(pairs), 3)
|
||||
check(pairs, tui.Key('a'), "a")
|
||||
check(pairs, tui.Key('b'), "b")
|
||||
check(pairs, tui.Key(','), ",")
|
||||
|
||||
pairs, _, _ = parseKeyChords("a,,,b", "")
|
||||
pairs, _ = parseKeyChords("a,,,b", "")
|
||||
checkN(len(pairs), 3)
|
||||
check(pairs, tui.Key('a'), "a")
|
||||
check(pairs, tui.Key('b'), "b")
|
||||
check(pairs, tui.Key(','), ",")
|
||||
|
||||
pairs, _, _ = parseKeyChords("a,,,b,c", "")
|
||||
pairs, _ = parseKeyChords("a,,,b,c", "")
|
||||
checkN(len(pairs), 4)
|
||||
check(pairs, tui.Key('a'), "a")
|
||||
check(pairs, tui.Key('b'), "b")
|
||||
check(pairs, tui.Key('c'), "c")
|
||||
check(pairs, tui.Key(','), ",")
|
||||
|
||||
pairs, _, _ = parseKeyChords(",,,", "")
|
||||
pairs, _ = parseKeyChords(",,,", "")
|
||||
checkN(len(pairs), 1)
|
||||
check(pairs, tui.Key(','), ",")
|
||||
|
||||
pairs, _, _ = parseKeyChords(",ALT-,,", "")
|
||||
pairs, _ = parseKeyChords(",ALT-,,", "")
|
||||
checkN(len(pairs), 1)
|
||||
check(pairs, tui.AltKey(','), "ALT-,")
|
||||
}
|
||||
|
@@ -237,7 +237,7 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
|
||||
if color.Fg().IsDefault() && origColor.HasBg() {
|
||||
color = origColor
|
||||
if curr.nth {
|
||||
color = color.WithAttr(attrNth &^ tui.AttrRegular)
|
||||
color = color.WithAttr(attrNth)
|
||||
}
|
||||
} else {
|
||||
color = origColor.MergeNonDefault(color)
|
||||
|
105
src/terminal.go
105
src/terminal.go
@@ -67,7 +67,7 @@ const maxFocusEvents = 10000
|
||||
const blockDuration = 1 * time.Second
|
||||
|
||||
func init() {
|
||||
placeholder = regexp.MustCompile(`\\?(?:{[+*sfr]*[0-9,-.]*}|{q(?::s?[0-9,-.]+)?}|{fzf:(?:query|action|prompt)}|{[+*]?f?nf?})`)
|
||||
placeholder = regexp.MustCompile(`\\?(?:{[+*sfr]*[0-9,-.]*}|{q(?::s?[0-9,-.]+)?}|{fzf:(?:query|action|prompt)}|{\+?f?nf?})`)
|
||||
whiteSuffix = regexp.MustCompile(`\s*$`)
|
||||
offsetComponentRegex = regexp.MustCompile(`([+-][0-9]+)|(-?/[1-9][0-9]*)`)
|
||||
offsetTrimCharsRegex = regexp.MustCompile(`[^0-9/+-]`)
|
||||
@@ -422,8 +422,6 @@ type Terminal struct {
|
||||
forcePreview bool
|
||||
clickHeaderLine int
|
||||
clickHeaderColumn int
|
||||
clickFooterLine int
|
||||
clickFooterColumn int
|
||||
proxyScript string
|
||||
numLinesCache map[int32]numLinesCacheValue
|
||||
}
|
||||
@@ -604,8 +602,6 @@ const (
|
||||
actTransformQuery
|
||||
actTransformSearch
|
||||
|
||||
actTrigger
|
||||
|
||||
actBgTransform
|
||||
actBgTransformBorderLabel
|
||||
actBgTransformGhost
|
||||
@@ -1263,10 +1259,7 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
||||
env = append(env, fmt.Sprintf("FZF_POS=%d", util.Min(t.merger.Length(), t.cy+1)))
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_HEADER_LINE=%d", t.clickHeaderLine))
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_HEADER_COLUMN=%d", t.clickHeaderColumn))
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_FOOTER_LINE=%d", t.clickFooterLine))
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_FOOTER_COLUMN=%d", t.clickFooterColumn))
|
||||
env = t.addClickHeaderWord(env)
|
||||
env = t.addClickFooterWord(env)
|
||||
|
||||
// Add preview environment variables if preview is enabled
|
||||
pwindowSize := t.pwindowSize()
|
||||
@@ -1641,8 +1634,6 @@ func (t *Terminal) changeFooter(footer string) {
|
||||
lines = strings.Split(strings.TrimSuffix(footer, "\n"), "\n")
|
||||
}
|
||||
t.footer = lines
|
||||
t.clickFooterLine = 0
|
||||
t.clickFooterColumn = 0
|
||||
}
|
||||
|
||||
// UpdateHeader updates the header
|
||||
@@ -1801,11 +1792,6 @@ func (t *Terminal) displayWidth(runes []rune) int {
|
||||
return width
|
||||
}
|
||||
|
||||
func (t *Terminal) displayWidthWithPrefix(str string, prefixWidth int) int {
|
||||
width, _ := util.RunesWidth([]rune(str), prefixWidth, t.tabstop, math.MaxInt32)
|
||||
return width
|
||||
}
|
||||
|
||||
const (
|
||||
minWidth = 4
|
||||
minHeight = 3
|
||||
@@ -2298,20 +2284,13 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
||||
innerMarginInt[0]+shift, innerMarginInt[3]+pwidth+m, innerWidth-pwidth-m, innerHeight-shrink, tui.WindowList, noBorder, true)
|
||||
|
||||
// Clear characters on the margin
|
||||
// fzf --bind 'space:toggle-preview' --preview ':' --preview-window left,1
|
||||
// fzf --bind 'space:preview(seq 100)' --preview-window left,1
|
||||
if !hasListBorder {
|
||||
for y := 0; y < innerHeight; y++ {
|
||||
t.window.Move(y, -1)
|
||||
t.window.Print(" ")
|
||||
}
|
||||
}
|
||||
// fzf --bind 'space:toggle-preview' --preview ':' --preview-window left,1,border-none
|
||||
if !previewOpts.Border().HasRight() {
|
||||
for y := 0; y < innerHeight; y++ {
|
||||
t.window.Move(y, -2)
|
||||
t.window.Print(" ")
|
||||
}
|
||||
}
|
||||
|
||||
innerBorderFn(marginInt[0], marginInt[3]+pwidth, width-pwidth, height)
|
||||
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
|
||||
@@ -4772,7 +4751,6 @@ func (t *Terminal) addClickHeaderWord(env []string) []string {
|
||||
if t.layout == layoutReverse {
|
||||
headers[0], headers[1] = headers[1], headers[0]
|
||||
}
|
||||
var trimmedLine string
|
||||
var words []Token
|
||||
var lineNum int
|
||||
for lineNum = 0; lineNum <= clickHeaderLine; lineNum++ {
|
||||
@@ -4791,9 +4769,7 @@ func (t *Terminal) addClickHeaderWord(env []string) []string {
|
||||
return env
|
||||
}
|
||||
|
||||
// NOTE: We can't expand tabs here because the delimiter can contain tabs.
|
||||
trimmedLine, _, _ = extractColor(line, nil, nil)
|
||||
words = Tokenize(trimmedLine, t.delimiter)
|
||||
words = Tokenize(line, t.delimiter)
|
||||
if currentLine {
|
||||
break
|
||||
} else {
|
||||
@@ -4804,14 +4780,11 @@ func (t *Terminal) addClickHeaderWord(env []string) []string {
|
||||
}
|
||||
|
||||
colNum := t.clickHeaderColumn - 1
|
||||
prefixWidth, prefixLength := 0, 0
|
||||
for idx, token := range words {
|
||||
prefixWidth += t.displayWidthWithPrefix(trimmedLine[prefixLength:token.prefixLength], prefixWidth)
|
||||
prefixLength = int(token.prefixLength)
|
||||
|
||||
word, _ := t.processTabs(token.text.ToRunes(), prefixWidth)
|
||||
prefixWidth := int(token.prefixLength)
|
||||
word := token.text.ToString()
|
||||
trimmed := strings.TrimRightFunc(word, unicode.IsSpace)
|
||||
trimWidth := t.displayWidthWithPrefix(trimmed, prefixWidth)
|
||||
trimWidth, _ := util.RunesWidth([]rune(trimmed), prefixWidth, t.tabstop, math.MaxInt32)
|
||||
|
||||
// Find the position of the first non-space character in the word
|
||||
minPos := strings.IndexFunc(trimmed, func(r rune) bool {
|
||||
@@ -4830,37 +4803,6 @@ func (t *Terminal) addClickHeaderWord(env []string) []string {
|
||||
return env
|
||||
}
|
||||
|
||||
func (t *Terminal) addClickFooterWord(env []string) []string {
|
||||
clickFooterLine := t.clickFooterLine - 1
|
||||
if clickFooterLine < 0 || clickFooterLine >= len(t.footer) {
|
||||
// Never clicked on the footer
|
||||
return env
|
||||
}
|
||||
|
||||
// NOTE: Unlike in click-header, we don't use --delimiter here, since we're
|
||||
// only interested in the word, not nth. Does this make sense?
|
||||
trimmed, _, _ := extractColor(t.footer[clickFooterLine], nil, nil)
|
||||
trimmed, _ = t.processTabs([]rune(trimmed), 0)
|
||||
words := Tokenize(trimmed, Delimiter{})
|
||||
colNum := t.clickFooterColumn - 1
|
||||
for _, token := range words {
|
||||
prefixWidth := int(token.prefixLength)
|
||||
word := token.text.ToString()
|
||||
trimmed := strings.TrimRightFunc(word, unicode.IsSpace)
|
||||
trimWidth := t.displayWidthWithPrefix(trimmed, prefixWidth)
|
||||
|
||||
// Find the position of the first non-space character in the word
|
||||
minPos := strings.IndexFunc(trimmed, func(r rune) bool {
|
||||
return !unicode.IsSpace(r)
|
||||
})
|
||||
if colNum >= minPos && colNum >= prefixWidth && colNum < prefixWidth+trimWidth {
|
||||
env = append(env, fmt.Sprintf("FZF_CLICK_FOOTER_WORD=%s", trimmed))
|
||||
return env
|
||||
}
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
// Loop is called to start Terminal I/O
|
||||
func (t *Terminal) Loop() error {
|
||||
// prof := profile.Start(profile.ProfilePath("/tmp/"))
|
||||
@@ -5458,7 +5400,6 @@ func (t *Terminal) Loop() error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
triggering := map[tui.Event]struct{}{}
|
||||
previousInput := t.input
|
||||
previousCx := t.cx
|
||||
previousVersion := t.version
|
||||
@@ -5726,7 +5667,7 @@ func (t *Terminal) Loop() error {
|
||||
capture(true, func(expr string) {
|
||||
// Split nth expression
|
||||
tokens := strings.Split(expr, "|")
|
||||
if nth, err := splitNth(tokens[0]); err == nil || len(expr) == 0 {
|
||||
if nth, err := splitNth(tokens[0]); err == nil {
|
||||
// Changed
|
||||
newNth = &nth
|
||||
} else {
|
||||
@@ -6250,20 +6191,6 @@ func (t *Terminal) Loop() error {
|
||||
case actDisableSearch:
|
||||
t.paused = true
|
||||
req(reqPrompt)
|
||||
case actTrigger:
|
||||
if _, chords, err := parseKeyChords(a.a, ""); err == nil {
|
||||
for _, chord := range chords {
|
||||
if _, prs := triggering[chord]; prs {
|
||||
// Avoid recursive triggering
|
||||
continue
|
||||
}
|
||||
if acts, prs := t.keymap[chord]; prs {
|
||||
triggering[chord] = struct{}{}
|
||||
doActions(acts)
|
||||
delete(triggering, chord)
|
||||
}
|
||||
}
|
||||
}
|
||||
case actSigStop:
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
if err == nil {
|
||||
@@ -6453,18 +6380,6 @@ func (t *Terminal) Loop() error {
|
||||
return doActions(actionsFor(tui.ClickHeader))
|
||||
}
|
||||
|
||||
// Inside the footer window
|
||||
if clicked && t.footerWindow != nil && t.footerWindow.Enclose(my, mx) {
|
||||
mx -= t.footerWindow.Left() + t.headerIndent(t.footerBorderShape)
|
||||
my -= t.footerWindow.Top()
|
||||
if mx < 0 {
|
||||
break
|
||||
}
|
||||
t.clickFooterLine = my + 1
|
||||
t.clickFooterColumn = mx + 1
|
||||
return doActions(actionsFor(tui.ClickFooter))
|
||||
}
|
||||
|
||||
// Ignored
|
||||
if !t.window.Enclose(my, mx) && !barDragging {
|
||||
break
|
||||
@@ -6585,13 +6500,13 @@ func (t *Terminal) Loop() error {
|
||||
t.reading = true
|
||||
}
|
||||
case actUnbind:
|
||||
if keys, _, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||
if keys, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||
for key := range keys {
|
||||
delete(t.keymap, key)
|
||||
}
|
||||
}
|
||||
case actRebind:
|
||||
if keys, _, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||
if keys, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||
for key := range keys {
|
||||
if originalAction, found := t.keymapOrg[key]; found {
|
||||
t.keymap[key] = originalAction
|
||||
@@ -6599,7 +6514,7 @@ func (t *Terminal) Loop() error {
|
||||
}
|
||||
}
|
||||
case actToggleBind:
|
||||
if keys, _, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||
if keys, err := parseKeyChords(a.a, "PANIC"); err == nil {
|
||||
for key := range keys {
|
||||
if _, bound := t.keymap[key]; bound {
|
||||
delete(t.keymap, key)
|
||||
|
@@ -110,13 +110,12 @@ func _() {
|
||||
_ = x[Jump-99]
|
||||
_ = x[JumpCancel-100]
|
||||
_ = x[ClickHeader-101]
|
||||
_ = x[ClickFooter-102]
|
||||
_ = x[Multi-103]
|
||||
_ = x[Multi-102]
|
||||
}
|
||||
|
||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderClickFooterMulti"
|
||||
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLEnterCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidFatalBracketedPasteBeginBracketedPasteEndMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancelClickHeaderMulti"
|
||||
|
||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 466, 483, 488, 499, 508, 518, 528, 539, 547, 557, 566, 577, 592, 609, 615, 621, 632, 637, 641, 646, 649, 653, 659, 663, 673, 684, 695, 700}
|
||||
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 466, 483, 488, 499, 508, 518, 528, 539, 547, 557, 566, 577, 592, 609, 615, 621, 632, 637, 641, 646, 649, 653, 659, 663, 673, 684, 689}
|
||||
|
||||
func (i EventType) String() string {
|
||||
if i < 0 || i >= EventType(len(_EventType_index)-1) {
|
||||
|
@@ -132,7 +132,6 @@ const (
|
||||
Jump
|
||||
JumpCancel
|
||||
ClickHeader
|
||||
ClickFooter
|
||||
Multi
|
||||
)
|
||||
|
||||
@@ -505,7 +504,7 @@ type BorderCharacter int
|
||||
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
if shape == BorderNone || shape == BorderPhantom {
|
||||
return BorderStyle{
|
||||
shape: BorderNone,
|
||||
shape: shape,
|
||||
top: ' ',
|
||||
bottom: ' ',
|
||||
left: ' ',
|
||||
|
@@ -2035,29 +2035,4 @@ class TestCore < TestInteractive
|
||||
assert_equal 19, it.select_count
|
||||
end
|
||||
end
|
||||
|
||||
def test_trigger
|
||||
tmux.send_keys %(seq 100 | #{FZF} --bind 'a:up+trigger(a),b:trigger(a,a,b,a)'), :Enter
|
||||
tmux.until { assert_equal 100, it.match_count }
|
||||
tmux.until { |lines| assert_includes lines, '> 1' }
|
||||
tmux.send_keys :a
|
||||
tmux.until { |lines| assert_includes lines, '> 3' }
|
||||
tmux.send_keys :b
|
||||
tmux.until { |lines| assert_includes lines, '> 9' }
|
||||
end
|
||||
|
||||
def test_change_nth_unset_default
|
||||
tmux.send_keys %(echo foo bar | #{FZF} --nth 2 --query fb --bind space:change-nth:), :Enter
|
||||
tmux.until do
|
||||
assert_equal 1, it.item_count
|
||||
assert_equal 0, it.match_count
|
||||
end
|
||||
|
||||
tmux.send_keys :Space
|
||||
|
||||
tmux.until do
|
||||
assert_equal 1, it.item_count
|
||||
assert_equal 1, it.match_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@@ -995,8 +995,6 @@ class TestLayout < TestInteractive
|
||||
%[--header "$(seq 101 102)" --header-border sharp],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-first],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-lines 2],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-lines 2 --no-header-lines-border],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-lines 2 --header-lines-border none],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-lines 2 --header-lines-border sharp],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-lines 2 --header-lines-border sharp --header-first --input-border sharp],
|
||||
%[--header "$(seq 101 102)" --header-border sharp --header-lines 2 --header-lines-border sharp --header-first --no-input],
|
||||
@@ -1004,24 +1002,24 @@ class TestLayout < TestInteractive
|
||||
%[--header "$(seq 101 102)" --style full:sharp --header-first]
|
||||
]
|
||||
output = <<~BLOCK
|
||||
┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌───────── ┌──────── ┌──────── ┌─────────
|
||||
│ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ ┌─FOOT─ │ ┌─FOOT──
|
||||
│ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ │ 201 │ │ 201
|
||||
│ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT── │ ──FOOT─ │ │ 202 │ │ 202
|
||||
│ 3 │ 3 │ 3 │ > 3 │ > 3 │ 3 │ 3 │ > 3 │ > 3 │ > 3 │ > 3 │ > 3 │ > 3 │ └────── │ └───────
|
||||
│ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ ┌────── │ ┌────── │ 2 │ ┌────── │ ┌─────── │ ┌────── │ 3 │ ┌───────
|
||||
│ > 1 │ > 1 │ > 1 │ 1 │ 1 │ > 1 │ > 1 │ │ 2 │ │ 2 │ 1 │ │ 2 │ │ 2 │ │ 2 │ 2 │ │ 3
|
||||
│ 3/3 ─ │ 101 │ 3/3 ─ │ 101 │ 1/1 ─ │ ┌────── │ 3/3 ─ │ │ 1 │ │ 1 │ ┌────── │ │ 1 │ │ 1 │ │ 1 │ > 1 │ │ 2
|
||||
│ > │ 102 │ > │ 102 │ > │ │ 101 │ > │ │ 101 │ │ 101 │ │ 101 │ └────── │ └─────── │ └────── │ 101 │ │ > 1
|
||||
└──────── │ 3/3 ─ │ 101 │ 1/1 ─ │ 101 │ │ 102 │ ┌────── │ │ 102 │ │ 102 │ │ 102 │ ┌────── │ ┌─────── │ ┌────── │ 102 │ └───────
|
||||
│ > │ 102 │ > │ 102 │ └─HEAD─ │ │ 101 │ └─HEAD─ │ └─HEAD─ │ └─HEAD─ │ │ 101 │ │ 1/1 │ │ 101 │ ─────── │ ┌───────
|
||||
└──────── └──────── └──────── └──────── │ 3/3 ─ │ │ 102 │ 1/1 ─ │ 1/1 ─ │ 1/1 ─ │ │ 102 │ │ > │ │ 102 │ 3/3 │ │ >
|
||||
│ > │ └─HEAD─ │ > │ > │ > │ └─HEAD─ │ └─────── │ └─HEAD─ │ > │ └───────
|
||||
└──────── └──────── └──────── └──────── └──────── │ 1/1 ─ │ ┌─────── └──────── └──────── │ ┌───────
|
||||
│ > │ │ 101 │ │ 101
|
||||
└──────── │ │ 102 │ │ 102
|
||||
│ └─HEAD── │ └─HEAD──
|
||||
└───────── └─────────
|
||||
┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌──────── ┌───────── ┌──────── ┌──────── ┌─────────
|
||||
│ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ 201 │ ┌─FOOT─ │ ┌─FOOT──
|
||||
│ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ 202 │ │ 201 │ │ 201
|
||||
│ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT─ │ ──FOOT── │ ──FOOT─ │ │ 202 │ │ 202
|
||||
│ 3 │ 3 │ 3 │ > 3 │ > 3 │ 3 │ 3 │ > 3 │ > 3 │ > 3 │ > 3 │ └────── │ └───────
|
||||
│ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ 2 │ ┌────── │ ┌────── │ ┌─────── │ ┌────── │ 3 │ ┌───────
|
||||
│ > 1 │ > 1 │ > 1 │ 1 │ 1 │ > 1 │ > 1 │ │ 2 │ │ 2 │ │ 2 │ │ 2 │ 2 │ │ 3
|
||||
│ 3/3 ─ │ 101 │ 3/3 ─ │ 101 │ 1/1 ─ │ ┌────── │ 3/3 ─ │ │ 1 │ │ 1 │ │ 1 │ │ 1 │ > 1 │ │ 2
|
||||
│ > │ 102 │ > │ 102 │ > │ │ 101 │ > │ │ 101 │ └────── │ └─────── │ └────── │ 101 │ │ > 1
|
||||
└──────── │ 3/3 ─ │ 101 │ 1/1 ─ │ 101 │ │ 102 │ ┌────── │ │ 102 │ ┌────── │ ┌─────── │ ┌────── │ 102 │ └───────
|
||||
│ > │ 102 │ > │ 102 │ └─HEAD─ │ │ 101 │ └─HEAD─ │ │ 101 │ │ 1/1 │ │ 101 │ ─────── │ ┌───────
|
||||
└──────── └──────── └──────── └──────── │ 3/3 ─ │ │ 102 │ 1/1 ─ │ │ 102 │ │ > │ │ 102 │ 3/3 │ │ >
|
||||
│ > │ └─HEAD─ │ > │ └─HEAD─ │ └─────── │ └─HEAD─ │ > │ └───────
|
||||
└──────── └──────── └──────── │ 1/1 ─ │ ┌─────── └──────── └──────── │ ┌───────
|
||||
│ > │ │ 101 │ │ 101
|
||||
└──────── │ │ 102 │ │ 102
|
||||
│ └─HEAD── │ └─HEAD──
|
||||
└───────── └─────────
|
||||
BLOCK
|
||||
|
||||
expects = []
|
||||
|
@@ -190,17 +190,17 @@ class TestPreview < TestInteractive
|
||||
end
|
||||
|
||||
def test_preview_asterisk
|
||||
tmux.send_keys %(seq 5 | #{FZF} --multi --preview 'echo [{}/{+}/{*}/{*n}]' --preview-window '+{1}'), :Enter
|
||||
tmux.send_keys %(seq 5 | #{FZF} --multi --preview 'echo [{} / {+} / {*}]' --preview-window '+{1}'), :Enter
|
||||
tmux.until { |lines| assert_equal 5, lines.match_count }
|
||||
tmux.until { |lines| assert_includes lines[1], ' [1/1/1 2 3 4 5/0 1 2 3 4] ' }
|
||||
tmux.until { |lines| assert_includes lines[1], ' [1 / 1 / 1 2 3 4 5] ' }
|
||||
tmux.send_keys :BTab
|
||||
tmux.until { |lines| assert_includes lines[1], ' [2/1/1 2 3 4 5/0 1 2 3 4] ' }
|
||||
tmux.until { |lines| assert_includes lines[1], ' [2 / 1 / 1 2 3 4 5] ' }
|
||||
tmux.send_keys :BTab
|
||||
tmux.until { |lines| assert_includes lines[1], ' [3/1 2/1 2 3 4 5/0 1 2 3 4] ' }
|
||||
tmux.until { |lines| assert_includes lines[1], ' [3 / 1 2 / 1 2 3 4 5] ' }
|
||||
tmux.send_keys '5'
|
||||
tmux.until { |lines| assert_includes lines[1], ' [5/1 2/5/4] ' }
|
||||
tmux.until { |lines| assert_includes lines[1], ' [5 / 1 2 / 5] ' }
|
||||
tmux.send_keys '5'
|
||||
tmux.until { |lines| assert_includes lines[1], ' [/1 2//] ' }
|
||||
tmux.until { |lines| assert_includes lines[1], ' [ / 1 2 / ] ' }
|
||||
end
|
||||
|
||||
def test_preview_file
|
||||
|
Reference in New Issue
Block a user