Make 'current-fg' inherit from 'fg' to simplify configuration

If you do not want 'current-fg' to inherit attributes of 'fg', prefix it
with 'regular:' to reset them.

  # italic and underline
  fzf --color fg:italic,current-fg:underline

  # only underline
  fzf --color fg:italic,current-fg:regular:underline
This commit is contained in:
Junegunn Choi
2025-01-20 00:49:08 +09:00
parent f1c1b02d77
commit a4db8bd7b5
9 changed files with 70 additions and 49 deletions

View File

@@ -90,11 +90,11 @@ Also, fzf now offers "style presets" for quick customization, which can be activ
ls -al | fzf --nth -1 --color nth:reverse:bold
# Dim the other parts
ls -al | fzf --nth -1 --color nth:regular,fg:dim,current-fg:dim
ls -al | fzf --nth -1 --color nth:regular,fg:dim
# With 'change-nth'. The current nth option is exported as $FZF_NTH.
ps -ef | fzf --reverse --header-lines 1 --header-border bottom --input-border \
--color nth:regular,fg:dim,current-fg:dim \
--color nth:regular,fg:dim \
--bind 'ctrl-n:change-nth(8..|1|2|3|4|5|6|7|)' \
--bind 'result:transform-prompt:echo "${FZF_NTH}> "'
```

View File

@@ -44,7 +44,7 @@ func (s *ansiState) ToString() string {
}
ret := ""
if s.attr&tui.Bold > 0 {
if s.attr&tui.Bold > 0 || s.attr&tui.BoldForce > 0 {
ret += "1;"
}
if s.attr&tui.Dim > 0 {

View File

@@ -3135,7 +3135,7 @@ func postProcessOptions(opts *Options) error {
boldify := func(c tui.ColorAttr) tui.ColorAttr {
dup := c
if (c.Attr & tui.AttrRegular) == 0 {
dup.Attr |= tui.Bold
dup.Attr |= tui.BoldForce
}
return dup
}

View File

@@ -150,10 +150,6 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
}
for _, off := range nthOffsets {
// Exclude the whole line
if int(off[1])-int(off[0]) == result.item.text.Length() {
continue
}
for i := off[0]; i < off[1]; i++ {
cols[i].nth = true
}
@@ -190,7 +186,12 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
add := func(idx int) {
if (curr.color || curr.nth || curr.match) && idx > start {
if curr.match {
color := colMatch
var color tui.ColorPair
if curr.nth {
color = colBase.WithAttr(attrNth).Merge(colMatch)
} else {
color = colBase.Merge(colMatch)
}
var url *url
if curr.color && theme.Colored {
ansi := itemColors[curr.index]
@@ -206,13 +207,13 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
// echo -e "\x1b[42mfoo\x1b[mbar" | fzf --ansi --color bg+:1,hl+:-1:underline
if color.Fg().IsDefault() && origColor.HasBg() {
color = origColor
if curr.nth {
color = color.WithAttr(attrNth)
}
} else {
color = origColor.MergeNonDefault(color)
}
}
if curr.nth {
color = color.WithAttr(attrNth)
}
colors = append(colors, colorOffset{
offset: [2]int32{int32(start), int32(idx)}, color: color, match: true, url: url})
} else if curr.color {

View File

@@ -2725,6 +2725,9 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
sort.Sort(ByOrder(charOffsets))
}
// When postTask is nil, we're printing header lines. No need to care about nth.
var nthOffsets []Offset
if postTask != nil {
wholeCovered := len(t.nthCurrent) == 0
for _, nth := range t.nthCurrent {
// Do we still want to apply a different style when the current nth
@@ -2734,17 +2737,13 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
break
}
}
if wholeCovered && t.nthAttr&tui.AttrRegular > 0 {
// But if 'nth' is set to 'regular', it's a sign that you're applying
// a different style to the rest of the string. e.g. 'nth:regular,fg:dim'
// In this case, we still need to apply and clear the style.
// We do the same when postTask is nil, which means we're printing header lines.
if t.nthAttr == tui.AttrRegular && wholeCovered || postTask == nil {
if t.nthAttr == tui.AttrRegular {
// In this case, we still need to apply it to clear the style.
colBase = colBase.WithAttr(t.nthAttr)
}
}
var nthOffsets []Offset
if !wholeCovered && t.nthAttr > 0 && postTask != nil {
if !wholeCovered && t.nthAttr > 0 {
var tokens []Token
if item.transformed != nil {
tokens = item.transformed.tokens
@@ -2758,6 +2757,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, current)
maxLines := 1

View File

@@ -11,8 +11,9 @@ func HasFullscreenRenderer() bool {
var DefaultBorderShape = BorderRounded
func (a Attr) Merge(b Attr) Attr {
if b == AttrRegular {
return b
if b&AttrRegular > 0 {
// Only keep bold attribute set by the system
return b | (a & BoldForce)
}
return a | b
@@ -22,6 +23,7 @@ const (
AttrUndefined = Attr(0)
AttrRegular = Attr(1 << 8)
AttrClear = Attr(1 << 9)
BoldForce = Attr(1 << 10)
Bold = Attr(1)
Dim = Attr(1 << 1)

View File

@@ -1011,7 +1011,7 @@ func attrCodes(attr Attr) []string {
if (attr & AttrClear) > 0 {
return codes
}
if (attr & Bold) > 0 {
if (attr&Bold) > 0 || (attr&BoldForce) > 0 {
codes = append(codes, "1")
}
if (attr & Dim) > 0 {

View File

@@ -97,6 +97,7 @@ const (
AttrUndefined = Attr(0)
AttrRegular = Attr(1 << 7)
AttrClear = Attr(1 << 8)
BoldForce = Attr(1 << 10)
)
func (r *FullscreenRenderer) PassThrough(str string) {
@@ -141,6 +142,11 @@ func (c Color) Style() tcell.Color {
}
func (a Attr) Merge(b Attr) Attr {
if b&AttrRegular > 0 {
// Only keep bold attribute set by the system
return b | (a & BoldForce)
}
return a | b
}
@@ -556,13 +562,13 @@ func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int,
normal := ColBorder
switch windowType {
case WindowList:
normal = ColListBorder
normal = ColNormal
case WindowHeader:
normal = ColHeaderBorder
normal = ColHeader
case WindowInput:
normal = ColInputBorder
normal = ColInput
case WindowPreview:
normal = ColPreviewBorder
normal = ColPreview
}
w := &TcellWindow{
color: r.theme.Colored,
@@ -694,7 +700,7 @@ func (w *TcellWindow) fillString(text string, pair ColorPair) FillReturn {
}
style = style.
Blink(a&Attr(tcell.AttrBlink) != 0).
Bold(a&Attr(tcell.AttrBold) != 0).
Bold(a&Attr(tcell.AttrBold) != 0 || a&BoldForce != 0).
Dim(a&Attr(tcell.AttrDim) != 0).
Reverse(a&Attr(tcell.AttrReverse) != 0).
Underline(a&Attr(tcell.AttrUnderline) != 0).

View File

@@ -213,6 +213,16 @@ func NewColorAttr() ColorAttr {
return ColorAttr{Color: colUndefined, Attr: AttrUndefined}
}
func (a ColorAttr) Merge(other ColorAttr) ColorAttr {
if other.Color != colUndefined {
a.Color = other.Color
}
if other.Attr != AttrUndefined {
a.Attr = a.Attr.Merge(other.Attr)
}
return a
}
const (
colUndefined Color = -2
colDefault Color = -1
@@ -904,7 +914,9 @@ func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool, hasInp
theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg)
theme.Prompt = o(baseTheme.Prompt, theme.Prompt)
theme.Match = o(baseTheme.Match, theme.Match)
theme.Current = o(baseTheme.Current, theme.Current)
// Inherit from 'fg', so that we don't have to write 'current-fg:dim'
// e.g. fzf --delimiter / --nth -1 --color fg:dim,nth:regular
theme.Current = theme.Fg.Merge(o(baseTheme.Current, theme.Current))
theme.CurrentMatch = o(baseTheme.CurrentMatch, theme.CurrentMatch)
theme.Spinner = o(baseTheme.Spinner, theme.Spinner)
theme.Info = o(baseTheme.Info, theme.Info)