m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-18 08:13:40 -05:00

Add more --border options; default changed to "rounded"

--border option now takes an optional argument that defines the style

  - rounded (new default)
  - sharp
  - horizontal (previous default)
This commit is contained in:
Junegunn Choi
2020-03-05 20:15:15 +09:00
parent 99f1e02766
commit d9b1211191
6 changed files with 150 additions and 90 deletions

View File

@@ -57,7 +57,8 @@ const usage = `usage: fzf [options]
--min-height=HEIGHT Minimum height when --height is given in percent
(default: 10)
--layout=LAYOUT Choose layout: [default|reverse|reverse-list]
--border Draw border above and below the finder
--border[=STYLE] Draw border around the finder
[rounded|sharp|horizontal] (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: '> ')
@@ -212,7 +213,7 @@ type Options struct {
Header []string
HeaderLines int
Margin [4]sizeSpec
Bordered bool
BorderShape tui.BorderShape
Unicode bool
Tabstop int
ClearOnExit bool
@@ -301,12 +302,12 @@ func nextString(args []string, i *int, message string) string {
return args[*i]
}
func optionalNextString(args []string, i *int) string {
if len(args) > *i+1 && !strings.HasPrefix(args[*i+1], "-") {
func optionalNextString(args []string, i *int) (bool, string) {
if len(args) > *i+1 && !strings.HasPrefix(args[*i+1], "-") && !strings.HasPrefix(args[*i+1], "+") {
*i++
return args[*i]
return true, args[*i]
}
return ""
return false, ""
}
func atoi(str string) int {
@@ -400,6 +401,23 @@ func parseAlgo(str string) algo.Algo {
return algo.FuzzyMatchV2
}
func parseBorder(str string, optional bool) tui.BorderShape {
switch str {
case "rounded":
return tui.BorderRounded
case "sharp":
return tui.BorderSharp
case "horizontal":
return tui.BorderHorizontal
default:
if optional && str == "" {
return tui.BorderRounded
}
errorExit("invalid border style (expected: rounded|sharp|horizontal)")
}
return tui.BorderNone
}
func parseKeyChords(str string, message string) map[int]string {
if len(str) == 0 {
errorExit(message)
@@ -1098,7 +1116,7 @@ func parseOptions(opts *Options, allArgs []string) {
case "--bind":
parseKeymap(opts.Keymap, nextString(allArgs, &i, "bind expression required"))
case "--color":
spec := optionalNextString(allArgs, &i)
_, spec := optionalNextString(allArgs, &i)
if len(spec) == 0 {
opts.Theme = tui.EmptyTheme()
} else {
@@ -1246,9 +1264,10 @@ func parseOptions(opts *Options, allArgs []string) {
case "--no-margin":
opts.Margin = defaultMargin()
case "--no-border":
opts.Bordered = false
opts.BorderShape = tui.BorderNone
case "--border":
opts.Bordered = true
hasArg, arg := optionalNextString(allArgs, &i)
opts.BorderShape = parseBorder(arg, !hasArg)
case "--no-unicode":
opts.Unicode = false
case "--unicode":
@@ -1273,6 +1292,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Filter = &value
} else if match, value := optString(arg, "-d", "--delimiter="); match {
opts.Delimiter = delimiterRegexp(value)
} else if match, value := optString(arg, "--border="); match {
opts.BorderShape = parseBorder(value, false)
} else if match, value := optString(arg, "--prompt="); match {
opts.Prompt = value
} else if match, value := optString(arg, "--pointer="); match {

View File

@@ -100,7 +100,7 @@ type Terminal struct {
margin [4]sizeSpec
strong tui.Attr
unicode bool
bordered bool
borderShape tui.BorderShape
cleanExit bool
border tui.Window
window tui.Window
@@ -370,9 +370,9 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
effectiveMinHeight *= 2
}
if opts.InfoStyle != infoDefault {
effectiveMinHeight -= 1
effectiveMinHeight--
}
if opts.Bordered {
if opts.BorderShape != tui.BorderNone {
effectiveMinHeight += 2
}
return util.Min(termHeight, util.Max(maxHeight, effectiveMinHeight))
@@ -391,62 +391,62 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
spinner = []string{`-`, `\`, `|`, `/`, `-`, `\`, `|`, `/`}
}
t := Terminal{
initDelay: delay,
infoStyle: opts.InfoStyle,
spinner: spinner,
queryLen: [2]int{0, 0},
layout: opts.Layout,
fullscreen: fullscreen,
hscroll: opts.Hscroll,
hscrollOff: opts.HscrollOff,
wordRubout: wordRubout,
wordNext: wordNext,
cx: len(input),
cy: 0,
offset: 0,
xoffset: 0,
yanked: []rune{},
input: input,
multi: opts.Multi,
sort: opts.Sort > 0,
toggleSort: opts.ToggleSort,
delimiter: opts.Delimiter,
expect: opts.Expect,
keymap: opts.Keymap,
pressed: "",
printQuery: opts.PrintQuery,
history: opts.History,
margin: opts.Margin,
unicode: opts.Unicode,
bordered: opts.Bordered,
cleanExit: opts.ClearOnExit,
strong: strongAttr,
cycle: opts.Cycle,
header: header,
header0: header,
ansi: opts.Ansi,
tabstop: opts.Tabstop,
reading: true,
failed: nil,
jumping: jumpDisabled,
jumpLabels: opts.JumpLabels,
printer: opts.Printer,
printsep: opts.PrintSep,
merger: EmptyMerger,
selected: make(map[int32]selectedItem),
reqBox: util.NewEventBox(),
preview: opts.Preview,
previewer: previewer{"", 0, 0, previewBox != nil && !opts.Preview.hidden, false},
previewBox: previewBox,
eventBox: eventBox,
mutex: sync.Mutex{},
suppress: true,
slab: util.MakeSlab(slab16Size, slab32Size),
theme: opts.Theme,
startChan: make(chan bool, 1),
killChan: make(chan int),
tui: renderer,
initFunc: func() { renderer.Init() }}
initDelay: delay,
infoStyle: opts.InfoStyle,
spinner: spinner,
queryLen: [2]int{0, 0},
layout: opts.Layout,
fullscreen: fullscreen,
hscroll: opts.Hscroll,
hscrollOff: opts.HscrollOff,
wordRubout: wordRubout,
wordNext: wordNext,
cx: len(input),
cy: 0,
offset: 0,
xoffset: 0,
yanked: []rune{},
input: input,
multi: opts.Multi,
sort: opts.Sort > 0,
toggleSort: opts.ToggleSort,
delimiter: opts.Delimiter,
expect: opts.Expect,
keymap: opts.Keymap,
pressed: "",
printQuery: opts.PrintQuery,
history: opts.History,
margin: opts.Margin,
unicode: opts.Unicode,
borderShape: opts.BorderShape,
cleanExit: opts.ClearOnExit,
strong: strongAttr,
cycle: opts.Cycle,
header: header,
header0: header,
ansi: opts.Ansi,
tabstop: opts.Tabstop,
reading: true,
failed: nil,
jumping: jumpDisabled,
jumpLabels: opts.JumpLabels,
printer: opts.Printer,
printsep: opts.PrintSep,
merger: EmptyMerger,
selected: make(map[int32]selectedItem),
reqBox: util.NewEventBox(),
preview: opts.Preview,
previewer: previewer{"", 0, 0, previewBox != nil && !opts.Preview.hidden, false},
previewBox: previewBox,
eventBox: eventBox,
mutex: sync.Mutex{},
suppress: true,
slab: util.MakeSlab(slab16Size, slab32Size),
theme: opts.Theme,
startChan: make(chan bool, 1),
killChan: make(chan int),
tui: renderer,
initFunc: func() { renderer.Init() }}
t.prompt, t.promptLen = t.processTabs([]rune(opts.Prompt), 0)
t.pointer, t.pointerLen = t.processTabs([]rune(opts.Pointer), 0)
t.marker, t.markerLen = t.processTabs([]rune(opts.Marker), 0)
@@ -595,8 +595,11 @@ func (t *Terminal) resizeWindows() {
} else {
marginInt[idx] = int(sizeSpec.size)
}
if t.bordered && idx%2 == 0 {
marginInt[idx] += 1
switch t.borderShape {
case tui.BorderHorizontal:
marginInt[idx] += 1 - idx%2
case tui.BorderRounded, tui.BorderSharp:
marginInt[idx] += 1 + idx%2
}
}
adjust := func(idx1 int, idx2 int, max int, min int) {
@@ -636,18 +639,26 @@ func (t *Terminal) resizeWindows() {
width := screenWidth - marginInt[1] - marginInt[3]
height := screenHeight - marginInt[0] - marginInt[2]
if t.bordered {
switch t.borderShape {
case tui.BorderHorizontal:
t.border = t.tui.NewWindow(
marginInt[0]-1,
marginInt[3],
width,
height+2,
false, tui.MakeBorderStyle(tui.BorderHorizontal, t.unicode))
case tui.BorderRounded, tui.BorderSharp:
t.border = t.tui.NewWindow(
marginInt[0]-1,
marginInt[3]-2,
width+4,
height+2,
false, tui.MakeBorderStyle(t.borderShape, t.unicode))
}
noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode)
if previewVisible {
createPreviewWindow := func(y int, x int, w int, h int) {
previewBorder := tui.MakeBorderStyle(tui.BorderAround, t.unicode)
previewBorder := tui.MakeBorderStyle(tui.BorderRounded, t.unicode)
if !t.preview.border {
previewBorder = tui.MakeTransparentBorder()
}
@@ -1146,7 +1157,7 @@ func (t *Terminal) refresh() {
t.placeCursor()
if !t.suppress {
windows := make([]tui.Window, 0, 4)
if t.bordered {
if t.borderShape != tui.BorderNone {
windows = append(windows, t.border)
}
if t.hasPreviewWindow() {

View File

@@ -105,6 +105,7 @@ type LightRenderer struct {
type LightWindow struct {
renderer *LightRenderer
colored bool
preview bool
border BorderStyle
top int
left int
@@ -681,6 +682,7 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, prev
w := &LightWindow{
renderer: r,
colored: r.theme != nil,
preview: preview,
border: borderStyle,
top: top,
left: left,
@@ -704,7 +706,7 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, prev
func (w *LightWindow) drawBorder() {
switch w.border.shape {
case BorderAround:
case BorderRounded, BorderSharp:
w.drawBorderAround()
case BorderHorizontal:
w.drawBorderHorizontal()
@@ -720,16 +722,20 @@ func (w *LightWindow) drawBorderHorizontal() {
func (w *LightWindow) drawBorderAround() {
w.Move(0, 0)
w.CPrint(ColPreviewBorder, AttrRegular,
color := ColBorder
if w.preview {
color = ColPreviewBorder
}
w.CPrint(color, 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(ColPreviewBorder, AttrRegular, string(w.border.vertical))
w.CPrint(ColPreviewBorder, AttrRegular, repeat(' ', w.width-2))
w.CPrint(ColPreviewBorder, AttrRegular, string(w.border.vertical))
w.CPrint(color, AttrRegular, string(w.border.vertical))
w.CPrint(color, AttrRegular, repeat(' ', w.width-2))
w.CPrint(color, AttrRegular, string(w.border.vertical))
}
w.Move(w.height-1, 0)
w.CPrint(ColPreviewBorder, AttrRegular,
w.CPrint(color, AttrRegular,
string(w.border.bottomLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.bottomRight))
}

View File

@@ -28,6 +28,7 @@ type Attr tcell.Style
type TcellWindow struct {
color bool
preview bool
top int
left int
width int
@@ -418,6 +419,7 @@ func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int,
}
return &TcellWindow{
color: r.theme != nil,
preview: preview,
top: top,
left: left,
width: width,
@@ -591,7 +593,7 @@ func (w *TcellWindow) drawBorder() {
var style tcell.Style
if w.color {
if w.borderStyle.shape == BorderAround {
if w.preview {
style = ColPreviewBorder.style()
} else {
style = ColBorder.style()
@@ -605,7 +607,7 @@ func (w *TcellWindow) drawBorder() {
_screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
}
if w.borderStyle.shape == BorderAround {
if w.borderStyle.shape != BorderHorizontal {
for y := top; y < bot; y++ {
_screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
_screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style)

View File

@@ -210,7 +210,8 @@ type BorderShape int
const (
BorderNone BorderShape = iota
BorderAround
BorderRounded
BorderSharp
BorderHorizontal
)
@@ -228,14 +229,25 @@ type BorderCharacter int
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
if unicode {
if shape == BorderRounded {
return BorderStyle{
shape: shape,
horizontal: '─',
vertical: '│',
topLeft: '╭',
topRight: '╮',
bottomLeft: '╰',
bottomRight: '╯',
}
}
return BorderStyle{
shape: shape,
horizontal: '─',
vertical: '│',
topLeft: '',
topRight: '',
bottomLeft: '',
bottomRight: '',
topLeft: '',
topRight: '',
bottomLeft: '',
bottomRight: '',
}
}
return BorderStyle{
@@ -251,7 +263,7 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
func MakeTransparentBorder() BorderStyle {
return BorderStyle{
shape: BorderAround,
shape: BorderRounded,
horizontal: ' ',
vertical: ' ',
topLeft: ' ',