From af65aa298abe8920c20ee6a96e255e735cfedc5a Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Tue, 7 May 2024 23:38:06 +0900 Subject: [PATCH] Add color names: selected-{fg,bg,hl} --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ man/man1/fzf.1 | 3 +++ src/options.go | 8 +++++++- src/terminal.go | 22 +++++++++++++++++----- src/tui/tui.go | 49 +++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 93 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd594864..d4736bbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,33 @@ CHANGELOG ========= +0.52.0 +------ +- Added `--highlight-line` to highlight the whole current line (à la `set cursorline` of Vim) +- Added color names for selected lines: `selected-fg`, `selected-bg`, and `selected-hl` + ```sh + fzf --border --multi --info inline-right --layout reverse --marker ▏ --pointer ▌ \ + --highlight-line --color gutter:-1,selected-bg:238,selected-fg:146,current-fg:189 + ``` +- Added `click-header` event that is triggered when the header section is clicked. When the event is triggered, `$FZF_CLICK_HEADER_COLUMN` and `$FZF_CLICK_HEADER_LINE` are set. + ```sh + fd --type f | + fzf --header $'[Files] [Directories]' --header-first \ + --bind 'click-header:transform: + (( FZF_CLICK_HEADER_COLUMN <= 7 )) && echo "reload(fd --type f)" + (( FZF_CLICK_HEADER_COLUMN >= 9 )) && echo "reload(fd --type d)" + ' + ``` +- Add `$FZF_COMPLETION_{DIR,PATH}_OPTS` for separately customizing the behavior of fuzzy completion + ```sh + # Set --walker options without 'follow' not to follow symbolic links + FZF_COMPLETION_PATH_OPTS="--walker=file,dir,hidden" + FZF_COMPLETION_DIR_OPTS="--walker=dir,hidden" + ``` +- Fixed Windows argument escaping +- Bug fixes and improvements +- The code was heavily refactored to allow using fzf as a library in Go programs. The API is still experimental and subject to change. + 0.51.0 ------ - Added a new environment variable `$FZF_POS` exported to the child processes. It's the vertical position of the cursor in the list starting from 1. diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 6c417482..048ac05f 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -464,10 +464,13 @@ color mappings. .B COLOR NAMES: \fBfg \fRText + \fBselected-fg \fRSelected line text \fBpreview-fg \fRPreview window text \fBbg \fRBackground + \fBselected-bg \fRSelected line background \fBpreview-bg \fRPreview window background \fBhl \fRHighlighted substrings + \fBselected-hl \fRHighlighted substrings in the selected line \fBcurrent-fg (fg+) \fRText (current line) \fBcurrent-bg (bg+) \fRBackground (current line) \fBgutter \fRGutter on the left diff --git a/src/options.go b/src/options.go index e2ddca6b..5a4a9530 100644 --- a/src/options.go +++ b/src/options.go @@ -986,12 +986,18 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro mergeAttr(&theme.Current) case "current-bg", "bg+": mergeAttr(&theme.DarkBg) + case "selected-fg": + mergeAttr(&theme.SelectedFg) + case "selected-bg": + mergeAttr(&theme.SelectedBg) case "gutter": mergeAttr(&theme.Gutter) case "hl": mergeAttr(&theme.Match) case "current-hl", "hl+": mergeAttr(&theme.CurrentMatch) + case "selected-hl": + mergeAttr(&theme.SelectedMatch) case "border": mergeAttr(&theme.Border) case "preview-border": @@ -1015,7 +1021,7 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro case "pointer": mergeAttr(&theme.Cursor) case "marker": - mergeAttr(&theme.Selected) + mergeAttr(&theme.Marker) case "header": mergeAttr(&theme.Header) default: diff --git a/src/terminal.go b/src/terminal.go index 93e5c6f4..bdbc6bba 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1902,7 +1902,7 @@ func (t *Terminal) printItem(result Result, line int, i int, current bool, bar b t.window.CPrint(tui.ColCurrentCursor, label) } if selected { - t.window.CPrint(tui.ColCurrentSelected, t.marker) + t.window.CPrint(tui.ColCurrentMarker, t.marker) } else { t.window.CPrint(tui.ColCurrentSelectedEmpty, t.markerEmpty) } @@ -1914,18 +1914,30 @@ func (t *Terminal) printItem(result Result, line int, i int, current bool, bar b t.window.CPrint(tui.ColCursor, label) } if selected { - t.window.CPrint(tui.ColSelected, t.marker) + t.window.CPrint(tui.ColMarker, t.marker) } else { t.window.Print(t.markerEmpty) } - newLine.width = t.printHighlighted(result, tui.ColNormal, tui.ColMatch, false, true) + var base, match tui.ColorPair + if selected { + base = tui.ColSelected + match = tui.ColSelectedMatch + } else { + base = tui.ColNormal + match = tui.ColMatch + } + newLine.width = t.printHighlighted(result, base, match, false, true) } - if current && t.highlightLine { + if (current || selected) && t.highlightLine { + color := tui.ColSelected + if current { + color = tui.ColCurrent + } maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1) fillSpaces := maxWidth - newLine.width newLine.width = maxWidth if fillSpaces > 0 { - t.window.CPrint(tui.ColCurrent, strings.Repeat(" ", fillSpaces)) + t.window.CPrint(color, strings.Repeat(" ", fillSpaces)) } } else { fillSpaces := prevLine.width - newLine.width diff --git a/src/tui/tui.go b/src/tui/tui.go index e4858c66..aed41a9d 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -303,6 +303,9 @@ type ColorTheme struct { Disabled ColorAttr Fg ColorAttr Bg ColorAttr + SelectedFg ColorAttr + SelectedBg ColorAttr + SelectedMatch ColorAttr PreviewFg ColorAttr PreviewBg ColorAttr DarkBg ColorAttr @@ -314,7 +317,7 @@ type ColorTheme struct { Spinner ColorAttr Info ColorAttr Cursor ColorAttr - Selected ColorAttr + Marker ColorAttr Header ColorAttr Separator ColorAttr Scrollbar ColorAttr @@ -603,12 +606,14 @@ var ( ColMatch ColorPair ColCursor ColorPair ColCursorEmpty ColorPair + ColMarker ColorPair ColSelected ColorPair + ColSelectedMatch ColorPair ColCurrent ColorPair ColCurrentMatch ColorPair ColCurrentCursor ColorPair ColCurrentCursorEmpty ColorPair - ColCurrentSelected ColorPair + ColCurrentMarker ColorPair ColCurrentSelectedEmpty ColorPair ColSpinner ColorPair ColInfo ColorPair @@ -630,6 +635,9 @@ func EmptyTheme() *ColorTheme { Input: ColorAttr{colUndefined, AttrUndefined}, Fg: ColorAttr{colUndefined, AttrUndefined}, Bg: ColorAttr{colUndefined, AttrUndefined}, + SelectedFg: ColorAttr{colUndefined, AttrUndefined}, + SelectedBg: ColorAttr{colUndefined, AttrUndefined}, + SelectedMatch: ColorAttr{colUndefined, AttrUndefined}, DarkBg: ColorAttr{colUndefined, AttrUndefined}, Prompt: ColorAttr{colUndefined, AttrUndefined}, Match: ColorAttr{colUndefined, AttrUndefined}, @@ -638,7 +646,7 @@ func EmptyTheme() *ColorTheme { Spinner: ColorAttr{colUndefined, AttrUndefined}, Info: ColorAttr{colUndefined, AttrUndefined}, Cursor: ColorAttr{colUndefined, AttrUndefined}, - Selected: ColorAttr{colUndefined, AttrUndefined}, + Marker: ColorAttr{colUndefined, AttrUndefined}, Header: ColorAttr{colUndefined, AttrUndefined}, Border: ColorAttr{colUndefined, AttrUndefined}, BorderLabel: ColorAttr{colUndefined, AttrUndefined}, @@ -660,6 +668,9 @@ func NoColorTheme() *ColorTheme { Input: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined}, + SelectedFg: ColorAttr{colDefault, AttrUndefined}, + SelectedBg: ColorAttr{colDefault, AttrUndefined}, + SelectedMatch: ColorAttr{colDefault, AttrUndefined}, DarkBg: ColorAttr{colDefault, AttrUndefined}, Prompt: ColorAttr{colDefault, AttrUndefined}, Match: ColorAttr{colDefault, Underline}, @@ -668,7 +679,7 @@ func NoColorTheme() *ColorTheme { Spinner: ColorAttr{colDefault, AttrUndefined}, Info: ColorAttr{colDefault, AttrUndefined}, Cursor: ColorAttr{colDefault, AttrUndefined}, - Selected: ColorAttr{colDefault, AttrUndefined}, + Marker: ColorAttr{colDefault, AttrUndefined}, Header: ColorAttr{colDefault, AttrUndefined}, Border: ColorAttr{colDefault, AttrUndefined}, BorderLabel: ColorAttr{colDefault, AttrUndefined}, @@ -690,6 +701,9 @@ func init() { Input: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined}, + SelectedFg: ColorAttr{colDefault, AttrUndefined}, + SelectedBg: ColorAttr{colDefault, AttrUndefined}, + SelectedMatch: ColorAttr{colDefault, AttrUndefined}, DarkBg: ColorAttr{colBlack, AttrUndefined}, Prompt: ColorAttr{colBlue, AttrUndefined}, Match: ColorAttr{colGreen, AttrUndefined}, @@ -698,7 +712,7 @@ func init() { Spinner: ColorAttr{colGreen, AttrUndefined}, Info: ColorAttr{colWhite, AttrUndefined}, Cursor: ColorAttr{colRed, AttrUndefined}, - Selected: ColorAttr{colMagenta, AttrUndefined}, + Marker: ColorAttr{colMagenta, AttrUndefined}, Header: ColorAttr{colCyan, AttrUndefined}, Border: ColorAttr{colBlack, AttrUndefined}, BorderLabel: ColorAttr{colWhite, AttrUndefined}, @@ -717,6 +731,9 @@ func init() { Input: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined}, + SelectedFg: ColorAttr{colDefault, AttrUndefined}, + SelectedBg: ColorAttr{colDefault, AttrUndefined}, + SelectedMatch: ColorAttr{colDefault, AttrUndefined}, DarkBg: ColorAttr{236, AttrUndefined}, Prompt: ColorAttr{110, AttrUndefined}, Match: ColorAttr{108, AttrUndefined}, @@ -725,7 +742,7 @@ func init() { Spinner: ColorAttr{148, AttrUndefined}, Info: ColorAttr{144, AttrUndefined}, Cursor: ColorAttr{161, AttrUndefined}, - Selected: ColorAttr{168, AttrUndefined}, + Marker: ColorAttr{168, AttrUndefined}, Header: ColorAttr{109, AttrUndefined}, Border: ColorAttr{59, AttrUndefined}, BorderLabel: ColorAttr{145, AttrUndefined}, @@ -744,6 +761,9 @@ func init() { Input: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined}, + SelectedFg: ColorAttr{colDefault, AttrUndefined}, + SelectedBg: ColorAttr{colDefault, AttrUndefined}, + SelectedMatch: ColorAttr{colDefault, AttrUndefined}, DarkBg: ColorAttr{251, AttrUndefined}, Prompt: ColorAttr{25, AttrUndefined}, Match: ColorAttr{66, AttrUndefined}, @@ -752,7 +772,7 @@ func init() { Spinner: ColorAttr{65, AttrUndefined}, Info: ColorAttr{101, AttrUndefined}, Cursor: ColorAttr{161, AttrUndefined}, - Selected: ColorAttr{168, AttrUndefined}, + Marker: ColorAttr{168, AttrUndefined}, Header: ColorAttr{31, AttrUndefined}, Border: ColorAttr{145, AttrUndefined}, BorderLabel: ColorAttr{59, AttrUndefined}, @@ -794,12 +814,15 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) { theme.Spinner = o(baseTheme.Spinner, theme.Spinner) theme.Info = o(baseTheme.Info, theme.Info) theme.Cursor = o(baseTheme.Cursor, theme.Cursor) - theme.Selected = o(baseTheme.Selected, theme.Selected) + theme.Marker = o(baseTheme.Marker, theme.Marker) theme.Header = o(baseTheme.Header, theme.Header) theme.Border = o(baseTheme.Border, theme.Border) theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel) // These colors are not defined in the base themes + theme.SelectedFg = o(theme.Fg, theme.SelectedFg) + theme.SelectedBg = o(theme.Bg, theme.SelectedBg) + theme.SelectedMatch = o(theme.CurrentMatch, theme.SelectedMatch) theme.Disabled = o(theme.Input, theme.Disabled) theme.Gutter = o(theme.DarkBg, theme.Gutter) theme.PreviewFg = o(theme.Fg, theme.PreviewFg) @@ -825,17 +848,23 @@ func initPalette(theme *ColorTheme) { ColPrompt = pair(theme.Prompt, theme.Bg) ColNormal = pair(theme.Fg, theme.Bg) + ColSelected = pair(theme.SelectedFg, theme.SelectedBg) ColInput = pair(theme.Input, theme.Bg) ColDisabled = pair(theme.Disabled, theme.Bg) ColMatch = pair(theme.Match, theme.Bg) + ColSelectedMatch = pair(theme.SelectedMatch, theme.SelectedBg) ColCursor = pair(theme.Cursor, theme.Gutter) ColCursorEmpty = pair(blank, theme.Gutter) - ColSelected = pair(theme.Selected, theme.Gutter) + if theme.SelectedBg.Color != theme.Bg.Color { + ColMarker = pair(theme.Marker, theme.SelectedBg) + } else { + ColMarker = pair(theme.Marker, theme.Gutter) + } ColCurrent = pair(theme.Current, theme.DarkBg) ColCurrentMatch = pair(theme.CurrentMatch, theme.DarkBg) ColCurrentCursor = pair(theme.Cursor, theme.DarkBg) ColCurrentCursorEmpty = pair(blank, theme.DarkBg) - ColCurrentSelected = pair(theme.Selected, theme.DarkBg) + ColCurrentMarker = pair(theme.Marker, theme.DarkBg) ColCurrentSelectedEmpty = pair(blank, theme.DarkBg) ColSpinner = pair(theme.Spinner, theme.Bg) ColInfo = pair(theme.Info, theme.Bg)