diff --git a/CHANGELOG.md b/CHANGELOG.md index 099fc6b1..06dc3e77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG # Display "Type to search" when the input is empty fzf --ghost "Type to search" ``` +- Added `change-pointer` and `transform-pointer` actions for dynamically changing the pointer sign - Bug fixes and improvements 0.60.3 diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index f4c8322c..33ea2609 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -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 "Mar 2025" "fzf 0.60.3" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Mar 2025" "fzf 0.61.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -1616,6 +1616,7 @@ A key or an event can be bound to one or more of the following actions. \fBchange\-multi\fR (enable multi-select mode with no limit) \fBchange\-multi(...)\fR (enable multi-select mode with a limit or disable it with 0) \fBchange\-nth(...)\fR (change \fB\-\-nth\fR option; rotate through the multiple options separated by '|') + \fBchange\-pointer(...)\fR (change \fB\-\-pointer\fR option) \fBchange\-preview(...)\fR (change \fB\-\-preview\fR option) \fBchange\-preview\-label(...)\fR (change \fB\-\-preview\-label\fR to the given string) \fBchange\-preview\-window(...)\fR (change \fB\-\-preview\-window\fR option; rotate through the multiple option sets separated by '|') @@ -1709,6 +1710,7 @@ A key or an event can be bound to one or more of the following actions. \fBtransform\-input\-label(...)\fR (transform input label using an external command) \fBtransform\-list\-label(...)\fR (transform list label using an external command) \fBtransform\-nth(...)\fR (transform nth using an external command) + \fBtransform\-pointer(...)\fR (transform pointer using an external command) \fBtransform\-preview\-label(...)\fR (transform preview label using an external command) \fBtransform\-prompt(...)\fR (transform prompt string using an external command) \fBtransform\-query(...)\fR (transform query string using an external command) diff --git a/src/actiontype_string.go b/src/actiontype_string.go index ce388e38..19b5ea72 100644 --- a/src/actiontype_string.go +++ b/src/actiontype_string.go @@ -99,54 +99,56 @@ func _() { _ = x[actTransformHeader-88] _ = x[actTransformHeaderLabel-89] _ = x[actTransformNth-90] - _ = x[actTransformPreviewLabel-91] - _ = x[actTransformPrompt-92] - _ = x[actTransformQuery-93] - _ = x[actTransformSearch-94] - _ = x[actSearch-95] - _ = x[actPreview-96] - _ = x[actChangePreview-97] - _ = x[actChangePreviewWindow-98] - _ = x[actPreviewTop-99] - _ = x[actPreviewBottom-100] - _ = x[actPreviewUp-101] - _ = x[actPreviewDown-102] - _ = x[actPreviewPageUp-103] - _ = x[actPreviewPageDown-104] - _ = x[actPreviewHalfPageUp-105] - _ = x[actPreviewHalfPageDown-106] - _ = x[actPrevHistory-107] - _ = x[actPrevSelected-108] - _ = x[actPrint-109] - _ = x[actPut-110] - _ = x[actNextHistory-111] - _ = x[actNextSelected-112] - _ = x[actExecute-113] - _ = x[actExecuteSilent-114] - _ = x[actExecuteMulti-115] - _ = x[actSigStop-116] - _ = x[actFirst-117] - _ = x[actLast-118] - _ = x[actReload-119] - _ = x[actReloadSync-120] - _ = x[actDisableSearch-121] - _ = x[actEnableSearch-122] - _ = x[actSelect-123] - _ = x[actDeselect-124] - _ = x[actUnbind-125] - _ = x[actRebind-126] - _ = x[actToggleBind-127] - _ = x[actBecome-128] - _ = x[actShowHeader-129] - _ = x[actHideHeader-130] - _ = x[actBell-131] - _ = x[actExclude-132] - _ = x[actExcludeMulti-133] + _ = x[actTransformPointer-91] + _ = x[actTransformPreviewLabel-92] + _ = x[actTransformPrompt-93] + _ = x[actTransformQuery-94] + _ = x[actTransformSearch-95] + _ = x[actSearch-96] + _ = x[actPreview-97] + _ = x[actChangePointer-98] + _ = x[actChangePreview-99] + _ = x[actChangePreviewWindow-100] + _ = x[actPreviewTop-101] + _ = x[actPreviewBottom-102] + _ = x[actPreviewUp-103] + _ = x[actPreviewDown-104] + _ = x[actPreviewPageUp-105] + _ = x[actPreviewPageDown-106] + _ = x[actPreviewHalfPageUp-107] + _ = x[actPreviewHalfPageDown-108] + _ = x[actPrevHistory-109] + _ = x[actPrevSelected-110] + _ = x[actPrint-111] + _ = x[actPut-112] + _ = x[actNextHistory-113] + _ = x[actNextSelected-114] + _ = x[actExecute-115] + _ = x[actExecuteSilent-116] + _ = x[actExecuteMulti-117] + _ = x[actSigStop-118] + _ = x[actFirst-119] + _ = x[actLast-120] + _ = x[actReload-121] + _ = x[actReloadSync-122] + _ = x[actDisableSearch-123] + _ = x[actEnableSearch-124] + _ = x[actSelect-125] + _ = x[actDeselect-126] + _ = x[actUnbind-127] + _ = x[actRebind-128] + _ = x[actToggleBind-129] + _ = x[actBecome-130] + _ = x[actShowHeader-131] + _ = x[actHideHeader-132] + _ = x[actBell-133] + _ = x[actExclude-134] + _ = x[actExcludeMulti-135] } -const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformNthactTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMulti" +const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeInputLabelactChangeHeaderactChangeHeaderLabelactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactChangeNthactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformInputLabelactTransformHeaderactTransformHeaderLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactSearchactPreviewactChangePointeractChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMulti" -var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 287, 306, 321, 341, 355, 376, 391, 405, 417, 431, 444, 461, 469, 482, 498, 510, 518, 532, 546, 557, 568, 586, 603, 610, 629, 641, 655, 664, 679, 691, 704, 715, 726, 738, 752, 773, 788, 801, 819, 835, 850, 864, 876, 888, 905, 912, 917, 926, 937, 948, 961, 976, 987, 1000, 1015, 1022, 1035, 1048, 1065, 1080, 1093, 1107, 1121, 1137, 1157, 1169, 1192, 1213, 1235, 1253, 1276, 1291, 1315, 1333, 1350, 1368, 1377, 1387, 1403, 1425, 1438, 1454, 1466, 1480, 1496, 1514, 1534, 1556, 1570, 1585, 1593, 1599, 1613, 1628, 1638, 1654, 1669, 1679, 1687, 1694, 1703, 1716, 1732, 1747, 1756, 1767, 1776, 1785, 1798, 1807, 1820, 1833, 1840, 1850, 1865} +var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 249, 269, 287, 306, 321, 341, 355, 376, 391, 405, 417, 431, 444, 461, 469, 482, 498, 510, 518, 532, 546, 557, 568, 586, 603, 610, 629, 641, 655, 664, 679, 691, 704, 715, 726, 738, 752, 773, 788, 801, 819, 835, 850, 864, 876, 888, 905, 912, 917, 926, 937, 948, 961, 976, 987, 1000, 1015, 1022, 1035, 1048, 1065, 1080, 1093, 1107, 1121, 1137, 1157, 1169, 1192, 1213, 1235, 1253, 1276, 1291, 1310, 1334, 1352, 1369, 1387, 1396, 1406, 1422, 1438, 1460, 1473, 1489, 1501, 1515, 1531, 1549, 1569, 1591, 1605, 1620, 1628, 1634, 1648, 1663, 1673, 1689, 1704, 1714, 1722, 1729, 1738, 1751, 1767, 1782, 1791, 1802, 1811, 1820, 1833, 1842, 1855, 1868, 1875, 1885, 1900} 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 1f431c45..80e428e3 100644 --- a/src/options.go +++ b/src/options.go @@ -1404,7 +1404,7 @@ const ( func init() { executeRegexp = regexp.MustCompile( - `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header|search|nth)|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`) + `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:query|prompt|(?:border|list|preview|input|header)-label|header|search|nth|pointer)|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search)`) splitRegexp = regexp.MustCompile("[,:]+") actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+") } @@ -1799,6 +1799,8 @@ func isExecuteAction(str string) actionType { return actChangeInputLabel case "change-header-label": return actChangeHeaderLabel + case "change-pointer": + return actChangePointer case "change-preview-window": return actChangePreviewWindow case "change-preview": @@ -1839,6 +1841,8 @@ func isExecuteAction(str string) actionType { return actTransformHeader case "transform-nth": return actTransformNth + case "transform-pointer": + return actTransformPointer case "transform-prompt": return actTransformPrompt case "transform-query": diff --git a/src/terminal.go b/src/terminal.go index cd8d4924..ec6e5d9b 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -547,12 +547,14 @@ const ( actTransformHeader actTransformHeaderLabel actTransformNth + actTransformPointer actTransformPreviewLabel actTransformPrompt actTransformQuery actTransformSearch actSearch actPreview + actChangePointer actChangePreview actChangePreviewWindow actPreviewTop @@ -5951,6 +5953,21 @@ func (t *Terminal) Loop() error { } } } + case actChangePointer, actTransformPointer: + pointer := a.a + if a.t == actTransformPointer { + pointer = t.captureLine(a.a) + } + length := uniseg.StringWidth(pointer) + if length <= 2 { + if length != t.pointerLen { + t.forceRerenderList() + } + t.pointer = pointer + t.pointerLen = length + t.pointerEmpty = strings.Repeat(" ", t.pointerLen) + req(reqList) + } case actChangePreview: if t.previewOpts.command != a.a { t.previewOpts.command = a.a diff --git a/test/test_core.rb b/test/test_core.rb index 2d3cc307..ec0a1da8 100644 --- a/test/test_core.rb +++ b/test/test_core.rb @@ -1890,4 +1890,34 @@ class TestCore < TestInteractive tmux.send_keys :Space tmux.until { |lines| assert_includes lines, '> 777' } end + + def test_change_pointer + tmux.send_keys %(seq 2 | #{FZF} --bind 'a:change-pointer(a),b:change-pointer(bb),c:change-pointer(),d:change-pointer(ddd)'), :Enter + tmux.until { |lines| assert_includes lines, '> 1' } + tmux.send_keys 'a' + tmux.until { |lines| assert_includes lines, 'a 1' } + tmux.send_keys 'b' + tmux.until { |lines| assert_includes lines, 'bb 1' } + tmux.send_keys 'c' + tmux.until { |lines| assert_includes lines, ' 1' } + tmux.send_keys 'd' + tmux.until { |lines| refute_includes lines, 'ddd 1' } + tmux.send_keys :Up + tmux.until { |lines| assert_includes lines, ' 2' } + end + + def test_transform_pointer + tmux.send_keys %(seq 2 | #{FZF} --bind 'a:transform-pointer(echo a),b:transform-pointer(echo bb),c:transform-pointer(),d:transform-pointer(echo ddd)'), :Enter + tmux.until { |lines| assert_includes lines, '> 1' } + tmux.send_keys 'a' + tmux.until { |lines| assert_includes lines, 'a 1' } + tmux.send_keys 'b' + tmux.until { |lines| assert_includes lines, 'bb 1' } + tmux.send_keys 'c' + tmux.until { |lines| assert_includes lines, ' 1' } + tmux.send_keys 'd' + tmux.until { |lines| refute_includes lines, 'ddd 1' } + tmux.send_keys :Up + tmux.until { |lines| assert_includes lines, ' 2' } + end end