diff --git a/CHANGELOG.md b/CHANGELOG.md index e2a14101..f0f63ef4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 0b3cabfc..c767fe14 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -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 diff --git a/src/actiontype_string.go b/src/actiontype_string.go index 123c0651..e178670f 100644 --- a/src/actiontype_string.go +++ b/src/actiontype_string.go @@ -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) { diff --git a/src/options.go b/src/options.go index a22916e3..b7eed83c 100644 --- a/src/options.go +++ b/src/options.go @@ -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": diff --git a/src/terminal.go b/src/terminal.go index d6e7eadc..1a738da9 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -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 diff --git a/src/tui/dummy.go b/src/tui/dummy.go index 8dd58457..cd856233 100644 --- a/src/tui/dummy.go +++ b/src/tui/dummy.go @@ -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{} } diff --git a/src/tui/light.go b/src/tui/light.go index 7b40efbb..ab7bd87f 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -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") } diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 9d6fde80..5f70f54a 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -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 diff --git a/src/tui/tui.go b/src/tui/tui.go index 0c778ad6..8423c631 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -616,6 +616,7 @@ type Renderer interface { ShouldEmitResizeEvent() bool Bell() HideCursor() + ShowCursor() GetChar() Event