mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2025-01-30 02:28:29 +00:00
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.
This commit is contained in:
parent
a5beb08ed7
commit
0e0b868342
@ -43,6 +43,7 @@ CHANGELOG
|
|||||||
- `change-header-label`
|
- `change-header-label`
|
||||||
- `transform-header-label`
|
- `transform-header-label`
|
||||||
- Added `--preview-border[=STYLE]` as short for `--preview-window=border[-STYLE]`
|
- Added `--preview-border[=STYLE]` as short for `--preview-window=border[-STYLE]`
|
||||||
|
- Added new preview border style `line` which draws a single separator line between the preview window and the rest of the interface
|
||||||
- You can specify `border-native` to `--tmux` so that native tmux border is used instead of `--border`. This can be useful if you start a different program from inside the popup.
|
- You can specify `border-native` to `--tmux` so that native tmux border is used instead of `--border`. This can be useful if you start a different program from inside the popup.
|
||||||
```sh
|
```sh
|
||||||
fzf --tmux border-native --bind 'enter:execute:less {}'
|
fzf --tmux border-native --bind 'enter:execute:less {}'
|
||||||
|
@ -775,7 +775,10 @@ e.g.
|
|||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-preview\-border" [=STYLE]
|
.BI "\-\-preview\-border" [=STYLE]
|
||||||
Short for \fB\-\-preview\-window=border\-STYLE\fR
|
Short for \fB\-\-preview\-window=border\-STYLE\fR. In addition to the other
|
||||||
|
styles, \fBline\fR style is also supported for preview border, which draws
|
||||||
|
a single separator line between the preview window and the rest of the
|
||||||
|
interface.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-preview\-label" [=LABEL]
|
.BI "\-\-preview\-label" [=LABEL]
|
||||||
@ -812,7 +815,7 @@ default value 0 (or \fBcenter\fR) will put the label at the center of the
|
|||||||
border line.
|
border line.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.BI "\-\-preview\-window=" "[POSITION][,SIZE[%]][,border\-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]info][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
|
.BI "\-\-preview\-window=" "[POSITION][,SIZE[%]][,border\-STYLE][,[no]wrap][,[no]follow][,[no]cycle][,[no]info][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]"
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
.B POSITION: (default: right)
|
.B POSITION: (default: right)
|
||||||
@ -855,6 +858,10 @@ e.g. \fBborder\-rounded\fR (border with rounded edges, default),
|
|||||||
\fBborder\-sharp\fR (border with sharp edges), \fBborder\-left\fR,
|
\fBborder\-sharp\fR (border with sharp edges), \fBborder\-left\fR,
|
||||||
\fBborder\-none\fR, etc.
|
\fBborder\-none\fR, etc.
|
||||||
|
|
||||||
|
* In addition to the other border styles, \fBborder\-line\fR style is also
|
||||||
|
supported, which draws a single separator line between the preview window and
|
||||||
|
the rest of the interface.
|
||||||
|
|
||||||
* \fB[:+SCROLL[OFFSETS][/DENOM]]\fR determines the initial scroll offset of the
|
* \fB[:+SCROLL[OFFSETS][/DENOM]]\fR determines the initial scroll offset of the
|
||||||
preview window.
|
preview window.
|
||||||
|
|
||||||
|
@ -146,10 +146,12 @@ Usage: fzf [options]
|
|||||||
--preview-window=OPT Preview window layout (default: right:50%)
|
--preview-window=OPT Preview window layout (default: right:50%)
|
||||||
[up|down|left|right][,SIZE[%]]
|
[up|down|left|right][,SIZE[%]]
|
||||||
[,[no]wrap][,[no]cycle][,[no]follow][,[no]info]
|
[,[no]wrap][,[no]cycle][,[no]follow][,[no]info]
|
||||||
[,[no]hidden][,border-BORDER_OPT]
|
[,[no]hidden][,border-STYLE]
|
||||||
[,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
|
[,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES]
|
||||||
[,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
|
[,default][,<SIZE_THRESHOLD(ALTERNATIVE_LAYOUT)]
|
||||||
--preview-border[=STYLE] Short for --preview-window=border-STYLE
|
--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=LABEL
|
||||||
--preview-label-pos=N Same as --border-label and --border-label-pos,
|
--preview-label-pos=N Same as --border-label and --border-label-pos,
|
||||||
but for preview window
|
but for preview window
|
||||||
@ -313,6 +315,10 @@ func (o *previewOpts) Toggle() {
|
|||||||
o.hidden = !o.hidden
|
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 {
|
func defaultTmuxOptions(index int) *tmuxOptions {
|
||||||
return &tmuxOptions{
|
return &tmuxOptions{
|
||||||
position: posCenter,
|
position: posCenter,
|
||||||
@ -832,8 +838,13 @@ func processScheme(opts *Options) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseBorder(str string, optional bool) (tui.BorderShape, error) {
|
func parseBorder(str string, optional bool, allowLine bool) (tui.BorderShape, error) {
|
||||||
switch str {
|
switch str {
|
||||||
|
case "line":
|
||||||
|
if !allowLine {
|
||||||
|
return tui.BorderNone, errors.New("'line' is only allowed for preview border")
|
||||||
|
}
|
||||||
|
return tui.BorderLine, nil
|
||||||
case "rounded":
|
case "rounded":
|
||||||
return tui.BorderRounded, nil
|
return tui.BorderRounded, nil
|
||||||
case "sharp":
|
case "sharp":
|
||||||
@ -1900,6 +1911,8 @@ func parsePreviewWindowImpl(opts *previewOpts, input string) error {
|
|||||||
opts.position = posRight
|
opts.position = posRight
|
||||||
case "rounded", "border", "border-rounded":
|
case "rounded", "border", "border-rounded":
|
||||||
opts.border = tui.BorderRounded
|
opts.border = tui.BorderRounded
|
||||||
|
case "border-line":
|
||||||
|
opts.border = tui.BorderLine
|
||||||
case "sharp", "border-sharp":
|
case "sharp", "border-sharp":
|
||||||
opts.border = tui.BorderSharp
|
opts.border = tui.BorderSharp
|
||||||
case "border-bold":
|
case "border-bold":
|
||||||
@ -2501,7 +2514,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
case "--no-preview":
|
case "--no-preview":
|
||||||
opts.Preview.command = ""
|
opts.Preview.command = ""
|
||||||
case "--preview-window":
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -2512,7 +2525,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
opts.Preview.border = tui.BorderNone
|
opts.Preview.border = tui.BorderNone
|
||||||
case "--preview-border":
|
case "--preview-border":
|
||||||
hasArg, arg := optionalNextString(allArgs, &i)
|
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
|
return err
|
||||||
}
|
}
|
||||||
case "--height":
|
case "--height":
|
||||||
@ -2537,12 +2550,12 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
opts.BorderShape = tui.BorderNone
|
opts.BorderShape = tui.BorderNone
|
||||||
case "--border":
|
case "--border":
|
||||||
hasArg, arg := optionalNextString(allArgs, &i)
|
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
|
return err
|
||||||
}
|
}
|
||||||
case "--list-border":
|
case "--list-border":
|
||||||
hasArg, arg := optionalNextString(allArgs, &i)
|
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
|
return err
|
||||||
}
|
}
|
||||||
case "--no-list-border":
|
case "--no-list-border":
|
||||||
@ -2566,7 +2579,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
opts.HeaderBorderShape = tui.BorderNone
|
opts.HeaderBorderShape = tui.BorderNone
|
||||||
case "--header-border":
|
case "--header-border":
|
||||||
hasArg, arg := optionalNextString(allArgs, &i)
|
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
|
return err
|
||||||
}
|
}
|
||||||
case "--no-header-label":
|
case "--no-header-label":
|
||||||
@ -2587,7 +2600,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
opts.InputBorderShape = tui.BorderNone
|
opts.InputBorderShape = tui.BorderNone
|
||||||
case "--input-border":
|
case "--input-border":
|
||||||
hasArg, arg := optionalNextString(allArgs, &i)
|
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
|
return err
|
||||||
}
|
}
|
||||||
case "--no-input-label":
|
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 {
|
} else if match, value := optString(arg, "-d", "--delimiter="); match {
|
||||||
opts.Delimiter = delimiterRegexp(value)
|
opts.Delimiter = delimiterRegexp(value)
|
||||||
} else if match, value := optString(arg, "--border="); match {
|
} 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
|
return err
|
||||||
}
|
}
|
||||||
} else if match, value := optString(arg, "--preview-border="); match {
|
} 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
|
return err
|
||||||
}
|
}
|
||||||
} else if match, value := optString(arg, "--list-border="); match {
|
} 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
|
return err
|
||||||
}
|
}
|
||||||
} else if match, value := optString(arg, "--list-label="); match {
|
} else if match, value := optString(arg, "--list-label="); match {
|
||||||
@ -2756,7 +2769,7 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if match, value := optString(arg, "--input-border="); match {
|
} 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
|
return err
|
||||||
}
|
}
|
||||||
} else if match, value := optString(arg, "--input-label="); match {
|
} else if match, value := optString(arg, "--input-label="); match {
|
||||||
|
@ -1513,7 +1513,7 @@ func (t *Terminal) minPreviewSize(opts *previewOpts) (int, int) {
|
|||||||
|
|
||||||
switch opts.position {
|
switch opts.position {
|
||||||
case posLeft, posRight:
|
case posLeft, posRight:
|
||||||
if len(t.scrollbar) > 0 && !opts.border.HasRight() {
|
if len(t.scrollbar) > 0 && !opts.HasBorderRight() {
|
||||||
// Need a column to show scrollbar
|
// Need a column to show scrollbar
|
||||||
minPreviewWidth++
|
minPreviewWidth++
|
||||||
}
|
}
|
||||||
@ -1757,17 +1757,30 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
createPreviewWindow := func(y int, x int, w int, h int) {
|
createPreviewWindow := func(y int, x int, w int, h int) {
|
||||||
pwidth := w
|
pwidth := w
|
||||||
pheight := h
|
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)
|
t.pborder = t.tui.NewWindow(y, x, w, h, tui.WindowPreview, previewBorder, false)
|
||||||
pwidth -= borderColumns(previewOpts.border, bw)
|
pwidth -= borderColumns(shape, bw)
|
||||||
pheight -= borderLines(previewOpts.border)
|
pheight -= borderLines(shape)
|
||||||
if previewOpts.border.HasLeft() {
|
if shape.HasLeft() {
|
||||||
x += 1 + bw
|
x += 1 + bw
|
||||||
}
|
}
|
||||||
if previewOpts.border.HasTop() {
|
if shape.HasTop() {
|
||||||
y += 1
|
y += 1
|
||||||
}
|
}
|
||||||
if len(t.scrollbar) > 0 && !previewOpts.border.HasRight() {
|
if len(t.scrollbar) > 0 && !shape.HasRight() {
|
||||||
// Need a column to show scrollbar
|
// Need a column to show scrollbar
|
||||||
pwidth -= 1
|
pwidth -= 1
|
||||||
}
|
}
|
||||||
@ -1800,6 +1813,14 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
if previewOpts.hidden {
|
if previewOpts.hidden {
|
||||||
return
|
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
|
maxPreviewLines := availableLines
|
||||||
if t.wborder != nil {
|
if t.wborder != nil {
|
||||||
@ -1870,7 +1891,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
|
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
|
||||||
} else {
|
} else {
|
||||||
// NOTE: fzf --preview 'cat {}' --preview-window border-left --border
|
// NOTE: fzf --preview 'cat {}' --preview-window border-left --border
|
||||||
stickToRight = !previewOpts.border.HasRight() && t.borderShape.HasRight()
|
stickToRight = !previewOpts.HasBorderRight() && t.borderShape.HasRight()
|
||||||
if stickToRight {
|
if stickToRight {
|
||||||
innerWidth++
|
innerWidth++
|
||||||
width++
|
width++
|
||||||
@ -3187,7 +3208,7 @@ func (t *Terminal) renderPreviewScrollbar(yoff int, barLength int, barStart int)
|
|||||||
t.previewer.xw = xw
|
t.previewer.xw = xw
|
||||||
}
|
}
|
||||||
xshift := -1 - t.borderWidth
|
xshift := -1 - t.borderWidth
|
||||||
if !t.activePreviewOpts.border.HasRight() {
|
if !t.activePreviewOpts.HasBorderRight() {
|
||||||
xshift = -1
|
xshift = -1
|
||||||
}
|
}
|
||||||
yshift := 1
|
yshift := 1
|
||||||
|
@ -358,6 +358,7 @@ type BorderShape int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
BorderUndefined BorderShape = iota
|
BorderUndefined BorderShape = iota
|
||||||
|
BorderLine
|
||||||
BorderNone
|
BorderNone
|
||||||
BorderRounded
|
BorderRounded
|
||||||
BorderSharp
|
BorderSharp
|
||||||
@ -375,7 +376,7 @@ const (
|
|||||||
|
|
||||||
func (s BorderShape) HasLeft() bool {
|
func (s BorderShape) HasLeft() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
case BorderNone, BorderLine, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -383,7 +384,7 @@ func (s BorderShape) HasLeft() bool {
|
|||||||
|
|
||||||
func (s BorderShape) HasRight() bool {
|
func (s BorderShape) HasRight() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
case BorderNone, BorderLine, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -391,7 +392,7 @@ func (s BorderShape) HasRight() bool {
|
|||||||
|
|
||||||
func (s BorderShape) HasTop() bool {
|
func (s BorderShape) HasTop() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
case BorderNone, BorderLine, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -399,7 +400,7 @@ func (s BorderShape) HasTop() bool {
|
|||||||
|
|
||||||
func (s BorderShape) HasBottom() bool {
|
func (s BorderShape) HasBottom() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
case BorderNone, BorderLine, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
Loading…
x
Reference in New Issue
Block a user