Add {show,hide,toggle}-input and expose $FZF_INPUT_STATE

This commit is contained in:
Junegunn Choi 2025-02-01 11:16:16 +09:00
parent e1e171a3c4
commit e84afe196a
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
9 changed files with 156 additions and 81 deletions

View File

@ -35,6 +35,7 @@ CHANGELOG
--header-border bottom --input-border \
--bind 'click-header:transform-search:echo ${FZF_CLICK_HEADER_WORD:1:-1}'
```
- You can later show the input section using `show-input` or `toggle-input` action, and hide it again using `hide-input`, or `toggle-input`.
- Extended `{q}` placeholder to support ranges. e.g. `{q:1}`, `{q:2..}`, etc.
- Added `search(...)` and `transform-search(...)` action to trigger an fzf search with an arbitrary query string. This can be used to extend the search syntax of fzf. In the following example, fzf will use the first word of the query to trigger ripgrep search, and use the rest of the query to perform fzf search within the result.
```sh

View File

@ -623,7 +623,9 @@ Position of the list label
.TP
.B "\-\-no\-input"
Disable and hide the input section. You can no longer type in queries. To
trigger a search, use \fBsearch\fR action.
trigger a search, use \fBsearch\fR action. You can later show the input section
using \fBshow\-input\fR or \fBtoggle\-input\fR action, and hide it again using
\fBhide\-input\fR, or \fBtoggle\-input\fR.
.TP
.BI "\-\-prompt=" "STR"
@ -1222,6 +1224,8 @@ fzf exports the following environment variables to its child processes.
.br
.BR FZF_QUERY " Current query string"
.br
.BR FZF_INPUT_STATE " Current input state (enabled, disabled, hidden)"
.br
.BR FZF_NTH " Current \-\-nth option"
.br
.BR FZF_PROMPT " Prompt string"
@ -1610,6 +1614,7 @@ A key or an event can be bound to one or more of the following actions.
\fBhalf\-page\-down\fR
\fBhalf\-page\-up\fR
\fBhide\-header\fR
\fBhide\-input\fR
\fBhide\-preview\fR
\fBoffset\-down\fR (similar to CTRL\-E of Vim)
\fBoffset\-up\fR (similar to CTRL\-Y of Vim)
@ -1638,6 +1643,7 @@ A key or an event can be bound to one or more of the following actions.
\fBselect\fR
\fBselect\-all\fR (select all matches)
\fBshow\-header\fR
\fBshow\-input\fR
\fBshow\-preview\fR
\fBtoggle\fR (\fIright\-click\fR)
\fBtoggle\-all\fR (toggle all matches)
@ -1646,6 +1652,7 @@ A key or an event can be bound to one or more of the following actions.
\fBtoggle\-bind\fR
\fBtoggle\-header\fR
\fBtoggle\-hscroll\fR
\fBtoggle\-input\fR
\fBtoggle\-multi\-line\fR
\fBtoggle\-preview\fR
\fBtoggle\-preview\-wrap\fR

View File

@ -66,80 +66,83 @@ func _() {
_ = x[actToggleMultiLine-55]
_ = x[actToggleHscroll-56]
_ = x[actTrackCurrent-57]
_ = x[actUntrackCurrent-58]
_ = x[actDown-59]
_ = x[actUp-60]
_ = x[actPageUp-61]
_ = x[actPageDown-62]
_ = x[actPosition-63]
_ = x[actHalfPageUp-64]
_ = x[actHalfPageDown-65]
_ = x[actOffsetUp-66]
_ = x[actOffsetDown-67]
_ = x[actOffsetMiddle-68]
_ = x[actJump-69]
_ = x[actJumpAccept-70]
_ = x[actPrintQuery-71]
_ = x[actRefreshPreview-72]
_ = x[actReplaceQuery-73]
_ = x[actToggleSort-74]
_ = x[actShowPreview-75]
_ = x[actHidePreview-76]
_ = x[actTogglePreview-77]
_ = x[actTogglePreviewWrap-78]
_ = x[actTransform-79]
_ = x[actTransformBorderLabel-80]
_ = x[actTransformListLabel-81]
_ = x[actTransformInputLabel-82]
_ = x[actTransformHeader-83]
_ = x[actTransformHeaderLabel-84]
_ = x[actTransformNth-85]
_ = x[actTransformPreviewLabel-86]
_ = x[actTransformPrompt-87]
_ = x[actTransformQuery-88]
_ = x[actTransformSearch-89]
_ = x[actSearch-90]
_ = x[actPreview-91]
_ = x[actChangePreview-92]
_ = x[actChangePreviewWindow-93]
_ = x[actPreviewTop-94]
_ = x[actPreviewBottom-95]
_ = x[actPreviewUp-96]
_ = x[actPreviewDown-97]
_ = x[actPreviewPageUp-98]
_ = x[actPreviewPageDown-99]
_ = x[actPreviewHalfPageUp-100]
_ = x[actPreviewHalfPageDown-101]
_ = x[actPrevHistory-102]
_ = x[actPrevSelected-103]
_ = x[actPrint-104]
_ = x[actPut-105]
_ = x[actNextHistory-106]
_ = x[actNextSelected-107]
_ = x[actExecute-108]
_ = x[actExecuteSilent-109]
_ = x[actExecuteMulti-110]
_ = x[actSigStop-111]
_ = x[actFirst-112]
_ = x[actLast-113]
_ = x[actReload-114]
_ = x[actReloadSync-115]
_ = x[actDisableSearch-116]
_ = x[actEnableSearch-117]
_ = x[actSelect-118]
_ = x[actDeselect-119]
_ = x[actUnbind-120]
_ = x[actRebind-121]
_ = x[actToggleBind-122]
_ = x[actBecome-123]
_ = x[actShowHeader-124]
_ = x[actHideHeader-125]
_ = x[actBell-126]
_ = x[actToggleInput-58]
_ = x[actHideInput-59]
_ = x[actShowInput-60]
_ = x[actUntrackCurrent-61]
_ = x[actDown-62]
_ = x[actUp-63]
_ = x[actPageUp-64]
_ = x[actPageDown-65]
_ = x[actPosition-66]
_ = x[actHalfPageUp-67]
_ = x[actHalfPageDown-68]
_ = x[actOffsetUp-69]
_ = x[actOffsetDown-70]
_ = x[actOffsetMiddle-71]
_ = x[actJump-72]
_ = x[actJumpAccept-73]
_ = x[actPrintQuery-74]
_ = x[actRefreshPreview-75]
_ = x[actReplaceQuery-76]
_ = x[actToggleSort-77]
_ = x[actShowPreview-78]
_ = x[actHidePreview-79]
_ = x[actTogglePreview-80]
_ = x[actTogglePreviewWrap-81]
_ = x[actTransform-82]
_ = x[actTransformBorderLabel-83]
_ = x[actTransformListLabel-84]
_ = x[actTransformInputLabel-85]
_ = x[actTransformHeader-86]
_ = x[actTransformHeaderLabel-87]
_ = x[actTransformNth-88]
_ = x[actTransformPreviewLabel-89]
_ = x[actTransformPrompt-90]
_ = x[actTransformQuery-91]
_ = x[actTransformSearch-92]
_ = x[actSearch-93]
_ = x[actPreview-94]
_ = x[actChangePreview-95]
_ = x[actChangePreviewWindow-96]
_ = x[actPreviewTop-97]
_ = x[actPreviewBottom-98]
_ = x[actPreviewUp-99]
_ = x[actPreviewDown-100]
_ = x[actPreviewPageUp-101]
_ = x[actPreviewPageDown-102]
_ = x[actPreviewHalfPageUp-103]
_ = x[actPreviewHalfPageDown-104]
_ = x[actPrevHistory-105]
_ = x[actPrevSelected-106]
_ = x[actPrint-107]
_ = x[actPut-108]
_ = x[actNextHistory-109]
_ = x[actNextSelected-110]
_ = x[actExecute-111]
_ = x[actExecuteSilent-112]
_ = x[actExecuteMulti-113]
_ = x[actSigStop-114]
_ = x[actFirst-115]
_ = x[actLast-116]
_ = x[actReload-117]
_ = x[actReloadSync-118]
_ = x[actDisableSearch-119]
_ = x[actEnableSearch-120]
_ = x[actSelect-121]
_ = x[actDeselect-122]
_ = x[actUnbind-123]
_ = x[actRebind-124]
_ = x[actToggleBind-125]
_ = x[actBecome-126]
_ = x[actShowHeader-127]
_ = x[actHideHeader-128]
_ = x[actBell-129]
}
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformNthactTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBell"
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformNthactTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBell"
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 375, 389, 402, 419, 427, 440, 456, 468, 476, 490, 504, 515, 526, 544, 561, 568, 587, 599, 613, 622, 637, 649, 662, 673, 684, 696, 710, 731, 746, 759, 777, 793, 808, 825, 832, 837, 846, 857, 868, 881, 896, 907, 920, 935, 942, 955, 968, 985, 1000, 1013, 1027, 1041, 1057, 1077, 1089, 1112, 1133, 1155, 1173, 1196, 1211, 1235, 1253, 1270, 1288, 1297, 1307, 1323, 1345, 1358, 1374, 1386, 1400, 1416, 1434, 1454, 1476, 1490, 1505, 1513, 1519, 1533, 1548, 1558, 1574, 1589, 1599, 1607, 1614, 1623, 1636, 1652, 1667, 1676, 1687, 1696, 1705, 1718, 1727, 1740, 1753, 1760}
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 264, 279, 299, 313, 334, 349, 363, 375, 389, 402, 419, 427, 440, 456, 468, 476, 490, 504, 515, 526, 544, 561, 568, 587, 599, 613, 622, 637, 649, 662, 673, 684, 696, 710, 731, 746, 759, 777, 793, 808, 822, 834, 846, 863, 870, 875, 884, 895, 906, 919, 934, 945, 958, 973, 980, 993, 1006, 1023, 1038, 1051, 1065, 1079, 1095, 1115, 1127, 1150, 1171, 1193, 1211, 1234, 1249, 1273, 1291, 1308, 1326, 1335, 1345, 1361, 1383, 1396, 1412, 1424, 1438, 1454, 1472, 1492, 1514, 1528, 1543, 1551, 1557, 1571, 1586, 1596, 1612, 1627, 1637, 1645, 1652, 1661, 1674, 1690, 1705, 1714, 1725, 1734, 1743, 1756, 1765, 1778, 1791, 1798}
func (i actionType) String() string {
if i < 0 || i >= actionType(len(_actionType_index)-1) {

View File

@ -1500,6 +1500,12 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actToggleTrack)
case "toggle-track-current":
appendAction(actToggleTrackCurrent)
case "toggle-input":
appendAction(actToggleInput)
case "hide-input":
appendAction(actHideInput)
case "show-input":
appendAction(actShowInput)
case "toggle-header":
appendAction(actToggleHeader)
case "toggle-wrap":

View File

@ -505,6 +505,9 @@ const (
actToggleMultiLine
actToggleHscroll
actTrackCurrent
actToggleInput
actHideInput
actShowInput
actUntrackCurrent
actDown
actUp
@ -1064,6 +1067,13 @@ func (t *Terminal) environImpl(forPreview bool) []string {
if len(t.nthCurrent) > 0 {
env = append(env, "FZF_NTH="+RangesToString(t.nthCurrent))
}
inputState := "enabled"
if t.inputless {
inputState = "hidden"
} else if t.paused {
inputState = "disabled"
}
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.merger.Length()))
env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected)))
@ -2492,22 +2502,29 @@ func (t *Terminal) printInfoImpl() {
}
}
func (t *Terminal) printHeader() {
func (t *Terminal) resizeIfNeeded() bool {
// Check if input border is used and input has changed
if t.inputBorderShape.Visible() && t.inputWindow == nil && !t.inputless {
t.printAll()
return true
}
// Check if the header borders are used and header has changed
allHeaderLines := t.visibleHeaderLines()
primaryHeaderLines := allHeaderLines
if t.headerLinesShape.Visible() {
primaryHeaderLines -= t.headerLines
}
// We may need to resize header windows
if (t.headerBorderShape.Visible() || t.headerLinesShape.Visible()) &&
(t.headerWindow == nil && primaryHeaderLines > 0 || t.headerWindow != nil && primaryHeaderLines != t.headerWindow.Height()) ||
t.headerLinesShape.Visible() && (t.headerLinesWindow == nil && t.headerLines > 0 || t.headerLinesWindow != nil && t.headerLines != t.headerLinesWindow.Height()) {
t.resizeWindows(false, true)
t.printList()
t.printPrompt()
t.printInfo()
t.printPreview()
t.printAll()
return true
}
return false
}
func (t *Terminal) printHeader() {
if !t.headerVisible {
return
}
@ -4498,7 +4515,11 @@ func (t *Terminal) Loop() error {
// U t.uiMutex |
t.uiMutex.Lock()
t.mutex.Lock()
printInfo := util.RunOnce(t.printInfo)
printInfo := util.RunOnce(func() {
if !t.resizeIfNeeded() {
t.printInfo()
}
})
for _, key := range keys {
req := util.EventType(key)
value := (*events)[req]
@ -4540,7 +4561,9 @@ func (t *Terminal) Loop() error {
}
t.printList()
case reqHeader:
t.printHeader()
if !t.resizeIfNeeded() {
t.printHeader()
}
case reqActivate:
t.suppress = false
if t.hasPreviewer() {
@ -4796,6 +4819,7 @@ func (t *Terminal) Loop() error {
return true
}
doAction = func(a *action) bool {
Action:
switch a.t {
case actIgnore, actStart, actClick:
case actBecome:
@ -5416,6 +5440,28 @@ func (t *Terminal) Loop() error {
t.forceRerenderList()
t.hscroll = !t.hscroll
req(reqList)
case actToggleInput, actShowInput, actHideInput:
switch a.t {
case actToggleInput:
t.inputless = !t.inputless
case actShowInput:
if !t.inputless {
break Action
}
t.inputless = false
case actHideInput:
if t.inputless {
break Action
}
t.inputless = true
}
t.forceRerenderList()
if t.inputless {
t.tui.HideCursor()
} else {
t.tui.ShowCursor()
}
req(reqList, reqInfo, reqPrompt, reqHeader)
case actTrackCurrent:
if t.track == trackDisabled {
t.track = trackCurrent

View File

@ -46,6 +46,7 @@ func (r *FullscreenRenderer) NeedScrollbarRedraw() bool { return false
func (r *FullscreenRenderer) ShouldEmitResizeEvent() bool { return false }
func (r *FullscreenRenderer) Bell() {}
func (r *FullscreenRenderer) HideCursor() {}
func (r *FullscreenRenderer) ShowCursor() {}
func (r *FullscreenRenderer) Refresh() {}
func (r *FullscreenRenderer) Close() {}
func (r *FullscreenRenderer) Size() TermSize { return TermSize{} }

View File

@ -1228,4 +1228,10 @@ func (w *LightWindow) EraseMaybe() bool {
func (r *LightRenderer) HideCursor() {
r.showCursor = false
r.csi("?25l")
}
func (r *LightRenderer) ShowCursor() {
r.showCursor = true
r.csi("?25h")
}

View File

@ -111,6 +111,10 @@ func (r *FullscreenRenderer) HideCursor() {
r.showCursor = false
}
func (r *FullscreenRenderer) ShowCursor() {
r.showCursor = true
}
func (r *FullscreenRenderer) PassThrough(str string) {
// No-op
// https://github.com/gdamore/tcell/pull/650#issuecomment-1806442846

View File

@ -616,6 +616,7 @@ type Renderer interface {
ShouldEmitResizeEvent() bool
Bell()
HideCursor()
ShowCursor()
GetChar() Event