diff --git a/CHANGELOG.md b/CHANGELOG.md index ecbade6b..ed6c9ce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ CHANGELOG --color pointer:reverse,prompt:reverse,input:159 \ --pointer ' ' ``` +- More `--border` options + - `vertical`, `top`, `bottom`, `left`, `right` - To indicate if `--multi` mode is enabled, fzf will print the number of selected items even when no item is selected ```sh diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index da2642eb..9f2051ff 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -192,6 +192,16 @@ Draw border around the finder .br .BR horizontal " Horizontal lines above and below the finder" .br +.BR vertical " Vertical lines on each side of the finder" +.br +.BR top +.br +.BR bottom +.br +.BR left +.br +.BR right +.br .TP .B "--no-unicode" diff --git a/plugin/fzf.vim b/plugin/fzf.vim index 83e1cef5..065ac156 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -432,6 +432,7 @@ try elseif use_term let optstr .= ' --no-height' endif + let optstr .= s:border_opt(get(dict, 'window', 0)) let command = prefix.(use_tmux ? s:fzf_tmux(dict) : fzf_exec).' '.optstr.' > '.temps.result if use_term @@ -656,6 +657,27 @@ function! s:getpos() return {'tab': tabpagenr(), 'win': winnr(), 'winid': win_getid(), 'cnt': winnr('$'), 'tcnt': tabpagenr('$')} endfunction +function! s:border_opt(window) + if type(a:window) != type({}) + return '' + endif + + " Border style + let style = tolower(get(a:window, 'border', 'rounded')) + if !has_key(a:window, 'border') && !get(a:window, 'rounded', 1) + let style = 'sharp' + endif + + let opt = ' --border=' . style + if has_key(a:window, 'highlight') + let color = s:get_color('fg', a:window.highlight) + if len(color) + let opt .= ' --color=border:' . color + endif + endif + return opt +endfunction + function! s:split(dict) let directions = { \ 'up': ['topleft', 'resize', &lines], @@ -869,12 +891,8 @@ else endif function! s:popup(opts) abort - " Support ambiwidth == 'double' - let ambidouble = &ambiwidth == 'double' ? 2 : 1 - " Size and position let width = min([max([8, a:opts.width > 1 ? a:opts.width : float2nr(&columns * a:opts.width)]), &columns]) - let width += width % ambidouble let height = min([max([4, a:opts.height > 1 ? a:opts.height : float2nr(&lines * a:opts.height)]), &lines - has('nvim')]) let row = float2nr(get(a:opts, 'yoffset', 0.5) * (&lines - height)) let col = float2nr(get(a:opts, 'xoffset', 0.5) * (&columns - width)) @@ -885,45 +903,9 @@ function! s:popup(opts) abort let row += !has('nvim') let col += !has('nvim') - " Border style - let style = tolower(get(a:opts, 'border', 'rounded')) - if !has_key(a:opts, 'border') && !get(a:opts, 'rounded', 1) - let style = 'sharp' - endif - - if style =~ 'vertical\|left\|right' - let mid = style == 'vertical' ? '│' .. repeat(' ', width - 2 * ambidouble) .. '│' : - \ style == 'left' ? '│' .. repeat(' ', width - 1 * ambidouble) - \ : repeat(' ', width - 1 * ambidouble) .. '│' - let border = repeat([mid], height) - let shift = { 'row': 0, 'col': style == 'right' ? 0 : 2, 'width': style == 'vertical' ? -4 : -2, 'height': 0 } - elseif style =~ 'horizontal\|top\|bottom' - let hor = repeat('─', width / ambidouble) - let mid = repeat(' ', width) - let border = style == 'horizontal' ? [hor] + repeat([mid], height - 2) + [hor] : - \ style == 'top' ? [hor] + repeat([mid], height - 1) - \ : repeat([mid], height - 1) + [hor] - let shift = { 'row': style == 'bottom' ? 0 : 1, 'col': 0, 'width': 0, 'height': style == 'horizontal' ? -2 : -1 } - else - let edges = style == 'sharp' ? ['┌', '┐', '└', '┘'] : ['╭', '╮', '╰', '╯'] - let bar = repeat('─', width / ambidouble - 2) - let top = edges[0] .. bar .. edges[1] - let mid = '│' .. repeat(' ', width - 2 * ambidouble) .. '│' - let bot = edges[2] .. bar .. edges[3] - let border = [top] + repeat([mid], height - 2) + [bot] - let shift = { 'row': 1, 'col': 2, 'width': -4, 'height': -2 } - endif - - let highlight = get(a:opts, 'highlight', 'Comment') - let frame = s:create_popup(highlight, { - \ 'row': row, 'col': col, 'width': width, 'height': height, 'border': border - \ }) call s:create_popup('Normal', { - \ 'row': row + shift.row, 'col': col + shift.col, 'width': width + shift.width, 'height': height + shift.height + \ 'row': row, 'col': col, 'width': width, 'height': height \ }) - if has('nvim') - execute 'autocmd BufWipeout bwipeout '..frame - endif endfunction let s:default_action = { diff --git a/src/options.go b/src/options.go index ce000a03..ab5ae27a 100644 --- a/src/options.go +++ b/src/options.go @@ -58,7 +58,8 @@ const usage = `usage: fzf [options] (default: 10) --layout=LAYOUT Choose layout: [default|reverse|reverse-list] --border[=STYLE] Draw border around the finder - [rounded|sharp|horizontal] (default: rounded) + [rounded|sharp|horizontal|vertical| + top|bottom|left|right] (default: rounded) --margin=MARGIN Screen margin (TRBL / TB,RL / T,RL,B / T,R,B,L) --info=STYLE Finder info style [default|inline|hidden] --prompt=STR Input prompt (default: '> ') @@ -421,11 +422,21 @@ func parseBorder(str string, optional bool) tui.BorderShape { return tui.BorderSharp case "horizontal": return tui.BorderHorizontal + case "vertical": + return tui.BorderVertical + case "top": + return tui.BorderTop + case "bottom": + return tui.BorderBottom + case "left": + return tui.BorderLeft + case "right": + return tui.BorderRight default: if optional && str == "" { return tui.BorderRounded } - errorExit("invalid border style (expected: rounded|sharp|horizontal)") + errorExit("invalid border style (expected: rounded|sharp|horizontal|vertical|top|bottom|left|right)") } return tui.BorderNone } diff --git a/src/terminal.go b/src/terminal.go index d896d1de..85001c7d 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -670,7 +670,7 @@ func calculateSize(base int, size sizeSpec, occupied int, minSize int, pad int) func (t *Terminal) resizeWindows() { screenWidth := t.tui.MaxX() screenHeight := t.tui.MaxY() - marginInt := [4]int{} + marginInt := [4]int{} // TRBL t.prevLines = make([]itemLine, screenHeight) for idx, sizeSpec := range t.margin { if sizeSpec.percent { @@ -687,6 +687,24 @@ func (t *Terminal) resizeWindows() { switch t.borderShape { case tui.BorderHorizontal: marginInt[idx] += 1 - idx%2 + case tui.BorderVertical: + marginInt[idx] += 2 * (idx % 2) + case tui.BorderTop: + if idx == 0 { + marginInt[idx]++ + } + case tui.BorderRight: + if idx == 1 { + marginInt[idx] += 2 + } + case tui.BorderBottom: + if idx == 2 { + marginInt[idx]++ + } + case tui.BorderLeft: + if idx == 3 { + marginInt[idx] += 2 + } case tui.BorderRounded, tui.BorderSharp: marginInt[idx] += 1 + idx%2 } @@ -735,17 +753,31 @@ func (t *Terminal) resizeWindows() { switch t.borderShape { case tui.BorderHorizontal: t.border = t.tui.NewWindow( - marginInt[0]-1, - marginInt[3], - width, - height+2, + marginInt[0]-1, marginInt[3], width, height+2, false, tui.MakeBorderStyle(tui.BorderHorizontal, t.unicode)) + case tui.BorderVertical: + t.border = t.tui.NewWindow( + marginInt[0], marginInt[3]-2, width+4, height, + false, tui.MakeBorderStyle(tui.BorderVertical, t.unicode)) + case tui.BorderTop: + t.border = t.tui.NewWindow( + marginInt[0]-1, marginInt[3], width, height+1, + false, tui.MakeBorderStyle(tui.BorderTop, t.unicode)) + case tui.BorderBottom: + t.border = t.tui.NewWindow( + marginInt[0], marginInt[3], width, height+1, + false, tui.MakeBorderStyle(tui.BorderBottom, t.unicode)) + case tui.BorderLeft: + t.border = t.tui.NewWindow( + marginInt[0], marginInt[3]-2, width+2, height, + false, tui.MakeBorderStyle(tui.BorderLeft, t.unicode)) + case tui.BorderRight: + t.border = t.tui.NewWindow( + marginInt[0], marginInt[3], width+2, height, + false, tui.MakeBorderStyle(tui.BorderRight, t.unicode)) case tui.BorderRounded, tui.BorderSharp: t.border = t.tui.NewWindow( - marginInt[0]-1, - marginInt[3]-2, - width+4, - height+2, + marginInt[0]-1, marginInt[3]-2, width+4, height+2, false, tui.MakeBorderStyle(t.borderShape, t.unicode)) } noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode) diff --git a/src/tui/light.go b/src/tui/light.go index 6bd08216..ad536f6d 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -653,15 +653,46 @@ func (w *LightWindow) drawBorder() { case BorderRounded, BorderSharp: w.drawBorderAround() case BorderHorizontal: - w.drawBorderHorizontal() + w.drawBorderHorizontal(true, true) + case BorderVertical: + w.drawBorderVertical(true, true) + case BorderTop: + w.drawBorderHorizontal(true, false) + case BorderBottom: + w.drawBorderHorizontal(false, true) + case BorderLeft: + w.drawBorderVertical(true, false) + case BorderRight: + w.drawBorderVertical(false, true) } } -func (w *LightWindow) drawBorderHorizontal() { - w.Move(0, 0) - w.CPrint(ColBorder, repeat(w.border.horizontal, w.width)) - w.Move(w.height-1, 0) - w.CPrint(ColBorder, repeat(w.border.horizontal, w.width)) +func (w *LightWindow) drawBorderHorizontal(top, bottom bool) { + if top { + w.Move(0, 0) + w.CPrint(ColBorder, repeat(w.border.horizontal, w.width)) + } + if bottom { + w.Move(w.height-1, 0) + w.CPrint(ColBorder, repeat(w.border.horizontal, w.width)) + } +} + +func (w *LightWindow) drawBorderVertical(left, right bool) { + width := w.width - 2 + if !left || !right { + width++ + } + for y := 0; y < w.height; y++ { + w.Move(y, 0) + if left { + w.CPrint(ColBorder, string(w.border.vertical)) + } + w.CPrint(ColBorder, repeat(' ', width)) + if right { + w.CPrint(ColBorder, string(w.border.vertical)) + } + } } func (w *LightWindow) drawBorderAround() { diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 0ad1488f..4f80d069 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -583,7 +583,8 @@ func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn { } func (w *TcellWindow) drawBorder() { - if w.borderStyle.shape == BorderNone { + shape := w.borderStyle.shape + if shape == BorderNone { return } @@ -603,17 +604,32 @@ func (w *TcellWindow) drawBorder() { style = w.normal.style() } - for x := left; x < right; x++ { - _screen.SetContent(x, top, w.borderStyle.horizontal, nil, style) - _screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style) + switch shape { + case BorderRounded, BorderSharp, BorderHorizontal, BorderTop: + for x := left; x < right; x++ { + _screen.SetContent(x, top, w.borderStyle.horizontal, nil, style) + } } - - if w.borderStyle.shape != BorderHorizontal { + switch shape { + case BorderRounded, BorderSharp, BorderHorizontal, BorderBottom: + for x := left; x < right; x++ { + _screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style) + } + } + switch shape { + case BorderRounded, BorderSharp, BorderVertical, BorderLeft: for y := top; y < bot; y++ { _screen.SetContent(left, y, w.borderStyle.vertical, nil, style) + } + } + switch shape { + case BorderRounded, BorderSharp, BorderVertical, BorderRight: + for y := top; y < bot; y++ { _screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style) } - + } + switch shape { + case BorderRounded, BorderSharp: _screen.SetContent(left, top, w.borderStyle.topLeft, nil, style) _screen.SetContent(right-1, top, w.borderStyle.topRight, nil, style) _screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style) diff --git a/src/tui/tui.go b/src/tui/tui.go index 40c75112..3cade215 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -259,6 +259,11 @@ const ( BorderRounded BorderSharp BorderHorizontal + BorderVertical + BorderTop + BorderBottom + BorderLeft + BorderRight ) type BorderStyle struct {