Add dashed border style

New --border=dashed / --list-border=dashed / --header-border=dashed etc.
Uses U+2576 (╶) for horizontal edges and U+2506 (┆) for verticals, with
rounded corners (╭╮╰╯) and sharp T-junction mids (├┤). Terminal cells
are taller than wide (~2:1), so horizontals use a sparse stub per cell
while verticals need more dashes per cell to look evenly dashed.
Works with inline sections.
This commit is contained in:
Junegunn Choi
2026-04-20 22:23:41 +09:00
parent 43f0508dd2
commit 7782da6c00
5 changed files with 39 additions and 10 deletions
+3
View File
@@ -16,6 +16,9 @@ CHANGELOG
- `--header-label` and `--footer-label` render on their respective separator row. - `--header-label` and `--footer-label` render on their respective separator row.
- The separator inherits `--color list-border` when the section's own border color is not explicitly set. - The separator inherits `--color list-border` when the section's own border color is not explicitly set.
- `inline` takes precedence over `--header-first`: the inline section stays inside the list frame. `--header-border=inline` requires `--header-lines-border` to be `inline` or unset. - `inline` takes precedence over `--header-first`: the inline section stays inside the list frame. `--header-border=inline` requires `--header-lines-border` to be `inline` or unset.
- New `dashed` border style with dashed edges (`` / ``) and rounded corners.
- `--border=dashed`, `--list-border=dashed`, etc.
- Works with inline sections (T-junctions render correctly).
- [vim] Move and resize popup window when detecting `VimResized` event (#4778) (@Vulcalien) - [vim] Move and resize popup window when detecting `VimResized` event (#4778) (@Vulcalien)
- Bug fixes - Bug fixes
- Fixed gutter display in `--style=minimal` - Fixed gutter display in `--style=minimal`
+5 -1
View File
@@ -517,6 +517,8 @@ Draw border around the finder
.br .br
.BR double " Border with double lines" .BR double " Border with double lines"
.br .br
.BR dashed " Border with dashed lines and rounded corners"
.br
.BR block " Border using block elements; suitable when using different background colors" .BR block " Border using block elements; suitable when using different background colors"
.br .br
.BR thinblock " Border using legacy computing symbols; may not be displayed on some terminals" .BR thinblock " Border using legacy computing symbols; may not be displayed on some terminals"
@@ -955,6 +957,8 @@ Should be used with one of the following \fB\-\-preview\-window\fR options.
.br .br
.B * border\-double .B * border\-double
.br .br
.B * border\-dashed
.br
.B * border\-block .B * border\-block
.br .br
.B * border\-thinblock .B * border\-thinblock
@@ -1104,7 +1108,7 @@ separator line between the header window and the list section. \fBinline\fR
style embeds the header inside the list border frame, joined to the list style embeds the header inside the list border frame, joined to the list
section by a horizontal separator; it requires a \fB\-\-list\-border\fR section by a horizontal separator; it requires a \fB\-\-list\-border\fR
shape that has both top and bottom segments (rounded / sharp / bold / shape that has both top and bottom segments (rounded / sharp / bold /
double / block / thinblock / horizontal) and falls back to \fBline\fR double / dashed / block / thinblock / horizontal) and falls back to \fBline\fR
otherwise. When the list border also has side segments, the separator otherwise. When the list border also has side segments, the separator
joins them with T-junctions; \fBhorizontal\fR has no side borders, so the joins them with T-junctions; \fBhorizontal\fR has no side borders, so the
separator is drawn without T-junction endpoints. Takes precedence over separator is drawn without T-junction endpoints. Takes precedence over
+11 -7
View File
@@ -85,7 +85,7 @@ Usage: fzf [options]
--margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L) --margin=MARGIN Screen margin (TRBL | TB,RL | T,RL,B | T,R,B,L)
--padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L) --padding=PADDING Padding inside border (TRBL | TB,RL | T,RL,B | T,R,B,L)
--border[=STYLE] Draw border around the finder --border[=STYLE] Draw border around the finder
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical| [rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|
top|bottom|left|right|line|none] (default: rounded) top|bottom|left|right|line|none] (default: rounded)
--border-label=LABEL Label to print on the border --border-label=LABEL Label to print on the border
--border-label-pos=COL Position of the border label --border-label-pos=COL Position of the border label
@@ -128,7 +128,7 @@ Usage: fzf [options]
(each for list section and preview window) (each for list section and preview window)
--no-scrollbar Hide scrollbar --no-scrollbar Hide scrollbar
--list-border[=STYLE] Draw border around the list section --list-border[=STYLE] Draw border around the list section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical| [rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|
top|bottom|left|right|none] (default: rounded) top|bottom|left|right|none] (default: rounded)
--list-label=LABEL Label to print on the list border --list-label=LABEL Label to print on the list border
--list-label-pos=COL Position of the list label --list-label-pos=COL Position of the list label
@@ -148,7 +148,7 @@ Usage: fzf [options]
--ghost=TEXT Ghost text to display when the input is empty --ghost=TEXT Ghost text to display when the input is empty
--filepath-word Make word-wise movements respect path separators --filepath-word Make word-wise movements respect path separators
--input-border[=STYLE] Draw border around the input section --input-border[=STYLE] Draw border around the input section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical| [rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|
top|bottom|left|right|line|none] (default: rounded) top|bottom|left|right|line|none] (default: rounded)
--input-label=LABEL Label to print on the input border --input-label=LABEL Label to print on the input border
--input-label-pos=COL Position of the input label --input-label-pos=COL Position of the input label
@@ -165,7 +165,7 @@ Usage: fzf [options]
[,+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| [rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|
top|bottom|left|right|line|none] (default: rounded) 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,
@@ -177,7 +177,7 @@ Usage: fzf [options]
--header-lines=N The first N lines of the input are treated as header --header-lines=N The first N lines of the input are treated as header
--header-first Print header before the prompt line --header-first Print header before the prompt line
--header-border[=STYLE] Draw border around the header section --header-border[=STYLE] Draw border around the header section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical| [rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|
top|bottom|left|right|line|inline|none] (default: rounded) top|bottom|left|right|line|inline|none] (default: rounded)
--header-lines-border[=STYLE] --header-lines-border[=STYLE]
Display header from --header-lines with a separate border. Display header from --header-lines with a separate border.
@@ -192,7 +192,7 @@ Usage: fzf [options]
FOOTER FOOTER
--footer=STR String to print as footer --footer=STR String to print as footer
--footer-border[=STYLE] Draw border around the footer section --footer-border[=STYLE] Draw border around the footer section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical| [rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|
top|bottom|left|right|line|inline|none] (default: line) top|bottom|left|right|line|inline|none] (default: line)
--footer-label=LABEL Label to print on the footer border --footer-label=LABEL Label to print on the footer border
--footer-label-pos=COL Position of the footer label --footer-label-pos=COL Position of the footer label
@@ -968,6 +968,8 @@ func parseBorder(str string, optional bool) (tui.BorderShape, error) {
return tui.BorderThinBlock, nil return tui.BorderThinBlock, nil
case "double": case "double":
return tui.BorderDouble, nil return tui.BorderDouble, nil
case "dashed":
return tui.BorderDashed, nil
case "horizontal": case "horizontal":
return tui.BorderHorizontal, nil return tui.BorderHorizontal, nil
case "vertical": case "vertical":
@@ -986,7 +988,7 @@ func parseBorder(str string, optional bool) (tui.BorderShape, error) {
if optional && str == "" { if optional && str == "" {
return defaultBorderShape, nil return defaultBorderShape, nil
} }
return tui.BorderNone, errors.New("invalid border style (expected: rounded|sharp|bold|block|thinblock|double|horizontal|vertical|top|bottom|left|right|line|inline|none)") return tui.BorderNone, errors.New("invalid border style (expected: rounded|sharp|bold|block|thinblock|double|dashed|horizontal|vertical|top|bottom|left|right|line|inline|none)")
} }
func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Event, error) { func parseKeyChords(str string, message string) (map[tui.Event]string, []tui.Event, error) {
@@ -2341,6 +2343,8 @@ func parsePreviewWindowImpl(opts *previewOpts, input string) error {
opts.border = tui.BorderThinBlock opts.border = tui.BorderThinBlock
case "border-double": case "border-double":
opts.border = tui.BorderDouble opts.border = tui.BorderDouble
case "border-dashed":
opts.border = tui.BorderDashed
case "noborder", "border-none": case "noborder", "border-none":
opts.border = tui.BorderNone opts.border = tui.BorderNone
case "border-horizontal": case "border-horizontal":
+2 -2
View File
@@ -2155,7 +2155,7 @@ func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) {
if idx == 3 { if idx == 3 {
extraMargin[idx] += 1 + bw extraMargin[idx] += 1 + bw
} }
case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderThinBlock, tui.BorderDouble: case tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderThinBlock, tui.BorderDouble, tui.BorderDashed:
extraMargin[idx] += 1 + bw*(idx%2) extraMargin[idx] += 1 + bw*(idx%2)
} }
marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx] marginInt[idx] = sizeSpecToInt(idx, sizeSpec) + extraMargin[idx]
@@ -3017,7 +3017,7 @@ func (t *Terminal) printLabel(window tui.Window, render labelPrinter, opts label
return return
} }
switch borderShape { switch borderShape {
case tui.BorderHorizontal, tui.BorderTop, tui.BorderBottom, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderThinBlock, tui.BorderDouble: case tui.BorderHorizontal, tui.BorderTop, tui.BorderBottom, tui.BorderRounded, tui.BorderSharp, tui.BorderBold, tui.BorderBlock, tui.BorderThinBlock, tui.BorderDouble, tui.BorderDashed:
if redrawBorder { if redrawBorder {
window.DrawHBorder() window.DrawHBorder()
} }
+18
View File
@@ -596,6 +596,7 @@ const (
BorderLeft BorderLeft
BorderRight BorderRight
BorderInline BorderInline
BorderDashed
) )
func (s BorderShape) HasLeft() bool { func (s BorderShape) HasLeft() bool {
@@ -759,6 +760,23 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
leftMid: '╠', leftMid: '╠',
rightMid: '╣', rightMid: '╣',
} }
case BorderDashed:
// Terminal cells are taller than wide (~2:1), so horizontals can use a
// sparse stub per cell while verticals need more dashes per cell to look
// evenly dashed. Rounded corners and sharp T-junction mids.
return BorderStyle{
shape: shape,
top: '╶',
bottom: '╶',
left: '┆',
right: '┆',
topLeft: '╭',
topRight: '╮',
bottomLeft: '╰',
bottomRight: '╯',
leftMid: '├',
rightMid: '┤',
}
} }
return BorderStyle{ return BorderStyle{
shape: shape, shape: shape,