mirror of
https://github.com/junegunn/fzf.git
synced 2026-07-19 22:50:35 +08:00
Add --{header,header-lines,footer}-border=inline
New BorderShape that embeds the section inside the --list-border frame, joined to the list content by a horizontal separator with T-junctions where the list shape has side borders. Requires a list border with both top and bottom segments; falls back to 'line' otherwise. Stacks when multiple sections are inline. Sections inherit --color list-border by default and are colored as a uniform block via their own --color *-border and *-bg. Incompatible with --header-first. --header-border=inline requires --header-lines-border to be inline or unset.
This commit is contained in:
+124
-109
@@ -1129,127 +1129,142 @@ func (w *LightWindow) DrawHBorder() {
|
||||
w.drawBorder(true)
|
||||
}
|
||||
|
||||
// drawHLine fills row `row` with `line` between optional left/right caps.
|
||||
// A zero rune means "no cap"; caps are placed at the very edges of `w`.
|
||||
func (w *LightWindow) drawHLine(row int, line, leftCap, rightCap rune, color ColorPair) {
|
||||
w.Move(row, 0)
|
||||
hw := runeWidth(line)
|
||||
width := w.width
|
||||
if leftCap != 0 {
|
||||
w.CPrint(color, string(leftCap))
|
||||
width -= runeWidth(leftCap)
|
||||
}
|
||||
if rightCap != 0 {
|
||||
width -= runeWidth(rightCap)
|
||||
}
|
||||
if width < 0 {
|
||||
width = 0
|
||||
}
|
||||
inner := width / hw
|
||||
rem := width - inner*hw
|
||||
w.CPrint(color, repeat(line, inner)+repeat(' ', rem))
|
||||
if rightCap != 0 {
|
||||
w.CPrint(color, string(rightCap))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LightWindow) DrawHSeparator(row int, windowType WindowType, useBottom bool) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
}
|
||||
shape := w.border.shape
|
||||
if shape == BorderNone {
|
||||
return
|
||||
}
|
||||
color := BorderColor(windowType)
|
||||
line := w.border.top
|
||||
if useBottom {
|
||||
line = w.border.bottom
|
||||
}
|
||||
var leftCap, rightCap rune
|
||||
if shape.HasLeft() || shape.HasRight() {
|
||||
leftCap = w.border.leftMid
|
||||
rightCap = w.border.rightMid
|
||||
}
|
||||
w.drawHLine(row, line, leftCap, rightCap, color)
|
||||
}
|
||||
|
||||
func (w *LightWindow) PaintSectionFrame(topContent, bottomContent int, windowType WindowType, edge SectionEdge) {
|
||||
if w.height == 0 || w.border.shape == BorderNone {
|
||||
return
|
||||
}
|
||||
color := BorderColor(windowType)
|
||||
shape := w.border.shape
|
||||
hasLeft := shape.HasLeft()
|
||||
hasRight := shape.HasRight()
|
||||
rightW := runeWidth(w.border.right)
|
||||
// Content rows: overpaint left/right verticals + their 1-char margin.
|
||||
for row := topContent; row <= bottomContent; row++ {
|
||||
if hasLeft {
|
||||
w.Move(row, 0)
|
||||
w.CPrint(color, string(w.border.left)+" ")
|
||||
}
|
||||
if hasRight {
|
||||
w.Move(row, w.width-rightW-1)
|
||||
w.CPrint(color, " "+string(w.border.right))
|
||||
}
|
||||
}
|
||||
if edge == SectionEdgeTop && shape.HasTop() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.border.topLeft
|
||||
}
|
||||
if hasRight {
|
||||
rightCap = w.border.topRight
|
||||
}
|
||||
w.drawHLine(0, w.border.top, leftCap, rightCap, color)
|
||||
}
|
||||
if edge == SectionEdgeBottom && shape.HasBottom() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.border.bottomLeft
|
||||
}
|
||||
if hasRight {
|
||||
rightCap = w.border.bottomRight
|
||||
}
|
||||
w.drawHLine(w.height-1, w.border.bottom, leftCap, rightCap, color)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LightWindow) drawBorder(onlyHorizontal bool) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
}
|
||||
switch w.border.shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble:
|
||||
w.drawBorderAround(onlyHorizontal)
|
||||
case BorderHorizontal:
|
||||
w.drawBorderHorizontal(true, true)
|
||||
case BorderVertical:
|
||||
if onlyHorizontal {
|
||||
return
|
||||
}
|
||||
w.drawBorderVertical(true, true)
|
||||
case BorderTop:
|
||||
w.drawBorderHorizontal(true, false)
|
||||
case BorderBottom:
|
||||
w.drawBorderHorizontal(false, true)
|
||||
case BorderLeft:
|
||||
if onlyHorizontal {
|
||||
return
|
||||
}
|
||||
w.drawBorderVertical(true, false)
|
||||
case BorderRight:
|
||||
if onlyHorizontal {
|
||||
return
|
||||
}
|
||||
w.drawBorderVertical(false, true)
|
||||
shape := w.border.shape
|
||||
if shape == BorderNone {
|
||||
return
|
||||
}
|
||||
}
|
||||
color := BorderColor(w.windowType)
|
||||
hasLeft := shape.HasLeft()
|
||||
hasRight := shape.HasRight()
|
||||
|
||||
func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
|
||||
color := ColBorder
|
||||
switch w.windowType {
|
||||
case WindowList:
|
||||
color = ColListBorder
|
||||
case WindowInput:
|
||||
color = ColInputBorder
|
||||
case WindowHeader:
|
||||
color = ColHeaderBorder
|
||||
case WindowFooter:
|
||||
color = ColFooterBorder
|
||||
case WindowPreview:
|
||||
color = ColPreviewBorder
|
||||
}
|
||||
hw := runeWidth(w.border.top)
|
||||
if top {
|
||||
w.Move(0, 0)
|
||||
w.CPrint(color, repeat(w.border.top, w.width/hw))
|
||||
}
|
||||
|
||||
if bottom {
|
||||
w.Move(w.height-1, 0)
|
||||
w.CPrint(color, repeat(w.border.bottom, w.width/hw))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LightWindow) drawBorderVertical(left, right bool) {
|
||||
vw := runeWidth(w.border.left)
|
||||
color := ColBorder
|
||||
switch w.windowType {
|
||||
case WindowList:
|
||||
color = ColListBorder
|
||||
case WindowInput:
|
||||
color = ColInputBorder
|
||||
case WindowHeader:
|
||||
color = ColHeaderBorder
|
||||
case WindowFooter:
|
||||
color = ColFooterBorder
|
||||
case WindowPreview:
|
||||
color = ColPreviewBorder
|
||||
}
|
||||
for y := 0; y < w.height; y++ {
|
||||
if left {
|
||||
w.Move(y, 0)
|
||||
w.CPrint(color, string(w.border.left))
|
||||
w.CPrint(color, " ") // Margin
|
||||
if shape.HasTop() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.border.topLeft
|
||||
}
|
||||
if right {
|
||||
w.Move(y, w.width-vw-1)
|
||||
w.CPrint(color, " ") // Margin
|
||||
w.CPrint(color, string(w.border.right))
|
||||
if hasRight {
|
||||
rightCap = w.border.topRight
|
||||
}
|
||||
w.drawHLine(0, w.border.top, leftCap, rightCap, color)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LightWindow) drawBorderAround(onlyHorizontal bool) {
|
||||
w.Move(0, 0)
|
||||
color := ColBorder
|
||||
switch w.windowType {
|
||||
case WindowList:
|
||||
color = ColListBorder
|
||||
case WindowInput:
|
||||
color = ColInputBorder
|
||||
case WindowHeader:
|
||||
color = ColHeaderBorder
|
||||
case WindowFooter:
|
||||
color = ColFooterBorder
|
||||
case WindowPreview:
|
||||
color = ColPreviewBorder
|
||||
}
|
||||
hw := runeWidth(w.border.top)
|
||||
tcw := runeWidth(w.border.topLeft) + runeWidth(w.border.topRight)
|
||||
bcw := runeWidth(w.border.bottomLeft) + runeWidth(w.border.bottomRight)
|
||||
rem := (w.width - tcw) % hw
|
||||
w.CPrint(color, string(w.border.topLeft)+repeat(w.border.top, (w.width-tcw)/hw)+repeat(' ', rem)+string(w.border.topRight))
|
||||
if !onlyHorizontal {
|
||||
if !onlyHorizontal && (hasLeft || hasRight) {
|
||||
vw := runeWidth(w.border.left)
|
||||
for y := 1; y < w.height-1; y++ {
|
||||
w.Move(y, 0)
|
||||
w.CPrint(color, string(w.border.left))
|
||||
w.CPrint(color, " ") // Margin
|
||||
|
||||
w.Move(y, w.width-vw-1)
|
||||
w.CPrint(color, " ") // Margin
|
||||
w.CPrint(color, string(w.border.right))
|
||||
for y := 0; y < w.height; y++ {
|
||||
// Corner rows are already painted by drawHLine above / below.
|
||||
if (y == 0 && shape.HasTop()) || (y == w.height-1 && shape.HasBottom()) {
|
||||
continue
|
||||
}
|
||||
if hasLeft {
|
||||
w.Move(y, 0)
|
||||
w.CPrint(color, string(w.border.left)+" ")
|
||||
}
|
||||
if hasRight {
|
||||
w.Move(y, w.width-vw-1)
|
||||
w.CPrint(color, " "+string(w.border.right))
|
||||
}
|
||||
}
|
||||
}
|
||||
w.Move(w.height-1, 0)
|
||||
rem = (w.width - bcw) % hw
|
||||
w.CPrint(color, string(w.border.bottomLeft)+repeat(w.border.bottom, (w.width-bcw)/hw)+repeat(' ', rem)+string(w.border.bottomRight))
|
||||
if shape.HasBottom() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.border.bottomLeft
|
||||
}
|
||||
if hasRight {
|
||||
rightCap = w.border.bottomRight
|
||||
}
|
||||
w.drawHLine(w.height-1, w.border.bottom, leftCap, rightCap, color)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *LightWindow) csi(code string) string {
|
||||
|
||||
+133
-54
@@ -1017,6 +1017,113 @@ func (w *TcellWindow) DrawHBorder() {
|
||||
w.drawBorder(true)
|
||||
}
|
||||
|
||||
// borderStyleFor returns the tcell.Style used to draw borders for `wt`, honoring
|
||||
// whether the window is rendering with colors.
|
||||
func (w *TcellWindow) borderStyleFor(wt WindowType) tcell.Style {
|
||||
if !w.color {
|
||||
return w.normal.style()
|
||||
}
|
||||
return BorderColor(wt).style()
|
||||
}
|
||||
|
||||
// drawHLine fills row `y` with `line` between optional left/right caps.
|
||||
// A zero rune means "no cap"; caps are placed at the very edges of `w`.
|
||||
// tcell has an issue displaying two overlapping wide runes, so the line
|
||||
// stops before the cap position rather than overpainting.
|
||||
func (w *TcellWindow) drawHLine(y int, line, leftCap, rightCap rune, style tcell.Style) {
|
||||
left := w.left
|
||||
right := left + w.width
|
||||
hw := runeWidth(line)
|
||||
lw := 0
|
||||
rw := 0
|
||||
if leftCap != 0 {
|
||||
lw = runeWidth(leftCap)
|
||||
}
|
||||
if rightCap != 0 {
|
||||
rw = runeWidth(rightCap)
|
||||
}
|
||||
for x := left + lw; x <= right-rw-hw; x += hw {
|
||||
_screen.SetContent(x, y, line, nil, style)
|
||||
}
|
||||
if leftCap != 0 {
|
||||
_screen.SetContent(left, y, leftCap, nil, style)
|
||||
}
|
||||
if rightCap != 0 {
|
||||
_screen.SetContent(right-rw, y, rightCap, nil, style)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *TcellWindow) DrawHSeparator(row int, windowType WindowType, useBottom bool) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
}
|
||||
shape := w.borderStyle.shape
|
||||
if shape == BorderNone {
|
||||
return
|
||||
}
|
||||
style := w.borderStyleFor(windowType)
|
||||
line := w.borderStyle.top
|
||||
if useBottom {
|
||||
line = w.borderStyle.bottom
|
||||
}
|
||||
var leftCap, rightCap rune
|
||||
if shape.HasLeft() || shape.HasRight() {
|
||||
leftCap = w.borderStyle.leftMid
|
||||
rightCap = w.borderStyle.rightMid
|
||||
}
|
||||
w.drawHLine(w.top+row, line, leftCap, rightCap, style)
|
||||
}
|
||||
|
||||
func (w *TcellWindow) PaintSectionFrame(topContent, bottomContent int, windowType WindowType, edge SectionEdge) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
}
|
||||
shape := w.borderStyle.shape
|
||||
if shape == BorderNone {
|
||||
return
|
||||
}
|
||||
style := w.borderStyleFor(windowType)
|
||||
left := w.left
|
||||
right := left + w.width
|
||||
hasLeft := shape.HasLeft()
|
||||
hasRight := shape.HasRight()
|
||||
leftW := runeWidth(w.borderStyle.left)
|
||||
rightW := runeWidth(w.borderStyle.right)
|
||||
// Content rows: overpaint the left and right verticals (+ their 1-char margin) in
|
||||
// the section's color. Inner margin stays at whatever bg the sub-window set.
|
||||
for row := topContent; row <= bottomContent; row++ {
|
||||
y := w.top + row
|
||||
if hasLeft {
|
||||
_screen.SetContent(left, y, w.borderStyle.left, nil, style)
|
||||
_screen.SetContent(left+leftW, y, ' ', nil, style)
|
||||
}
|
||||
if hasRight {
|
||||
_screen.SetContent(right-rightW-1, y, ' ', nil, style)
|
||||
_screen.SetContent(right-rightW, y, w.borderStyle.right, nil, style)
|
||||
}
|
||||
}
|
||||
if edge == SectionEdgeTop && shape.HasTop() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.borderStyle.topLeft
|
||||
}
|
||||
if hasRight {
|
||||
rightCap = w.borderStyle.topRight
|
||||
}
|
||||
w.drawHLine(w.top, w.borderStyle.top, leftCap, rightCap, style)
|
||||
}
|
||||
if edge == SectionEdgeBottom && shape.HasBottom() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.borderStyle.bottomLeft
|
||||
}
|
||||
if hasRight {
|
||||
rightCap = w.borderStyle.bottomRight
|
||||
}
|
||||
w.drawHLine(w.top+w.height-1, w.borderStyle.bottom, leftCap, rightCap, style)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
||||
if w.height == 0 {
|
||||
return
|
||||
@@ -1031,72 +1138,44 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
|
||||
top := w.top
|
||||
bot := top + w.height
|
||||
|
||||
var style tcell.Style
|
||||
if w.color {
|
||||
switch w.windowType {
|
||||
case WindowBase:
|
||||
style = ColBorder.style()
|
||||
case WindowList:
|
||||
style = ColListBorder.style()
|
||||
case WindowHeader:
|
||||
style = ColHeaderBorder.style()
|
||||
case WindowFooter:
|
||||
style = ColFooterBorder.style()
|
||||
case WindowInput:
|
||||
style = ColInputBorder.style()
|
||||
case WindowPreview:
|
||||
style = ColPreviewBorder.style()
|
||||
}
|
||||
} else {
|
||||
style = w.normal.style()
|
||||
}
|
||||
style := w.borderStyleFor(w.windowType)
|
||||
|
||||
hw := runeWidth(w.borderStyle.top)
|
||||
switch shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderHorizontal, BorderTop:
|
||||
max := right - 2*hw
|
||||
if shape == BorderHorizontal || shape == BorderTop {
|
||||
max = right - hw
|
||||
hasLeft := shape.HasLeft()
|
||||
hasRight := shape.HasRight()
|
||||
|
||||
if shape.HasTop() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.borderStyle.topLeft
|
||||
}
|
||||
// tcell has an issue displaying two overlapping wide runes
|
||||
// e.g. SetContent( HH )
|
||||
// SetContent( TR )
|
||||
// ==================
|
||||
// ( HH ) => TR is ignored
|
||||
for x := left; x <= max; x += hw {
|
||||
_screen.SetContent(x, top, w.borderStyle.top, nil, style)
|
||||
if hasRight {
|
||||
rightCap = w.borderStyle.topRight
|
||||
}
|
||||
w.drawHLine(top, w.borderStyle.top, leftCap, rightCap, style)
|
||||
}
|
||||
switch shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderHorizontal, BorderBottom:
|
||||
max := right - 2*hw
|
||||
if shape == BorderHorizontal || shape == BorderBottom {
|
||||
max = right - hw
|
||||
if shape.HasBottom() {
|
||||
var leftCap, rightCap rune
|
||||
if hasLeft {
|
||||
leftCap = w.borderStyle.bottomLeft
|
||||
}
|
||||
for x := left; x <= max; x += hw {
|
||||
_screen.SetContent(x, bot-1, w.borderStyle.bottom, nil, style)
|
||||
if hasRight {
|
||||
rightCap = w.borderStyle.bottomRight
|
||||
}
|
||||
w.drawHLine(bot-1, w.borderStyle.bottom, leftCap, rightCap, style)
|
||||
}
|
||||
if !onlyHorizontal {
|
||||
switch shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderVertical, BorderLeft:
|
||||
for y := top; y < bot; y++ {
|
||||
vw := runeWidth(w.borderStyle.right)
|
||||
for y := top; y < bot; y++ {
|
||||
// Corner rows are already painted by drawHLine above / below.
|
||||
if (y == top && shape.HasTop()) || (y == bot-1 && shape.HasBottom()) {
|
||||
continue
|
||||
}
|
||||
if hasLeft {
|
||||
_screen.SetContent(left, y, w.borderStyle.left, nil, style)
|
||||
}
|
||||
}
|
||||
switch shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderVertical, BorderRight:
|
||||
vw := runeWidth(w.borderStyle.right)
|
||||
for y := top; y < bot; y++ {
|
||||
if hasRight {
|
||||
_screen.SetContent(right-vw, y, w.borderStyle.right, nil, style)
|
||||
}
|
||||
}
|
||||
}
|
||||
switch shape {
|
||||
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble:
|
||||
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
|
||||
_screen.SetContent(right-runeWidth(w.borderStyle.topRight), top, w.borderStyle.topRight, nil, style)
|
||||
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
|
||||
_screen.SetContent(right-runeWidth(w.borderStyle.bottomRight), bot-1, w.borderStyle.bottomRight, nil, style)
|
||||
}
|
||||
}
|
||||
|
||||
+80
-8
@@ -595,11 +595,12 @@ const (
|
||||
BorderBottom
|
||||
BorderLeft
|
||||
BorderRight
|
||||
BorderInline
|
||||
)
|
||||
|
||||
func (s BorderShape) HasLeft() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderInline, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -607,7 +608,7 @@ func (s BorderShape) HasLeft() bool {
|
||||
|
||||
func (s BorderShape) HasRight() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderInline, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -615,7 +616,7 @@ func (s BorderShape) HasRight() bool {
|
||||
|
||||
func (s BorderShape) HasTop() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderInline, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -623,7 +624,7 @@ func (s BorderShape) HasTop() bool {
|
||||
|
||||
func (s BorderShape) HasBottom() bool {
|
||||
switch s {
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
||||
case BorderNone, BorderPhantom, BorderLine, BorderInline, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -643,6 +644,8 @@ type BorderStyle struct {
|
||||
topRight rune
|
||||
bottomLeft rune
|
||||
bottomRight rune
|
||||
leftMid rune
|
||||
rightMid rune
|
||||
}
|
||||
|
||||
type BorderCharacter int
|
||||
@@ -658,7 +661,9 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topLeft: ' ',
|
||||
topRight: ' ',
|
||||
bottomLeft: ' ',
|
||||
bottomRight: ' '}
|
||||
bottomRight: ' ',
|
||||
leftMid: ' ',
|
||||
rightMid: ' '}
|
||||
}
|
||||
if !unicode {
|
||||
return BorderStyle{
|
||||
@@ -671,6 +676,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '+',
|
||||
bottomLeft: '+',
|
||||
bottomRight: '+',
|
||||
leftMid: '+',
|
||||
rightMid: '+',
|
||||
}
|
||||
}
|
||||
switch shape {
|
||||
@@ -685,6 +692,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '┐',
|
||||
bottomLeft: '└',
|
||||
bottomRight: '┘',
|
||||
leftMid: '├',
|
||||
rightMid: '┤',
|
||||
}
|
||||
case BorderBold:
|
||||
return BorderStyle{
|
||||
@@ -697,6 +706,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '┓',
|
||||
bottomLeft: '┗',
|
||||
bottomRight: '┛',
|
||||
leftMid: '┣',
|
||||
rightMid: '┫',
|
||||
}
|
||||
case BorderBlock:
|
||||
// ▛▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▜
|
||||
@@ -712,6 +723,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '▜',
|
||||
bottomLeft: '▙',
|
||||
bottomRight: '▟',
|
||||
leftMid: '▌',
|
||||
rightMid: '▐',
|
||||
}
|
||||
|
||||
case BorderThinBlock:
|
||||
@@ -728,6 +741,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '🭾',
|
||||
bottomLeft: '🭼',
|
||||
bottomRight: '🭿',
|
||||
leftMid: '▏',
|
||||
rightMid: '▕',
|
||||
}
|
||||
|
||||
case BorderDouble:
|
||||
@@ -741,6 +756,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '╗',
|
||||
bottomLeft: '╚',
|
||||
bottomRight: '╝',
|
||||
leftMid: '╠',
|
||||
rightMid: '╣',
|
||||
}
|
||||
}
|
||||
return BorderStyle{
|
||||
@@ -753,6 +770,8 @@ func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||
topRight: '╮',
|
||||
bottomLeft: '╰',
|
||||
bottomRight: '╯',
|
||||
leftMid: '├',
|
||||
rightMid: '┤',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,6 +793,35 @@ const (
|
||||
WindowFooter
|
||||
)
|
||||
|
||||
// BorderColor returns the ColorPair used to draw borders for the given WindowType.
|
||||
func BorderColor(wt WindowType) ColorPair {
|
||||
switch wt {
|
||||
case WindowList:
|
||||
return ColListBorder
|
||||
case WindowInput:
|
||||
return ColInputBorder
|
||||
case WindowHeader:
|
||||
return ColHeaderBorder
|
||||
case WindowFooter:
|
||||
return ColFooterBorder
|
||||
case WindowPreview:
|
||||
return ColPreviewBorder
|
||||
}
|
||||
return ColBorder
|
||||
}
|
||||
|
||||
// SectionEdge selects which outer edge of the frame an inline section
|
||||
// should claim when PaintSectionFrame overpaints its adjacent border.
|
||||
// SectionEdgeNone paints only the inner verticals (for sections that
|
||||
// don't touch the outer top or bottom).
|
||||
type SectionEdge int
|
||||
|
||||
const (
|
||||
SectionEdgeNone SectionEdge = iota
|
||||
SectionEdgeTop
|
||||
SectionEdgeBottom
|
||||
)
|
||||
|
||||
type Renderer interface {
|
||||
DefaultTheme() *ColorTheme
|
||||
Init() error
|
||||
@@ -811,6 +859,19 @@ type Window interface {
|
||||
|
||||
DrawBorder()
|
||||
DrawHBorder()
|
||||
// DrawHSeparator draws an inline horizontal separator at `row` (relative to the
|
||||
// window's top) using the color for `windowType`. The separator is conceptually
|
||||
// the section's inner edge (e.g. the bottom border of an inline header), so the
|
||||
// whole row including junctions carries the section's fg + bg. When useBottom is
|
||||
// true the `bottom` horizontal char is used instead of `top`; for thinblock/block
|
||||
// styles this keeps the thin line bonded to the list content on the opposite side.
|
||||
DrawHSeparator(row int, windowType WindowType, useBottom bool)
|
||||
// PaintSectionFrame overpaints the border cells around the rows [topContent,
|
||||
// bottomContent] (inclusive, relative to the window's top) with the color for
|
||||
// `windowType`. When edge is SectionEdgeTop / SectionEdgeBottom, the
|
||||
// corresponding outer horizontal (+ corners) is also painted, letting the
|
||||
// inline section claim that edge of the outer frame.
|
||||
PaintSectionFrame(topContent, bottomContent int, windowType WindowType, edge SectionEdge)
|
||||
Refresh()
|
||||
FinishFill()
|
||||
|
||||
@@ -1166,7 +1227,7 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, boldify bool, forceBlack bool, hasInputWindow bool, hasHeaderWindow bool) {
|
||||
func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, boldify bool, forceBlack bool, hasInputWindow bool, hasHeaderWindow bool, headerInline bool, footerInline bool) {
|
||||
if forceBlack {
|
||||
theme.Bg = ColorAttr{colBlack, AttrUndefined}
|
||||
}
|
||||
@@ -1300,11 +1361,22 @@ func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, boldify bool, forceBlac
|
||||
} else {
|
||||
theme.HeaderBg = o(theme.Bg, theme.ListBg)
|
||||
}
|
||||
theme.HeaderBorder = o(theme.Border, theme.HeaderBorder)
|
||||
// Inline header/footer borders sit inside the list frame, so default their color
|
||||
// to the list-border color when the user has not explicitly set it. The inline
|
||||
// separator then matches the surrounding frame.
|
||||
headerBorderFallback := theme.Border
|
||||
if headerInline {
|
||||
headerBorderFallback = theme.ListBorder
|
||||
}
|
||||
theme.HeaderBorder = o(headerBorderFallback, theme.HeaderBorder)
|
||||
theme.HeaderLabel = o(theme.BorderLabel, theme.HeaderLabel)
|
||||
|
||||
theme.FooterBg = o(theme.Bg, theme.FooterBg)
|
||||
theme.FooterBorder = o(theme.Border, theme.FooterBorder)
|
||||
footerBorderFallback := theme.Border
|
||||
if footerInline {
|
||||
footerBorderFallback = theme.ListBorder
|
||||
}
|
||||
theme.FooterBorder = o(footerBorderFallback, theme.FooterBorder)
|
||||
theme.FooterLabel = o(theme.BorderLabel, theme.FooterLabel)
|
||||
|
||||
if theme.Nomatch.IsUndefined() {
|
||||
|
||||
Reference in New Issue
Block a user