mirror of
https://github.com/junegunn/fzf.git
synced 2026-02-27 12:02:33 +08:00
Add change-header-lines action to dynamically change --header-lines
All input lines now enter the chunklist with sequential indices, and header lines are excluded from matching via Pattern.startIndex and PassMerger offset. This allows the number of header lines to be changed at runtime with change-header-lines(N), transform-header-lines, and bg-transform-header-lines actions. - Remove EvtHeader event; header items are read directly from chunks - Add startIndex to Pattern and PassMerger for skipping header items - Add targetIndex field to Terminal for cursor repositioning across header-lines changes Close #4659
This commit is contained in:
@@ -1881,6 +1881,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string)
|
\fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string)
|
||||||
\fBchange\-ghost(...)\fR (change ghost text to the given string)
|
\fBchange\-ghost(...)\fR (change ghost text to the given string)
|
||||||
\fBchange\-header(...)\fR (change header to the given string; doesn't affect \fB\-\-header\-lines\fR)
|
\fBchange\-header(...)\fR (change header to the given string; doesn't affect \fB\-\-header\-lines\fR)
|
||||||
|
\fBchange\-header\-lines(N)\fR (change the number of \fB\-\-header\-lines\fR)
|
||||||
\fBchange\-header\-label(...)\fR (change \fB\-\-header\-label\fR to the given string)
|
\fBchange\-header\-label(...)\fR (change \fB\-\-header\-label\fR to the given string)
|
||||||
\fBchange\-input\-label(...)\fR (change \fB\-\-input\-label\fR to the given string)
|
\fBchange\-input\-label(...)\fR (change \fB\-\-input\-label\fR to the given string)
|
||||||
\fBchange\-list\-label(...)\fR (change \fB\-\-list\-label\fR to the given string)
|
\fBchange\-list\-label(...)\fR (change \fB\-\-list\-label\fR to the given string)
|
||||||
@@ -1987,6 +1988,7 @@ A key or an event can be bound to one or more of the following actions.
|
|||||||
\fBtransform\-border\-label(...)\fR (transform border label using an external command)
|
\fBtransform\-border\-label(...)\fR (transform border label using an external command)
|
||||||
\fBtransform\-ghost(...)\fR (transform ghost text using an external command)
|
\fBtransform\-ghost(...)\fR (transform ghost text using an external command)
|
||||||
\fBtransform\-header(...)\fR (transform header using an external command)
|
\fBtransform\-header(...)\fR (transform header using an external command)
|
||||||
|
\fBtransform\-header\-lines(...)\fR (transform the number of \fB\-\-header\-lines\fR using an external command)
|
||||||
\fBtransform\-header\-label(...)\fR (transform header label using an external command)
|
\fBtransform\-header\-label(...)\fR (transform header label using an external command)
|
||||||
\fBtransform\-input\-label(...)\fR (transform input label using an external command)
|
\fBtransform\-input\-label(...)\fR (transform input label using an external command)
|
||||||
\fBtransform\-list\-label(...)\fR (transform list label using an external command)
|
\fBtransform\-list\-label(...)\fR (transform list label using an external command)
|
||||||
|
|||||||
@@ -30,161 +30,164 @@ func _() {
|
|||||||
_ = x[actChangeBorderLabel-19]
|
_ = x[actChangeBorderLabel-19]
|
||||||
_ = x[actChangeGhost-20]
|
_ = x[actChangeGhost-20]
|
||||||
_ = x[actChangeHeader-21]
|
_ = x[actChangeHeader-21]
|
||||||
_ = x[actChangeFooter-22]
|
_ = x[actChangeHeaderLines-22]
|
||||||
_ = x[actChangeHeaderLabel-23]
|
_ = x[actChangeFooter-23]
|
||||||
_ = x[actChangeFooterLabel-24]
|
_ = x[actChangeHeaderLabel-24]
|
||||||
_ = x[actChangeInputLabel-25]
|
_ = x[actChangeFooterLabel-25]
|
||||||
_ = x[actChangeListLabel-26]
|
_ = x[actChangeInputLabel-26]
|
||||||
_ = x[actChangeMulti-27]
|
_ = x[actChangeListLabel-27]
|
||||||
_ = x[actChangeNth-28]
|
_ = x[actChangeMulti-28]
|
||||||
_ = x[actChangePointer-29]
|
_ = x[actChangeNth-29]
|
||||||
_ = x[actChangePreview-30]
|
_ = x[actChangePointer-30]
|
||||||
_ = x[actChangePreviewLabel-31]
|
_ = x[actChangePreview-31]
|
||||||
_ = x[actChangePreviewWindow-32]
|
_ = x[actChangePreviewLabel-32]
|
||||||
_ = x[actChangePrompt-33]
|
_ = x[actChangePreviewWindow-33]
|
||||||
_ = x[actChangeQuery-34]
|
_ = x[actChangePrompt-34]
|
||||||
_ = x[actClearScreen-35]
|
_ = x[actChangeQuery-35]
|
||||||
_ = x[actClearQuery-36]
|
_ = x[actClearScreen-36]
|
||||||
_ = x[actClearSelection-37]
|
_ = x[actClearQuery-37]
|
||||||
_ = x[actClose-38]
|
_ = x[actClearSelection-38]
|
||||||
_ = x[actDeleteChar-39]
|
_ = x[actClose-39]
|
||||||
_ = x[actDeleteCharEof-40]
|
_ = x[actDeleteChar-40]
|
||||||
_ = x[actEndOfLine-41]
|
_ = x[actDeleteCharEof-41]
|
||||||
_ = x[actFatal-42]
|
_ = x[actEndOfLine-42]
|
||||||
_ = x[actForwardChar-43]
|
_ = x[actFatal-43]
|
||||||
_ = x[actForwardWord-44]
|
_ = x[actForwardChar-44]
|
||||||
_ = x[actForwardSubWord-45]
|
_ = x[actForwardWord-45]
|
||||||
_ = x[actKillLine-46]
|
_ = x[actForwardSubWord-46]
|
||||||
_ = x[actKillWord-47]
|
_ = x[actKillLine-47]
|
||||||
_ = x[actKillSubWord-48]
|
_ = x[actKillWord-48]
|
||||||
_ = x[actUnixLineDiscard-49]
|
_ = x[actKillSubWord-49]
|
||||||
_ = x[actUnixWordRubout-50]
|
_ = x[actUnixLineDiscard-50]
|
||||||
_ = x[actYank-51]
|
_ = x[actUnixWordRubout-51]
|
||||||
_ = x[actBackwardKillWord-52]
|
_ = x[actYank-52]
|
||||||
_ = x[actBackwardKillSubWord-53]
|
_ = x[actBackwardKillWord-53]
|
||||||
_ = x[actSelectAll-54]
|
_ = x[actBackwardKillSubWord-54]
|
||||||
_ = x[actDeselectAll-55]
|
_ = x[actSelectAll-55]
|
||||||
_ = x[actToggle-56]
|
_ = x[actDeselectAll-56]
|
||||||
_ = x[actToggleSearch-57]
|
_ = x[actToggle-57]
|
||||||
_ = x[actToggleAll-58]
|
_ = x[actToggleSearch-58]
|
||||||
_ = x[actToggleDown-59]
|
_ = x[actToggleAll-59]
|
||||||
_ = x[actToggleUp-60]
|
_ = x[actToggleDown-60]
|
||||||
_ = x[actToggleIn-61]
|
_ = x[actToggleUp-61]
|
||||||
_ = x[actToggleOut-62]
|
_ = x[actToggleIn-62]
|
||||||
_ = x[actToggleTrack-63]
|
_ = x[actToggleOut-63]
|
||||||
_ = x[actToggleTrackCurrent-64]
|
_ = x[actToggleTrack-64]
|
||||||
_ = x[actToggleHeader-65]
|
_ = x[actToggleTrackCurrent-65]
|
||||||
_ = x[actToggleWrap-66]
|
_ = x[actToggleHeader-66]
|
||||||
_ = x[actToggleWrapWord-67]
|
_ = x[actToggleWrap-67]
|
||||||
_ = x[actToggleMultiLine-68]
|
_ = x[actToggleWrapWord-68]
|
||||||
_ = x[actToggleHscroll-69]
|
_ = x[actToggleMultiLine-69]
|
||||||
_ = x[actToggleRaw-70]
|
_ = x[actToggleHscroll-70]
|
||||||
_ = x[actEnableRaw-71]
|
_ = x[actToggleRaw-71]
|
||||||
_ = x[actDisableRaw-72]
|
_ = x[actEnableRaw-72]
|
||||||
_ = x[actTrackCurrent-73]
|
_ = x[actDisableRaw-73]
|
||||||
_ = x[actToggleInput-74]
|
_ = x[actTrackCurrent-74]
|
||||||
_ = x[actHideInput-75]
|
_ = x[actToggleInput-75]
|
||||||
_ = x[actShowInput-76]
|
_ = x[actHideInput-76]
|
||||||
_ = x[actUntrackCurrent-77]
|
_ = x[actShowInput-77]
|
||||||
_ = x[actDown-78]
|
_ = x[actUntrackCurrent-78]
|
||||||
_ = x[actDownMatch-79]
|
_ = x[actDown-79]
|
||||||
_ = x[actUp-80]
|
_ = x[actDownMatch-80]
|
||||||
_ = x[actUpMatch-81]
|
_ = x[actUp-81]
|
||||||
_ = x[actPageUp-82]
|
_ = x[actUpMatch-82]
|
||||||
_ = x[actPageDown-83]
|
_ = x[actPageUp-83]
|
||||||
_ = x[actPosition-84]
|
_ = x[actPageDown-84]
|
||||||
_ = x[actHalfPageUp-85]
|
_ = x[actPosition-85]
|
||||||
_ = x[actHalfPageDown-86]
|
_ = x[actHalfPageUp-86]
|
||||||
_ = x[actOffsetUp-87]
|
_ = x[actHalfPageDown-87]
|
||||||
_ = x[actOffsetDown-88]
|
_ = x[actOffsetUp-88]
|
||||||
_ = x[actOffsetMiddle-89]
|
_ = x[actOffsetDown-89]
|
||||||
_ = x[actJump-90]
|
_ = x[actOffsetMiddle-90]
|
||||||
_ = x[actJumpAccept-91]
|
_ = x[actJump-91]
|
||||||
_ = x[actPrintQuery-92]
|
_ = x[actJumpAccept-92]
|
||||||
_ = x[actRefreshPreview-93]
|
_ = x[actPrintQuery-93]
|
||||||
_ = x[actReplaceQuery-94]
|
_ = x[actRefreshPreview-94]
|
||||||
_ = x[actToggleSort-95]
|
_ = x[actReplaceQuery-95]
|
||||||
_ = x[actShowPreview-96]
|
_ = x[actToggleSort-96]
|
||||||
_ = x[actHidePreview-97]
|
_ = x[actShowPreview-97]
|
||||||
_ = x[actTogglePreview-98]
|
_ = x[actHidePreview-98]
|
||||||
_ = x[actTogglePreviewWrap-99]
|
_ = x[actTogglePreview-99]
|
||||||
_ = x[actTogglePreviewWrapWord-100]
|
_ = x[actTogglePreviewWrap-100]
|
||||||
_ = x[actTransform-101]
|
_ = x[actTogglePreviewWrapWord-101]
|
||||||
_ = x[actTransformBorderLabel-102]
|
_ = x[actTransform-102]
|
||||||
_ = x[actTransformGhost-103]
|
_ = x[actTransformBorderLabel-103]
|
||||||
_ = x[actTransformHeader-104]
|
_ = x[actTransformGhost-104]
|
||||||
_ = x[actTransformFooter-105]
|
_ = x[actTransformHeader-105]
|
||||||
_ = x[actTransformHeaderLabel-106]
|
_ = x[actTransformHeaderLines-106]
|
||||||
_ = x[actTransformFooterLabel-107]
|
_ = x[actTransformFooter-107]
|
||||||
_ = x[actTransformInputLabel-108]
|
_ = x[actTransformHeaderLabel-108]
|
||||||
_ = x[actTransformListLabel-109]
|
_ = x[actTransformFooterLabel-109]
|
||||||
_ = x[actTransformNth-110]
|
_ = x[actTransformInputLabel-110]
|
||||||
_ = x[actTransformPointer-111]
|
_ = x[actTransformListLabel-111]
|
||||||
_ = x[actTransformPreviewLabel-112]
|
_ = x[actTransformNth-112]
|
||||||
_ = x[actTransformPrompt-113]
|
_ = x[actTransformPointer-113]
|
||||||
_ = x[actTransformQuery-114]
|
_ = x[actTransformPreviewLabel-114]
|
||||||
_ = x[actTransformSearch-115]
|
_ = x[actTransformPrompt-115]
|
||||||
_ = x[actTrigger-116]
|
_ = x[actTransformQuery-116]
|
||||||
_ = x[actBgTransform-117]
|
_ = x[actTransformSearch-117]
|
||||||
_ = x[actBgTransformBorderLabel-118]
|
_ = x[actTrigger-118]
|
||||||
_ = x[actBgTransformGhost-119]
|
_ = x[actBgTransform-119]
|
||||||
_ = x[actBgTransformHeader-120]
|
_ = x[actBgTransformBorderLabel-120]
|
||||||
_ = x[actBgTransformFooter-121]
|
_ = x[actBgTransformGhost-121]
|
||||||
_ = x[actBgTransformHeaderLabel-122]
|
_ = x[actBgTransformHeader-122]
|
||||||
_ = x[actBgTransformFooterLabel-123]
|
_ = x[actBgTransformHeaderLines-123]
|
||||||
_ = x[actBgTransformInputLabel-124]
|
_ = x[actBgTransformFooter-124]
|
||||||
_ = x[actBgTransformListLabel-125]
|
_ = x[actBgTransformHeaderLabel-125]
|
||||||
_ = x[actBgTransformNth-126]
|
_ = x[actBgTransformFooterLabel-126]
|
||||||
_ = x[actBgTransformPointer-127]
|
_ = x[actBgTransformInputLabel-127]
|
||||||
_ = x[actBgTransformPreviewLabel-128]
|
_ = x[actBgTransformListLabel-128]
|
||||||
_ = x[actBgTransformPrompt-129]
|
_ = x[actBgTransformNth-129]
|
||||||
_ = x[actBgTransformQuery-130]
|
_ = x[actBgTransformPointer-130]
|
||||||
_ = x[actBgTransformSearch-131]
|
_ = x[actBgTransformPreviewLabel-131]
|
||||||
_ = x[actBgCancel-132]
|
_ = x[actBgTransformPrompt-132]
|
||||||
_ = x[actSearch-133]
|
_ = x[actBgTransformQuery-133]
|
||||||
_ = x[actPreview-134]
|
_ = x[actBgTransformSearch-134]
|
||||||
_ = x[actPreviewTop-135]
|
_ = x[actBgCancel-135]
|
||||||
_ = x[actPreviewBottom-136]
|
_ = x[actSearch-136]
|
||||||
_ = x[actPreviewUp-137]
|
_ = x[actPreview-137]
|
||||||
_ = x[actPreviewDown-138]
|
_ = x[actPreviewTop-138]
|
||||||
_ = x[actPreviewPageUp-139]
|
_ = x[actPreviewBottom-139]
|
||||||
_ = x[actPreviewPageDown-140]
|
_ = x[actPreviewUp-140]
|
||||||
_ = x[actPreviewHalfPageUp-141]
|
_ = x[actPreviewDown-141]
|
||||||
_ = x[actPreviewHalfPageDown-142]
|
_ = x[actPreviewPageUp-142]
|
||||||
_ = x[actPrevHistory-143]
|
_ = x[actPreviewPageDown-143]
|
||||||
_ = x[actPrevSelected-144]
|
_ = x[actPreviewHalfPageUp-144]
|
||||||
_ = x[actPrint-145]
|
_ = x[actPreviewHalfPageDown-145]
|
||||||
_ = x[actPut-146]
|
_ = x[actPrevHistory-146]
|
||||||
_ = x[actNextHistory-147]
|
_ = x[actPrevSelected-147]
|
||||||
_ = x[actNextSelected-148]
|
_ = x[actPrint-148]
|
||||||
_ = x[actExecute-149]
|
_ = x[actPut-149]
|
||||||
_ = x[actExecuteSilent-150]
|
_ = x[actNextHistory-150]
|
||||||
_ = x[actExecuteMulti-151]
|
_ = x[actNextSelected-151]
|
||||||
_ = x[actSigStop-152]
|
_ = x[actExecute-152]
|
||||||
_ = x[actBest-153]
|
_ = x[actExecuteSilent-153]
|
||||||
_ = x[actFirst-154]
|
_ = x[actExecuteMulti-154]
|
||||||
_ = x[actLast-155]
|
_ = x[actSigStop-155]
|
||||||
_ = x[actReload-156]
|
_ = x[actBest-156]
|
||||||
_ = x[actReloadSync-157]
|
_ = x[actFirst-157]
|
||||||
_ = x[actDisableSearch-158]
|
_ = x[actLast-158]
|
||||||
_ = x[actEnableSearch-159]
|
_ = x[actReload-159]
|
||||||
_ = x[actSelect-160]
|
_ = x[actReloadSync-160]
|
||||||
_ = x[actDeselect-161]
|
_ = x[actDisableSearch-161]
|
||||||
_ = x[actUnbind-162]
|
_ = x[actEnableSearch-162]
|
||||||
_ = x[actRebind-163]
|
_ = x[actSelect-163]
|
||||||
_ = x[actToggleBind-164]
|
_ = x[actDeselect-164]
|
||||||
_ = x[actBecome-165]
|
_ = x[actUnbind-165]
|
||||||
_ = x[actShowHeader-166]
|
_ = x[actRebind-166]
|
||||||
_ = x[actHideHeader-167]
|
_ = x[actToggleBind-167]
|
||||||
_ = x[actBell-168]
|
_ = x[actBecome-168]
|
||||||
_ = x[actExclude-169]
|
_ = x[actShowHeader-169]
|
||||||
_ = x[actExcludeMulti-170]
|
_ = x[actHideHeader-170]
|
||||||
_ = x[actAsync-171]
|
_ = x[actBell-171]
|
||||||
|
_ = x[actExclude-172]
|
||||||
|
_ = x[actExcludeMulti-173]
|
||||||
|
_ = x[actAsync-174]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeHeaderLinesactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleWrapWordactToggleMultiLineactToggleHscrollactToggleRawactEnableRawactDisableRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTogglePreviewWrapWordactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformHeaderLinesactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformHeaderLinesactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactBestactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
|
||||||
|
|
||||||
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 331, 351, 371, 390, 408, 422, 434, 450, 466, 487, 509, 524, 538, 552, 565, 582, 590, 603, 619, 631, 639, 653, 667, 684, 695, 706, 720, 738, 755, 762, 781, 803, 815, 829, 838, 853, 865, 878, 889, 900, 912, 926, 947, 962, 975, 992, 1010, 1026, 1038, 1050, 1063, 1078, 1092, 1104, 1116, 1133, 1140, 1152, 1157, 1167, 1176, 1187, 1198, 1211, 1226, 1237, 1250, 1265, 1272, 1285, 1298, 1315, 1330, 1343, 1357, 1371, 1387, 1407, 1431, 1443, 1466, 1483, 1501, 1519, 1542, 1565, 1587, 1608, 1623, 1642, 1666, 1684, 1701, 1719, 1729, 1743, 1768, 1787, 1807, 1827, 1852, 1877, 1901, 1924, 1941, 1962, 1988, 2008, 2027, 2047, 2058, 2067, 2077, 2090, 2106, 2118, 2132, 2148, 2166, 2186, 2208, 2222, 2237, 2245, 2251, 2265, 2280, 2290, 2306, 2321, 2331, 2338, 2346, 2353, 2362, 2375, 2391, 2406, 2415, 2426, 2435, 2444, 2457, 2466, 2479, 2492, 2499, 2509, 2524, 2532}
|
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 57, 77, 84, 92, 110, 118, 127, 144, 165, 180, 201, 225, 240, 258, 267, 287, 301, 316, 336, 351, 371, 391, 410, 428, 442, 454, 470, 486, 507, 529, 544, 558, 572, 585, 602, 610, 623, 639, 651, 659, 673, 687, 704, 715, 726, 740, 758, 775, 782, 801, 823, 835, 849, 858, 873, 885, 898, 909, 920, 932, 946, 967, 982, 995, 1012, 1030, 1046, 1058, 1070, 1083, 1098, 1112, 1124, 1136, 1153, 1160, 1172, 1177, 1187, 1196, 1207, 1218, 1231, 1246, 1257, 1270, 1285, 1292, 1305, 1318, 1335, 1350, 1363, 1377, 1391, 1407, 1427, 1451, 1463, 1486, 1503, 1521, 1544, 1562, 1585, 1608, 1630, 1651, 1666, 1685, 1709, 1727, 1744, 1762, 1772, 1786, 1811, 1830, 1850, 1875, 1895, 1920, 1945, 1969, 1992, 2009, 2030, 2056, 2076, 2095, 2115, 2126, 2135, 2145, 2158, 2174, 2186, 2200, 2216, 2234, 2254, 2276, 2290, 2305, 2313, 2319, 2333, 2348, 2358, 2374, 2389, 2399, 2406, 2414, 2421, 2430, 2443, 2459, 2474, 2483, 2494, 2503, 2512, 2525, 2534, 2547, 2560, 2567, 2577, 2592, 2600}
|
||||||
|
|
||||||
func (i actionType) String() string {
|
func (i actionType) String() string {
|
||||||
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
if i < 0 || i >= actionType(len(_actionType_index)-1) {
|
||||||
|
|||||||
@@ -52,6 +52,20 @@ func (cl *ChunkList) lastChunk() *Chunk {
|
|||||||
return cl.chunks[len(cl.chunks)-1]
|
return cl.chunks[len(cl.chunks)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetItems returns the first n items from the given chunks
|
||||||
|
func GetItems(chunks []*Chunk, n int) []Item {
|
||||||
|
items := make([]Item, 0, n)
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
for i := 0; i < chunk.count && len(items) < n; i++ {
|
||||||
|
items = append(items, chunk.items[i])
|
||||||
|
}
|
||||||
|
if len(items) >= n {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items
|
||||||
|
}
|
||||||
|
|
||||||
// CountItems returns the total number of Items
|
// CountItems returns the total number of Items
|
||||||
func CountItems(cs []*Chunk) int {
|
func CountItems(cs []*Chunk) int {
|
||||||
if len(cs) == 0 {
|
if len(cs) == 0 {
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ const (
|
|||||||
EvtSearchNew
|
EvtSearchNew
|
||||||
EvtSearchProgress
|
EvtSearchProgress
|
||||||
EvtSearchFin
|
EvtSearchFin
|
||||||
EvtHeader
|
|
||||||
EvtReady
|
EvtReady
|
||||||
EvtQuit
|
EvtQuit
|
||||||
)
|
)
|
||||||
|
|||||||
47
src/core.go
47
src/core.go
@@ -17,7 +17,6 @@ Reader -> EvtReadNew -> Matcher (restart)
|
|||||||
Terminal -> EvtSearchNew:bool -> Matcher (restart)
|
Terminal -> EvtSearchNew:bool -> Matcher (restart)
|
||||||
Matcher -> EvtSearchProgress -> Terminal (update info)
|
Matcher -> EvtSearchProgress -> Terminal (update info)
|
||||||
Matcher -> EvtSearchFin -> Terminal (update list)
|
Matcher -> EvtSearchFin -> Terminal (update list)
|
||||||
Matcher -> EvtHeader -> Terminal (update header)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type revision struct {
|
type revision struct {
|
||||||
@@ -113,14 +112,8 @@ func Run(opts *Options) (int, error) {
|
|||||||
cache := NewChunkCache()
|
cache := NewChunkCache()
|
||||||
var chunkList *ChunkList
|
var chunkList *ChunkList
|
||||||
var itemIndex int32
|
var itemIndex int32
|
||||||
header := make([]string, 0, opts.HeaderLines)
|
|
||||||
if opts.WithNth == nil {
|
if opts.WithNth == nil {
|
||||||
chunkList = NewChunkList(cache, func(item *Item, data []byte) bool {
|
chunkList = NewChunkList(cache, func(item *Item, data []byte) bool {
|
||||||
if len(header) < opts.HeaderLines {
|
|
||||||
header = append(header, byteString(data))
|
|
||||||
eventBox.Set(EvtHeader, header)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
item.text, item.colors = ansiProcessor(data)
|
item.text, item.colors = ansiProcessor(data)
|
||||||
item.text.Index = itemIndex
|
item.text.Index = itemIndex
|
||||||
itemIndex++
|
itemIndex++
|
||||||
@@ -147,11 +140,6 @@ func Run(opts *Options) (int, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
transformed := nthTransformer(tokens, itemIndex)
|
transformed := nthTransformer(tokens, itemIndex)
|
||||||
if len(header) < opts.HeaderLines {
|
|
||||||
header = append(header, transformed)
|
|
||||||
eventBox.Set(EvtHeader, header)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
item.text, item.colors = ansiProcessor(stringBytes(transformed))
|
item.text, item.colors = ansiProcessor(stringBytes(transformed))
|
||||||
|
|
||||||
// We should not trim trailing whitespaces with background colors
|
// We should not trim trailing whitespaces with background colors
|
||||||
@@ -236,13 +224,15 @@ func Run(opts *Options) (int, error) {
|
|||||||
denylist = make(map[int32]struct{})
|
denylist = make(map[int32]struct{})
|
||||||
denyMutex.Unlock()
|
denyMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
headerLines := int32(opts.HeaderLines)
|
||||||
|
headerUpdated := false
|
||||||
patternBuilder := func(runes []rune) *Pattern {
|
patternBuilder := func(runes []rune) *Pattern {
|
||||||
denyMutex.Lock()
|
denyMutex.Lock()
|
||||||
denylistCopy := maps.Clone(denylist)
|
denylistCopy := maps.Clone(denylist)
|
||||||
denyMutex.Unlock()
|
denyMutex.Unlock()
|
||||||
return BuildPattern(cache, patternCache,
|
return BuildPattern(cache, patternCache,
|
||||||
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
|
opts.Fuzzy, opts.FuzzyAlgo, opts.Extended, opts.Case, opts.Normalize, forward, withPos,
|
||||||
opts.Filter == nil, nth, opts.Delimiter, inputRevision, runes, denylistCopy)
|
opts.Filter == nil, nth, opts.Delimiter, inputRevision, runes, denylistCopy, headerLines)
|
||||||
}
|
}
|
||||||
matcher := NewMatcher(cache, patternBuilder, sort, opts.Tac, eventBox, inputRevision)
|
matcher := NewMatcher(cache, patternBuilder, sort, opts.Tac, eventBox, inputRevision)
|
||||||
|
|
||||||
@@ -265,6 +255,9 @@ func Run(opts *Options) (int, error) {
|
|||||||
func(runes []byte) bool {
|
func(runes []byte) bool {
|
||||||
item := Item{}
|
item := Item{}
|
||||||
if chunkList.trans(&item, runes) {
|
if chunkList.trans(&item, runes) {
|
||||||
|
if item.Index() < headerLines {
|
||||||
|
return false
|
||||||
|
}
|
||||||
mutex.Lock()
|
mutex.Lock()
|
||||||
if result, _, _ := pattern.MatchItem(&item, false, slab); result != nil {
|
if result, _, _ := pattern.MatchItem(&item, false, slab); result != nil {
|
||||||
opts.Printer(transformer(&item))
|
opts.Printer(transformer(&item))
|
||||||
@@ -349,11 +342,11 @@ func Run(opts *Options) (int, error) {
|
|||||||
clearDenylist()
|
clearDenylist()
|
||||||
}
|
}
|
||||||
reading = true
|
reading = true
|
||||||
|
headerUpdated = false
|
||||||
startTick = ticks
|
startTick = ticks
|
||||||
chunkList.Clear()
|
chunkList.Clear()
|
||||||
itemIndex = 0
|
itemIndex = 0
|
||||||
inputRevision.bumpMajor()
|
inputRevision.bumpMajor()
|
||||||
header = make([]string, 0, opts.HeaderLines)
|
|
||||||
readyChan := make(chan bool)
|
readyChan := make(chan bool)
|
||||||
go reader.restart(command, environ, readyChan)
|
go reader.restart(command, environ, readyChan)
|
||||||
<-readyChan
|
<-readyChan
|
||||||
@@ -411,7 +404,11 @@ func Run(opts *Options) (int, error) {
|
|||||||
snapshotRevision = inputRevision
|
snapshotRevision = inputRevision
|
||||||
}
|
}
|
||||||
total = count
|
total = count
|
||||||
terminal.UpdateCount(total, !reading, value.(*string))
|
terminal.UpdateCount(max(0, total-int(headerLines)), !reading, value.(*string))
|
||||||
|
if headerLines > 0 && !headerUpdated {
|
||||||
|
terminal.UpdateHeader(GetItems(snapshot, int(headerLines)))
|
||||||
|
headerUpdated = int32(total) >= headerLines
|
||||||
|
}
|
||||||
if heightUnknown && !deferred {
|
if heightUnknown && !deferred {
|
||||||
determine(!reading)
|
determine(!reading)
|
||||||
}
|
}
|
||||||
@@ -421,6 +418,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
var command *commandSpec
|
var command *commandSpec
|
||||||
var environ []string
|
var environ []string
|
||||||
var changed bool
|
var changed bool
|
||||||
|
headerLinesChanged := false
|
||||||
switch val := value.(type) {
|
switch val := value.(type) {
|
||||||
case searchRequest:
|
case searchRequest:
|
||||||
sort = val.sort
|
sort = val.sort
|
||||||
@@ -441,6 +439,12 @@ func Run(opts *Options) (int, error) {
|
|||||||
nth = *val.nth
|
nth = *val.nth
|
||||||
bump = true
|
bump = true
|
||||||
}
|
}
|
||||||
|
if val.headerLines != nil {
|
||||||
|
headerLines = int32(*val.headerLines)
|
||||||
|
headerUpdated = false
|
||||||
|
headerLinesChanged = true
|
||||||
|
bump = true
|
||||||
|
}
|
||||||
if bump {
|
if bump {
|
||||||
patternCache = make(map[string]*Pattern)
|
patternCache = make(map[string]*Pattern)
|
||||||
cache.Clear()
|
cache.Clear()
|
||||||
@@ -477,6 +481,14 @@ func Run(opts *Options) (int, error) {
|
|||||||
snapshotRevision = inputRevision
|
snapshotRevision = inputRevision
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if headerLinesChanged {
|
||||||
|
terminal.UpdateCount(max(0, total-int(headerLines)), !reading, nil)
|
||||||
|
if headerLines > 0 {
|
||||||
|
terminal.UpdateHeader(GetItems(snapshot, int(headerLines)))
|
||||||
|
} else {
|
||||||
|
terminal.UpdateHeader(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
matcher.Reset(snapshot, input(), true, !reading, sort, snapshotRevision)
|
matcher.Reset(snapshot, input(), true, !reading, sort, snapshotRevision)
|
||||||
delay = false
|
delay = false
|
||||||
|
|
||||||
@@ -486,11 +498,6 @@ func Run(opts *Options) (int, error) {
|
|||||||
terminal.UpdateProgress(val)
|
terminal.UpdateProgress(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
case EvtHeader:
|
|
||||||
headerPadded := make([]string, opts.HeaderLines)
|
|
||||||
copy(headerPadded, value.([]string))
|
|
||||||
terminal.UpdateHeader(headerPadded)
|
|
||||||
|
|
||||||
case EvtSearchFin:
|
case EvtSearchFin:
|
||||||
switch val := value.(type) {
|
switch val := value.(type) {
|
||||||
case MatchResult:
|
case MatchResult:
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ func (m *Matcher) scan(request MatchRequest) MatchResult {
|
|||||||
return MatchResult{m, m, false}
|
return MatchResult{m, m, false}
|
||||||
}
|
}
|
||||||
pattern := request.pattern
|
pattern := request.pattern
|
||||||
passMerger := PassMerger(&request.chunks, m.tac, request.revision)
|
passMerger := PassMerger(&request.chunks, m.tac, request.revision, pattern.startIndex)
|
||||||
if pattern.IsEmpty() {
|
if pattern.IsEmpty() {
|
||||||
return MatchResult{passMerger, passMerger, false}
|
return MatchResult{passMerger, passMerger, false}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,42 +10,46 @@ func EmptyMerger(revision revision) *Merger {
|
|||||||
// Merger holds a set of locally sorted lists of items and provides the view of
|
// Merger holds a set of locally sorted lists of items and provides the view of
|
||||||
// a single, globally-sorted list
|
// a single, globally-sorted list
|
||||||
type Merger struct {
|
type Merger struct {
|
||||||
pattern *Pattern
|
pattern *Pattern
|
||||||
lists [][]Result
|
lists [][]Result
|
||||||
merged []Result
|
merged []Result
|
||||||
chunks *[]*Chunk
|
chunks *[]*Chunk
|
||||||
cursors []int
|
cursors []int
|
||||||
sorted bool
|
sorted bool
|
||||||
tac bool
|
tac bool
|
||||||
final bool
|
final bool
|
||||||
count int
|
count int
|
||||||
pass bool
|
pass bool
|
||||||
revision revision
|
startIndex int
|
||||||
minIndex int32
|
revision revision
|
||||||
maxIndex int32
|
minIndex int32
|
||||||
|
maxIndex int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// PassMerger returns a new Merger that simply returns the items in the
|
// PassMerger returns a new Merger that simply returns the items in the
|
||||||
// original order
|
// original order. startIndex items are skipped from the beginning.
|
||||||
func PassMerger(chunks *[]*Chunk, tac bool, revision revision) *Merger {
|
func PassMerger(chunks *[]*Chunk, tac bool, revision revision, startIndex int32) *Merger {
|
||||||
var minIndex, maxIndex int32
|
var minIndex, maxIndex int32
|
||||||
if len(*chunks) > 0 {
|
if len(*chunks) > 0 {
|
||||||
minIndex = (*chunks)[0].items[0].Index()
|
minIndex = (*chunks)[0].items[0].Index()
|
||||||
maxIndex = (*chunks)[len(*chunks)-1].lastIndex(minIndex)
|
maxIndex = (*chunks)[len(*chunks)-1].lastIndex(minIndex)
|
||||||
}
|
}
|
||||||
|
si := int(startIndex)
|
||||||
mg := Merger{
|
mg := Merger{
|
||||||
pattern: nil,
|
pattern: nil,
|
||||||
chunks: chunks,
|
chunks: chunks,
|
||||||
tac: tac,
|
tac: tac,
|
||||||
count: 0,
|
count: 0,
|
||||||
pass: true,
|
pass: true,
|
||||||
revision: revision,
|
startIndex: si,
|
||||||
minIndex: minIndex,
|
revision: revision,
|
||||||
maxIndex: maxIndex}
|
minIndex: minIndex + startIndex,
|
||||||
|
maxIndex: maxIndex}
|
||||||
|
|
||||||
for _, chunk := range *mg.chunks {
|
for _, chunk := range *mg.chunks {
|
||||||
mg.count += chunk.count
|
mg.count += chunk.count
|
||||||
}
|
}
|
||||||
|
mg.count = max(0, mg.count-si)
|
||||||
return &mg
|
return &mg
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,6 +117,7 @@ func (mg *Merger) Get(idx int) Result {
|
|||||||
if mg.tac {
|
if mg.tac {
|
||||||
idx = mg.count - idx - 1
|
idx = mg.count - idx - 1
|
||||||
}
|
}
|
||||||
|
idx += mg.startIndex
|
||||||
firstChunk := (*mg.chunks)[0]
|
firstChunk := (*mg.chunks)[0]
|
||||||
if firstChunk.count < chunkSize && idx >= firstChunk.count {
|
if firstChunk.count < chunkSize && idx >= firstChunk.count {
|
||||||
idx -= firstChunk.count
|
idx -= firstChunk.count
|
||||||
|
|||||||
@@ -1626,7 +1626,7 @@ const (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
executeRegexp = regexp.MustCompile(
|
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-lines|header|footer|search|nth|pointer|ghost)|bg-transform|transform|change-(?:preview-window|preview|multi)|(?:re|un|toggle-)bind|pos|put|print|search|trigger)`)
|
||||||
splitRegexp = regexp.MustCompile("[,:]+")
|
splitRegexp = regexp.MustCompile("[,:]+")
|
||||||
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
|
||||||
}
|
}
|
||||||
@@ -2037,6 +2037,8 @@ func isExecuteAction(str string) actionType {
|
|||||||
return actPreview
|
return actPreview
|
||||||
case "change-header":
|
case "change-header":
|
||||||
return actChangeHeader
|
return actChangeHeader
|
||||||
|
case "change-header-lines":
|
||||||
|
return actChangeHeaderLines
|
||||||
case "change-footer":
|
case "change-footer":
|
||||||
return actChangeFooter
|
return actChangeFooter
|
||||||
case "change-list-label":
|
case "change-list-label":
|
||||||
@@ -2097,6 +2099,8 @@ func isExecuteAction(str string) actionType {
|
|||||||
return actTransformFooter
|
return actTransformFooter
|
||||||
case "transform-header":
|
case "transform-header":
|
||||||
return actTransformHeader
|
return actTransformHeader
|
||||||
|
case "transform-header-lines":
|
||||||
|
return actTransformHeaderLines
|
||||||
case "transform-ghost":
|
case "transform-ghost":
|
||||||
return actTransformGhost
|
return actTransformGhost
|
||||||
case "transform-nth":
|
case "transform-nth":
|
||||||
@@ -2127,6 +2131,8 @@ func isExecuteAction(str string) actionType {
|
|||||||
return actBgTransformFooter
|
return actBgTransformFooter
|
||||||
case "bg-transform-header":
|
case "bg-transform-header":
|
||||||
return actBgTransformHeader
|
return actBgTransformHeader
|
||||||
|
case "bg-transform-header-lines":
|
||||||
|
return actBgTransformHeaderLines
|
||||||
case "bg-transform-ghost":
|
case "bg-transform-ghost":
|
||||||
return actBgTransformGhost
|
return actBgTransformGhost
|
||||||
case "bg-transform-nth":
|
case "bg-transform-nth":
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ type Pattern struct {
|
|||||||
procFun map[termType]algo.Algo
|
procFun map[termType]algo.Algo
|
||||||
cache *ChunkCache
|
cache *ChunkCache
|
||||||
denylist map[int32]struct{}
|
denylist map[int32]struct{}
|
||||||
|
startIndex int32
|
||||||
}
|
}
|
||||||
|
|
||||||
var _splitRegex *regexp.Regexp
|
var _splitRegex *regexp.Regexp
|
||||||
@@ -74,7 +75,7 @@ func init() {
|
|||||||
|
|
||||||
// BuildPattern builds Pattern object from the given arguments
|
// BuildPattern builds Pattern object from the given arguments
|
||||||
func BuildPattern(cache *ChunkCache, patternCache map[string]*Pattern, fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, normalize bool, forward bool,
|
func BuildPattern(cache *ChunkCache, patternCache map[string]*Pattern, fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case, normalize bool, forward bool,
|
||||||
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, revision revision, runes []rune, denylist map[int32]struct{}) *Pattern {
|
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, revision revision, runes []rune, denylist map[int32]struct{}, startIndex int32) *Pattern {
|
||||||
|
|
||||||
var asString string
|
var asString string
|
||||||
if extended {
|
if extended {
|
||||||
@@ -146,6 +147,7 @@ func BuildPattern(cache *ChunkCache, patternCache map[string]*Pattern, fuzzy boo
|
|||||||
delimiter: delimiter,
|
delimiter: delimiter,
|
||||||
cache: cache,
|
cache: cache,
|
||||||
denylist: denylist,
|
denylist: denylist,
|
||||||
|
startIndex: startIndex,
|
||||||
procFun: make(map[termType]algo.Algo)}
|
procFun: make(map[termType]algo.Algo)}
|
||||||
|
|
||||||
ptr.cacheKey = ptr.buildCacheKey()
|
ptr.cacheKey = ptr.buildCacheKey()
|
||||||
@@ -301,10 +303,19 @@ func (p *Pattern) Match(chunk *Chunk, slab *util.Slab) []Result {
|
|||||||
func (p *Pattern) matchChunk(chunk *Chunk, space []Result, slab *util.Slab) []Result {
|
func (p *Pattern) matchChunk(chunk *Chunk, space []Result, slab *util.Slab) []Result {
|
||||||
matches := []Result{}
|
matches := []Result{}
|
||||||
|
|
||||||
|
// Skip header items in chunks that contain them
|
||||||
|
startIdx := 0
|
||||||
|
if p.startIndex > 0 && chunk.count > 0 && chunk.items[0].Index() < p.startIndex {
|
||||||
|
startIdx = int(p.startIndex - chunk.items[0].Index())
|
||||||
|
if startIdx >= chunk.count {
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(p.denylist) == 0 {
|
if len(p.denylist) == 0 {
|
||||||
// Huge code duplication for minimizing unnecessary map lookups
|
// Huge code duplication for minimizing unnecessary map lookups
|
||||||
if space == nil {
|
if space == nil {
|
||||||
for idx := 0; idx < chunk.count; idx++ {
|
for idx := startIdx; idx < chunk.count; idx++ {
|
||||||
if match, _, _ := p.MatchItem(&chunk.items[idx], p.withPos, slab); match != nil {
|
if match, _, _ := p.MatchItem(&chunk.items[idx], p.withPos, slab); match != nil {
|
||||||
matches = append(matches, *match)
|
matches = append(matches, *match)
|
||||||
}
|
}
|
||||||
@@ -320,7 +331,7 @@ func (p *Pattern) matchChunk(chunk *Chunk, space []Result, slab *util.Slab) []Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
if space == nil {
|
if space == nil {
|
||||||
for idx := 0; idx < chunk.count; idx++ {
|
for idx := startIdx; idx < chunk.count; idx++ {
|
||||||
if _, prs := p.denylist[chunk.items[idx].Index()]; prs {
|
if _, prs := p.denylist[chunk.items[idx].Index()]; prs {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ func buildPattern(fuzzy bool, fuzzyAlgo algo.Algo, extended bool, caseMode Case,
|
|||||||
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, runes []rune) *Pattern {
|
withPos bool, cacheable bool, nth []Range, delimiter Delimiter, runes []rune) *Pattern {
|
||||||
return BuildPattern(NewChunkCache(), make(map[string]*Pattern),
|
return BuildPattern(NewChunkCache(), make(map[string]*Pattern),
|
||||||
fuzzy, fuzzyAlgo, extended, caseMode, normalize, forward,
|
fuzzy, fuzzyAlgo, extended, caseMode, normalize, forward,
|
||||||
withPos, cacheable, nth, delimiter, revision{}, runes, nil)
|
withPos, cacheable, nth, delimiter, revision{}, runes, nil, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExact(t *testing.T) {
|
func TestExact(t *testing.T) {
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ type Terminal struct {
|
|||||||
sort bool
|
sort bool
|
||||||
toggleSort bool
|
toggleSort bool
|
||||||
track trackOption
|
track trackOption
|
||||||
|
targetIndex int32
|
||||||
delimiter Delimiter
|
delimiter Delimiter
|
||||||
expect map[tui.Event]string
|
expect map[tui.Event]string
|
||||||
keymap map[tui.Event][]*action
|
keymap map[tui.Event][]*action
|
||||||
@@ -327,7 +328,7 @@ type Terminal struct {
|
|||||||
headerVisible bool
|
headerVisible bool
|
||||||
headerFirst bool
|
headerFirst bool
|
||||||
headerLines int
|
headerLines int
|
||||||
header []string
|
header []Item
|
||||||
header0 []string
|
header0 []string
|
||||||
footer []string
|
footer []string
|
||||||
ellipsis string
|
ellipsis string
|
||||||
@@ -542,6 +543,7 @@ const (
|
|||||||
actChangeBorderLabel
|
actChangeBorderLabel
|
||||||
actChangeGhost
|
actChangeGhost
|
||||||
actChangeHeader
|
actChangeHeader
|
||||||
|
actChangeHeaderLines
|
||||||
actChangeFooter
|
actChangeFooter
|
||||||
actChangeHeaderLabel
|
actChangeHeaderLabel
|
||||||
actChangeFooterLabel
|
actChangeFooterLabel
|
||||||
@@ -627,6 +629,7 @@ const (
|
|||||||
actTransformBorderLabel
|
actTransformBorderLabel
|
||||||
actTransformGhost
|
actTransformGhost
|
||||||
actTransformHeader
|
actTransformHeader
|
||||||
|
actTransformHeaderLines
|
||||||
actTransformFooter
|
actTransformFooter
|
||||||
actTransformHeaderLabel
|
actTransformHeaderLabel
|
||||||
actTransformFooterLabel
|
actTransformFooterLabel
|
||||||
@@ -645,6 +648,7 @@ const (
|
|||||||
actBgTransformBorderLabel
|
actBgTransformBorderLabel
|
||||||
actBgTransformGhost
|
actBgTransformGhost
|
||||||
actBgTransformHeader
|
actBgTransformHeader
|
||||||
|
actBgTransformHeaderLines
|
||||||
actBgTransformFooter
|
actBgTransformFooter
|
||||||
actBgTransformHeaderLabel
|
actBgTransformHeaderLabel
|
||||||
actBgTransformFooterLabel
|
actBgTransformFooterLabel
|
||||||
@@ -710,6 +714,7 @@ func processExecution(action actionType) bool {
|
|||||||
actTransformBorderLabel,
|
actTransformBorderLabel,
|
||||||
actTransformGhost,
|
actTransformGhost,
|
||||||
actTransformHeader,
|
actTransformHeader,
|
||||||
|
actTransformHeaderLines,
|
||||||
actTransformFooter,
|
actTransformFooter,
|
||||||
actTransformHeaderLabel,
|
actTransformHeaderLabel,
|
||||||
actTransformFooterLabel,
|
actTransformFooterLabel,
|
||||||
@@ -725,6 +730,7 @@ func processExecution(action actionType) bool {
|
|||||||
actBgTransformBorderLabel,
|
actBgTransformBorderLabel,
|
||||||
actBgTransformGhost,
|
actBgTransformGhost,
|
||||||
actBgTransformHeader,
|
actBgTransformHeader,
|
||||||
|
actBgTransformHeaderLines,
|
||||||
actBgTransformFooter,
|
actBgTransformFooter,
|
||||||
actBgTransformHeaderLabel,
|
actBgTransformHeaderLabel,
|
||||||
actBgTransformFooterLabel,
|
actBgTransformFooterLabel,
|
||||||
@@ -761,14 +767,15 @@ type placeholderFlags struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type searchRequest struct {
|
type searchRequest struct {
|
||||||
sort bool
|
sort bool
|
||||||
sync bool
|
sync bool
|
||||||
nth *[]Range
|
nth *[]Range
|
||||||
command *commandSpec
|
headerLines *int
|
||||||
environ []string
|
command *commandSpec
|
||||||
changed bool
|
environ []string
|
||||||
denylist []int32
|
changed bool
|
||||||
revision revision
|
denylist []int32
|
||||||
|
revision revision
|
||||||
}
|
}
|
||||||
|
|
||||||
type previewRequest struct {
|
type previewRequest struct {
|
||||||
@@ -1022,6 +1029,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
sort: opts.Sort > 0,
|
sort: opts.Sort > 0,
|
||||||
toggleSort: opts.ToggleSort,
|
toggleSort: opts.ToggleSort,
|
||||||
track: opts.Track,
|
track: opts.Track,
|
||||||
|
targetIndex: minItem.Index(),
|
||||||
delimiter: opts.Delimiter,
|
delimiter: opts.Delimiter,
|
||||||
expect: opts.Expect,
|
expect: opts.Expect,
|
||||||
keymap: opts.Keymap,
|
keymap: opts.Keymap,
|
||||||
@@ -1063,7 +1071,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
headerFirst: opts.HeaderFirst,
|
headerFirst: opts.HeaderFirst,
|
||||||
headerLines: opts.HeaderLines,
|
headerLines: opts.HeaderLines,
|
||||||
gap: opts.Gap,
|
gap: opts.Gap,
|
||||||
header: []string{},
|
header: []Item{},
|
||||||
footer: opts.Footer,
|
footer: opts.Footer,
|
||||||
header0: opts.Header,
|
header0: opts.Header,
|
||||||
ansi: opts.Ansi,
|
ansi: opts.Ansi,
|
||||||
@@ -1364,7 +1372,7 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
env = append(env, "FZF_INPUT_STATE="+inputState)
|
env = append(env, "FZF_INPUT_STATE="+inputState)
|
||||||
env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", t.count))
|
env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", max(0, t.count-t.headerLines)))
|
||||||
env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.resultMerger.Length()))
|
env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.resultMerger.Length()))
|
||||||
env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected)))
|
env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected)))
|
||||||
env = append(env, fmt.Sprintf("FZF_LINES=%d", t.areaLines))
|
env = append(env, fmt.Sprintf("FZF_LINES=%d", t.areaLines))
|
||||||
@@ -1755,8 +1763,14 @@ func (t *Terminal) changeFooter(footer string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateHeader updates the header
|
// UpdateHeader updates the header
|
||||||
func (t *Terminal) UpdateHeader(header []string) {
|
func (t *Terminal) UpdateHeader(header []Item) {
|
||||||
t.mutex.Lock()
|
t.mutex.Lock()
|
||||||
|
// Pad to t.headerLines so that click coordinate mapping works correctly
|
||||||
|
if len(header) < t.headerLines {
|
||||||
|
padded := make([]Item, t.headerLines)
|
||||||
|
copy(padded, header)
|
||||||
|
header = padded
|
||||||
|
}
|
||||||
t.header = header
|
t.header = header
|
||||||
t.mutex.Unlock()
|
t.mutex.Unlock()
|
||||||
t.reqBox.Set(reqHeader, nil)
|
t.reqBox.Set(reqHeader, nil)
|
||||||
@@ -1788,6 +1802,10 @@ func (t *Terminal) UpdateList(result MatchResult) {
|
|||||||
prevIndex = merger.First().item.Index()
|
prevIndex = merger.First().item.Index()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if t.targetIndex != minItem.Index() {
|
||||||
|
prevIndex = t.targetIndex
|
||||||
|
t.targetIndex = minItem.Index()
|
||||||
|
}
|
||||||
t.progress = 100
|
t.progress = 100
|
||||||
t.merger = merger
|
t.merger = merger
|
||||||
t.resultMerger = merger
|
t.resultMerger = merger
|
||||||
@@ -3079,11 +3097,11 @@ func (t *Terminal) printHeader() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
t.withWindow(t.headerWindow, func() {
|
t.withWindow(t.headerWindow, func() {
|
||||||
var lines []string
|
var headerItems []Item
|
||||||
if !t.hasHeaderLinesWindow() {
|
if !t.hasHeaderLinesWindow() {
|
||||||
lines = t.header
|
headerItems = t.header
|
||||||
}
|
}
|
||||||
t.printHeaderImpl(t.headerWindow, t.headerBorderShape, t.header0, lines)
|
t.printHeaderImpl(t.headerWindow, t.headerBorderShape, t.header0, headerItems)
|
||||||
})
|
})
|
||||||
if w, shape := t.determineHeaderLinesShape(); w {
|
if w, shape := t.determineHeaderLinesShape(); w {
|
||||||
t.withWindow(t.headerLinesWindow, func() {
|
t.withWindow(t.headerLinesWindow, func() {
|
||||||
@@ -3145,7 +3163,7 @@ func (t *Terminal) headerIndentImpl(base int, borderShape tui.BorderShape) int {
|
|||||||
return indentSize
|
return indentSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShape, lines1 []string, lines2 []string) {
|
func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShape, lines1 []string, lines2 []Item) {
|
||||||
max := t.window.Height()
|
max := t.window.Height()
|
||||||
if !t.inputless && t.inputWindow == nil && window == nil && t.headerFirst {
|
if !t.inputless && t.inputWindow == nil && window == nil && t.headerFirst {
|
||||||
max--
|
max--
|
||||||
@@ -3172,7 +3190,8 @@ func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShap
|
|||||||
}
|
}
|
||||||
indent := strings.Repeat(" ", indentSize)
|
indent := strings.Repeat(" ", indentSize)
|
||||||
t.wrap = false
|
t.wrap = false
|
||||||
for idx, lineStr := range append(append([]string{}, lines1...), lines2...) {
|
totalLines := len(lines1) + len(lines2)
|
||||||
|
for idx := 0; idx < totalLines; idx++ {
|
||||||
line := idx
|
line := idx
|
||||||
if needReverse && idx < len(lines1) {
|
if needReverse && idx < len(lines1) {
|
||||||
line = len(lines1) - idx - 1
|
line = len(lines1) - idx - 1
|
||||||
@@ -3186,11 +3205,18 @@ func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShap
|
|||||||
if line >= max {
|
if line >= max {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
trimmed, colors, newState := extractColor(lineStr, state, nil)
|
|
||||||
state = newState
|
var item *Item
|
||||||
item := &Item{
|
if idx < len(lines1) {
|
||||||
text: util.ToChars([]byte(trimmed)),
|
trimmed, colors, newState := extractColor(lines1[idx], state, nil)
|
||||||
colors: colors}
|
state = newState
|
||||||
|
item = &Item{
|
||||||
|
text: util.ToChars([]byte(trimmed)),
|
||||||
|
colors: colors}
|
||||||
|
} else {
|
||||||
|
headerItem := lines2[idx-len(lines1)]
|
||||||
|
item = &headerItem
|
||||||
|
}
|
||||||
|
|
||||||
t.printHighlighted(Result{item: item},
|
t.printHighlighted(Result{item: item},
|
||||||
tui.ColHeader, tui.ColHeader, false, false, false, line, line, true,
|
tui.ColHeader, tui.ColHeader, false, false, false, line, line, true,
|
||||||
@@ -5288,9 +5314,13 @@ func (t *Terminal) addClickHeaderWord(env []string) []string {
|
|||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: t.header is padded with empty strings so that its size is equal to t.headerLines
|
|
||||||
nthBase := 0
|
nthBase := 0
|
||||||
headers := [2][]string{t.header, t.header0}
|
// Convert header items to strings for click handling
|
||||||
|
headerStrs := make([]string, len(t.header))
|
||||||
|
for i, item := range t.header {
|
||||||
|
headerStrs[i] = item.text.ToString()
|
||||||
|
}
|
||||||
|
headers := [2][]string{headerStrs, t.header0}
|
||||||
if t.layout == layoutReverse {
|
if t.layout == layoutReverse {
|
||||||
headers[0], headers[1] = headers[1], headers[0]
|
headers[0], headers[1] = headers[1], headers[0]
|
||||||
}
|
}
|
||||||
@@ -5892,6 +5922,7 @@ func (t *Terminal) Loop() error {
|
|||||||
events := []util.EventType{}
|
events := []util.EventType{}
|
||||||
changed := false
|
changed := false
|
||||||
var newNth *[]Range
|
var newNth *[]Range
|
||||||
|
var newHeaderLines *int
|
||||||
req := func(evts ...util.EventType) {
|
req := func(evts ...util.EventType) {
|
||||||
for _, event := range evts {
|
for _, event := range evts {
|
||||||
events = append(events, event)
|
events = append(events, event)
|
||||||
@@ -5908,6 +5939,7 @@ func (t *Terminal) Loop() error {
|
|||||||
events = []util.EventType{}
|
events = []util.EventType{}
|
||||||
changed = false
|
changed = false
|
||||||
newNth = nil
|
newNth = nil
|
||||||
|
newHeaderLines = nil
|
||||||
beof := false
|
beof := false
|
||||||
queryChanged := false
|
queryChanged := false
|
||||||
denylist := []int32{}
|
denylist := []int32{}
|
||||||
@@ -6247,6 +6279,23 @@ func (t *Terminal) Loop() error {
|
|||||||
}
|
}
|
||||||
case actPrintQuery:
|
case actPrintQuery:
|
||||||
req(reqPrintQuery)
|
req(reqPrintQuery)
|
||||||
|
case actChangeHeaderLines, actTransformHeaderLines, actBgTransformHeaderLines:
|
||||||
|
capture(true, func(expr string) {
|
||||||
|
if n, err := strconv.Atoi(expr); err == nil && n >= 0 && n != t.headerLines {
|
||||||
|
t.headerLines = n
|
||||||
|
newHeaderLines = &n
|
||||||
|
changed = true
|
||||||
|
// Deselect items that are now part of the header
|
||||||
|
for idx := range t.selected {
|
||||||
|
if idx < int32(n) {
|
||||||
|
delete(t.selected, idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Tell UpdateList to reposition cursor to the current item
|
||||||
|
t.targetIndex = t.currentIndex()
|
||||||
|
req(reqList, reqPrompt, reqInfo, reqHeader)
|
||||||
|
}
|
||||||
|
})
|
||||||
case actChangeMulti:
|
case actChangeMulti:
|
||||||
multi := t.multi
|
multi := t.multi
|
||||||
if a.a == "" {
|
if a.a == "" {
|
||||||
@@ -7428,7 +7477,7 @@ func (t *Terminal) Loop() error {
|
|||||||
reload := changed || newCommand != nil
|
reload := changed || newCommand != nil
|
||||||
var reloadRequest *searchRequest
|
var reloadRequest *searchRequest
|
||||||
if reload {
|
if reload {
|
||||||
reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.resultMerger.Revision()}
|
reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, headerLines: newHeaderLines, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.resultMerger.Revision()}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch queued background requests
|
// Dispatch queued background requests
|
||||||
|
|||||||
@@ -2176,6 +2176,80 @@ class TestCore < TestInteractive
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_change_header_lines
|
||||||
|
tmux.send_keys %(seq 10 | #{FZF} --header-lines 3 --bind 'space:change-header-lines(5),enter:transform-header-lines(echo 1)'), :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 7, lines.item_count
|
||||||
|
assert lines.any_include?('> 4')
|
||||||
|
end
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 5, lines.item_count
|
||||||
|
assert lines.any_include?('> 6')
|
||||||
|
end
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 9, lines.item_count
|
||||||
|
assert lines.any_include?('> 6')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_change_header_lines_to_zero
|
||||||
|
tmux.send_keys %(seq 5 | #{FZF} --header-lines 3 --bind 'space:bg-transform-header-lines(echo 0)'), :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 2, lines.item_count
|
||||||
|
assert lines.any_include?('> 4')
|
||||||
|
end
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 5, lines.item_count
|
||||||
|
# All items are now in the list, cursor stays on item 4
|
||||||
|
assert lines.any_include?('> 4')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_change_header_lines_deselect
|
||||||
|
# Selected items that become part of the header should be deselected
|
||||||
|
tmux.send_keys %(seq 10 | #{FZF} --multi --header-lines 0 --bind 'space:change-header-lines(3),enter:change-header-lines(1)'), :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 10, lines.item_count
|
||||||
|
assert lines.any_include?('> 1')
|
||||||
|
end
|
||||||
|
# Select items 1, 2, 3 (these will become header lines)
|
||||||
|
tmux.send_keys :BTab, :BTab, :BTab
|
||||||
|
tmux.until { |lines| assert_equal 3, lines.select_count }
|
||||||
|
# Also select item 4 (this should remain selected)
|
||||||
|
tmux.send_keys :BTab
|
||||||
|
tmux.until { |lines| assert_equal 4, lines.select_count }
|
||||||
|
# Change header-lines to 3: items 1, 2, 3 become headers and should be deselected
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 7, lines.item_count
|
||||||
|
assert_equal 1, lines.select_count
|
||||||
|
assert lines.any_include?('> 5')
|
||||||
|
end
|
||||||
|
# Change header-lines to 1
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 9, lines.item_count
|
||||||
|
assert_equal 1, lines.select_count
|
||||||
|
assert lines.any_include?('> 5')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_change_header_lines_reverse
|
||||||
|
tmux.send_keys %(seq 10 | #{FZF} --header-lines 2 --reverse --bind 'space:change-header-lines(4)'), :Enter
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 8, lines.item_count
|
||||||
|
assert lines.any_include?('> 3')
|
||||||
|
end
|
||||||
|
tmux.send_keys :Space
|
||||||
|
tmux.until do |lines|
|
||||||
|
assert_equal 6, lines.item_count
|
||||||
|
assert lines.any_include?('> 5')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_zero_width_characters
|
def test_zero_width_characters
|
||||||
tmux.send_keys %(for i in {1..1000}; do string+="a̱$i"; printf '\\e[43m%s\\e[0m\\n' "$string"; done | #{FZF} --ansi --query a500 --ellipsis XX), :Enter
|
tmux.send_keys %(for i in {1..1000}; do string+="a̱$i"; printf '\\e[43m%s\\e[0m\\n' "$string"; done | #{FZF} --ansi --query a500 --ellipsis XX), :Enter
|
||||||
tmux.until do |lines|
|
tmux.until do |lines|
|
||||||
|
|||||||
@@ -326,4 +326,27 @@ class TestFilter < TestBase
|
|||||||
writelines(['emp001 Alice Engineering', 'emp002 Bob Marketing'])
|
writelines(['emp001 Alice Engineering', 'emp002 Bob Marketing'])
|
||||||
assert_equal 'emp001', `#{FZF} -d' ' --with-nth 2 --accept-nth 1 -f Alice < #{tempname}`.chomp
|
assert_equal 'emp001', `#{FZF} -d' ' --with-nth 2 --accept-nth 1 -f Alice < #{tempname}`.chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_header_lines_filter
|
||||||
|
assert_equal %w[4 5 6 7 8 9 10],
|
||||||
|
`seq 10 | #{FZF} --header-lines 3 -f ""`.lines(chomp: true)
|
||||||
|
assert_equal %w[5],
|
||||||
|
`seq 10 | #{FZF} --header-lines 3 -f 5`.lines(chomp: true)
|
||||||
|
# Header items should not be matched
|
||||||
|
assert_empty `seq 10 | #{FZF} --header-lines 3 -f "^1$"`.lines(chomp: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_header_lines_filter_with_nth
|
||||||
|
writelines(%w[a:1 b:2 c:3 d:4 e:5])
|
||||||
|
assert_equal %w[c:3 d:4 e:5],
|
||||||
|
`#{FZF} --header-lines 2 -d: --with-nth 2 -f "" < #{tempname}`.lines(chomp: true)
|
||||||
|
assert_equal %w[d:4],
|
||||||
|
`#{FZF} --header-lines 2 -d: --with-nth 2 -f 4 < #{tempname}`.lines(chomp: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_header_lines_all_headers
|
||||||
|
# When all lines are header lines, no results
|
||||||
|
assert_empty `seq 3 | #{FZF} --header-lines 10 -f ""`.chomp
|
||||||
|
assert_equal 1, $CHILD_STATUS.exitstatus
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user