diff --git a/CHANGELOG.md b/CHANGELOG.md index ee88c41f..a30bdbeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,14 @@ fzf --raw --color hidden:red:strikethrough:dim fzf --raw --color hidden:red:strikethrough:dim:italic ``` +For colored input, dimming alone may not be enough, and you may prefer to remove +colors entirely. For that case, a new special style attribute `strip` has been +added. + +```sh +fd --color always | fzf --ansi --raw --color hidden:dim:strip:strikethrough +``` + #### Conditional actions for raw mode You may want to perform different actions depending on whether the current item diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index ffd47f12..4be02c97 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -325,7 +325,8 @@ color mappings. Each entry is separated by a comma and/or whitespaces. \fB#rrggbb \fR24-bit colors .B ANSI ATTRIBUTES: (Only applies to foreground colors) - \fBregular \fRClears previously set attributes; should precede the other ones + \fBregular \fRClear previously set attributes; should precede the other ones + \fBstrip \fRRemove colors \fBbold\fR \fBunderline\fR \fBreverse\fR diff --git a/src/options.go b/src/options.go index 79e016b6..aa50dc54 100644 --- a/src/options.go +++ b/src/options.go @@ -1366,6 +1366,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, *tui cattr.Attr |= tui.Bold case "dim": cattr.Attr |= tui.Dim + case "strip": + cattr.Attr |= tui.Strip case "italic": cattr.Attr |= tui.Italic case "underline": diff --git a/src/result.go b/src/result.go index 36f56fb7..d6811dc8 100644 --- a/src/result.go +++ b/src/result.go @@ -123,7 +123,7 @@ func minRank() Result { return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}} } -func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr) []colorOffset { +func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr, hidden bool) []colorOffset { itemColors := result.item.Colors() // No ANSI codes @@ -194,6 +194,10 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t if !theme.Colored { return tui.NewColorPair(-1, -1, ansi.color.attr).MergeAttr(base) } + // fd --color always | fzf --ansi --delimiter / --nth -1 --color fg:dim:strip,nth:regular + if base.ShouldStripColors() { + return base + } fg := ansi.color.fg bg := ansi.color.bg if fg == -1 { @@ -251,6 +255,9 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t if curr.nth { base = base.WithAttr(attrNth) } + if hidden { + base = base.WithFg(theme.Hidden) + } color := ansiToColorPair(ansi, base) colors = append(colors, colorOffset{ offset: [2]int32{int32(start), int32(idx)}, @@ -258,9 +265,13 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t match: false, url: ansi.color.url}) } else { + color := colBase.WithAttr(attrNth) + if hidden { + color = color.WithFg(theme.Hidden) + } colors = append(colors, colorOffset{ offset: [2]int32{int32(start), int32(idx)}, - color: colBase.WithAttr(attrNth), + color: color, match: false, url: nil}) } diff --git a/src/result_test.go b/src/result_test.go index 6e6d4387..1f6a003e 100644 --- a/src/result_test.go +++ b/src/result_test.go @@ -131,7 +131,7 @@ func TestColorOffset(t *testing.T) { colBase := tui.NewColorPair(89, 189, tui.AttrUndefined) colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined) - colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined) + colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined, false) assert := func(idx int, b int32, e int32, c tui.ColorPair) { o := colors[idx] if o.offset[0] != b || o.offset[1] != e || o.color != c { @@ -158,7 +158,7 @@ func TestColorOffset(t *testing.T) { nthOffsets := []Offset{{37, 39}, {42, 45}} for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} { - colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr) + colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr, false) // [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}} // {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}} diff --git a/src/terminal.go b/src/terminal.go index 5d578540..e96ac96f 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1485,7 +1485,7 @@ func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool) printFn := func(window tui.Window, limit int) { if offsets == nil { // tui.Col* are not initialized until renderer.Init() - offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr) + offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr, false) } for limit > 0 { if length > limit { @@ -1548,7 +1548,7 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) { return 1 } t.printHighlighted( - Result{item: item}, tui.ColPrompt, tui.ColPrompt, false, false, line, line, true, preTask, nil) + Result{item: item}, tui.ColPrompt, tui.ColPrompt, false, false, false, line, line, true, preTask, nil) }) t.wrap = wrap } @@ -3070,7 +3070,7 @@ func (t *Terminal) printFooter() { colors: colors} t.printHighlighted(Result{item: item}, - tui.ColFooter, tui.ColFooter, false, false, line, line, true, + tui.ColFooter, tui.ColFooter, false, false, false, line, line, true, func(markerClass) int { t.footerWindow.Print(indent) return indentSize @@ -3142,7 +3142,7 @@ func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShap colors: colors} t.printHighlighted(Result{item: item}, - tui.ColHeader, tui.ColHeader, false, false, line, line, true, + tui.ColHeader, tui.ColHeader, false, false, false, line, line, true, func(markerClass) int { t.window.Print(indent) return indentSize @@ -3378,13 +3378,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu } return indentSize } - 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) + finalLineNum = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true, !matched, line, maxLine, forceRedraw, preTask, postTask) } else { preTask := func(marker markerClass) int { w := t.window.Width() - t.pointerLen @@ -3418,11 +3412,7 @@ 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) + finalLineNum = t.printHighlighted(result, base, match, false, true, !matched, line, maxLine, forceRedraw, preTask, postTask) } for i := 0; i < t.gap && finalLineNum < maxLine; i++ { finalLineNum++ @@ -3469,7 +3459,7 @@ func (t *Terminal) overflow(runes []rune, max int) bool { return t.displayWidthWithLimit(runes, 0, max) > max } -func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMatch tui.ColorPair, current bool, match bool, lineNum int, maxLineNum int, forceRedraw bool, preTask func(markerClass) int, postTask func(int, int, bool, bool, tui.ColorPair)) int { +func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMatch tui.ColorPair, current bool, match bool, hidden bool, lineNum int, maxLineNum int, forceRedraw bool, preTask func(markerClass) int, postTask func(int, int, bool, bool, tui.ColorPair)) int { var displayWidth int item := result.item matchOffsets := []Offset{} @@ -3521,7 +3511,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat sort.Sort(ByOrder(nthOffsets)) } } - allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr) + allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr, hidden) maxLines := 1 if t.canSpanMultiLines() { diff --git a/src/tui/tui.go b/src/tui/tui.go index 563d3c2a..33fb626f 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -16,6 +16,7 @@ const ( AttrClear = Attr(1 << 9) BoldForce = Attr(1 << 10) FullBg = Attr(1 << 11) + Strip = Attr(1 << 12) ) func (a Attr) Merge(b Attr) Attr { @@ -384,6 +385,10 @@ func (p ColorPair) IsFullBgMarker() bool { return p.attr&FullBg > 0 } +func (p ColorPair) ShouldStripColors() bool { + return p.attr&Strip > 0 +} + func (p ColorPair) HasBg() bool { return p.attr&Reverse == 0 && p.bg != colDefault || p.attr&Reverse > 0 && p.fg != colDefault