summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2017-02-04 21:51:22 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2017-02-04 21:51:22 +0900
commit4b700192c1f07aa6ba8d0ed7cb9c1b1dcb6f7ddb (patch)
tree611efbf17b9b8e0f71a2d2d68992d3efc9a0378b
parentfe83589ade42e1d6c24b792ec0fa303f07e953e1 (diff)
Add --border option to draw horizontal lines above and below the finder
Goes well with --height
-rw-r--r--CHANGELOG.md5
-rw-r--r--README.md4
-rw-r--r--man/man1/fzf.13
-rw-r--r--src/options.go6
-rw-r--r--src/terminal.go63
-rw-r--r--src/tui/dummy.go2
-rw-r--r--src/tui/light.go30
-rw-r--r--src/tui/ncurses.go5
-rw-r--r--src/tui/tcell.go59
-rw-r--r--src/tui/tui.go10
10 files changed, 127 insertions, 60 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 37ede605..0ea9ee26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+0.16.4
+------
+- Added `--border` option to draw border above and below the finder
+- Bug fixes and improvements
+
0.16.3
------
- Fixed a bug where fzf incorrectly display the lines when straddling tab
diff --git a/README.md b/README.md
index 303ca4cd..c016de49 100644
--- a/README.md
+++ b/README.md
@@ -141,10 +141,10 @@ vim $(fzf --height 40% --reverse)
```
You can add these options to `$FZF_DEFAULT_OPTS` so that they're applied by
-default.
+default. For example,
```sh
-export FZF_DEFAULT_OPTS='--height 40% --reverse'
+export FZF_DEFAULT_OPTS='--height 40% --reverse --border'
```
#### Search syntax
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index f7d3a441..74ac2a49 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -156,6 +156,9 @@ Ignored when \fB--height\fR is not specified.
.B "--reverse"
Reverse orientation
.TP
+.B "--border"
+Draw border above and below the finder
+.TP
.BI "--margin=" MARGIN
Comma-separated expression for margins around the finder.
.br
diff --git a/src/options.go b/src/options.go
index 3fadb4eb..30cc7519 100644
--- a/src/options.go
+++ b/src/options.go
@@ -54,6 +54,7 @@ const usage = `usage: fzf [options]
--min-height=HEIGHT Minimum height when --height is given in percent
(default: 10)
--reverse Reverse orientation
+ --border Draw border above and below the finder
--margin=MARGIN Screen margin (TRBL / TB,RL / T,RL,B / T,R,B,L)
--inline-info Display finder info inline with the query
--prompt=STR Input prompt (default: '> ')
@@ -183,6 +184,7 @@ type Options struct {
Header []string
HeaderLines int
Margin [4]sizeSpec
+ Bordered bool
Tabstop int
Version bool
}
@@ -1086,6 +1088,10 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Height = sizeSpec{}
case "--no-margin":
opts.Margin = defaultMargin()
+ case "--no-border":
+ opts.Bordered = false
+ case "--border":
+ opts.Bordered = true
case "--margin":
opts.Margin = parseMargin(
nextString(allArgs, &i, "margin required (TRBL / TB,RL / T,RL,B / T,R,B,L)"))
diff --git a/src/terminal.go b/src/terminal.go
index 134462ec..5853022a 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -83,8 +83,10 @@ type Terminal struct {
tabstop int
margin [4]sizeSpec
strong tui.Attr
+ bordered bool
+ border tui.Window
window tui.Window
- bwindow tui.Window
+ pborder tui.Window
pwindow tui.Window
count int
progress int
@@ -295,15 +297,22 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
maxHeightFunc := func(termHeight int) int {
var maxHeight int
if opts.Height.percent {
- maxHeight = util.Min(termHeight,
- util.Max(int(opts.Height.size*float64(termHeight)/100.0), opts.MinHeight))
+ maxHeight = util.Max(int(opts.Height.size*float64(termHeight)/100.0), opts.MinHeight)
} else {
- maxHeight = util.Min(termHeight, int(opts.Height.size))
+ maxHeight = int(opts.Height.size)
+ }
+
+ effectiveMinHeight := minHeight
+ if previewBox != nil && (opts.Preview.position == posUp || opts.Preview.position == posDown) {
+ effectiveMinHeight *= 2
}
if opts.InlineInfo {
- return util.Max(maxHeight, minHeight-1)
+ effectiveMinHeight -= 1
+ }
+ if opts.Bordered {
+ effectiveMinHeight += 2
}
- return util.Max(maxHeight, minHeight)
+ return util.Min(termHeight, util.Max(maxHeight, effectiveMinHeight))
}
renderer = tui.NewLightRenderer(opts.Theme, opts.Black, opts.Mouse, opts.Tabstop, maxHeightFunc)
} else if tui.HasFullscreenRenderer() {
@@ -343,6 +352,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
printQuery: opts.PrintQuery,
history: opts.History,
margin: opts.Margin,
+ bordered: opts.Bordered,
strong: strongAttr,
cycle: opts.Cycle,
header: header,
@@ -499,6 +509,9 @@ func (t *Terminal) resizeWindows() {
} else {
marginInt[idx] = int(sizeSpec.size)
}
+ if t.bordered && idx%2 == 0 {
+ marginInt[idx] += 1
+ }
}
adjust := func(idx1 int, idx2 int, max int, min int) {
if max >= min {
@@ -524,19 +537,29 @@ func (t *Terminal) resizeWindows() {
}
adjust(1, 3, screenWidth, minAreaWidth)
adjust(0, 2, screenHeight, minAreaHeight)
+ if t.border != nil {
+ t.border.Close()
+ }
if t.window != nil {
t.window.Close()
}
- if t.bwindow != nil {
- t.bwindow.Close()
+ if t.pborder != nil {
+ t.pborder.Close()
t.pwindow.Close()
}
width := screenWidth - marginInt[1] - marginInt[3]
height := screenHeight - marginInt[0] - marginInt[2]
+ if t.bordered {
+ t.border = t.tui.NewWindow(
+ marginInt[0]-1,
+ marginInt[3],
+ width,
+ height+2, tui.BorderHorizontal)
+ }
if previewVisible {
createPreviewWindow := func(y int, x int, w int, h int) {
- t.bwindow = t.tui.NewWindow(y, x, w, h, true)
+ t.pborder = t.tui.NewWindow(y, x, w, h, tui.BorderAround)
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
@@ -544,28 +567,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, false)
+ t.pwindow = t.tui.NewWindow(y+1, x+2, pwidth, h-2, tui.BorderNone)
}
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, false)
+ marginInt[0]+pheight, marginInt[3], width, height-pheight, tui.BorderNone)
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, false)
+ marginInt[0], marginInt[3], width, height-pheight, tui.BorderNone)
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, false)
+ marginInt[0], marginInt[3]+pwidth, width-pwidth, height, tui.BorderNone)
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, false)
+ marginInt[0], marginInt[3], width-pwidth, height, tui.BorderNone)
createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height)
}
} else {
@@ -573,7 +596,7 @@ func (t *Terminal) resizeWindows() {
marginInt[0],
marginInt[3],
width,
- height, false)
+ height, tui.BorderNone)
}
if !t.tui.IsOptimized() && t.theme != nil && t.theme.HasBg() {
for i := 0; i < t.window.Height(); i++ {
@@ -978,11 +1001,15 @@ func (t *Terminal) printAll() {
func (t *Terminal) refresh() {
if !t.suppress {
+ windows := make([]tui.Window, 0, 4)
+ if t.bordered {
+ windows = append(windows, t.border)
+ }
if t.hasPreviewWindow() {
- t.tui.RefreshWindows([]tui.Window{t.bwindow, t.pwindow, t.window})
- } else {
- t.tui.RefreshWindows([]tui.Window{t.window})
+ windows = append(windows, t.pborder, t.pwindow)
}
+ windows = append(windows, t.window)
+ t.tui.RefreshWindows(windows)
}
}
diff --git a/src/tui/dummy.go b/src/tui/dummy.go
index 01179c89..60a23fb6 100644
--- a/src/tui/dummy.go
+++ b/src/tui/dummy.go
@@ -40,6 +40,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, border bool) Window {
+func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window {
return nil
}
diff --git a/src/tui/light.go b/src/tui/light.go
index 2ce0d5ff..9465c49a 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -95,7 +95,7 @@ type LightRenderer struct {
type LightWindow struct {
renderer *LightRenderer
colored bool
- border bool
+ border BorderStyle
top int
left int
width int
@@ -600,11 +600,11 @@ func (r *LightRenderer) IsOptimized() bool {
return false
}
-func (r *LightRenderer) NewWindow(top int, left int, width int, height int, border bool) Window {
+func (r *LightRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window {
w := &LightWindow{
renderer: r,
colored: r.theme != nil,
- border: border,
+ border: borderStyle,
top: top,
left: left,
width: width,
@@ -614,13 +614,27 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, bord
if r.theme != nil {
w.bg = r.theme.Bg
}
- if w.border {
- w.drawBorder()
- }
+ w.drawBorder()
return w
}
func (w *LightWindow) drawBorder() {
+ switch w.border {
+ case BorderAround:
+ w.drawBorderAround()
+ case BorderHorizontal:
+ w.drawBorderHorizontal()
+ }
+}
+
+func (w *LightWindow) drawBorderHorizontal() {
+ w.Move(0, 0)
+ w.CPrint(ColBorder, AttrRegular, repeat("─", w.width))
+ w.Move(w.height-1, 0)
+ w.CPrint(ColBorder, AttrRegular, repeat("─", w.width))
+}
+
+func (w *LightWindow) drawBorderAround() {
w.Move(0, 0)
w.CPrint(ColBorder, AttrRegular, "┌"+repeat("─", w.width-2)+"┐")
for y := 1; y < w.height-1; y++ {
@@ -854,9 +868,7 @@ func (w *LightWindow) FinishFill() {
}
func (w *LightWindow) Erase() {
- if w.border {
- w.drawBorder()
- }
+ w.drawBorder()
// We don't erase the window here to avoid flickering during scroll
w.Move(0, 0)
}
diff --git a/src/tui/ncurses.go b/src/tui/ncurses.go
index 978b2e72..4b88b447 100644
--- a/src/tui/ncurses.go
+++ b/src/tui/ncurses.go
@@ -189,12 +189,13 @@ func (r *FullscreenRenderer) Close() {
C.delscreen(_screen)
}
-func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, border bool) Window {
+func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window {
win := C.newwin(C.int(height), C.int(width), C.int(top), C.int(left))
if r.theme != nil {
C.wbkgd(win, C.chtype(C.COLOR_PAIR(C.int(ColNormal.index()))))
}
- if border {
+ // FIXME Does not implement BorderHorizontal
+ if borderStyle != BorderNone {
pair, attr := _colorFn(ColBorder, 0)
C.wcolor_set(win, pair, nil)
C.wattron(win, attr)
diff --git a/src/tui/tcell.go b/src/tui/tcell.go
index aa67ae1a..964c19e1 100644
--- a/src/tui/tcell.go
+++ b/src/tui/tcell.go
@@ -27,15 +27,15 @@ func (p ColorPair) style() tcell.Style {
type Attr tcell.Style
type TcellWindow struct {
- color bool
- top int
- left int
- width int
- height int
- lastX int
- lastY int
- moveCursor bool
- border bool
+ color bool
+ top int
+ left int
+ width int
+ height int
+ lastX int
+ lastY int
+ moveCursor bool
+ borderStyle BorderStyle
}
func (w *TcellWindow) Top() int {
@@ -61,8 +61,11 @@ func (w *TcellWindow) Refresh() {
}
w.lastX = 0
w.lastY = 0
- if w.border {
- w.drawBorder()
+ switch w.borderStyle {
+ case BorderAround:
+ w.drawBorder(true)
+ case BorderHorizontal:
+ w.drawBorder(false)
}
}
@@ -377,15 +380,15 @@ func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
_screen.Show()
}
-func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, border bool) Window {
+func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window {
// TODO
return &TcellWindow{
- color: r.theme != nil,
- top: top,
- left: left,
- width: width,
- height: height,
- border: border}
+ color: r.theme != nil,
+ top: top,
+ left: left,
+ width: width,
+ height: height,
+ borderStyle: borderStyle}
}
func (w *TcellWindow) Close() {
@@ -536,7 +539,7 @@ func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn {
return w.fillString(str, ColorPair{fg, bg, -1}, a)
}
-func (w *TcellWindow) drawBorder() {
+func (w *TcellWindow) drawBorder(around bool) {
left := w.left
right := left + w.width
top := w.top
@@ -554,13 +557,15 @@ func (w *TcellWindow) drawBorder() {
_screen.SetContent(x, bot-1, tcell.RuneHLine, nil, style)
}
- for y := top; y < bot; y++ {
- _screen.SetContent(left, y, tcell.RuneVLine, nil, style)
- _screen.SetContent(right-1, y, tcell.RuneVLine, nil, style)
- }
+ if around {
+ for y := top; y < bot; y++ {
+ _screen.SetContent(left, y, tcell.RuneVLine, nil, style)
+ _screen.SetContent(right-1, y, tcell.RuneVLine, nil, style)
+ }
- _screen.SetContent(left, top, tcell.RuneULCorner, nil, style)
- _screen.SetContent(right-1, top, tcell.RuneURCorner, nil, style)
- _screen.SetContent(left, bot-1, tcell.RuneLLCorner, nil, style)
- _screen.SetContent(right-1, bot-1, tcell.RuneLRCorner, nil, style)
+ _screen.SetContent(left, top, tcell.RuneULCorner, nil, style)
+ _screen.SetContent(right-1, top, tcell.RuneURCorner, nil, style)
+ _screen.SetContent(left, bot-1, tcell.RuneLLCorner, nil, style)
+ _screen.SetContent(right-1, bot-1, tcell.RuneLRCorner, nil, style)
+ }
}
diff --git a/src/tui/tui.go b/src/tui/tui.go
index 2508aa68..f8d905ab 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -195,6 +195,14 @@ type MouseEvent struct {
Mod bool
}
+type BorderStyle int
+
+const (
+ BorderNone BorderStyle = iota
+ BorderAround
+ BorderHorizontal
+)
+
type Renderer interface {
Init()
Pause()
@@ -211,7 +219,7 @@ type Renderer interface {
DoesAutoWrap() bool
IsOptimized() bool
- NewWindow(top int, left int, width int, height int, border bool) Window
+ NewWindow(top int, left int, width int, height int, borderStyle BorderStyle) Window
}
type Window interface {