From 3db6b88d82d77f29478771f416fcab708e841fc4 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Thu, 12 Dec 2019 23:03:17 +0900 Subject: [PATCH] Add preview-fg and preview-bg for --color Close #1776 --- CHANGELOG.md | 8 +++++++- man/man1/fzf-tmux.1 | 2 +- man/man1/fzf.1 | 34 ++++++++++++++++++---------------- src/options.go | 4 ++++ src/terminal.go | 19 ++++++++++--------- src/tui/dummy.go | 2 +- src/tui/light.go | 21 +++++++++++++-------- src/tui/tcell.go | 37 +++++++++++++++++++++++-------------- src/tui/tui.go | 20 +++++++++++++++++++- 9 files changed, 96 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c0d3a67..fda3315d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,14 @@ CHANGELOG ========= -0.19.1 (WIP) +0.20.0 (WIP) ------ +- Customizable preview window color (`preview-fg` and `preview-bg` for `--color`) + ```sh + fzf --preview 'cat {}' \ + --color 'fg:#bbccdd,fg+:#ddeeff,bg:#334455,preview-bg:#223344,border:#778899' \ + --border --height 20 --layout reverse --info inline + ``` - Removed the immediate flicking of the screen on `reload` action. ```sh : | fzf --bind 'change:reload:seq {q}' --phony diff --git a/man/man1/fzf-tmux.1 b/man/man1/fzf-tmux.1 index 6a5ee467..30a9ebb4 100644 --- a/man/man1/fzf-tmux.1 +++ b/man/man1/fzf-tmux.1 @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf-tmux 1 "Nov 2019" "fzf 0.19.0" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Dec 2019" "fzf 0.20.0" "fzf-tmux - open fzf in tmux split pane" .SH NAME fzf-tmux - open fzf in tmux split pane diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index db7d2870..1c281691 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Nov 2019" "fzf 0.19.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Dec 2019" "fzf 0.20.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -262,23 +262,25 @@ format. \fBdark \fRColor scheme for dark 256-color terminal \fBlight \fRColor scheme for light 256-color terminal \fB16 \fRColor scheme for 16-color terminal - \fBbw \fRNo colors + \fBbw \fRNo colors (equivalent to \fB--no-color\fR) .B COLOR: - \fBfg \fRText - \fBbg \fRBackground - \fBhl \fRHighlighted substrings - \fBfg+ \fRText (current line) - \fBbg+ \fRBackground (current line) - \fBgutter \fRGutter on the left (defaults to \fBbg+\fR) - \fBhl+ \fRHighlighted substrings (current line) - \fBinfo \fRInfo - \fBborder \fRBorder of the preview window and horizontal separators (\fB--border\fR) - \fBprompt \fRPrompt - \fBpointer \fRPointer to the current line - \fBmarker \fRMulti-select marker - \fBspinner \fRStreaming input indicator - \fBheader \fRHeader + \fBfg \fRText + \fBbg \fRBackground + \fBpreview-fg \fRPreview window text + \fBpreview-bg \fRPreview window background + \fBhl \fRHighlighted substrings + \fBfg+ \fRText (current line) + \fBbg+ \fRBackground (current line) + \fBgutter \fRGutter on the left (defaults to \fBbg+\fR) + \fBhl+ \fRHighlighted substrings (current line) + \fBinfo \fRInfo + \fBborder \fRBorder of the preview window and horizontal separators (\fB--border\fR) + \fBprompt \fRPrompt + \fBpointer \fRPointer to the current line + \fBmarker \fRMulti-select marker + \fBspinner \fRStreaming input indicator + \fBheader \fRHeader .B EXAMPLES: diff --git a/src/options.go b/src/options.go index bd88f23f..20d18589 100644 --- a/src/options.go +++ b/src/options.go @@ -597,6 +597,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme { theme.Fg = ansi case "bg": theme.Bg = ansi + case "preview-fg": + theme.PreviewFg = ansi + case "preview-bg": + theme.PreviewBg = ansi case "fg+": theme.Current = ansi case "bg+": diff --git a/src/terminal.go b/src/terminal.go index 87789a51..9a72d08d 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -624,7 +624,8 @@ func (t *Terminal) resizeWindows() { marginInt[0]-1, marginInt[3], width, - height+2, tui.MakeBorderStyle(tui.BorderHorizontal, t.unicode)) + height+2, + false, tui.MakeBorderStyle(tui.BorderHorizontal, t.unicode)) } noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode) if previewVisible { @@ -633,7 +634,7 @@ func (t *Terminal) resizeWindows() { if !t.preview.border { previewBorder = tui.MakeTransparentBorder() } - t.pborder = t.tui.NewWindow(y, x, w, h, previewBorder) + t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder) pwidth := w - 4 // ncurses auto-wraps the line when the cursor reaches the right-end of // the window. To prevent unintended line-wraps, we use the width one @@ -641,28 +642,28 @@ func (t *Terminal) resizeWindows() { if !t.preview.wrap && t.tui.DoesAutoWrap() { pwidth += 1 } - t.pwindow = t.tui.NewWindow(y+1, x+2, pwidth, h-2, noBorder) + t.pwindow = t.tui.NewWindow(y+1, x+2, pwidth, h-2, true, noBorder) } switch t.preview.position { case posUp: pheight := calculateSize(height, t.preview.size, minHeight, 3) t.window = t.tui.NewWindow( - marginInt[0]+pheight, marginInt[3], width, height-pheight, noBorder) + marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder) createPreviewWindow(marginInt[0], marginInt[3], width, pheight) case posDown: pheight := calculateSize(height, t.preview.size, minHeight, 3) t.window = t.tui.NewWindow( - marginInt[0], marginInt[3], width, height-pheight, noBorder) + marginInt[0], marginInt[3], width, height-pheight, false, noBorder) createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight) case posLeft: pwidth := calculateSize(width, t.preview.size, minWidth, 5) t.window = t.tui.NewWindow( - marginInt[0], marginInt[3]+pwidth, width-pwidth, height, noBorder) + marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder) createPreviewWindow(marginInt[0], marginInt[3], pwidth, height) case posRight: pwidth := calculateSize(width, t.preview.size, minWidth, 5) t.window = t.tui.NewWindow( - marginInt[0], marginInt[3], width-pwidth, height, noBorder) + marginInt[0], marginInt[3], width-pwidth, height, false, noBorder) createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height) } } else { @@ -670,7 +671,7 @@ func (t *Terminal) resizeWindows() { marginInt[0], marginInt[3], width, - height, noBorder) + height, false, noBorder) } for i := 0; i < t.window.Height(); i++ { t.window.MoveAndClear(i, 0) @@ -1071,7 +1072,7 @@ func (t *Terminal) printPreview() { if t.theme != nil && ansi != nil && ansi.colored() { fillRet = t.pwindow.CFill(ansi.fg, ansi.bg, ansi.attr, str) } else { - fillRet = t.pwindow.CFill(tui.ColNormal.Fg(), tui.ColNormal.Bg(), tui.AttrRegular, str) + fillRet = t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, str) } return fillRet == tui.FillContinue }) diff --git a/src/tui/dummy.go b/src/tui/dummy.go index 3965c9ea..76a16e55 100644 --- a/src/tui/dummy.go +++ b/src/tui/dummy.go @@ -39,6 +39,6 @@ func (r *FullscreenRenderer) MaxY() int { return 0 } func (r *FullscreenRenderer) RefreshWindows(windows []Window) {} -func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window { +func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window { return nil } diff --git a/src/tui/light.go b/src/tui/light.go index d1020a99..5c4fadf7 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -666,7 +666,7 @@ func (r *LightRenderer) DoesAutoWrap() bool { return false } -func (r *LightRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window { +func (r *LightRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window { w := &LightWindow{ renderer: r, colored: r.theme != nil, @@ -679,8 +679,13 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, bord fg: colDefault, bg: colDefault} if r.theme != nil { - w.fg = r.theme.Fg - w.bg = r.theme.Bg + if preview { + w.fg = r.theme.PreviewFg + w.bg = r.theme.PreviewBg + } else { + w.fg = r.theme.Fg + w.bg = r.theme.Bg + } } w.drawBorder() return w @@ -704,16 +709,16 @@ func (w *LightWindow) drawBorderHorizontal() { func (w *LightWindow) drawBorderAround() { w.Move(0, 0) - w.CPrint(ColBorder, AttrRegular, + w.CPrint(ColPreviewBorder, AttrRegular, string(w.border.topLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.topRight)) for y := 1; y < w.height-1; y++ { w.Move(y, 0) - w.CPrint(ColBorder, AttrRegular, string(w.border.vertical)) - w.cprint2(colDefault, w.bg, AttrRegular, repeat(' ', w.width-2)) - w.CPrint(ColBorder, AttrRegular, string(w.border.vertical)) + w.CPrint(ColPreviewBorder, AttrRegular, string(w.border.vertical)) + w.CPrint(ColPreviewBorder, AttrRegular, repeat(' ', w.width-2)) + w.CPrint(ColPreviewBorder, AttrRegular, string(w.border.vertical)) } w.Move(w.height-1, 0) - w.CPrint(ColBorder, AttrRegular, + w.CPrint(ColPreviewBorder, AttrRegular, string(w.border.bottomLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.bottomRight)) } diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 4bd7c812..339f7dff 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -32,6 +32,7 @@ type TcellWindow struct { left int width int height int + normal ColorPair lastX int lastY int moveCursor bool @@ -408,14 +409,18 @@ func (r *FullscreenRenderer) RefreshWindows(windows []Window) { _screen.Show() } -func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window { - // TODO +func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window { + normal := ColNormal + if preview { + normal = ColPreview + } return &TcellWindow{ color: r.theme != nil, top: top, left: left, width: width, height: height, + normal: normal, borderStyle: borderStyle} } @@ -423,16 +428,16 @@ func (w *TcellWindow) Close() { // TODO } -func fill(x, y, w, h int, r rune) { +func fill(x, y, w, h int, n ColorPair, r rune) { for ly := 0; ly <= h; ly++ { for lx := 0; lx <= w; lx++ { - _screen.SetContent(x+lx, y+ly, r, nil, ColNormal.style()) + _screen.SetContent(x+lx, y+ly, r, nil, n.style()) } } } func (w *TcellWindow) Erase() { - fill(w.left-1, w.top, w.width+1, w.height, ' ') + fill(w.left-1, w.top, w.width+1, w.height, w.normal, ' ') } func (w *TcellWindow) Enclose(y int, x int) bool { @@ -449,13 +454,13 @@ func (w *TcellWindow) Move(y int, x int) { func (w *TcellWindow) MoveAndClear(y int, x int) { w.Move(y, x) for i := w.lastX; i < w.width; i++ { - _screen.SetContent(i+w.left, w.lastY+w.top, rune(' '), nil, ColNormal.style()) + _screen.SetContent(i+w.left, w.lastY+w.top, rune(' '), nil, w.normal.style()) } w.lastX = x } func (w *TcellWindow) Print(text string) { - w.printString(text, ColNormal, 0) + w.printString(text, w.normal, 0) } func (w *TcellWindow) printString(text string, pair ColorPair, a Attr) { @@ -468,7 +473,7 @@ func (w *TcellWindow) printString(text string, pair ColorPair, a Attr) { Reverse(a&Attr(tcell.AttrReverse) != 0). Underline(a&Attr(tcell.AttrUnderline) != 0) } else { - style = ColNormal.style(). + style = w.normal.style(). Reverse(a&Attr(tcell.AttrReverse) != 0 || pair == ColCurrent || pair == ColCurrentMatch). Underline(a&Attr(tcell.AttrUnderline) != 0 || pair == ColMatch || pair == ColCurrentMatch) } @@ -519,7 +524,7 @@ func (w *TcellWindow) fillString(text string, pair ColorPair, a Attr) FillReturn if w.color { style = pair.style() } else { - style = ColNormal.style() + style = w.normal.style() } style = style. Blink(a&Attr(tcell.AttrBlink) != 0). @@ -559,15 +564,15 @@ func (w *TcellWindow) fillString(text string, pair ColorPair, a Attr) FillReturn } func (w *TcellWindow) Fill(str string) FillReturn { - return w.fillString(str, ColNormal, 0) + return w.fillString(str, w.normal, 0) } func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn { if fg == colDefault { - fg = ColNormal.Fg() + fg = w.normal.Fg() } if bg == colDefault { - bg = ColNormal.Bg() + bg = w.normal.Bg() } return w.fillString(str, NewColorPair(fg, bg), a) } @@ -584,9 +589,13 @@ func (w *TcellWindow) drawBorder() { var style tcell.Style if w.color { - style = ColBorder.style() + if w.borderStyle.shape == BorderAround { + style = ColPreviewBorder.style() + } else { + style = ColBorder.style() + } } else { - style = ColNormal.style() + style = w.normal.style() } for x := left; x < right; x++ { diff --git a/src/tui/tui.go b/src/tui/tui.go index 4ec852e3..9af11472 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -173,6 +173,8 @@ func (p ColorPair) Bg() Color { type ColorTheme struct { Fg Color Bg Color + PreviewFg Color + PreviewBg Color DarkBg Color Gutter Color Prompt Color @@ -272,7 +274,7 @@ type Renderer interface { MaxY() int DoesAutoWrap() bool - NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window + NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window } type Window interface { @@ -334,12 +336,16 @@ var ( ColInfo ColorPair ColHeader ColorPair ColBorder ColorPair + ColPreview ColorPair + ColPreviewBorder ColorPair ) func EmptyTheme() *ColorTheme { return &ColorTheme{ Fg: colUndefined, Bg: colUndefined, + PreviewFg: colUndefined, + PreviewBg: colUndefined, DarkBg: colUndefined, Gutter: colUndefined, Prompt: colUndefined, @@ -363,6 +369,8 @@ func init() { Default16 = &ColorTheme{ Fg: colDefault, Bg: colDefault, + PreviewFg: colUndefined, + PreviewBg: colUndefined, DarkBg: colBlack, Gutter: colUndefined, Prompt: colBlue, @@ -378,6 +386,8 @@ func init() { Dark256 = &ColorTheme{ Fg: colDefault, Bg: colDefault, + PreviewFg: colUndefined, + PreviewBg: colUndefined, DarkBg: 236, Gutter: colUndefined, Prompt: 110, @@ -393,6 +403,8 @@ func init() { Light256 = &ColorTheme{ Fg: colDefault, Bg: colDefault, + PreviewFg: colUndefined, + PreviewBg: colUndefined, DarkBg: 251, Gutter: colUndefined, Prompt: 25, @@ -425,6 +437,8 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) { } theme.Fg = o(baseTheme.Fg, theme.Fg) theme.Bg = o(baseTheme.Bg, theme.Bg) + theme.PreviewFg = o(theme.Fg, o(baseTheme.PreviewFg, theme.PreviewFg)) + theme.PreviewBg = o(theme.Bg, o(baseTheme.PreviewBg, theme.PreviewBg)) theme.DarkBg = o(baseTheme.DarkBg, theme.DarkBg) theme.Gutter = o(theme.DarkBg, o(baseTheme.Gutter, theme.Gutter)) theme.Prompt = o(baseTheme.Prompt, theme.Prompt) @@ -461,6 +475,8 @@ func initPalette(theme *ColorTheme) { ColInfo = pair(theme.Info, theme.Bg) ColHeader = pair(theme.Header, theme.Bg) ColBorder = pair(theme.Border, theme.Bg) + ColPreview = pair(theme.PreviewFg, theme.PreviewBg) + ColPreviewBorder = pair(theme.Border, theme.PreviewBg) } else { ColPrompt = pair(colDefault, colDefault) ColNormal = pair(colDefault, colDefault) @@ -475,6 +491,8 @@ func initPalette(theme *ColorTheme) { ColInfo = pair(colDefault, colDefault) ColHeader = pair(colDefault, colDefault) ColBorder = pair(colDefault, colDefault) + ColPreview = pair(colDefault, colDefault) + ColPreviewBorder = pair(colDefault, colDefault) } }