summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2025-09-28 20:59:20 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2025-10-09 00:17:00 +0900
commit65df0abf0e4143470d824145ecc313e40dd8773d (patch)
tree8b5df786eb5aed184ddc4aeb9718c684495c8420 /src
parentb51bc6b50e90169553c48209c00c5f4d548ec0a0 (diff)
downloadfzf-65df0abf0e4143470d824145ecc313e40dd8773d.tar.gz
Introduce 'raw' mode
Diffstat (limited to 'src')
-rw-r--r--src/actiontype_string.go197
-rw-r--r--src/core.go19
-rw-r--r--src/matcher.go56
-rw-r--r--src/merger.go9
-rw-r--r--src/options.go34
-rw-r--r--src/options_test.go4
-rw-r--r--src/terminal.go225
-rw-r--r--src/tui/tui.go12
8 files changed, 393 insertions, 163 deletions
diff --git a/src/actiontype_string.go b/src/actiontype_string.go
index 2a6873b8..f6316a51 100644
--- a/src/actiontype_string.go
+++ b/src/actiontype_string.go
@@ -77,106 +77,109 @@ func _() {
_ = x[actToggleWrap-66]
_ = x[actToggleMultiLine-67]
_ = x[actToggleHscroll-68]
- _ = x[actTrackCurrent-69]
- _ = x[actToggleInput-70]
- _ = x[actHideInput-71]
- _ = x[actShowInput-72]
- _ = x[actUntrackCurrent-73]
- _ = x[actDown-74]
- _ = x[actUp-75]
- _ = x[actPageUp-76]
- _ = x[actPageDown-77]
- _ = x[actPosition-78]
- _ = x[actHalfPageUp-79]
- _ = x[actHalfPageDown-80]
- _ = x[actOffsetUp-81]
- _ = x[actOffsetDown-82]
- _ = x[actOffsetMiddle-83]
- _ = x[actJump-84]
- _ = x[actJumpAccept-85]
- _ = x[actPrintQuery-86]
- _ = x[actRefreshPreview-87]
- _ = x[actReplaceQuery-88]
- _ = x[actToggleSort-89]
- _ = x[actShowPreview-90]
- _ = x[actHidePreview-91]
- _ = x[actTogglePreview-92]
- _ = x[actTogglePreviewWrap-93]
- _ = x[actTransform-94]
- _ = x[actTransformBorderLabel-95]
- _ = x[actTransformGhost-96]
- _ = x[actTransformHeader-97]
- _ = x[actTransformFooter-98]
- _ = x[actTransformHeaderLabel-99]
- _ = x[actTransformFooterLabel-100]
- _ = x[actTransformInputLabel-101]
- _ = x[actTransformListLabel-102]
- _ = x[actTransformNth-103]
- _ = x[actTransformPointer-104]
- _ = x[actTransformPreviewLabel-105]
- _ = x[actTransformPrompt-106]
- _ = x[actTransformQuery-107]
- _ = x[actTransformSearch-108]
- _ = x[actTrigger-109]
- _ = x[actBgTransform-110]
- _ = x[actBgTransformBorderLabel-111]
- _ = x[actBgTransformGhost-112]
- _ = x[actBgTransformHeader-113]
- _ = x[actBgTransformFooter-114]
- _ = x[actBgTransformHeaderLabel-115]
- _ = x[actBgTransformFooterLabel-116]
- _ = x[actBgTransformInputLabel-117]
- _ = x[actBgTransformListLabel-118]
- _ = x[actBgTransformNth-119]
- _ = x[actBgTransformPointer-120]
- _ = x[actBgTransformPreviewLabel-121]
- _ = x[actBgTransformPrompt-122]
- _ = x[actBgTransformQuery-123]
- _ = x[actBgTransformSearch-124]
- _ = x[actBgCancel-125]
- _ = x[actSearch-126]
- _ = x[actPreview-127]
- _ = x[actPreviewTop-128]
- _ = x[actPreviewBottom-129]
- _ = x[actPreviewUp-130]
- _ = x[actPreviewDown-131]
- _ = x[actPreviewPageUp-132]
- _ = x[actPreviewPageDown-133]
- _ = x[actPreviewHalfPageUp-134]
- _ = x[actPreviewHalfPageDown-135]
- _ = x[actPrevHistory-136]
- _ = x[actPrevSelected-137]
- _ = x[actPrint-138]
- _ = x[actPut-139]
- _ = x[actNextHistory-140]
- _ = x[actNextSelected-141]
- _ = x[actExecute-142]
- _ = x[actExecuteSilent-143]
- _ = x[actExecuteMulti-144]
- _ = x[actSigStop-145]
- _ = x[actFirst-146]
- _ = x[actLast-147]
- _ = x[actReload-148]
- _ = x[actReloadSync-149]
- _ = x[actDisableSearch-150]
- _ = x[actEnableSearch-151]
- _ = x[actSelect-152]
- _ = x[actDeselect-153]
- _ = x[actUnbind-154]
- _ = x[actRebind-155]
- _ = x[actToggleBind-156]
- _ = x[actBecome-157]
- _ = x[actShowHeader-158]
- _ = x[actHideHeader-159]
- _ = x[actBell-160]
- _ = x[actExclude-161]
- _ = x[actExcludeMulti-162]
- _ = x[actAsync-163]
+ _ = x[actToggleRaw-69]
+ _ = x[actTrackCurrent-70]
+ _ = x[actToggleInput-71]
+ _ = x[actHideInput-72]
+ _ = x[actShowInput-73]
+ _ = x[actUntrackCurrent-74]
+ _ = x[actDown-75]
+ _ = x[actDownMatch-76]
+ _ = x[actUp-77]
+ _ = x[actUpMatch-78]
+ _ = x[actPageUp-79]
+ _ = x[actPageDown-80]
+ _ = x[actPosition-81]
+ _ = x[actHalfPageUp-82]
+ _ = x[actHalfPageDown-83]
+ _ = x[actOffsetUp-84]
+ _ = x[actOffsetDown-85]
+ _ = x[actOffsetMiddle-86]
+ _ = x[actJump-87]
+ _ = x[actJumpAccept-88]
+ _ = x[actPrintQuery-89]
+ _ = x[actRefreshPreview-90]
+ _ = x[actReplaceQuery-91]
+ _ = x[actToggleSort-92]
+ _ = x[actShowPreview-93]
+ _ = x[actHidePreview-94]
+ _ = x[actTogglePreview-95]
+ _ = x[actTogglePreviewWrap-96]
+ _ = x[actTransform-97]
+ _ = x[actTransformBorderLabel-98]
+ _ = x[actTransformGhost-99]
+ _ = x[actTransformHeader-100]
+ _ = x[actTransformFooter-101]
+ _ = x[actTransformHeaderLabel-102]
+ _ = x[actTransformFooterLabel-103]
+ _ = x[actTransformInputLabel-104]
+ _ = x[actTransformListLabel-105]
+ _ = x[actTransformNth-106]
+ _ = x[actTransformPointer-107]
+ _ = x[actTransformPreviewLabel-108]
+ _ = x[actTransformPrompt-109]
+ _ = x[actTransformQuery-110]
+ _ = x[actTransformSearch-111]
+ _ = x[actTrigger-112]
+ _ = x[actBgTransform-113]
+ _ = x[actBgTransformBorderLabel-114]
+ _ = x[actBgTransformGhost-115]
+ _ = x[actBgTransformHeader-116]
+ _ = x[actBgTransformFooter-117]
+ _ = x[actBgTransformHeaderLabel-118]
+ _ = x[actBgTransformFooterLabel-119]
+ _ = x[actBgTransformInputLabel-120]
+ _ = x[actBgTransformListLabel-121]
+ _ = x[actBgTransformNth-122]
+ _ = x[actBgTransformPointer-123]
+ _ = x[actBgTransformPreviewLabel-124]
+ _ = x[actBgTransformPrompt-125]
+ _ = x[actBgTransformQuery-126]
+ _ = x[actBgTransformSearch-127]
+ _ = x[actBgCancel-128]
+ _ = x[actSearch-129]
+ _ = x[actPreview-130]
+ _ = x[actPreviewTop-131]
+ _ = x[actPreviewBottom-132]
+ _ = x[actPreviewUp-133]
+ _ = x[actPreviewDown-134]
+ _ = x[actPreviewPageUp-135]
+ _ = x[actPreviewPageDown-136]
+ _ = x[actPreviewHalfPageUp-137]
+ _ = x[actPreviewHalfPageDown-138]
+ _ = x[actPrevHistory-139]
+ _ = x[actPrevSelected-140]
+ _ = x[actPrint-141]
+ _ = x[actPut-142]
+ _ = x[actNextHistory-143]
+ _ = x[actNextSelected-144]
+ _ = x[actExecute-145]
+ _ = x[actExecuteSilent-146]
+ _ = x[actExecuteMulti-147]
+ _ = x[actSigStop-148]
+ _ = x[actFirst-149]
+ _ = x[actLast-150]
+ _ = x[actReload-151]
+ _ = x[actReloadSync-152]
+ _ = x[actDisableSearch-153]
+ _ = x[actEnableSearch-154]
+ _ = x[actSelect-155]
+ _ = x[actDeselect-156]
+ _ = x[actUnbind-157]
+ _ = x[actRebind-158]
+ _ = x[actToggleBind-159]
+ _ = x[actBecome-160]
+ _ = x[actShowHeader-161]
+ _ = x[actHideHeader-162]
+ _ = x[actBell-163]
+ _ = x[actExclude-164]
+ _ = x[actExcludeMulti-165]
+ _ = x[actAsync-166]
}
-const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
+const _actionType_name = "actIgnoreactStartactClickactInvalidactBracketedPasteBeginactBracketedPasteEndactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactBackwardSubWordactCancelactChangeBorderLabelactChangeGhostactChangeHeaderactChangeFooteractChangeHeaderLabelactChangeFooterLabelactChangeInputLabelactChangeListLabelactChangeMultiactChangeNthactChangePointeractChangePreviewactChangePreviewLabelactChangePreviewWindowactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactForwardSubWordactKillLineactKillWordactKillSubWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactBackwardKillSubWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactToggleRawactTrackCurrentactToggleInputactHideInputactShowInputactUntrackCurrentactDownactDownMatchactUpactUpMatchactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformGhostactTransformHeaderactTransformFooteractTransformHeaderLabelactTransformFooterLabelactTransformInputLabelactTransformListLabelactTransformNthactTransformPointeractTransformPreviewLabelactTransformPromptactTransformQueryactTransformSearchactTriggeractBgTransformactBgTransformBorderLabelactBgTransformGhostactBgTransformHeaderactBgTransformFooteractBgTransformHeaderLabelactBgTransformFooterLabelactBgTransformInputLabelactBgTransformListLabelactBgTransformNthactBgTransformPointeractBgTransformPreviewLabelactBgTransformPromptactBgTransformQueryactBgTransformSearchactBgCancelactSearchactPreviewactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactToggleBindactBecomeactShowHeaderactHideHeaderactBellactExcludeactExcludeMultiactAsync"
-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, 993, 1009, 1024, 1038, 1050, 1062, 1079, 1086, 1091, 1100, 1111, 1122, 1135, 1150, 1161, 1174, 1189, 1196, 1209, 1222, 1239, 1254, 1267, 1281, 1295, 1311, 1331, 1343, 1366, 1383, 1401, 1419, 1442, 1465, 1487, 1508, 1523, 1542, 1566, 1584, 1601, 1619, 1629, 1643, 1668, 1687, 1707, 1727, 1752, 1777, 1801, 1824, 1841, 1862, 1888, 1908, 1927, 1947, 1958, 1967, 1977, 1990, 2006, 2018, 2032, 2048, 2066, 2086, 2108, 2122, 2137, 2145, 2151, 2165, 2180, 2190, 2206, 2221, 2231, 2239, 2246, 2255, 2268, 2284, 2299, 2308, 2319, 2328, 2337, 2350, 2359, 2372, 2385, 2392, 2402, 2417, 2425}
+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, 993, 1009, 1021, 1036, 1050, 1062, 1074, 1091, 1098, 1110, 1115, 1125, 1134, 1145, 1156, 1169, 1184, 1195, 1208, 1223, 1230, 1243, 1256, 1273, 1288, 1301, 1315, 1329, 1345, 1365, 1377, 1400, 1417, 1435, 1453, 1476, 1499, 1521, 1542, 1557, 1576, 1600, 1618, 1635, 1653, 1663, 1677, 1702, 1721, 1741, 1761, 1786, 1811, 1835, 1858, 1875, 1896, 1922, 1942, 1961, 1981, 1992, 2001, 2011, 2024, 2040, 2052, 2066, 2082, 2100, 2120, 2142, 2156, 2171, 2179, 2185, 2199, 2214, 2224, 2240, 2255, 2265, 2273, 2280, 2289, 2302, 2318, 2333, 2342, 2353, 2362, 2371, 2384, 2393, 2406, 2419, 2426, 2436, 2451, 2459}
func (i actionType) String() string {
if i < 0 || i >= actionType(len(_actionType_index)-1) {
diff --git a/src/core.go b/src/core.go
index a4fbfe04..286d574a 100644
--- a/src/core.go
+++ b/src/core.go
@@ -267,11 +267,11 @@ func Run(opts *Options) (int, error) {
// NOTE: Streaming filter is inherently not compatible with --tail
snapshot, _, _ := chunkList.Snapshot(opts.Tail)
- merger, _ := matcher.scan(MatchRequest{
+ result := matcher.scan(MatchRequest{
chunks: snapshot,
pattern: pattern})
- for i := 0; i < merger.Length(); i++ {
- opts.Printer(merger.Get(i).item.AsString(opts.Ansi))
+ for i := 0; i < result.merger.Length(); i++ {
+ opts.Printer(result.merger.Get(i).item.AsString(opts.Ansi))
found = true
}
}
@@ -479,12 +479,13 @@ func Run(opts *Options) (int, error) {
case EvtSearchFin:
switch val := value.(type) {
- case *Merger:
+ case MatchResult:
+ merger := val.merger
if deferred {
- count := val.Length()
+ count := merger.Length()
if opts.Select1 && count > 1 || opts.Exit0 && !opts.Select1 && count > 0 {
- determine(val.final)
- } else if val.final {
+ determine(merger.final)
+ } else if merger.final {
if opts.Exit0 && count == 0 || opts.Select1 && count == 1 {
if opts.PrintQuery {
opts.Printer(opts.Query)
@@ -502,7 +503,7 @@ func Run(opts *Options) (int, error) {
}
}
for i := 0; i < count; i++ {
- opts.Printer(transformer(val.Get(i).item))
+ opts.Printer(transformer(merger.Get(i).item))
}
if count == 0 {
exitCode = ExitNoMatch
@@ -510,7 +511,7 @@ func Run(opts *Options) (int, error) {
stop = true
return
}
- determine(val.final)
+ determine(merger.final)
}
}
terminal.UpdateList(val)
diff --git a/src/matcher.go b/src/matcher.go
index 95926fe4..7fd01353 100644
--- a/src/matcher.go
+++ b/src/matcher.go
@@ -19,6 +19,20 @@ type MatchRequest struct {
revision revision
}
+type MatchResult struct {
+ merger *Merger
+ passMerger *Merger
+ cancelled bool
+}
+
+func (mr MatchResult) cacheable() bool {
+ return mr.merger != nil && mr.merger.cacheable()
+}
+
+func (mr MatchResult) final() bool {
+ return mr.merger != nil && mr.merger.final
+}
+
// Matcher is responsible for performing search
type Matcher struct {
cache *ChunkCache
@@ -29,7 +43,7 @@ type Matcher struct {
reqBox *util.EventBox
partitions int
slab []*util.Slab
- mergerCache map[string]*Merger
+ mergerCache map[string]MatchResult
revision revision
}
@@ -51,7 +65,7 @@ func NewMatcher(cache *ChunkCache, patternBuilder func([]rune) *Pattern,
reqBox: util.NewEventBox(),
partitions: partitions,
slab: make([]*util.Slab, partitions),
- mergerCache: make(map[string]*Merger),
+ mergerCache: make(map[string]MatchResult),
revision: revision}
}
@@ -85,7 +99,7 @@ func (m *Matcher) Loop() {
cacheCleared := false
if request.sort != m.sort || request.revision != m.revision {
m.sort = request.sort
- m.mergerCache = make(map[string]*Merger)
+ m.mergerCache = make(map[string]MatchResult)
if !request.revision.compatible(m.revision) {
m.cache.Clear()
}
@@ -95,33 +109,32 @@ func (m *Matcher) Loop() {
// Restart search
patternString := request.pattern.AsString()
- var merger *Merger
- cancelled := false
+ var result MatchResult
count := CountItems(request.chunks)
if !cacheCleared {
if count == prevCount {
// Look up mergerCache
- if cached, found := m.mergerCache[patternString]; found && cached.final == request.final {
- merger = cached
+ if cached, found := m.mergerCache[patternString]; found && cached.final() == request.final {
+ result = cached
}
} else {
// Invalidate mergerCache
prevCount = count
- m.mergerCache = make(map[string]*Merger)
+ m.mergerCache = make(map[string]MatchResult)
}
}
- if merger == nil {
- merger, cancelled = m.scan(request)
+ if result.merger == nil {
+ result = m.scan(request)
}
- if !cancelled {
- if merger.cacheable() {
- m.mergerCache[patternString] = merger
+ if !result.cancelled {
+ if result.cacheable() {
+ m.mergerCache[patternString] = result
}
- merger.final = request.final
- m.eventBox.Set(EvtSearchFin, merger)
+ result.merger.final = request.final
+ m.eventBox.Set(EvtSearchFin, result)
}
}
}
@@ -152,16 +165,18 @@ type partialResult struct {
matches []Result
}
-func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
+func (m *Matcher) scan(request MatchRequest) MatchResult {
startedAt := time.Now()
numChunks := len(request.chunks)
if numChunks == 0 {
- return EmptyMerger(request.revision), false
+ m := EmptyMerger(request.revision)
+ return MatchResult{m, m, false}
}
pattern := request.pattern
+ passMerger := PassMerger(&request.chunks, m.tac, request.revision)
if pattern.IsEmpty() {
- return PassMerger(&request.chunks, m.tac, request.revision), false
+ return MatchResult{passMerger, passMerger, false}
}
minIndex := request.chunks[0].items[0].Index()
@@ -224,7 +239,7 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
}
if m.reqBox.Peek(reqReset) {
- return nil, wait()
+ return MatchResult{nil, nil, wait()}
}
if time.Since(startedAt) > progressMinDuration {
@@ -237,7 +252,8 @@ func (m *Matcher) scan(request MatchRequest) (*Merger, bool) {
partialResult := <-resultChan
partialResults[partialResult.index] = partialResult.matches
}
- return NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex, maxIndex), false
+ merger := NewMerger(pattern, partialResults, m.sort && request.pattern.sortable, m.tac, request.revision, minIndex, maxIndex)
+ return MatchResult{merger, passMerger, false}
}
// Reset is called to interrupt/signal the ongoing search
diff --git a/src/merger.go b/src/merger.go
index 688f3571..b9bdabb8 100644
--- a/src/merger.go
+++ b/src/merger.go
@@ -141,6 +141,15 @@ func (mg *Merger) Get(idx int) Result {
panic(fmt.Sprintf("Index out of bounds (unsorted, %d/%d)", idx, mg.count))
}
+func (mg *Merger) ToMap() map[int32]Result {
+ ret := make(map[int32]Result, mg.count)
+ for i := 0; i < mg.count; i++ {
+ result := mg.Get(i)
+ ret[result.Index()] = result
+ }
+ return ret
+}
+
func (mg *Merger) cacheable() bool {
return mg.count < mergerCacheMax
}
diff --git a/src/options.go b/src/options.go
index f3ba8518..e7f693b6 100644
--- a/src/options.go
+++ b/src/options.go
@@ -98,6 +98,7 @@ Usage: fzf [options]
--wrap Enable line wrap
--wrap-sign=STR Indicator for wrapped lines
--no-multi-line Disable multi-line display of items when using --read0
+ --raw Enable raw mode (show non-matching items)
--track Track the current selection when the result is updated
--tac Reverse the order of the input
--gap[=N] Render empty lines between each item
@@ -111,6 +112,7 @@ Usage: fzf [options]
highlighted substring (default: 10)
--jump-labels=CHARS Label characters for jump mode
--gutter=CHAR Character used for the gutter column (default: '▌')
+ --gutter-raw=CHAR Character used for the gutter column in raw mode (default: '▖')
--pointer=STR Pointer to the current line (default: '▌' or '>')
--marker=STR Multi-select marker (default: '┃' or '>')
--marker-multi-line=STR Multi-select marker for multi-line entries;
@@ -562,6 +564,7 @@ type Options struct {
AcceptNth func(Delimiter) func([]Token, int32) string
Delimiter Delimiter
Sort int
+ Raw bool
Track trackOption
Tac bool
Tail int
@@ -593,6 +596,7 @@ type Options struct {
JumpLabels string
Prompt string
Gutter *string
+ GutterRaw *string
Pointer *string
Marker *string
MarkerMulti *[3]string
@@ -714,6 +718,7 @@ func defaultOptions() *Options {
JumpLabels: defaultJumpLabels,
Prompt: "> ",
Gutter: nil,
+ GutterRaw: nil,
Pointer: nil,
Marker: nil,
MarkerMulti: nil,
@@ -1442,6 +1447,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
mergeAttr(&theme.SelectedBg)
case "nth":
mergeAttr(&theme.Nth)
+ case "hidden":
+ mergeAttr(&theme.Hidden)
case "gutter":
mergeAttr(&theme.Gutter)
case "hl":
@@ -1741,6 +1748,8 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actToggleMultiLine)
case "toggle-hscroll":
appendAction(actToggleHscroll)
+ case "toggle-raw":
+ appendAction(actToggleRaw)
case "show-header":
appendAction(actShowHeader)
case "hide-header":
@@ -1761,8 +1770,12 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actToggle)
case "down":
appendAction(actDown)
+ case "down-match":
+ appendAction(actDownMatch)
case "up":
appendAction(actUp)
+ case "up-match":
+ appendAction(actUpMatch)
case "first", "top":
appendAction(actFirst)
case "last":
@@ -1779,9 +1792,9 @@ func parseActionList(masked string, original string, prevActions []*action, putA
appendAction(actPrevHistory)
case "next-history":
appendAction(actNextHistory)
- case "prev-selected":
+ case "up-selected", "prev-selected":
appendAction(actPrevSelected)
- case "next-selected":
+ case "down-selected", "next-selected":
appendAction(actNextSelected)
case "show-preview":
appendAction(actShowPreview)
@@ -2682,6 +2695,10 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
}
case "+s", "--no-sort":
opts.Sort = 0
+ case "--raw":
+ opts.Raw = true
+ case "--no-raw":
+ opts.Raw = false
case "--track":
opts.Track = trackEnabled
case "--no-track":
@@ -2866,6 +2883,13 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
}
str = firstLine(str)
opts.Gutter = &str
+ case "--gutter-raw":
+ str, err := nextString("gutter character for raw mode required")
+ if err != nil {
+ return err
+ }
+ str = firstLine(str)
+ opts.GutterRaw = &str
case "--pointer":
str, err := nextString("pointer sign required")
if err != nil {
@@ -3390,6 +3414,12 @@ func validateOptions(opts *Options) error {
}
}
+ if opts.GutterRaw != nil {
+ if err := validateSign(*opts.GutterRaw, "gutter", 1); err != nil {
+ return err
+ }
+ }
+
if opts.Scrollbar != nil {
runes := []rune(*opts.Scrollbar)
if len(runes) > 2 {
diff --git a/src/options_test.go b/src/options_test.go
index a14dece7..7b152d75 100644
--- a/src/options_test.go
+++ b/src/options_test.go
@@ -350,8 +350,8 @@ func TestDefaultCtrlNP(t *testing.T) {
t.Error()
}
}
- check([]string{}, tui.CtrlN, actDown)
- check([]string{}, tui.CtrlP, actUp)
+ check([]string{}, tui.CtrlN, actDownMatch)
+ check([]string{}, tui.CtrlP, actUpMatch)
check([]string{"--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
check([]string{"--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
diff --git a/src/terminal.go b/src/terminal.go
index 1f0a6e41..96b06259 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -274,9 +274,11 @@ type Terminal struct {
footerLabelLen int
footerLabelOpts labelOpts
gutterReverse bool
+ gutterRawReverse bool
pointer string
pointerLen int
pointerEmpty string
+ pointerEmptyRaw string
marker string
markerLen int
markerEmpty string
@@ -297,6 +299,7 @@ type Terminal struct {
subWordNext string
cx int
cy int
+ lastMatchingIndex int32
offset int
xoffset int
yanked []rune
@@ -383,6 +386,9 @@ type Terminal struct {
printer func(string)
printsep string
merger *Merger
+ passMerger *Merger
+ resultMerger *Merger
+ matchMap map[int32]Result
selected map[int32]selectedItem
version int64
revision revision
@@ -429,6 +435,7 @@ type Terminal struct {
clickFooterColumn int
proxyScript string
numLinesCache map[int32]numLinesCacheValue
+ raw bool
}
type numLinesCacheValue struct {
@@ -569,13 +576,16 @@ const (
actToggleWrap
actToggleMultiLine
actToggleHscroll
+ actToggleRaw
actTrackCurrent
actToggleInput
actHideInput
actShowInput
actUntrackCurrent
actDown
+ actDownMatch
actUp
+ actUpMatch
actPageUp
actPageDown
actPosition
@@ -796,8 +806,10 @@ func defaultKeymap() map[tui.Event][]*action {
add(tui.CtrlK, actUp)
add(tui.CtrlL, actClearScreen)
add(tui.Enter, actAccept)
- add(tui.CtrlN, actDown)
- add(tui.CtrlP, actUp)
+ add(tui.CtrlN, actDownMatch)
+ add(tui.CtrlP, actUpMatch)
+ add(tui.AltDown, actDownMatch)
+ add(tui.AltUp, actUpMatch)
add(tui.CtrlU, actUnixLineDiscard)
add(tui.CtrlW, actUnixWordRubout)
add(tui.CtrlY, actYank)
@@ -953,6 +965,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
}
keymapCopy := maps.Clone(opts.Keymap)
+ em := EmptyMerger(revision{})
t := Terminal{
initDelay: delay,
infoCommand: opts.InfoCommand,
@@ -980,6 +993,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
subWordNext: subWordNext,
cx: len(input),
cy: 0,
+ lastMatchingIndex: minItem.Index(),
offset: 0,
xoffset: 0,
yanked: []rune{},
@@ -1039,6 +1053,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
nth: opts.Nth,
nthCurrent: opts.Nth,
tabstop: opts.Tabstop,
+ raw: opts.Raw,
hasStartActions: false,
hasResultActions: false,
hasFocusActions: false,
@@ -1052,7 +1067,10 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
printer: opts.Printer,
printsep: opts.PrintSep,
proxyScript: opts.ProxyScript,
- merger: EmptyMerger(revision{}),
+ merger: em,
+ passMerger: em,
+ resultMerger: em,
+ matchMap: make(map[int32]Result),
selected: make(map[int32]selectedItem),
runningCmds: util.NewConcurrentSet[*runningCmd](),
reqBox: util.NewEventBox(),
@@ -1093,7 +1111,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
tui.InitTheme(opts.Theme, renderer.DefaultTheme(), opts.Black, opts.InputBorderShape.Visible(), opts.HeaderBorderShape.Visible())
// Gutter character
- var gutterChar string
+ var gutterChar, gutterRawChar string
if opts.Gutter != nil {
gutterChar = *opts.Gutter
} else if t.unicode && !t.theme.Gutter.Color.IsDefault() {
@@ -1103,12 +1121,24 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
t.gutterReverse = true
}
+ if opts.GutterRaw != nil {
+ gutterRawChar = *opts.GutterRaw
+ } else if t.unicode && !t.theme.Gutter.Color.IsDefault() {
+ // TODO: Doesn't look too good. Maybe use a different color instead, or both?
+ gutterRawChar = "▖"
+ } else {
+ gutterRawChar = ":"
+ t.gutterRawReverse = false
+ }
+
t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
// Pre-calculated empty pointer and marker signs
if t.pointerLen == 0 {
t.pointerEmpty = ""
+ t.pointerEmptyRaw = ""
} else {
t.pointerEmpty = gutterChar + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
+ t.pointerEmptyRaw = gutterRawChar + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
}
t.markerEmpty = strings.Repeat(" ", t.markerLen)
@@ -1282,7 +1312,7 @@ func (t *Terminal) environImpl(forPreview bool) []string {
}
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_MATCH_COUNT=%d", t.resultMerger.Length()))
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_COLUMNS=%d", t.areaColumns))
@@ -1693,7 +1723,8 @@ func (t *Terminal) UpdateProgress(progress float32) {
}
// UpdateList updates Merger to display the list
-func (t *Terminal) UpdateList(merger *Merger) {
+func (t *Terminal) UpdateList(result MatchResult) {
+ merger := result.merger
t.mutex.Lock()
prevIndex := minItem.Index()
newRevision := merger.Revision()
@@ -1706,6 +1737,15 @@ func (t *Terminal) UpdateList(merger *Merger) {
}
t.progress = 100
t.merger = merger
+ t.resultMerger = merger
+ t.passMerger = result.passMerger
+ if t.raw {
+ t.merger = result.passMerger
+ t.matchMap = t.resultMerger.ToMap()
+ } else {
+ t.merger = result.merger
+ t.matchMap = make(map[int32]Result)
+ }
if t.revision != newRevision {
if !t.revision.compatible(newRevision) {
// Reloaded: clear selection
@@ -1754,7 +1794,7 @@ func (t *Terminal) UpdateList(merger *Merger) {
}
needActivation := false
if !t.reading {
- switch t.merger.Length() {
+ switch t.resultMerger.Length() {
case 0:
zero := tui.Zero.AsEvent()
if _, prs := t.keymap[zero]; prs {
@@ -2801,7 +2841,7 @@ func (t *Terminal) printInfoImpl() {
return
}
- found := t.merger.Length()
+ found := t.resultMerger.Length()
total := util.Max(found, t.count)
output := fmt.Sprintf("%d/%d", found, total)
if t.toggleSort {
@@ -3122,12 +3162,16 @@ func (t *Terminal) gutter(current bool) {
var color tui.ColorPair
if current {
color = tui.ColCurrentCursorEmpty
- } else if t.gutterReverse {
+ } else if !t.raw && t.gutterReverse || t.raw && t.gutterRawReverse {
color = tui.ColCursorEmpty
} else {
color = tui.ColCursorEmptyChar
}
- t.window.CPrint(color, t.pointerEmpty)
+ gutter := t.pointerEmpty
+ if t.raw {
+ gutter = t.pointerEmptyRaw
+ }
+ t.window.CPrint(color, gutter)
}
func (t *Terminal) renderGapLine(line int, barRange [2]int, drawLine bool) {
@@ -3162,7 +3206,11 @@ func (t *Terminal) printList() {
for line, itemCount := startLine, 0; line <= maxy; line, itemCount = line+1, itemCount+1 {
if itemCount < count {
item := t.merger.Get(itemCount + t.offset)
- line = t.printItem(item, line, maxy, itemCount, itemCount == t.cy-t.offset, barRange)
+ current := itemCount == t.cy-t.offset
+ if current && (!t.raw || t.isItemMatch(item.item)) {
+ t.lastMatchingIndex = item.Index()
+ }
+ line = t.printItem(item, line, maxy, itemCount, current, barRange)
} else if !t.prevLines[line].empty {
t.renderEmptyLine(line, barRange)
}
@@ -3184,6 +3232,14 @@ func (t *Terminal) printBar(lineNum int, forceRedraw bool, barRange [2]int) bool
func (t *Terminal) printItem(result Result, line int, maxLine int, index int, current bool, barRange [2]int) int {
item := result.item
+ matched := true
+ var matchResult Result
+ if t.raw {
+ if matchResult, matched = t.matchMap[item.Index()]; matched {
+ result = matchResult
+ }
+ }
+
_, selected := t.selected[item.Index()]
label := ""
extraWidth := 0
@@ -3310,7 +3366,13 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
}
return indentSize
}
- finalLineNum = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true, line, maxLine, forceRedraw, preTask, postTask)
+ base := tui.ColCurrent
+ match := tui.ColCurrentMatch
+ if !matched {
+ base = base.WithFg(t.theme.Hidden)
+ match = match.WithFg(t.theme.Hidden)
+ }
+ finalLineNum = t.printHighlighted(result, base, match, true, true, line, maxLine, forceRedraw, preTask, postTask)
} else {
preTask := func(marker markerClass) int {
w := t.window.Width() - t.pointerLen
@@ -3344,6 +3406,10 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
base = base.WithBg(altBg)
match = match.WithBg(altBg)
}
+ if !matched {
+ base = base.WithFg(t.theme.Hidden)
+ match = match.WithFg(t.theme.Hidden)
+ }
finalLineNum = t.printHighlighted(result, base, match, false, true, line, maxLine, forceRedraw, preTask, postTask)
}
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
@@ -3396,8 +3462,8 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
item := result.item
matchOffsets := []Offset{}
var pos *[]int
- if match && t.merger.pattern != nil {
- _, matchOffsets, pos = t.merger.pattern.MatchItem(item, true, t.slab)
+ if match && t.resultMerger.pattern != nil {
+ _, matchOffsets, pos = t.resultMerger.pattern.MatchItem(item, true, t.slab)
}
charOffsets := matchOffsets
if pos != nil {
@@ -3429,7 +3495,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
}
if !wholeCovered && t.nthAttr > 0 {
var tokens []Token
- if item.transformed != nil && item.transformed.revision == t.merger.revision {
+ if item.transformed != nil && item.transformed.revision == t.resultMerger.revision {
tokens = item.transformed.tokens
} else {
tokens = Transform(Tokenize(item.text.ToString(), t.delimiter), t.nthCurrent)
@@ -4677,6 +4743,33 @@ func (t *Terminal) currentItem() *Item {
return nil
}
+func (t *Terminal) isCurrentItemMatch() bool {
+ cnt := t.merger.Length()
+ if t.cy >= 0 && cnt > 0 && cnt > t.cy {
+ if !t.raw {
+ return true
+ }
+ item := t.merger.Get(t.cy).item
+ return t.isItemMatch(item)
+ }
+ return false
+}
+
+func (t *Terminal) isItemMatch(item *Item) bool {
+ _, matched := t.matchMap[item.Index()]
+ return matched
+}
+
+func (t *Terminal) filterSelected() {
+ filtered := make(map[int32]selectedItem)
+ for k, v := range t.selected {
+ if t.isItemMatch(v.item) {
+ filtered[k] = v
+ }
+ }
+ t.selected = filtered
+}
+
func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, [3][]*Item) {
current := t.currentItem()
slot, plus, asterisk, forceUpdate := hasPreviewFlags(template)
@@ -4721,6 +4814,10 @@ func (t *Terminal) selectItem(item *Item) bool {
if len(t.selected) >= t.multi {
return false
}
+ // TODO: Should we allow selecting non-matching items?
+ // if t.raw && !t.isItemMatch(item) {
+ // return false
+ // }
if _, found := t.selected[item.Index()]; found {
return true
}
@@ -5917,8 +6014,9 @@ func (t *Terminal) Loop() error {
}
case actSelectAll:
if t.multi > 0 {
- for i := 0; i < t.merger.Length(); i++ {
- if !t.selectItem(t.merger.Get(i).item) {
+ // Limit the scope only to the matching items
+ for i := 0; i < t.resultMerger.Length(); i++ {
+ if !t.selectItem(t.resultMerger.Get(i).item) {
break
}
}
@@ -5926,8 +6024,10 @@ func (t *Terminal) Loop() error {
}
case actDeselectAll:
if t.multi > 0 {
- for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
- t.deselectItem(t.merger.Get(i).item)
+ // Also limit the scope only to the matching items, while this may
+ // not be straightforward in raw mode.
+ for i := 0; i < t.resultMerger.Length() && len(t.selected) > 0; i++ {
+ t.deselectItem(t.resultMerger.Get(i).item)
}
req(reqList, reqInfo)
}
@@ -5955,17 +6055,17 @@ func (t *Terminal) Loop() error {
case actToggleAll:
if t.multi > 0 {
prevIndexes := make(map[int]struct{})
- for i := 0; i < t.merger.Length() && len(t.selected) > 0; i++ {
- item := t.merger.Get(i).item
+ for i := 0; i < t.resultMerger.Length() && len(t.selected) > 0; i++ {
+ item := t.resultMerger.Get(i).item
if _, found := t.selected[item.Index()]; found {
prevIndexes[i] = struct{}{}
t.deselectItem(item)
}
}
- for i := 0; i < t.merger.Length(); i++ {
+ for i := 0; i < t.resultMerger.Length(); i++ {
if _, found := prevIndexes[i]; !found {
- item := t.merger.Get(i).item
+ item := t.resultMerger.Get(i).item
if !t.selectItem(item) {
break
}
@@ -5993,19 +6093,77 @@ func (t *Terminal) Loop() error {
t.vmove(1, true)
req(reqList)
}
- case actDown:
- t.vmove(-1, true)
+ case actDown, actDownMatch:
+ if t.raw && a.t == actDownMatch {
+ if t.resultMerger.Length() > 0 {
+ prevCy := t.cy
+ for t.vmove(-1, true) && !t.isCurrentItemMatch() {
+ }
+ if !t.isCurrentItemMatch() {
+ t.vset(prevCy)
+ }
+ }
+ } else {
+ t.vmove(-1, true)
+ }
req(reqList)
- case actUp:
- t.vmove(1, true)
+ case actUp, actUpMatch:
+ if t.raw && a.t == actUpMatch {
+ if t.resultMerger.Length() > 0 {
+ prevCy := t.cy
+ for t.vmove(1, true) && !t.isCurrentItemMatch() {
+ }
+ if !t.isCurrentItemMatch() {
+ t.vset(prevCy)
+ }
+ }
+ } else {
+ t.vmove(1, true)
+ }
+ req(reqList)
+ case actToggleRaw:
+ t.raw = !t.raw
+ prevPos := t.cy - t.offset
+ prevIndex := t.currentIndex()
+ if t.raw {
+ // Build matchMap if not available
+ if len(t.matchMap) == 0 {
+ t.matchMap = t.resultMerger.ToMap()
+ }
+ t.merger = t.passMerger
+ } else {
+ t.merger = t.resultMerger
+
+ // Need to remove non-matching items from the selection
+ if t.multi > 0 && len(t.selected) > 0 {
+ t.filterSelected()
+ req(reqInfo)
+ }
+ }
+
+ // Try to retain position
+ if prevIndex != minItem.Index() {
+ i := t.merger.FindIndex(prevIndex)
+ if i >= 0 {
+ t.cy = i
+ } else {
+ t.cy = t.merger.FindIndex(t.lastMatchingIndex)
+ }
+ t.offset = t.cy - prevPos
+ }
+
+ // List needs to be rerendered
+ t.forceRerenderList()
req(reqList)
case actAccept:
req(reqClose)
case actAcceptNonEmpty:
+ // TODO: Allow accepting unmatched items in raw mode?
if len(t.selected) > 0 || t.merger.Length() > 0 || !t.reading && t.count == 0 {
req(reqClose)
}
case actAcceptOrPrintQuery:
+ // TODO: Allow accepting unmatched items in raw mode?
if len(t.selected) > 0 || t.merger.Length() > 0 {
req(reqClose)
} else {
@@ -6841,7 +6999,7 @@ func (t *Terminal) Loop() error {
reload := changed || newCommand != nil
var reloadRequest *searchRequest
if reload {
- reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.merger.Revision()}
+ reloadRequest = &searchRequest{sort: t.sort, sync: reloadSync, nth: newNth, command: newCommand, environ: t.environ(), changed: changed, denylist: denylist, revision: t.resultMerger.Revision()}
}
// Dispatch queued background requests
@@ -6961,7 +7119,8 @@ func (t *Terminal) constrain() {
}
}
-func (t *Terminal) vmove(o int, allowCycle bool) {
+// Returns true if the cursor position is successfully updated
+func (t *Terminal) vmove(o int, allowCycle bool) bool {
if t.layout != layoutDefault {
o *= -1
}
@@ -6978,7 +7137,7 @@ func (t *Terminal) vmove(o int, allowCycle bool) {
}
}
}
- t.vset(dest)
+ return t.vset(dest)
}
func (t *Terminal) vset(o int) bool {
@@ -7045,9 +7204,9 @@ func (t *Terminal) dumpStatus(params getParams) string {
selected[i] = t.dumpItem(selectedItems[i+params.offset].item)
}
- matches := make([]StatusItem, util.Max(0, util.Min(params.limit, t.merger.Length()-params.offset)))
+ matches := make([]StatusItem, util.Max(0, util.Min(params.limit, t.resultMerger.Length()-params.offset)))
for i := range matches {
- matches[i] = t.dumpItem(t.merger.Get(i + params.offset).item)
+ matches[i] = t.dumpItem(t.resultMerger.Get(i + params.offset).item)
}
var current *StatusItem
@@ -7064,7 +7223,7 @@ func (t *Terminal) dumpStatus(params getParams) string {
Position: t.cy,
Sort: t.sort,
TotalCount: t.count,
- MatchCount: t.merger.Length(),
+ MatchCount: t.resultMerger.Length(),
Current: current,
Matches: matches,
Selected: selected,
diff --git a/src/tui/tui.go b/src/tui/tui.go
index 106d6c86..ae9e8c49 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -381,6 +381,12 @@ func (p ColorPair) WithAttr(attr Attr) ColorPair {
return dup
}
+func (p ColorPair) WithFg(fg ColorAttr) ColorPair {
+ dup := p
+ fgPair := ColorPair{fg.Color, colUndefined, fg.Attr}
+ return dup.Merge(fgPair)
+}
+
func (p ColorPair) WithBg(bg ColorAttr) ColorPair {
dup := p
bgPair := ColorPair{colUndefined, bg.Color, bg.Attr}
@@ -410,6 +416,7 @@ type ColorTheme struct {
ListBg ColorAttr
AltBg ColorAttr
Nth ColorAttr
+ Hidden ColorAttr
SelectedFg ColorAttr
SelectedBg ColorAttr
SelectedMatch ColorAttr
@@ -866,6 +873,7 @@ func EmptyTheme() *ColorTheme {
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
GapLine: ColorAttr{colUndefined, AttrUndefined},
Nth: ColorAttr{colUndefined, AttrUndefined},
+ Hidden: ColorAttr{colUndefined, Dim},
}
}
@@ -916,6 +924,7 @@ func NoColorTheme() *ColorTheme {
FooterLabel: ColorAttr{colDefault, AttrUndefined},
GapLine: ColorAttr{colDefault, AttrUndefined},
Nth: ColorAttr{colUndefined, AttrUndefined},
+ Hidden: ColorAttr{colUndefined, Dim},
}
}
@@ -967,6 +976,7 @@ func init() {
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
GapLine: ColorAttr{colUndefined, AttrUndefined},
Nth: ColorAttr{colUndefined, AttrUndefined},
+ Hidden: ColorAttr{colUndefined, Dim},
}
Dark256 = &ColorTheme{
Colored: true,
@@ -1015,6 +1025,7 @@ func init() {
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
GapLine: ColorAttr{colUndefined, AttrUndefined},
Nth: ColorAttr{colUndefined, AttrUndefined},
+ Hidden: ColorAttr{colUndefined, Dim},
}
Light256 = &ColorTheme{
Colored: true,
@@ -1063,6 +1074,7 @@ func init() {
FooterLabel: ColorAttr{colUndefined, AttrUndefined},
GapLine: ColorAttr{colUndefined, AttrUndefined},
Nth: ColorAttr{colUndefined, AttrUndefined},
+ Hidden: ColorAttr{colUndefined, Dim},
}
}