summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2025-01-06 00:44:59 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2025-01-06 00:44:59 +0900
commit0e0b86834294e1befb9e1ce16239230aa40d1add (patch)
tree4e8fec876561cdb810299c0126a838f27d7b9553 /src
parenta5beb08ed72215e8b015851ad70bf3beca526429 (diff)
downloadfzf-0e0b86834294e1befb9e1ce16239230aa40d1add.tar.gz
Add preview border style 'line'
It draws a single line between the preview window and the rest of the interface. i.e. automatically choose between 'left', 'right', 'top', and 'bottom' depending on the position of the preview window.
Diffstat (limited to 'src')
-rw-r--r--src/options.go37
-rw-r--r--src/terminal.go39
-rw-r--r--src/tui/tui.go9
3 files changed, 60 insertions, 25 deletions
diff --git a/src/options.go b/src/options.go
index f6b7245f..7db7418b 100644
--- a/src/options.go
+++ b/src/options.go
@@ -146,10 +146,12 @@ Usage: fzf [options]
--preview-window=OPT Preview window layout (default: right:50%)
[up|down|left|right][,SIZE[%]]
[,[no]wrap][,[no]cycle][,[no]follow][,[no]info]
- [,[no]hidden][,border-BORDER_OPT]
+ [,[no]hidden][,border-STYLE]
[,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
[,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
--preview-border[=STYLE] Short for --preview-window=border-STYLE
+ [rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
+ top|bottom|left|right|line|none] (default: rounded)
--preview-label=LABEL
--preview-label-pos=N Same as --border-label and --border-label-pos,
but for preview window
@@ -313,6 +315,10 @@ func (o *previewOpts) Toggle() {
o.hidden = !o.hidden
}
+func (o *previewOpts) HasBorderRight() bool {
+ return o.border.HasRight() || o.border == tui.BorderLine && o.position == posLeft
+}
+
func defaultTmuxOptions(index int) *tmuxOptions {
return &tmuxOptions{
position: posCenter,
@@ -832,8 +838,13 @@ func processScheme(opts *Options) error {
return nil
}
-func parseBorder(str string, optional bool) (tui.BorderShape, error) {
+func parseBorder(str string, optional bool, allowLine bool) (tui.BorderShape, error) {
switch str {
+ case "line":
+ if !allowLine {
+ return tui.BorderNone, errors.New("'line' is only allowed for preview border")
+ }
+ return tui.BorderLine, nil
case "rounded":
return tui.BorderRounded, nil
case "sharp":
@@ -1900,6 +1911,8 @@ func parsePreviewWindowImpl(opts *previewOpts, input string) error {
opts.position = posRight
case "rounded", "border", "border-rounded":
opts.border = tui.BorderRounded
+ case "border-line":
+ opts.border = tui.BorderLine
case "sharp", "border-sharp":
opts.border = tui.BorderSharp
case "border-bold":
@@ -2501,7 +2514,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
case "--no-preview":
opts.Preview.command = ""
case "--preview-window":
- str, err := nextString(allArgs, &i, "preview window layout required: [up|down|left|right][,SIZE[%]][,border-BORDER_OPT][,wrap][,cycle][,hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]")
+ str, err := nextString(allArgs, &i, "preview window layout required: [up|down|left|right][,SIZE[%]][,border-STYLE][,wrap][,cycle][,hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]")
if err != nil {
return err
}
@@ -2512,7 +2525,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.Preview.border = tui.BorderNone
case "--preview-border":
hasArg, arg := optionalNextString(allArgs, &i)
- if opts.Preview.border, err = parseBorder(arg, !hasArg); err != nil {
+ if opts.Preview.border, err = parseBorder(arg, !hasArg, true); err != nil {
return err
}
case "--height":
@@ -2537,12 +2550,12 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.BorderShape = tui.BorderNone
case "--border":
hasArg, arg := optionalNextString(allArgs, &i)
- if opts.BorderShape, err = parseBorder(arg, !hasArg); err != nil {
+ if opts.BorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
return err
}
case "--list-border":
hasArg, arg := optionalNextString(allArgs, &i)
- if opts.ListBorderShape, err = parseBorder(arg, !hasArg); err != nil {
+ if opts.ListBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
return err
}
case "--no-list-border":
@@ -2566,7 +2579,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.HeaderBorderShape = tui.BorderNone
case "--header-border":
hasArg, arg := optionalNextString(allArgs, &i)
- if opts.HeaderBorderShape, err = parseBorder(arg, !hasArg); err != nil {
+ if opts.HeaderBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
return err
}
case "--no-header-label":
@@ -2587,7 +2600,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.InputBorderShape = tui.BorderNone
case "--input-border":
hasArg, arg := optionalNextString(allArgs, &i)
- if opts.InputBorderShape, err = parseBorder(arg, !hasArg); err != nil {
+ if opts.InputBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
return err
}
case "--no-input-label":
@@ -2738,15 +2751,15 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
} else if match, value := optString(arg, "-d", "--delimiter="); match {
opts.Delimiter = delimiterRegexp(value)
} else if match, value := optString(arg, "--border="); match {
- if opts.BorderShape, err = parseBorder(value, false); err != nil {
+ if opts.BorderShape, err = parseBorder(value, false, false); err != nil {
return err
}
} else if match, value := optString(arg, "--preview-border="); match {
- if opts.Preview.border, err = parseBorder(value, false); err != nil {
+ if opts.Preview.border, err = parseBorder(value, false, true); err != nil {
return err
}
} else if match, value := optString(arg, "--list-border="); match {
- if opts.ListBorderShape, err = parseBorder(value, false); err != nil {
+ if opts.ListBorderShape, err = parseBorder(value, false, false); err != nil {
return err
}
} else if match, value := optString(arg, "--list-label="); match {
@@ -2756,7 +2769,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
return err
}
} else if match, value := optString(arg, "--input-border="); match {
- if opts.InputBorderShape, err = parseBorder(value, false); err != nil {
+ if opts.InputBorderShape, err = parseBorder(value, false, false); err != nil {
return err
}
} else if match, value := optString(arg, "--input-label="); match {
diff --git a/src/terminal.go b/src/terminal.go
index 764284a9..344246de 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -1513,7 +1513,7 @@ func (t *Terminal) minPreviewSize(opts *previewOpts) (int, int) {
switch opts.position {
case posLeft, posRight:
- if len(t.scrollbar) > 0 && !opts.border.HasRight() {
+ if len(t.scrollbar) > 0 && !opts.HasBorderRight() {
// Need a column to show scrollbar
minPreviewWidth++
}
@@ -1757,17 +1757,30 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
createPreviewWindow := func(y int, x int, w int, h int) {
pwidth := w
pheight := h
- previewBorder := tui.MakeBorderStyle(previewOpts.border, t.unicode)
+ shape := previewOpts.border
+ if shape == tui.BorderLine {
+ switch previewOpts.position {
+ case posUp:
+ shape = tui.BorderBottom
+ case posDown:
+ shape = tui.BorderTop
+ case posLeft:
+ shape = tui.BorderRight
+ case posRight:
+ shape = tui.BorderLeft
+ }
+ }
+ previewBorder := tui.MakeBorderStyle(shape, t.unicode)
t.pborder = t.tui.NewWindow(y, x, w, h, tui.WindowPreview, previewBorder, false)
- pwidth -= borderColumns(previewOpts.border, bw)
- pheight -= borderLines(previewOpts.border)
- if previewOpts.border.HasLeft() {
+ pwidth -= borderColumns(shape, bw)
+ pheight -= borderLines(shape)
+ if shape.HasLeft() {
x += 1 + bw
}
- if previewOpts.border.HasTop() {
+ if shape.HasTop() {
y += 1
}
- if len(t.scrollbar) > 0 && !previewOpts.border.HasRight() {
+ if len(t.scrollbar) > 0 && !shape.HasRight() {
// Need a column to show scrollbar
pwidth -= 1
}
@@ -1800,6 +1813,14 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
if previewOpts.hidden {
return
}
+ // If none of the inner borders has the right side, but the outer border does, increase the width by 1 column
+ stickToRight = t.borderShape.HasRight() &&
+ !previewOpts.HasBorderRight() && !t.listBorderShape.HasRight() && !t.inputBorderShape.HasRight() &&
+ (!t.headerVisible || !t.headerBorderShape.HasRight() || t.visibleHeaderLines() == 0)
+ if stickToRight {
+ innerWidth++
+ width++
+ }
maxPreviewLines := availableLines
if t.wborder != nil {
@@ -1870,7 +1891,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
} else {
// NOTE: fzf --preview 'cat {}' --preview-window border-left --border
- stickToRight = !previewOpts.border.HasRight() && t.borderShape.HasRight()
+ stickToRight = !previewOpts.HasBorderRight() && t.borderShape.HasRight()
if stickToRight {
innerWidth++
width++
@@ -3187,7 +3208,7 @@ func (t *Terminal) renderPreviewScrollbar(yoff int, barLength int, barStart int)
t.previewer.xw = xw
}
xshift := -1 - t.borderWidth
- if !t.activePreviewOpts.border.HasRight() {
+ if !t.activePreviewOpts.HasBorderRight() {
xshift = -1
}
yshift := 1
diff --git a/src/tui/tui.go b/src/tui/tui.go
index db846f75..2bd9caf9 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -358,6 +358,7 @@ type BorderShape int
const (
BorderUndefined BorderShape = iota
+ BorderLine
BorderNone
BorderRounded
BorderSharp
@@ -375,7 +376,7 @@ const (
func (s BorderShape) HasLeft() bool {
switch s {
- case BorderNone, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
+ case BorderNone, BorderLine, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
return false
}
return true
@@ -383,7 +384,7 @@ func (s BorderShape) HasLeft() bool {
func (s BorderShape) HasRight() bool {
switch s {
- case BorderNone, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
+ case BorderNone, BorderLine, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
return false
}
return true
@@ -391,7 +392,7 @@ func (s BorderShape) HasRight() bool {
func (s BorderShape) HasTop() bool {
switch s {
- case BorderNone, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
+ case BorderNone, BorderLine, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
return false
}
return true
@@ -399,7 +400,7 @@ func (s BorderShape) HasTop() bool {
func (s BorderShape) HasBottom() bool {
switch s {
- case BorderNone, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
+ case BorderNone, BorderLine, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
return false
}
return true