Add --list-border for additional border around the list section

Close #4148
This commit is contained in:
Junegunn Choi 2024-12-31 17:03:18 +09:00
parent b8d2b0df7e
commit 9a2b7f559c
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
11 changed files with 620 additions and 329 deletions

View File

@ -1,6 +1,22 @@
CHANGELOG CHANGELOG
========= =========
0.58.0
------
- Additional border and label for the list section
- Options
- `--list-border[=STYLE]`
- `--list-label=LABEL`
- `--list-label-pos=COL[:bottom]`
- Colors
- `list-fg`
- `list-bg`
- `list-border`
- `list-label`
- Actions
- `change-list-label`
- `transform-list-label`
0.57.0 0.57.0
------ ------
- You can now resize the preview window by dragging the border - You can now resize the preview window by dragging the border

View File

@ -553,9 +553,11 @@ color mappings.
.B COLOR NAMES: .B COLOR NAMES:
\fBfg \fRText \fBfg \fRText
\fBlist\-fg \fRText in the list section
\fBselected\-fg \fRSelected line text \fBselected\-fg \fRSelected line text
\fBpreview\-fg \fRPreview window text \fBpreview\-fg \fRPreview window text
\fBbg \fRBackground \fBbg \fRBackground
\fBlist\-bg \fRBackground in the list section
\fBselected\-bg \fRSelected line background \fBselected\-bg \fRSelected line background
\fBpreview\-bg \fRPreview window background \fBpreview\-bg \fRPreview window background
\fBhl \fRHighlighted substrings \fBhl \fRHighlighted substrings
@ -568,11 +570,13 @@ color mappings.
\fBdisabled \fRQuery string when search is disabled (\fB\-\-disabled\fR) \fBdisabled \fRQuery string when search is disabled (\fB\-\-disabled\fR)
\fBinfo \fRInfo line (match counters) \fBinfo \fRInfo line (match counters)
\fBborder \fRBorder around the window (\fB\-\-border\fR and \fB\-\-preview\fR) \fBborder \fRBorder around the window (\fB\-\-border\fR and \fB\-\-preview\fR)
\fBlist\-border \fRBorder around the list section (\fB\-\-list\-border\fR)
\fBscrollbar \fRScrollbar \fBscrollbar \fRScrollbar
\fBseparator \fRHorizontal separator on info line
\fBpreview\-border \fRBorder around the preview window (\fB\-\-preview\fR) \fBpreview\-border \fRBorder around the preview window (\fB\-\-preview\fR)
\fBpreview\-scrollbar \fRScrollbar \fBpreview\-scrollbar \fRScrollbar
\fBseparator \fRHorizontal separator on info line \fBlabel \fRBorder label (\fB\-\-border\-label\fR, \fB\-\-list\-label\fR, and \fB\-\-preview\-label\fR)
\fBlabel \fRBorder label (\fB\-\-border\-label\fR and \fB\-\-preview\-label\fR) \fBlist\-label \fRBorder label of the list section (\fB\-\-list\-label\fR)
\fBpreview\-label \fRBorder label of the preview window (\fB\-\-preview\-label\fR) \fBpreview\-label \fRBorder label of the preview window (\fB\-\-preview\-label\fR)
\fBprompt \fRPrompt \fBprompt \fRPrompt
\fBpointer \fRPointer to the current line \fBpointer \fRPointer to the current line
@ -1440,6 +1444,7 @@ A key or an event can be bound to one or more of the following actions.
\fBcancel\fR (clear query string if not empty, abort fzf otherwise) \fBcancel\fR (clear query string if not empty, abort fzf otherwise)
\fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string) \fBchange\-border\-label(...)\fR (change \fB\-\-border\-label\fR to the given string)
\fBchange\-header(...)\fR (change header to the given string; doesn't affect \fB\-\-header\-lines\fR) \fBchange\-header(...)\fR (change header to the given string; doesn't affect \fB\-\-header\-lines\fR)
\fBchange\-list\-label(...)\fR (change \fB\-\-list\-label\fR to the given string)
\fBchange\-multi\fR (enable multi-select mode with no limit) \fBchange\-multi\fR (enable multi-select mode with no limit)
\fBchange\-multi(...)\fR (enable multi-select mode with a limit or disable it with 0) \fBchange\-multi(...)\fR (enable multi-select mode with a limit or disable it with 0)
\fBchange\-preview(...)\fR (change \fB\-\-preview\fR option) \fBchange\-preview(...)\fR (change \fB\-\-preview\fR option)
@ -1524,6 +1529,7 @@ A key or an event can be bound to one or more of the following actions.
\fBtransform(...)\fR (transform states using the output of an external command) \fBtransform(...)\fR (transform states using the output of an external command)
\fBtransform\-border\-label(...)\fR (transform border label using an external command) \fBtransform\-border\-label(...)\fR (transform border label using an external command)
\fBtransform\-header(...)\fR (transform header using an external command) \fBtransform\-header(...)\fR (transform header using an external command)
\fBtransform\-list\-label(...)\fR (transform list label using an external command)
\fBtransform\-preview\-label(...)\fR (transform preview label using an external command) \fBtransform\-preview\-label(...)\fR (transform preview label using an external command)
\fBtransform\-prompt(...)\fR (transform prompt string using an external command) \fBtransform\-prompt(...)\fR (transform prompt string using an external command)
\fBtransform\-query(...)\fR (transform query string using an external command) \fBtransform\-query(...)\fR (transform query string using an external command)

View File

@ -25,109 +25,111 @@ func _() {
_ = x[actBackwardWord-14] _ = x[actBackwardWord-14]
_ = x[actCancel-15] _ = x[actCancel-15]
_ = x[actChangeBorderLabel-16] _ = x[actChangeBorderLabel-16]
_ = x[actChangeHeader-17] _ = x[actChangeListLabel-17]
_ = x[actChangeMulti-18] _ = x[actChangeHeader-18]
_ = x[actChangePreviewLabel-19] _ = x[actChangeMulti-19]
_ = x[actChangePrompt-20] _ = x[actChangePreviewLabel-20]
_ = x[actChangeQuery-21] _ = x[actChangePrompt-21]
_ = x[actClearScreen-22] _ = x[actChangeQuery-22]
_ = x[actClearQuery-23] _ = x[actClearScreen-23]
_ = x[actClearSelection-24] _ = x[actClearQuery-24]
_ = x[actClose-25] _ = x[actClearSelection-25]
_ = x[actDeleteChar-26] _ = x[actClose-26]
_ = x[actDeleteCharEof-27] _ = x[actDeleteChar-27]
_ = x[actEndOfLine-28] _ = x[actDeleteCharEof-28]
_ = x[actFatal-29] _ = x[actEndOfLine-29]
_ = x[actForwardChar-30] _ = x[actFatal-30]
_ = x[actForwardWord-31] _ = x[actForwardChar-31]
_ = x[actKillLine-32] _ = x[actForwardWord-32]
_ = x[actKillWord-33] _ = x[actKillLine-33]
_ = x[actUnixLineDiscard-34] _ = x[actKillWord-34]
_ = x[actUnixWordRubout-35] _ = x[actUnixLineDiscard-35]
_ = x[actYank-36] _ = x[actUnixWordRubout-36]
_ = x[actBackwardKillWord-37] _ = x[actYank-37]
_ = x[actSelectAll-38] _ = x[actBackwardKillWord-38]
_ = x[actDeselectAll-39] _ = x[actSelectAll-39]
_ = x[actToggle-40] _ = x[actDeselectAll-40]
_ = x[actToggleSearch-41] _ = x[actToggle-41]
_ = x[actToggleAll-42] _ = x[actToggleSearch-42]
_ = x[actToggleDown-43] _ = x[actToggleAll-43]
_ = x[actToggleUp-44] _ = x[actToggleDown-44]
_ = x[actToggleIn-45] _ = x[actToggleUp-45]
_ = x[actToggleOut-46] _ = x[actToggleIn-46]
_ = x[actToggleTrack-47] _ = x[actToggleOut-47]
_ = x[actToggleTrackCurrent-48] _ = x[actToggleTrack-48]
_ = x[actToggleHeader-49] _ = x[actToggleTrackCurrent-49]
_ = x[actToggleWrap-50] _ = x[actToggleHeader-50]
_ = x[actToggleMultiLine-51] _ = x[actToggleWrap-51]
_ = x[actToggleHscroll-52] _ = x[actToggleMultiLine-52]
_ = x[actTrackCurrent-53] _ = x[actToggleHscroll-53]
_ = x[actUntrackCurrent-54] _ = x[actTrackCurrent-54]
_ = x[actDown-55] _ = x[actUntrackCurrent-55]
_ = x[actUp-56] _ = x[actDown-56]
_ = x[actPageUp-57] _ = x[actUp-57]
_ = x[actPageDown-58] _ = x[actPageUp-58]
_ = x[actPosition-59] _ = x[actPageDown-59]
_ = x[actHalfPageUp-60] _ = x[actPosition-60]
_ = x[actHalfPageDown-61] _ = x[actHalfPageUp-61]
_ = x[actOffsetUp-62] _ = x[actHalfPageDown-62]
_ = x[actOffsetDown-63] _ = x[actOffsetUp-63]
_ = x[actOffsetMiddle-64] _ = x[actOffsetDown-64]
_ = x[actJump-65] _ = x[actOffsetMiddle-65]
_ = x[actJumpAccept-66] _ = x[actJump-66]
_ = x[actPrintQuery-67] _ = x[actJumpAccept-67]
_ = x[actRefreshPreview-68] _ = x[actPrintQuery-68]
_ = x[actReplaceQuery-69] _ = x[actRefreshPreview-69]
_ = x[actToggleSort-70] _ = x[actReplaceQuery-70]
_ = x[actShowPreview-71] _ = x[actToggleSort-71]
_ = x[actHidePreview-72] _ = x[actShowPreview-72]
_ = x[actTogglePreview-73] _ = x[actHidePreview-73]
_ = x[actTogglePreviewWrap-74] _ = x[actTogglePreview-74]
_ = x[actTransform-75] _ = x[actTogglePreviewWrap-75]
_ = x[actTransformBorderLabel-76] _ = x[actTransform-76]
_ = x[actTransformHeader-77] _ = x[actTransformBorderLabel-77]
_ = x[actTransformPreviewLabel-78] _ = x[actTransformListLabel-78]
_ = x[actTransformPrompt-79] _ = x[actTransformHeader-79]
_ = x[actTransformQuery-80] _ = x[actTransformPreviewLabel-80]
_ = x[actPreview-81] _ = x[actTransformPrompt-81]
_ = x[actChangePreview-82] _ = x[actTransformQuery-82]
_ = x[actChangePreviewWindow-83] _ = x[actPreview-83]
_ = x[actPreviewTop-84] _ = x[actChangePreview-84]
_ = x[actPreviewBottom-85] _ = x[actChangePreviewWindow-85]
_ = x[actPreviewUp-86] _ = x[actPreviewTop-86]
_ = x[actPreviewDown-87] _ = x[actPreviewBottom-87]
_ = x[actPreviewPageUp-88] _ = x[actPreviewUp-88]
_ = x[actPreviewPageDown-89] _ = x[actPreviewDown-89]
_ = x[actPreviewHalfPageUp-90] _ = x[actPreviewPageUp-90]
_ = x[actPreviewHalfPageDown-91] _ = x[actPreviewPageDown-91]
_ = x[actPrevHistory-92] _ = x[actPreviewHalfPageUp-92]
_ = x[actPrevSelected-93] _ = x[actPreviewHalfPageDown-93]
_ = x[actPrint-94] _ = x[actPrevHistory-94]
_ = x[actPut-95] _ = x[actPrevSelected-95]
_ = x[actNextHistory-96] _ = x[actPrint-96]
_ = x[actNextSelected-97] _ = x[actPut-97]
_ = x[actExecute-98] _ = x[actNextHistory-98]
_ = x[actExecuteSilent-99] _ = x[actNextSelected-99]
_ = x[actExecuteMulti-100] _ = x[actExecute-100]
_ = x[actSigStop-101] _ = x[actExecuteSilent-101]
_ = x[actFirst-102] _ = x[actExecuteMulti-102]
_ = x[actLast-103] _ = x[actSigStop-103]
_ = x[actReload-104] _ = x[actFirst-104]
_ = x[actReloadSync-105] _ = x[actLast-105]
_ = x[actDisableSearch-106] _ = x[actReload-106]
_ = x[actEnableSearch-107] _ = x[actReloadSync-107]
_ = x[actSelect-108] _ = x[actDisableSearch-108]
_ = x[actDeselect-109] _ = x[actEnableSearch-109]
_ = x[actUnbind-110] _ = x[actSelect-110]
_ = x[actRebind-111] _ = x[actDeselect-111]
_ = x[actBecome-112] _ = x[actUnbind-112]
_ = x[actShowHeader-113] _ = x[actRebind-113]
_ = x[actHideHeader-114] _ = x[actBecome-114]
_ = x[actShowHeader-115]
_ = x[actHideHeader-116]
} }
const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeHeaderactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformHeaderactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader" const _actionType_name = "actIgnoreactStartactClickactInvalidactCharactMouseactBeginningOfLineactAbortactAcceptactAcceptNonEmptyactAcceptOrPrintQueryactBackwardCharactBackwardDeleteCharactBackwardDeleteCharEofactBackwardWordactCancelactChangeBorderLabelactChangeListLabelactChangeHeaderactChangeMultiactChangePreviewLabelactChangePromptactChangeQueryactClearScreenactClearQueryactClearSelectionactCloseactDeleteCharactDeleteCharEofactEndOfLineactFatalactForwardCharactForwardWordactKillLineactKillWordactUnixLineDiscardactUnixWordRuboutactYankactBackwardKillWordactSelectAllactDeselectAllactToggleactToggleSearchactToggleAllactToggleDownactToggleUpactToggleInactToggleOutactToggleTrackactToggleTrackCurrentactToggleHeaderactToggleWrapactToggleMultiLineactToggleHscrollactTrackCurrentactUntrackCurrentactDownactUpactPageUpactPageDownactPositionactHalfPageUpactHalfPageDownactOffsetUpactOffsetDownactOffsetMiddleactJumpactJumpAcceptactPrintQueryactRefreshPreviewactReplaceQueryactToggleSortactShowPreviewactHidePreviewactTogglePreviewactTogglePreviewWrapactTransformactTransformBorderLabelactTransformListLabelactTransformHeaderactTransformPreviewLabelactTransformPromptactTransformQueryactPreviewactChangePreviewactChangePreviewWindowactPreviewTopactPreviewBottomactPreviewUpactPreviewDownactPreviewPageUpactPreviewPageDownactPreviewHalfPageUpactPreviewHalfPageDownactPrevHistoryactPrevSelectedactPrintactPutactNextHistoryactNextSelectedactExecuteactExecuteSilentactExecuteMultiactSigStopactFirstactLastactReloadactReloadSyncactDisableSearchactEnableSearchactSelectactDeselectactUnbindactRebindactBecomeactShowHeaderactHideHeader"
var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 242, 256, 277, 292, 306, 320, 333, 350, 358, 371, 387, 399, 407, 421, 435, 446, 457, 475, 492, 499, 518, 530, 544, 553, 568, 580, 593, 604, 615, 627, 641, 662, 677, 690, 708, 724, 739, 756, 763, 768, 777, 788, 799, 812, 827, 838, 851, 866, 873, 886, 899, 916, 931, 944, 958, 972, 988, 1008, 1020, 1043, 1061, 1085, 1103, 1120, 1130, 1146, 1168, 1181, 1197, 1209, 1223, 1239, 1257, 1277, 1299, 1313, 1328, 1336, 1342, 1356, 1371, 1381, 1397, 1412, 1422, 1430, 1437, 1446, 1459, 1475, 1490, 1499, 1510, 1519, 1528, 1537, 1550, 1563} var _actionType_index = [...]uint16{0, 9, 17, 25, 35, 42, 50, 68, 76, 85, 102, 123, 138, 159, 183, 198, 207, 227, 245, 260, 274, 295, 310, 324, 338, 351, 368, 376, 389, 405, 417, 425, 439, 453, 464, 475, 493, 510, 517, 536, 548, 562, 571, 586, 598, 611, 622, 633, 645, 659, 680, 695, 708, 726, 742, 757, 774, 781, 786, 795, 806, 817, 830, 845, 856, 869, 884, 891, 904, 917, 934, 949, 962, 976, 990, 1006, 1026, 1038, 1061, 1082, 1100, 1124, 1142, 1159, 1169, 1185, 1207, 1220, 1236, 1248, 1262, 1278, 1296, 1316, 1338, 1352, 1367, 1375, 1381, 1395, 1410, 1420, 1436, 1451, 1461, 1469, 1476, 1485, 1498, 1514, 1529, 1538, 1549, 1558, 1567, 1576, 1589, 1602}
func (i actionType) String() string { func (i actionType) String() string {
if i < 0 || i >= actionType(len(_actionType_index)-1) { if i < 0 || i >= actionType(len(_actionType_index)-1) {

View File

@ -87,6 +87,14 @@ Usage: fzf [options]
[POSITIVE_INTEGER: columns from left| [POSITIVE_INTEGER: columns from left|
NEGATIVE_INTEGER: columns from right][:bottom] NEGATIVE_INTEGER: columns from right][:bottom]
(default: 0 or center) (default: 0 or center)
--list-border[=STYLE] Draw border around the list section
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
top|bottom|left|right|none] (default: none)
--list-label=LABEL Label to print on the list border
--list-label-pos=COL Position of the list label
[POSITIVE_INTEGER: columns from left|
NEGATIVE_INTEGER: columns from right][:bottom]
(default: 0 or center)
--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)
--info=STYLE Finder info style --info=STYLE Finder info style
@ -512,7 +520,9 @@ type Options struct {
Margin [4]sizeSpec Margin [4]sizeSpec
Padding [4]sizeSpec Padding [4]sizeSpec
BorderShape tui.BorderShape BorderShape tui.BorderShape
ListBorderShape tui.BorderShape
BorderLabel labelOpts BorderLabel labelOpts
ListLabel labelOpts
PreviewLabel labelOpts PreviewLabel labelOpts
Unicode bool Unicode bool
Ambidouble bool Ambidouble bool
@ -1166,6 +1176,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
mergeAttr(&theme.Fg) mergeAttr(&theme.Fg)
case "bg": case "bg":
mergeAttr(&theme.Bg) mergeAttr(&theme.Bg)
case "list-fg":
mergeAttr(&theme.ListFg)
case "list-bg":
mergeAttr(&theme.ListBg)
case "preview-fg": case "preview-fg":
mergeAttr(&theme.PreviewFg) mergeAttr(&theme.PreviewFg)
case "preview-bg": case "preview-bg":
@ -1198,6 +1212,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
mergeAttr(&theme.PreviewScrollbar) mergeAttr(&theme.PreviewScrollbar)
case "label": case "label":
mergeAttr(&theme.BorderLabel) mergeAttr(&theme.BorderLabel)
case "list-label":
mergeAttr(&theme.ListLabel)
case "list-border":
mergeAttr(&theme.ListBorder)
case "preview-label": case "preview-label":
mergeAttr(&theme.PreviewLabel) mergeAttr(&theme.PreviewLabel)
case "prompt": case "prompt":
@ -1265,7 +1283,7 @@ const (
func init() { func init() {
executeRegexp = regexp.MustCompile( executeRegexp = regexp.MustCompile(
`(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:header|query|prompt|border-label|preview-label)|transform|change-(?:preview-window|preview|multi)|(?:re|un)bind|pos|put|print)`) `(?si)[:+](become|execute(?:-multi|-silent)?|reload(?:-sync)?|preview|(?:change|transform)-(?:header|query|prompt|border-label|list-label|preview-label)|transform|change-(?:preview-window|preview|multi)|(?:re|un)bind|pos|put|print)`)
splitRegexp = regexp.MustCompile("[,:]+") splitRegexp = regexp.MustCompile("[,:]+")
actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+") actionNameRegexp = regexp.MustCompile("(?i)^[a-z-]+")
} }
@ -1621,6 +1639,8 @@ func isExecuteAction(str string) actionType {
return actRebind return actRebind
case "preview": case "preview":
return actPreview return actPreview
case "change-list-label":
return actChangeListLabel
case "change-border-label": case "change-border-label":
return actChangeBorderLabel return actChangeBorderLabel
case "change-header": case "change-header":
@ -1651,6 +1671,8 @@ func isExecuteAction(str string) actionType {
return actPut return actPut
case "transform": case "transform":
return actTransform return actTransform
case "transform-list-label":
return actTransformListLabel
case "transform-border-label": case "transform-border-label":
return actTransformBorderLabel return actTransformBorderLabel
case "transform-preview-label": case "transform-preview-label":
@ -2456,6 +2478,28 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if opts.BorderShape, err = parseBorder(arg, !hasArg); err != nil { if opts.BorderShape, err = parseBorder(arg, !hasArg); err != nil {
return err return err
} }
case "--list-border":
hasArg, arg := optionalNextString(allArgs, &i)
if opts.ListBorderShape, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--no-list-border":
opts.ListBorderShape = tui.BorderNone
case "--no-list-label":
opts.ListLabel.label = ""
case "--list-label":
opts.ListLabel.label, err = nextString(allArgs, &i, "label required")
if err != nil {
return err
}
case "--list-label-pos":
pos, err := nextString(allArgs, &i, "label position required (positive or negative integer or 'center')")
if err != nil {
return err
}
if err := parseLabelPosition(&opts.ListLabel, pos); err != nil {
return err
}
case "--no-border-label": case "--no-border-label":
opts.BorderLabel.label = "" opts.BorderLabel.label = ""
case "--border-label": case "--border-label":
@ -2593,6 +2637,12 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if opts.BorderShape, err = parseBorder(value, false); err != nil { if opts.BorderShape, err = parseBorder(value, false); err != nil {
return err return err
} }
} else if match, value := optString(arg, "--list-label="); match {
opts.ListLabel.label = value
} else if match, value := optString(arg, "--list-label-pos="); match {
if err := parseLabelPosition(&opts.ListLabel, value); err != nil {
return err
}
} else if match, value := optString(arg, "--border-label="); match { } else if match, value := optString(arg, "--border-label="); match {
opts.BorderLabel.label = value opts.BorderLabel.label = value
} else if match, value := optString(arg, "--border-label-pos="); match { } else if match, value := optString(arg, "--border-label-pos="); match {
@ -2864,6 +2914,10 @@ func postProcessOptions(opts *Options) error {
opts.BorderShape = tui.BorderNone opts.BorderShape = tui.BorderNone
} }
if opts.ListBorderShape == tui.BorderUndefined {
opts.ListBorderShape = tui.BorderNone
}
if opts.Pointer == nil { if opts.Pointer == nil {
defaultPointer := "▌" defaultPointer := "▌"
if !opts.Unicode { if !opts.Unicode {

View File

@ -297,11 +297,16 @@ type Terminal struct {
listener net.Listener listener net.Listener
listenUnsafe bool listenUnsafe bool
borderShape tui.BorderShape borderShape tui.BorderShape
listBorderShape tui.BorderShape
listLabel labelPrinter
listLabelLen int
listLabelOpts labelOpts
cleanExit bool cleanExit bool
executor *util.Executor executor *util.Executor
paused bool paused bool
border tui.Window border tui.Window
window tui.Window window tui.Window
wborder tui.Window
pborder tui.Window pborder tui.Window
pwindow tui.Window pwindow tui.Window
borderWidth int borderWidth int
@ -389,6 +394,7 @@ const (
reqReinit reqReinit
reqFullRedraw reqFullRedraw
reqResize reqResize
reqRedrawListLabel
reqRedrawBorderLabel reqRedrawBorderLabel
reqRedrawPreviewLabel reqRedrawPreviewLabel
reqClose reqClose
@ -429,6 +435,7 @@ const (
actBackwardWord actBackwardWord
actCancel actCancel
actChangeBorderLabel actChangeBorderLabel
actChangeListLabel
actChangeHeader actChangeHeader
actChangeMulti actChangeMulti
actChangePreviewLabel actChangePreviewLabel
@ -489,6 +496,7 @@ const (
actTogglePreviewWrap actTogglePreviewWrap
actTransform actTransform
actTransformBorderLabel actTransformBorderLabel
actTransformListLabel
actTransformHeader actTransformHeader
actTransformPreviewLabel actTransformPreviewLabel
actTransformPrompt actTransformPrompt
@ -823,7 +831,10 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
listenAddr: opts.ListenAddr, listenAddr: opts.ListenAddr,
listenUnsafe: opts.Unsafe, listenUnsafe: opts.Unsafe,
borderShape: opts.BorderShape, borderShape: opts.BorderShape,
listBorderShape: opts.ListBorderShape,
borderWidth: 1, borderWidth: 1,
listLabel: nil,
listLabelOpts: opts.ListLabel,
borderLabel: nil, borderLabel: nil,
borderLabelOpts: opts.BorderLabel, borderLabelOpts: opts.BorderLabel,
previewLabel: nil, previewLabel: nil,
@ -880,10 +891,15 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
executing: util.NewAtomicBool(false), executing: util.NewAtomicBool(false),
lastAction: actStart, lastAction: actStart,
lastFocus: minItem.Index()} lastFocus: minItem.Index()}
// This should be called before accessing tui.Color*
tui.InitTheme(opts.Theme, renderer.DefaultTheme(), opts.Black)
t.prompt, t.promptLen = t.parsePrompt(opts.Prompt) t.prompt, t.promptLen = t.parsePrompt(opts.Prompt)
// Pre-calculated empty pointer and marker signs // Pre-calculated empty pointer and marker signs
t.pointerEmpty = strings.Repeat(" ", t.pointerLen) t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
t.markerEmpty = strings.Repeat(" ", t.markerLen) t.markerEmpty = strings.Repeat(" ", t.markerLen)
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(opts.ListLabel.label, &tui.ColListLabel, false)
t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(opts.BorderLabel.label, &tui.ColBorderLabel, false) t.borderLabel, t.borderLabelLen = t.ansiLabelPrinter(opts.BorderLabel.label, &tui.ColBorderLabel, false)
t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(opts.PreviewLabel.label, &tui.ColPreviewLabel, false) t.previewLabel, t.previewLabelLen = t.ansiLabelPrinter(opts.PreviewLabel.label, &tui.ColPreviewLabel, false)
if opts.Separator == nil || len(*opts.Separator) > 0 { if opts.Separator == nil || len(*opts.Separator) > 0 {
@ -973,6 +989,7 @@ func (t *Terminal) environ() []string {
env = append(env, "FZF_PROMPT="+string(t.promptString)) env = append(env, "FZF_PROMPT="+string(t.promptString))
env = append(env, "FZF_PREVIEW_LABEL="+t.previewLabelOpts.label) env = append(env, "FZF_PREVIEW_LABEL="+t.previewLabelOpts.label)
env = append(env, "FZF_BORDER_LABEL="+t.borderLabelOpts.label) env = append(env, "FZF_BORDER_LABEL="+t.borderLabelOpts.label)
env = append(env, "FZF_LIST_LABEL="+t.listLabelOpts.label)
env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", t.count)) env = append(env, fmt.Sprintf("FZF_TOTAL_COUNT=%d", t.count))
env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.merger.Length())) env = append(env, fmt.Sprintf("FZF_MATCH_COUNT=%d", t.merger.Length()))
env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected))) env = append(env, fmt.Sprintf("FZF_SELECT_COUNT=%d", len(t.selected)))
@ -1114,7 +1131,7 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) {
// // unless the part has a non-default ANSI state // // unless the part has a non-default ANSI state
loc := whiteSuffix.FindStringIndex(trimmed) loc := whiteSuffix.FindStringIndex(trimmed)
if loc != nil { if loc != nil {
blankState := ansiOffset{[2]int32{int32(loc[0]), int32(loc[1])}, ansiState{-1, -1, tui.AttrClear, -1, nil}} blankState := ansiOffset{[2]int32{int32(loc[0]), int32(loc[1])}, ansiState{tui.ColPrompt.Fg(), tui.ColPrompt.Bg(), tui.AttrClear, -1, nil}}
if item.colors != nil { if item.colors != nil {
lastColor := (*item.colors)[len(*item.colors)-1] lastColor := (*item.colors)[len(*item.colors)-1]
if lastColor.offset[1] < int32(loc[1]) { if lastColor.offset[1] < int32(loc[1]) {
@ -1546,6 +1563,9 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
if t.window != nil { if t.window != nil {
t.window = nil t.window = nil
} }
if t.wborder != nil {
t.wborder = nil
}
if t.pborder != nil { if t.pborder != nil {
t.pborder = nil t.pborder = nil
} }
@ -1572,10 +1592,10 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
offsets[1] -= 1 + bw offsets[1] -= 1 + bw
offsets[2] += 1 + bw offsets[2] += 1 + bw
} }
if t.border == nil && t.borderShape != tui.BorderNone { if t.border == nil && t.borderShape.Visible() {
t.border = t.tui.NewWindow( t.border = t.tui.NewWindow(
marginInt[0]+offsets[0], marginInt[3]+offsets[1], width+offsets[2], height+offsets[3], marginInt[0]+offsets[0], marginInt[3]+offsets[1], width+offsets[2], height+offsets[3],
false, tui.MakeBorderStyle(t.borderShape, t.unicode)) tui.WindowBase, tui.MakeBorderStyle(t.borderShape, t.unicode), true)
} }
// Add padding to margin // Add padding to margin
@ -1585,6 +1605,33 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
width -= paddingInt[1] + paddingInt[3] width -= paddingInt[1] + paddingInt[3]
height -= paddingInt[0] + paddingInt[2] height -= paddingInt[0] + paddingInt[2]
hasListBorder := t.listBorderShape.Visible()
innerWidth := width
innerHeight := height
innerMarginInt := marginInt
innerBorderFn := func(top int, left int, width int, height int) {
if hasListBorder {
t.wborder = t.tui.NewWindow(
top, left, width, height, tui.WindowList, tui.MakeBorderStyle(t.listBorderShape, t.unicode), false)
}
}
if hasListBorder {
if t.listBorderShape.HasTop() {
innerHeight--
innerMarginInt[0]++
}
if t.listBorderShape.HasBottom() {
innerHeight--
}
if t.listBorderShape.HasLeft() {
innerWidth -= 2
innerMarginInt[3] += 2
}
if t.listBorderShape.HasRight() {
innerWidth--
}
}
t.areaLines = height t.areaLines = height
t.areaColumns = width t.areaColumns = width
@ -1592,6 +1639,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode) noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode)
if forcePreview || t.needPreviewWindow() { if forcePreview || t.needPreviewWindow() {
var resizePreviewWindows func(previewOpts *previewOpts) var resizePreviewWindows func(previewOpts *previewOpts)
stickToRight := false
resizePreviewWindows = func(previewOpts *previewOpts) { resizePreviewWindows = func(previewOpts *previewOpts) {
t.activePreviewOpts = previewOpts t.activePreviewOpts = previewOpts
if previewOpts.size.size == 0 { if previewOpts.size.size == 0 {
@ -1602,7 +1650,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
pwidth := w pwidth := w
pheight := h pheight := h
previewBorder := tui.MakeBorderStyle(previewOpts.border, t.unicode) previewBorder := tui.MakeBorderStyle(previewOpts.border, t.unicode)
t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder) t.pborder = t.tui.NewWindow(y, x, w, h, tui.WindowPreview, previewBorder, false)
pwidth -= borderColumns(previewOpts.border, bw) pwidth -= borderColumns(previewOpts.border, bw)
pheight -= borderLines(previewOpts.border) pheight -= borderLines(previewOpts.border)
if previewOpts.border.HasLeft() { if previewOpts.border.HasLeft() {
@ -1617,7 +1665,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
} }
pwidth = util.Max(0, pwidth) pwidth = util.Max(0, pwidth)
pheight = util.Max(0, pheight) pheight = util.Max(0, pheight)
t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder) t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, tui.WindowPreview, noBorder, true)
if !hadPreviewWindow { if !hadPreviewWindow {
t.pwindow.Erase() t.pwindow.Erase()
} }
@ -1647,16 +1695,25 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
return return
} }
if previewOpts.position == posUp { if previewOpts.position == posUp {
innerBorderFn(marginInt[0]+pheight, marginInt[3], width, height-pheight)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder) innerMarginInt[0]+pheight, innerMarginInt[3], innerWidth, innerHeight-pheight, tui.WindowList, noBorder, true)
createPreviewWindow(marginInt[0], marginInt[3], width, pheight) createPreviewWindow(marginInt[0], marginInt[3], width, pheight)
} else { } else {
innerBorderFn(marginInt[0], marginInt[3], width, height-pheight)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width, height-pheight, false, noBorder) innerMarginInt[0], innerMarginInt[3], innerWidth, innerHeight-pheight, tui.WindowList, noBorder, true)
createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight) createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight)
} }
case posLeft, posRight: case posLeft, posRight:
pwidth := calculateSize(width, previewOpts.size, minWidth, minPreviewWidth) minListWidth := minWidth
if t.listBorderShape.HasLeft() {
minListWidth += 2
}
if t.listBorderShape.HasRight() {
minListWidth++
}
pwidth := calculateSize(width, previewOpts.size, minListWidth, minPreviewWidth)
if hasThreshold && pwidth < previewOpts.threshold { if hasThreshold && pwidth < previewOpts.threshold {
t.activePreviewOpts = previewOpts.alternative t.activePreviewOpts = previewOpts.alternative
if forcePreview { if forcePreview {
@ -1675,52 +1732,83 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
} }
if previewOpts.position == posLeft { if previewOpts.position == posLeft {
// Put scrollbar closer to the right border for consistent look // Put scrollbar closer to the right border for consistent look
if t.borderShape.HasRight() { if t.borderShape.HasRight() && !hasListBorder {
width++ innerWidth++
} }
// Add a 1-column margin between the preview window and the main window // Add a 1-column margin between the preview window and the main window
m := 0
if !hasListBorder {
m = 1
}
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], marginInt[3]+pwidth+1, width-pwidth-1, height, false, noBorder) innerMarginInt[0], innerMarginInt[3]+pwidth+m, innerWidth-pwidth-m, innerHeight, tui.WindowList, noBorder, true)
// Clear characters on the margin // Clear characters on the margin
// fzf --bind 'space:preview(seq 100)' --preview-window left,1 // fzf --bind 'space:preview(seq 100)' --preview-window left,1
for y := 0; y < height; y++ { if !hasListBorder {
for y := 0; y < innerHeight; y++ {
t.window.Move(y, -1) t.window.Move(y, -1)
t.window.Print(" ") t.window.Print(" ")
} }
}
innerBorderFn(marginInt[0], marginInt[3]+pwidth, width-pwidth, height)
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
if !previewOpts.border.HasRight() && t.borderShape.HasRight() { stickToRight = !previewOpts.border.HasRight() && t.borderShape.HasRight()
if stickToRight {
innerWidth++
width++ width++
} }
innerBorderFn(marginInt[0], marginInt[3], width-pwidth, height)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width-pwidth, height, false, noBorder) innerMarginInt[0], innerMarginInt[3], innerWidth-pwidth, innerHeight, tui.WindowList, noBorder, true)
x := marginInt[3] + width - pwidth x := marginInt[3] + width - pwidth
createPreviewWindow(marginInt[0], x, pwidth, height) createPreviewWindow(marginInt[0], x, pwidth, height)
} }
} }
} }
resizePreviewWindows(&t.previewOpts) resizePreviewWindows(&t.previewOpts)
if t.borderShape.HasRight() && !stickToRight {
// Need to clear the extra margin between the borders
// fzf --preview 'seq 1000' --preview-window border-left --bind space:change-preview-window:border-rounded --border vertical
// fzf --preview 'seq 1000' --preview-window up,hidden --bind space:toggle-preview --border vertical
y := 0
if t.borderShape.HasTop() {
y++
}
maxY := t.border.Height()
if t.borderShape.HasBottom() {
maxY--
}
for ; y < maxY; y++ {
t.border.Move(y, t.border.Width()-2)
t.border.Print(" ")
}
}
} else { } else {
t.activePreviewOpts = &t.previewOpts t.activePreviewOpts = &t.previewOpts
} }
// Without preview window // Without preview window
if t.window == nil { if t.window == nil {
if t.borderShape.HasRight() { if t.borderShape.HasRight() && !hasListBorder {
// Put scrollbar closer to the right border for consistent look // Put scrollbar closer to the right border for consistent look
innerWidth++
width++ width++
} }
innerBorderFn(marginInt[0], marginInt[3], width, height)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], innerMarginInt[0],
marginInt[3], innerMarginInt[3],
width, innerWidth,
height, false, noBorder) innerHeight, tui.WindowList, noBorder, true)
} }
// Print border label // Print border label
t.printLabel(t.wborder, t.listLabel, t.listLabelOpts, t.listLabelLen, t.listBorderShape, false)
t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, false) t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, false)
t.printLabel(t.pborder, t.previewLabel, t.previewLabelOpts, t.previewLabelLen, t.activePreviewOpts.border, false) t.printLabel(t.pborder, t.previewLabel, t.previewLabelOpts, t.previewLabelLen, t.activePreviewOpts.border, false)
} }
@ -1839,6 +1927,9 @@ func (t *Terminal) trimMessage(message string, maxWidth int) string {
} }
func (t *Terminal) printInfo() { func (t *Terminal) printInfo() {
if t.window.Width() <= 1 {
return
}
pos := 0 pos := 0
line := t.promptLine() line := t.promptLine()
maxHeight := t.window.Height() maxHeight := t.window.Height()
@ -1977,7 +2068,9 @@ func (t *Terminal) printInfo() {
} else { } else {
outputPrinter(t.window, maxWidth-1) outputPrinter(t.window, maxWidth-1)
} }
if fillLength >= 0 {
t.window.Print(" ") // Margin t.window.Print(" ") // Margin
}
return return
} }
@ -2115,7 +2208,7 @@ func (t *Terminal) printList() {
func (t *Terminal) printBar(lineNum int, forceRedraw bool, barRange [2]int) bool { func (t *Terminal) printBar(lineNum int, forceRedraw bool, barRange [2]int) bool {
hasBar := lineNum >= barRange[0] && lineNum < barRange[1] hasBar := lineNum >= barRange[0] && lineNum < barRange[1]
if hasBar != t.prevLines[lineNum].hasBar || forceRedraw { if (hasBar != t.prevLines[lineNum].hasBar || forceRedraw) && t.window.Width() > 0 {
t.move(lineNum, t.window.Width()-1, true) t.move(lineNum, t.window.Width()-1, true)
if len(t.scrollbar) > 0 && hasBar { if len(t.scrollbar) > 0 && hasBar {
t.window.CPrint(tui.ColScrollbar, t.scrollbar) t.window.CPrint(tui.ColScrollbar, t.scrollbar)
@ -2212,11 +2305,18 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
} }
if current { if current {
preTask := func(marker markerClass) { preTask := func(marker markerClass) {
w := t.window.Width() - t.pointerLen
if w < 0 {
return
}
if len(label) == 0 { if len(label) == 0 {
t.window.CPrint(tui.ColCurrentCursorEmpty, t.pointerEmpty) t.window.CPrint(tui.ColCurrentCursorEmpty, t.pointerEmpty)
} else { } else {
t.window.CPrint(tui.ColCurrentCursor, label) t.window.CPrint(tui.ColCurrentCursor, label)
} }
if w-t.markerLen < 0 {
return
}
if selected { if selected {
t.window.CPrint(tui.ColCurrentMarker, markerFor(marker)) t.window.CPrint(tui.ColCurrentMarker, markerFor(marker))
} else { } else {
@ -2226,11 +2326,18 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
finalLineNum = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true, line, maxLine, forceRedraw, preTask, postTask) finalLineNum = t.printHighlighted(result, tui.ColCurrent, tui.ColCurrentMatch, true, true, line, maxLine, forceRedraw, preTask, postTask)
} else { } else {
preTask := func(marker markerClass) { preTask := func(marker markerClass) {
w := t.window.Width() - t.pointerLen
if w < 0 {
return
}
if len(label) == 0 { if len(label) == 0 {
t.window.CPrint(tui.ColCursorEmpty, t.pointerEmpty) t.window.CPrint(tui.ColCursorEmpty, t.pointerEmpty)
} else { } else {
t.window.CPrint(tui.ColCursor, label) t.window.CPrint(tui.ColCursor, label)
} }
if w-t.markerLen < 0 {
return
}
if selected { if selected {
t.window.CPrint(tui.ColMarker, markerFor(marker)) t.window.CPrint(tui.ColMarker, markerFor(marker))
} else { } else {
@ -2946,7 +3053,7 @@ func (t *Terminal) flush() {
t.placeCursor() t.placeCursor()
if !t.suppress { if !t.suppress {
windows := make([]tui.Window, 0, 4) windows := make([]tui.Window, 0, 4)
if t.borderShape != tui.BorderNone { if t.borderShape.Visible() {
windows = append(windows, t.border) windows = append(windows, t.border)
} }
if t.hasPreviewWindow() { if t.hasPreviewWindow() {
@ -3855,6 +3962,8 @@ func (t *Terminal) Loop() error {
if t.hasPreviewer() { if t.hasPreviewer() {
t.previewBox.Set(reqPreviewReady, nil) t.previewBox.Set(reqPreviewReady, nil)
} }
case reqRedrawListLabel:
t.printLabel(t.wborder, t.listLabel, t.listLabelOpts, t.listLabelLen, t.listBorderShape, true)
case reqRedrawBorderLabel: case reqRedrawBorderLabel:
t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, true) t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, true)
case reqRedrawPreviewLabel: case reqRedrawPreviewLabel:
@ -3952,7 +4061,7 @@ func (t *Terminal) Loop() error {
previewDraggingPos := -1 previewDraggingPos := -1
barDragging := false barDragging := false
pbarDragging := false pbarDragging := false
pborderDragging := false pborderDragging := -1
wasDown := false wasDown := false
needBarrier := true needBarrier := true
@ -4236,6 +4345,12 @@ func (t *Terminal) Loop() error {
} else { } else {
req(reqHeader) req(reqHeader)
} }
case actChangeListLabel:
t.listLabelOpts.label = a.a
if t.wborder != nil {
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(a.a, &tui.ColListLabel, false)
req(reqRedrawListLabel)
}
case actChangeBorderLabel: case actChangeBorderLabel:
t.borderLabelOpts.label = a.a t.borderLabelOpts.label = a.a
if t.border != nil { if t.border != nil {
@ -4253,6 +4368,13 @@ func (t *Terminal) Loop() error {
if actions, err := parseSingleActionList(strings.Trim(body, "\r\n")); err == nil { if actions, err := parseSingleActionList(strings.Trim(body, "\r\n")); err == nil {
return doActions(actions) return doActions(actions)
} }
case actTransformListLabel:
label := t.executeCommand(a.a, false, true, true, true, "")
t.listLabelOpts.label = label
if t.wborder != nil {
t.listLabel, t.listLabelLen = t.ansiLabelPrinter(label, &tui.ColListLabel, false)
req(reqRedrawListLabel)
}
case actTransformBorderLabel: case actTransformBorderLabel:
label := t.executeCommand(a.a, false, true, true, true, "") label := t.executeCommand(a.a, false, true, true, true, "")
t.borderLabelOpts.label = label t.borderLabelOpts.label = label
@ -4684,7 +4806,7 @@ func (t *Terminal) Loop() error {
if !me.Down { if !me.Down {
barDragging = false barDragging = false
pbarDragging = false pbarDragging = false
pborderDragging = false pborderDragging = -1
previewDraggingPos = -1 previewDraggingPos = -1
} }
@ -4740,20 +4862,36 @@ func (t *Terminal) Loop() error {
} }
// Preview border dragging (resizing) // Preview border dragging (resizing)
if !pborderDragging && clicked && t.hasPreviewWindow() && t.pborder.Enclose(my, mx) { if pborderDragging < 0 && clicked && t.hasPreviewWindow() {
switch t.activePreviewOpts.position { switch t.activePreviewOpts.position {
case posUp: case posUp:
pborderDragging = my == t.pborder.Top()+t.pborder.Height()-1 if t.pborder.Enclose(my, mx) && my == t.pborder.Top()+t.pborder.Height()-1 {
pborderDragging = 0
} else if t.listBorderShape.HasTop() && t.wborder.Enclose(my, mx) && my == t.wborder.Top() {
pborderDragging = 1
}
case posDown: case posDown:
pborderDragging = my == t.pborder.Top() if t.pborder.Enclose(my, mx) && my == t.pborder.Top() {
pborderDragging = 0
} else if t.listBorderShape.HasBottom() && t.wborder.Enclose(my, mx) && my == t.wborder.Top()+t.wborder.Height()-1 {
pborderDragging = 1
}
case posLeft: case posLeft:
pborderDragging = mx == t.pborder.Left()+t.pborder.Width()-1 if t.pborder.Enclose(my, mx) && mx == t.pborder.Left()+t.pborder.Width()-1 {
pborderDragging = 0
} else if t.listBorderShape.HasLeft() && t.wborder.Enclose(my, mx) && mx == t.wborder.Left() {
pborderDragging = 1
}
case posRight: case posRight:
pborderDragging = mx == t.pborder.Left() if t.pborder.Enclose(my, mx) && mx == t.pborder.Left() {
pborderDragging = 0
} else if t.listBorderShape.HasRight() && t.wborder.Enclose(my, mx) && mx == t.wborder.Left()+t.wborder.Width()-1 {
pborderDragging = 1
}
} }
} }
if pborderDragging { if pborderDragging >= 0 {
var newSize int var newSize int
var prevSize int var prevSize int
switch t.activePreviewOpts.position { switch t.activePreviewOpts.position {
@ -4774,6 +4912,7 @@ func (t *Terminal) Loop() error {
offset := mx - t.pborder.Left() offset := mx - t.pborder.Left()
newSize = prevSize - offset newSize = prevSize - offset
} }
newSize -= pborderDragging
if newSize < 1 { if newSize < 1 {
newSize = 1 newSize = 1
} }

View File

@ -30,6 +30,7 @@ const (
) )
func (r *FullscreenRenderer) Init() error { return nil } func (r *FullscreenRenderer) Init() error { return nil }
func (r *FullscreenRenderer) DefaultTheme() *ColorTheme { return nil }
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {} func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
func (r *FullscreenRenderer) Pause(bool) {} func (r *FullscreenRenderer) Pause(bool) {}
func (r *FullscreenRenderer) Resume(bool, bool) {} func (r *FullscreenRenderer) Resume(bool, bool) {}
@ -48,6 +49,6 @@ func (r *FullscreenRenderer) MaxY() int { return 0 }
func (r *FullscreenRenderer) RefreshWindows(windows []Window) {} func (r *FullscreenRenderer) RefreshWindows(windows []Window) {}
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window { func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window {
return nil return nil
} }

View File

@ -118,7 +118,7 @@ type LightRenderer struct {
type LightWindow struct { type LightWindow struct {
renderer *LightRenderer renderer *LightRenderer
colored bool colored bool
preview bool windowType WindowType
border BorderStyle border BorderStyle
top int top int
left int left int
@ -174,7 +174,6 @@ func (r *LightRenderer) Init() error {
return err return err
} }
r.updateTerminalSize() r.updateTerminalSize()
initTheme(r.theme, r.defaultTheme(), r.forceBlack)
if r.fullscreen { if r.fullscreen {
r.smcup() r.smcup()
@ -780,11 +779,11 @@ func (r *LightRenderer) MaxY() int {
return r.height return r.height
} }
func (r *LightRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window { func (r *LightRenderer) NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window {
w := &LightWindow{ w := &LightWindow{
renderer: r, renderer: r,
colored: r.theme.Colored, colored: r.theme.Colored,
preview: preview, windowType: windowType,
border: borderStyle, border: borderStyle,
top: top, top: top,
left: left, left: left,
@ -793,14 +792,19 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, prev
tabstop: r.tabstop, tabstop: r.tabstop,
fg: colDefault, fg: colDefault,
bg: colDefault} bg: colDefault}
if preview { switch windowType {
w.fg = r.theme.PreviewFg.Color case WindowBase:
w.bg = r.theme.PreviewBg.Color
} else {
w.fg = r.theme.Fg.Color w.fg = r.theme.Fg.Color
w.bg = r.theme.Bg.Color w.bg = r.theme.Bg.Color
case WindowList:
w.fg = r.theme.ListFg.Color
w.bg = r.theme.ListBg.Color
case WindowPreview:
w.fg = r.theme.PreviewFg.Color
w.bg = r.theme.PreviewBg.Color
} }
if !w.bg.IsDefault() && w.border.shape != BorderNone { if erase && !w.bg.IsDefault() && w.border.shape != BorderNone {
// fzf --color bg:blue --border --padding 1,2
w.Erase() w.Erase()
} }
w.drawBorder(false) w.drawBorder(false)
@ -845,7 +849,10 @@ func (w *LightWindow) drawBorder(onlyHorizontal bool) {
func (w *LightWindow) drawBorderHorizontal(top, bottom bool) { func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
color := ColBorder color := ColBorder
if w.preview { switch w.windowType {
case WindowList:
color = ColListBorder
case WindowPreview:
color = ColPreviewBorder color = ColPreviewBorder
} }
hw := runeWidth(w.border.top) hw := runeWidth(w.border.top)
@ -863,7 +870,10 @@ func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
func (w *LightWindow) drawBorderVertical(left, right bool) { func (w *LightWindow) drawBorderVertical(left, right bool) {
vw := runeWidth(w.border.left) vw := runeWidth(w.border.left)
color := ColBorder color := ColBorder
if w.preview { switch w.windowType {
case WindowList:
color = ColListBorder
case WindowPreview:
color = ColPreviewBorder color = ColPreviewBorder
} }
for y := 0; y < w.height; y++ { for y := 0; y < w.height; y++ {
@ -883,7 +893,10 @@ func (w *LightWindow) drawBorderVertical(left, right bool) {
func (w *LightWindow) drawBorderAround(onlyHorizontal bool) { func (w *LightWindow) drawBorderAround(onlyHorizontal bool) {
w.Move(0, 0) w.Move(0, 0)
color := ColBorder color := ColBorder
if w.preview { switch w.windowType {
case WindowList:
color = ColListBorder
case WindowPreview:
color = ColPreviewBorder color = ColPreviewBorder
} }
hw := runeWidth(w.border.top) hw := runeWidth(w.border.top)

View File

@ -18,7 +18,7 @@ func IsLightRendererSupported() bool {
return true return true
} }
func (r *LightRenderer) defaultTheme() *ColorTheme { func (r *LightRenderer) DefaultTheme() *ColorTheme {
if strings.Contains(os.Getenv("TERM"), "256") { if strings.Contains(os.Getenv("TERM"), "256") {
return Dark256 return Dark256
} }

View File

@ -39,7 +39,7 @@ func IsLightRendererSupported() bool {
return canSetVt100 return canSetVt100
} }
func (r *LightRenderer) defaultTheme() *ColorTheme { func (r *LightRenderer) DefaultTheme() *ColorTheme {
// the getenv check is borrowed from here: https://github.com/gdamore/tcell/commit/0c473b86d82f68226a142e96cc5a34c5a29b3690#diff-b008fcd5e6934bf31bc3d33bf49f47d8R178: // the getenv check is borrowed from here: https://github.com/gdamore/tcell/commit/0c473b86d82f68226a142e96cc5a34c5a29b3690#diff-b008fcd5e6934bf31bc3d33bf49f47d8R178:
if !IsLightRendererSupported() || os.Getenv("ConEmuPID") != "" || os.Getenv("TCELL_TRUECOLOR") == "disable" { if !IsLightRendererSupported() || os.Getenv("ConEmuPID") != "" || os.Getenv("TCELL_TRUECOLOR") == "disable" {
return Default16 return Default16

View File

@ -40,7 +40,7 @@ type Attr int32
type TcellWindow struct { type TcellWindow struct {
color bool color bool
preview bool windowType WindowType
top int top int
left int left int
width int width int
@ -106,8 +106,12 @@ func (r *FullscreenRenderer) PassThrough(str string) {
func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {} func (r *FullscreenRenderer) Resize(maxHeightFunc func(int) int) {}
func (r *FullscreenRenderer) defaultTheme() *ColorTheme { func (r *FullscreenRenderer) DefaultTheme() *ColorTheme {
if _screen.Colors() >= 256 { s, e := r.getScreen()
if e != nil {
return Default16
}
if s.Colors() >= 256 {
return Dark256 return Dark256
} }
return Default16 return Default16
@ -148,8 +152,19 @@ var (
_initialResize bool = true _initialResize bool = true
) )
func (r *FullscreenRenderer) initScreen() error { func (r *FullscreenRenderer) getScreen() (tcell.Screen, error) {
if _screen == nil {
s, e := tcell.NewScreen() s, e := tcell.NewScreen()
if e != nil {
return nil, e
}
_screen = s
}
return _screen, nil
}
func (r *FullscreenRenderer) initScreen() error {
s, e := r.getScreen()
if e != nil { if e != nil {
return e return e
} }
@ -161,7 +176,6 @@ func (r *FullscreenRenderer) initScreen() error {
} else { } else {
s.DisableMouse() s.DisableMouse()
} }
_screen = s
return nil return nil
} }
@ -174,7 +188,6 @@ func (r *FullscreenRenderer) Init() error {
if err := r.initScreen(); err != nil { if err := r.initScreen(); err != nil {
return err return err
} }
initTheme(r.theme, r.defaultTheme(), r.forceBlack)
return nil return nil
} }
@ -537,14 +550,17 @@ func (r *FullscreenRenderer) RefreshWindows(windows []Window) {
_screen.Show() _screen.Show()
} }
func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window { func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window {
normal := ColNormal normal := ColBorder
if preview { switch windowType {
normal = ColPreview case WindowList:
normal = ColListBorder
case WindowPreview:
normal = ColPreviewBorder
} }
w := &TcellWindow{ w := &TcellWindow{
color: r.theme.Colored, color: r.theme.Colored,
preview: preview, windowType: windowType,
top: top, top: top,
left: left, left: left,
width: width, width: width,
@ -564,11 +580,7 @@ func fill(x, y, w, h int, n ColorPair, r rune) {
} }
func (w *TcellWindow) Erase() { func (w *TcellWindow) Erase() {
if w.borderStyle.shape.HasLeft() {
fill(w.left-1, w.top, w.width, w.height-1, w.normal, ' ')
} else {
fill(w.left, w.top, w.width-1, w.height-1, w.normal, ' ') fill(w.left, w.top, w.width-1, w.height-1, w.normal, ' ')
}
w.drawBorder(false) w.drawBorder(false)
} }
@ -768,10 +780,13 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
var style tcell.Style var style tcell.Style
if w.color { if w.color {
if w.preview { switch w.windowType {
style = ColPreviewBorder.style() case WindowBase:
} else {
style = ColBorder.style() style = ColBorder.style()
case WindowList:
style = ColListBorder.style()
case WindowPreview:
style = ColPreviewBorder.style()
} }
} else { } else {
style = w.normal.style() style = w.normal.style()

View File

@ -303,6 +303,8 @@ type ColorTheme struct {
Disabled ColorAttr Disabled ColorAttr
Fg ColorAttr Fg ColorAttr
Bg ColorAttr Bg ColorAttr
ListFg ColorAttr
ListBg ColorAttr
SelectedFg ColorAttr SelectedFg ColorAttr
SelectedBg ColorAttr SelectedBg ColorAttr
SelectedMatch ColorAttr SelectedMatch ColorAttr
@ -323,9 +325,11 @@ type ColorTheme struct {
Scrollbar ColorAttr Scrollbar ColorAttr
Border ColorAttr Border ColorAttr
PreviewBorder ColorAttr PreviewBorder ColorAttr
PreviewLabel ColorAttr
PreviewScrollbar ColorAttr PreviewScrollbar ColorAttr
BorderLabel ColorAttr BorderLabel ColorAttr
PreviewLabel ColorAttr ListLabel ColorAttr
ListBorder ColorAttr
} }
type Event struct { type Event struct {
@ -395,6 +399,10 @@ func (s BorderShape) HasBottom() bool {
return true return true
} }
func (s BorderShape) Visible() bool {
return s != BorderNone
}
type BorderStyle struct { type BorderStyle struct {
shape BorderShape shape BorderShape
top rune top rune
@ -525,7 +533,16 @@ type TermSize struct {
PxHeight int PxHeight int
} }
type WindowType int
const (
WindowBase WindowType = iota
WindowList
WindowPreview
)
type Renderer interface { type Renderer interface {
DefaultTheme() *ColorTheme
Init() error Init() error
Resize(maxHeightFunc func(int) int) Resize(maxHeightFunc func(int) int)
Pause(clear bool) Pause(clear bool)
@ -546,7 +563,7 @@ type Renderer interface {
Size() TermSize Size() TermSize
NewWindow(top int, left int, width int, height int, preview bool, borderStyle BorderStyle) Window NewWindow(top int, left int, width int, height int, windowType WindowType, borderStyle BorderStyle, erase bool) Window
} }
type Window interface { type Window interface {
@ -627,6 +644,8 @@ var (
ColPreviewLabel ColorPair ColPreviewLabel ColorPair
ColPreviewScrollbar ColorPair ColPreviewScrollbar ColorPair
ColPreviewSpinner ColorPair ColPreviewSpinner ColorPair
ColListBorder ColorPair
ColListLabel ColorPair
) )
func EmptyTheme() *ColorTheme { func EmptyTheme() *ColorTheme {
@ -635,6 +654,8 @@ func EmptyTheme() *ColorTheme {
Input: ColorAttr{colUndefined, AttrUndefined}, Input: ColorAttr{colUndefined, AttrUndefined},
Fg: ColorAttr{colUndefined, AttrUndefined}, Fg: ColorAttr{colUndefined, AttrUndefined},
Bg: ColorAttr{colUndefined, AttrUndefined}, Bg: ColorAttr{colUndefined, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined}, SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined}, SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined}, SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@ -650,6 +671,8 @@ func EmptyTheme() *ColorTheme {
Header: ColorAttr{colUndefined, AttrUndefined}, Header: ColorAttr{colUndefined, AttrUndefined},
Border: ColorAttr{colUndefined, AttrUndefined}, Border: ColorAttr{colUndefined, AttrUndefined},
BorderLabel: ColorAttr{colUndefined, AttrUndefined}, BorderLabel: ColorAttr{colUndefined, AttrUndefined},
ListLabel: ColorAttr{colUndefined, AttrUndefined},
ListBorder: ColorAttr{colUndefined, AttrUndefined},
Disabled: ColorAttr{colUndefined, AttrUndefined}, Disabled: ColorAttr{colUndefined, AttrUndefined},
PreviewFg: ColorAttr{colUndefined, AttrUndefined}, PreviewFg: ColorAttr{colUndefined, AttrUndefined},
PreviewBg: ColorAttr{colUndefined, AttrUndefined}, PreviewBg: ColorAttr{colUndefined, AttrUndefined},
@ -668,6 +691,8 @@ func NoColorTheme() *ColorTheme {
Input: ColorAttr{colDefault, AttrUndefined}, Input: ColorAttr{colDefault, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colDefault, AttrUndefined},
ListBg: ColorAttr{colDefault, AttrUndefined},
SelectedFg: ColorAttr{colDefault, AttrUndefined}, SelectedFg: ColorAttr{colDefault, AttrUndefined},
SelectedBg: ColorAttr{colDefault, AttrUndefined}, SelectedBg: ColorAttr{colDefault, AttrUndefined},
SelectedMatch: ColorAttr{colDefault, AttrUndefined}, SelectedMatch: ColorAttr{colDefault, AttrUndefined},
@ -690,6 +715,8 @@ func NoColorTheme() *ColorTheme {
PreviewBorder: ColorAttr{colDefault, AttrUndefined}, PreviewBorder: ColorAttr{colDefault, AttrUndefined},
PreviewScrollbar: ColorAttr{colDefault, AttrUndefined}, PreviewScrollbar: ColorAttr{colDefault, AttrUndefined},
PreviewLabel: ColorAttr{colDefault, AttrUndefined}, PreviewLabel: ColorAttr{colDefault, AttrUndefined},
ListLabel: ColorAttr{colDefault, AttrUndefined},
ListBorder: ColorAttr{colDefault, AttrUndefined},
Separator: ColorAttr{colDefault, AttrUndefined}, Separator: ColorAttr{colDefault, AttrUndefined},
Scrollbar: ColorAttr{colDefault, AttrUndefined}, Scrollbar: ColorAttr{colDefault, AttrUndefined},
} }
@ -701,6 +728,8 @@ func init() {
Input: ColorAttr{colDefault, AttrUndefined}, Input: ColorAttr{colDefault, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined}, SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined}, SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined}, SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@ -723,6 +752,8 @@ func init() {
PreviewBorder: ColorAttr{colUndefined, AttrUndefined}, PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined}, PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
PreviewLabel: ColorAttr{colUndefined, AttrUndefined}, PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
ListLabel: ColorAttr{colUndefined, AttrUndefined},
ListBorder: ColorAttr{colUndefined, AttrUndefined},
Separator: ColorAttr{colUndefined, AttrUndefined}, Separator: ColorAttr{colUndefined, AttrUndefined},
Scrollbar: ColorAttr{colUndefined, AttrUndefined}, Scrollbar: ColorAttr{colUndefined, AttrUndefined},
} }
@ -731,6 +762,8 @@ func init() {
Input: ColorAttr{colDefault, AttrUndefined}, Input: ColorAttr{colDefault, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined}, SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined}, SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined}, SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@ -753,6 +786,8 @@ func init() {
PreviewBorder: ColorAttr{colUndefined, AttrUndefined}, PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined}, PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
PreviewLabel: ColorAttr{colUndefined, AttrUndefined}, PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
ListLabel: ColorAttr{colUndefined, AttrUndefined},
ListBorder: ColorAttr{colUndefined, AttrUndefined},
Separator: ColorAttr{colUndefined, AttrUndefined}, Separator: ColorAttr{colUndefined, AttrUndefined},
Scrollbar: ColorAttr{colUndefined, AttrUndefined}, Scrollbar: ColorAttr{colUndefined, AttrUndefined},
} }
@ -761,6 +796,8 @@ func init() {
Input: ColorAttr{colDefault, AttrUndefined}, Input: ColorAttr{colDefault, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined}, Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined}, Bg: ColorAttr{colDefault, AttrUndefined},
ListFg: ColorAttr{colUndefined, AttrUndefined},
ListBg: ColorAttr{colUndefined, AttrUndefined},
SelectedFg: ColorAttr{colUndefined, AttrUndefined}, SelectedFg: ColorAttr{colUndefined, AttrUndefined},
SelectedBg: ColorAttr{colUndefined, AttrUndefined}, SelectedBg: ColorAttr{colUndefined, AttrUndefined},
SelectedMatch: ColorAttr{colUndefined, AttrUndefined}, SelectedMatch: ColorAttr{colUndefined, AttrUndefined},
@ -783,12 +820,14 @@ func init() {
PreviewBorder: ColorAttr{colUndefined, AttrUndefined}, PreviewBorder: ColorAttr{colUndefined, AttrUndefined},
PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined}, PreviewScrollbar: ColorAttr{colUndefined, AttrUndefined},
PreviewLabel: ColorAttr{colUndefined, AttrUndefined}, PreviewLabel: ColorAttr{colUndefined, AttrUndefined},
ListLabel: ColorAttr{colUndefined, AttrUndefined},
ListBorder: ColorAttr{colUndefined, AttrUndefined},
Separator: ColorAttr{colUndefined, AttrUndefined}, Separator: ColorAttr{colUndefined, AttrUndefined},
Scrollbar: ColorAttr{colUndefined, AttrUndefined}, Scrollbar: ColorAttr{colUndefined, AttrUndefined},
} }
} }
func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) { func InitTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
if forceBlack { if forceBlack {
theme.Bg = ColorAttr{colBlack, AttrUndefined} theme.Bg = ColorAttr{colBlack, AttrUndefined}
} }
@ -820,8 +859,10 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel) theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel)
// These colors are not defined in the base themes // These colors are not defined in the base themes
theme.SelectedFg = o(theme.Fg, theme.SelectedFg) theme.ListFg = o(theme.Fg, theme.ListFg)
theme.SelectedBg = o(theme.Bg, theme.SelectedBg) theme.ListBg = o(theme.Bg, theme.ListBg)
theme.SelectedFg = o(theme.ListFg, theme.SelectedFg)
theme.SelectedBg = o(theme.ListBg, theme.SelectedBg)
theme.SelectedMatch = o(theme.Match, theme.SelectedMatch) theme.SelectedMatch = o(theme.Match, theme.SelectedMatch)
theme.Disabled = o(theme.Input, theme.Disabled) theme.Disabled = o(theme.Input, theme.Disabled)
theme.Gutter = o(theme.DarkBg, theme.Gutter) theme.Gutter = o(theme.DarkBg, theme.Gutter)
@ -829,8 +870,10 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
theme.PreviewBg = o(theme.Bg, theme.PreviewBg) theme.PreviewBg = o(theme.Bg, theme.PreviewBg)
theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel) theme.PreviewLabel = o(theme.BorderLabel, theme.PreviewLabel)
theme.PreviewBorder = o(theme.Border, theme.PreviewBorder) theme.PreviewBorder = o(theme.Border, theme.PreviewBorder)
theme.Separator = o(theme.Border, theme.Separator) theme.ListLabel = o(theme.BorderLabel, theme.ListLabel)
theme.Scrollbar = o(theme.Border, theme.Scrollbar) theme.ListBorder = o(theme.Border, theme.ListBorder)
theme.Separator = o(theme.ListBorder, theme.Separator)
theme.Scrollbar = o(theme.ListBorder, theme.Scrollbar)
theme.PreviewScrollbar = o(theme.PreviewBorder, theme.PreviewScrollbar) theme.PreviewScrollbar = o(theme.PreviewBorder, theme.PreviewScrollbar)
initPalette(theme) initPalette(theme)
@ -843,19 +886,19 @@ func initPalette(theme *ColorTheme) {
} }
return ColorPair{fg.Color, bg.Color, fg.Attr} return ColorPair{fg.Color, bg.Color, fg.Attr}
} }
blank := theme.Fg blank := theme.ListFg
blank.Attr = AttrRegular blank.Attr = AttrRegular
ColPrompt = pair(theme.Prompt, theme.Bg) ColPrompt = pair(theme.Prompt, theme.ListBg)
ColNormal = pair(theme.Fg, theme.Bg) ColNormal = pair(theme.ListFg, theme.ListBg)
ColSelected = pair(theme.SelectedFg, theme.SelectedBg) ColSelected = pair(theme.SelectedFg, theme.SelectedBg)
ColInput = pair(theme.Input, theme.Bg) ColInput = pair(theme.Input, theme.ListBg)
ColDisabled = pair(theme.Disabled, theme.Bg) ColDisabled = pair(theme.Disabled, theme.ListBg)
ColMatch = pair(theme.Match, theme.Bg) ColMatch = pair(theme.Match, theme.ListBg)
ColSelectedMatch = pair(theme.SelectedMatch, theme.SelectedBg) ColSelectedMatch = pair(theme.SelectedMatch, theme.SelectedBg)
ColCursor = pair(theme.Cursor, theme.Gutter) ColCursor = pair(theme.Cursor, theme.Gutter)
ColCursorEmpty = pair(blank, theme.Gutter) ColCursorEmpty = pair(blank, theme.Gutter)
if theme.SelectedBg.Color != theme.Bg.Color { if theme.SelectedBg.Color != theme.ListBg.Color {
ColMarker = pair(theme.Marker, theme.SelectedBg) ColMarker = pair(theme.Marker, theme.SelectedBg)
} else { } else {
ColMarker = pair(theme.Marker, theme.Gutter) ColMarker = pair(theme.Marker, theme.Gutter)
@ -866,11 +909,11 @@ func initPalette(theme *ColorTheme) {
ColCurrentCursorEmpty = pair(blank, theme.DarkBg) ColCurrentCursorEmpty = pair(blank, theme.DarkBg)
ColCurrentMarker = pair(theme.Marker, theme.DarkBg) ColCurrentMarker = pair(theme.Marker, theme.DarkBg)
ColCurrentSelectedEmpty = pair(blank, theme.DarkBg) ColCurrentSelectedEmpty = pair(blank, theme.DarkBg)
ColSpinner = pair(theme.Spinner, theme.Bg) ColSpinner = pair(theme.Spinner, theme.ListBg)
ColInfo = pair(theme.Info, theme.Bg) ColInfo = pair(theme.Info, theme.ListBg)
ColHeader = pair(theme.Header, theme.Bg) ColHeader = pair(theme.Header, theme.ListBg)
ColSeparator = pair(theme.Separator, theme.Bg) ColSeparator = pair(theme.Separator, theme.ListBg)
ColScrollbar = pair(theme.Scrollbar, theme.Bg) ColScrollbar = pair(theme.Scrollbar, theme.ListBg)
ColBorder = pair(theme.Border, theme.Bg) ColBorder = pair(theme.Border, theme.Bg)
ColBorderLabel = pair(theme.BorderLabel, theme.Bg) ColBorderLabel = pair(theme.BorderLabel, theme.Bg)
ColPreviewLabel = pair(theme.PreviewLabel, theme.PreviewBg) ColPreviewLabel = pair(theme.PreviewLabel, theme.PreviewBg)
@ -878,6 +921,8 @@ func initPalette(theme *ColorTheme) {
ColPreviewBorder = pair(theme.PreviewBorder, theme.PreviewBg) ColPreviewBorder = pair(theme.PreviewBorder, theme.PreviewBg)
ColPreviewScrollbar = pair(theme.PreviewScrollbar, theme.PreviewBg) ColPreviewScrollbar = pair(theme.PreviewScrollbar, theme.PreviewBg)
ColPreviewSpinner = pair(theme.Spinner, theme.PreviewBg) ColPreviewSpinner = pair(theme.Spinner, theme.PreviewBg)
ColListLabel = pair(theme.ListLabel, theme.ListBg)
ColListBorder = pair(theme.ListBorder, theme.ListBg)
} }
func runeWidth(r rune) int { func runeWidth(r rune) int {