mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2025-01-23 15:18:29 +00:00
parent
0de1aacb0c
commit
e61585f2f3
15
CHANGELOG.md
15
CHANGELOG.md
@ -9,6 +9,21 @@ CHANGELOG
|
||||
```sh
|
||||
seq 100 | fzf --multi --sync --bind 'start:last+select-all+preview(echo welcome)'
|
||||
```
|
||||
- Added `--border-label` and `--border-label-pos` for putting label on the border
|
||||
```sh
|
||||
# ANSI color codes are supported
|
||||
# (with https://github.com/busyloop/lolcat)
|
||||
label=$(curl -s http://metaphorpsum.com/sentences/1 | lolcat -f)
|
||||
|
||||
# Border label at the center
|
||||
fzf --height=10 --border-label="╢ $label ╟" --border --color=label:italic:black
|
||||
|
||||
# Left-aligned (positive integer)
|
||||
fzf --height=10 --border-label="╢ $label ╟" --border=top --border-label-pos=3 --color=label:italic:black
|
||||
|
||||
# Right-aligned (negative integer)
|
||||
fzf --height=10 --border-label="╢ $label ╟" --border=bottom --border-label-pos=-3 --color=label:italic:black
|
||||
```
|
||||
|
||||
0.34.0
|
||||
------
|
||||
|
@ -226,6 +226,45 @@ Draw border around the finder
|
||||
.BR none
|
||||
.br
|
||||
|
||||
.TP
|
||||
.BI "--border-label" [=LABEL]
|
||||
Label to print on the horizontal border line. Should be used with one of the
|
||||
following \fB--border\fR options.
|
||||
|
||||
.br
|
||||
.B * rounded
|
||||
.br
|
||||
.B * sharp
|
||||
.br
|
||||
.B * horizontal
|
||||
.br
|
||||
.BR "* top" " (up)"
|
||||
.br
|
||||
.BR "* bottom" " (down)"
|
||||
.br
|
||||
|
||||
.br
|
||||
e.g.
|
||||
\fB# ANSI color codes are supported
|
||||
# (with https://github.com/busyloop/lolcat)
|
||||
label=$(curl -s http://metaphorpsum.com/sentences/1 | lolcat -f)
|
||||
|
||||
# Border label at the center
|
||||
fzf --height=10 --border-label="╢ $label ╟" --border --color=label:italic:black
|
||||
|
||||
# Left-aligned (positive integer)
|
||||
fzf --height=10 --border-label="╢ $label ╟" --border=top --border-label-pos=3 --color=label:italic:black
|
||||
|
||||
# Right-aligned (negative integer)
|
||||
fzf --height=10 --border-label="╢ $label ╟" --border=bottom --border-label-pos=-3 --color=label:italic:black\fR
|
||||
|
||||
.TP
|
||||
.BI "--border-label-pos" [=COL]
|
||||
Horizontal position of the border label on the border line. Specify a positive
|
||||
integer as the column position from the left. Specify a negative integer to
|
||||
right-align the label. The default value 0 (or \fBcenter\fR) will put
|
||||
the label at the center of the border line.
|
||||
|
||||
.TP
|
||||
.B "--no-unicode"
|
||||
Use ASCII characters instead of Unicode box drawing characters to draw border
|
||||
@ -356,6 +395,7 @@ color mappings.
|
||||
\fBdisabled \fRQuery string when search is disabled
|
||||
\fBinfo \fRInfo line (match counters)
|
||||
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
|
||||
\fBlabel \fRBorder label (\fB--border-label\fR)
|
||||
\fBprompt \fRPrompt
|
||||
\fBpointer \fRPointer to the current line
|
||||
\fBmarker \fRMulti-select marker
|
||||
|
@ -63,6 +63,10 @@ const usage = `usage: fzf [options]
|
||||
--border[=STYLE] Draw border around the finder
|
||||
[rounded|sharp|horizontal|vertical|
|
||||
top|bottom|left|right|none] (default: rounded)
|
||||
--border-label=LABEL Label to print on the border
|
||||
--border-label-pos=COL Position of the border label
|
||||
[POSITIVE_INTEGER: columns from left|
|
||||
NEGATIVE_INTEGER: columns from right] (default: 0)
|
||||
--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)
|
||||
--info=STYLE Finder info style [default|inline|hidden]
|
||||
@ -188,6 +192,13 @@ type previewOpts struct {
|
||||
alternative *previewOpts
|
||||
}
|
||||
|
||||
func parseLabelPosition(arg string) int {
|
||||
if strings.ToLower(arg) == "center" {
|
||||
return 0
|
||||
}
|
||||
return atoi(arg)
|
||||
}
|
||||
|
||||
func (a previewOpts) aboveOrBelow() bool {
|
||||
return a.size.size > 0 && (a.position == posUp || a.position == posDown)
|
||||
}
|
||||
@ -258,6 +269,8 @@ type Options struct {
|
||||
Margin [4]sizeSpec
|
||||
Padding [4]sizeSpec
|
||||
BorderShape tui.BorderShape
|
||||
Label string
|
||||
LabelPos int
|
||||
Unicode bool
|
||||
Tabstop int
|
||||
ClearOnExit bool
|
||||
@ -324,6 +337,8 @@ func defaultOptions() *Options {
|
||||
Padding: defaultMargin(),
|
||||
Unicode: true,
|
||||
Tabstop: 8,
|
||||
Label: "",
|
||||
LabelPos: 0,
|
||||
ClearOnExit: true,
|
||||
Version: false}
|
||||
}
|
||||
@ -798,6 +813,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
|
||||
mergeAttr(&theme.CurrentMatch)
|
||||
case "border":
|
||||
mergeAttr(&theme.Border)
|
||||
case "label":
|
||||
mergeAttr(&theme.BorderLabel)
|
||||
case "prompt":
|
||||
mergeAttr(&theme.Prompt)
|
||||
case "spinner":
|
||||
@ -1556,6 +1573,11 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
case "--border":
|
||||
hasArg, arg := optionalNextString(allArgs, &i)
|
||||
opts.BorderShape = parseBorder(arg, !hasArg)
|
||||
case "--border-label":
|
||||
opts.Label = nextString(allArgs, &i, "label required")
|
||||
case "--border-label-pos":
|
||||
pos := nextString(allArgs, &i, "label position required (positive or negative integer or 'center')")
|
||||
opts.LabelPos = parseLabelPosition(pos)
|
||||
case "--no-unicode":
|
||||
opts.Unicode = false
|
||||
case "--unicode":
|
||||
@ -1591,6 +1613,10 @@ func parseOptions(opts *Options, allArgs []string) {
|
||||
opts.Delimiter = delimiterRegexp(value)
|
||||
} else if match, value := optString(arg, "--border="); match {
|
||||
opts.BorderShape = parseBorder(value, false)
|
||||
} else if match, value := optString(arg, "--border-label="); match {
|
||||
opts.Label = value
|
||||
} else if match, value := optString(arg, "--border-label-pos="); match {
|
||||
opts.LabelPos = parseLabelPosition(value)
|
||||
} else if match, value := optString(arg, "--prompt="); match {
|
||||
opts.Prompt = value
|
||||
} else if match, value := optString(arg, "--pointer="); match {
|
||||
|
@ -114,6 +114,9 @@ type Terminal struct {
|
||||
spinner []string
|
||||
prompt func()
|
||||
promptLen int
|
||||
borderLabel func()
|
||||
borderLabelLen int
|
||||
borderLabelPos int
|
||||
pointer string
|
||||
pointerLen int
|
||||
pointerEmpty string
|
||||
@ -544,6 +547,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
padding: opts.Padding,
|
||||
unicode: opts.Unicode,
|
||||
borderShape: opts.BorderShape,
|
||||
borderLabel: nil,
|
||||
borderLabelPos: opts.LabelPos,
|
||||
cleanExit: opts.ClearOnExit,
|
||||
paused: opts.Phony,
|
||||
strong: strongAttr,
|
||||
@ -587,6 +592,9 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
|
||||
// Pre-calculated empty pointer and marker signs
|
||||
t.pointerEmpty = strings.Repeat(" ", t.pointerLen)
|
||||
t.markerEmpty = strings.Repeat(" ", t.markerLen)
|
||||
if len(opts.Label) > 0 {
|
||||
t.borderLabel, t.borderLabelLen = t.parseBorderLabel(opts.Label)
|
||||
}
|
||||
|
||||
return &t
|
||||
}
|
||||
@ -617,6 +625,25 @@ func (t *Terminal) MaxFitAndPad(opts *Options) (int, int) {
|
||||
return fit, padHeight
|
||||
}
|
||||
|
||||
func (t *Terminal) parseBorderLabel(borderLabel string) (func(), int) {
|
||||
text, colors, _ := extractColor(borderLabel, nil, nil)
|
||||
runes := []rune(text)
|
||||
item := &Item{text: util.RunesToChars(runes), colors: colors}
|
||||
result := Result{item: item}
|
||||
|
||||
var offsets []colorOffset
|
||||
borderLabelFn := func() {
|
||||
if offsets == nil {
|
||||
// tui.Col* are not initialized until renderer.Init()
|
||||
offsets = result.colorOffsets(nil, t.theme, tui.ColBorderLabel, tui.ColBorderLabel, false)
|
||||
}
|
||||
text, _ := t.trimRight(runes, t.border.Width())
|
||||
t.printColoredString(t.border, text, offsets, tui.ColBorderLabel)
|
||||
}
|
||||
borderLabelLen := runewidth.StringWidth(text)
|
||||
return borderLabelFn, borderLabelLen
|
||||
}
|
||||
|
||||
func (t *Terminal) parsePrompt(prompt string) (func(), int) {
|
||||
var state *ansiState
|
||||
trimmed, colors, _ := extractColor(prompt, state, nil)
|
||||
@ -911,6 +938,27 @@ func (t *Terminal) resizeWindows() {
|
||||
false, tui.MakeBorderStyle(t.borderShape, t.unicode))
|
||||
}
|
||||
|
||||
// Print border label
|
||||
if t.border != nil && t.borderLabel != nil {
|
||||
switch t.borderShape {
|
||||
case tui.BorderHorizontal, tui.BorderTop, tui.BorderBottom, tui.BorderRounded, tui.BorderSharp:
|
||||
var col int
|
||||
if t.borderLabelPos == 0 {
|
||||
col = util.Max(0, (t.border.Width()-t.borderLabelLen)/2)
|
||||
} else if t.borderLabelPos < 0 {
|
||||
col = util.Max(0, t.border.Width()+t.borderLabelPos+1-t.borderLabelLen)
|
||||
} else {
|
||||
col = util.Min(t.borderLabelPos-1, t.border.Width()-t.borderLabelLen)
|
||||
}
|
||||
row := 0
|
||||
if t.borderShape == tui.BorderBottom {
|
||||
row = t.border.Height() - 1
|
||||
}
|
||||
t.border.Move(row, col)
|
||||
t.borderLabel()
|
||||
}
|
||||
}
|
||||
|
||||
// Add padding to margin
|
||||
for idx, val := range paddingInt {
|
||||
marginInt[idx] += val
|
||||
@ -1394,6 +1442,11 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
||||
displayWidth = t.displayWidthWithLimit(text, 0, displayWidth)
|
||||
}
|
||||
|
||||
t.printColoredString(t.window, text, offsets, colBase)
|
||||
return displayWidth
|
||||
}
|
||||
|
||||
func (t *Terminal) printColoredString(window tui.Window, text []rune, offsets []colorOffset, colBase tui.ColorPair) {
|
||||
var index int32
|
||||
var substr string
|
||||
var prefixWidth int
|
||||
@ -1403,11 +1456,11 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
||||
e := util.Constrain32(offset.offset[1], index, maxOffset)
|
||||
|
||||
substr, prefixWidth = t.processTabs(text[index:b], prefixWidth)
|
||||
t.window.CPrint(colBase, substr)
|
||||
window.CPrint(colBase, substr)
|
||||
|
||||
if b < e {
|
||||
substr, prefixWidth = t.processTabs(text[b:e], prefixWidth)
|
||||
t.window.CPrint(offset.color, substr)
|
||||
window.CPrint(offset.color, substr)
|
||||
}
|
||||
|
||||
index = e
|
||||
@ -1417,9 +1470,8 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
||||
}
|
||||
if index < maxOffset {
|
||||
substr, _ = t.processTabs(text[index:], prefixWidth)
|
||||
t.window.CPrint(colBase, substr)
|
||||
window.CPrint(colBase, substr)
|
||||
}
|
||||
return displayWidth
|
||||
}
|
||||
|
||||
func (t *Terminal) renderPreviewSpinner() {
|
||||
|
@ -268,6 +268,7 @@ type ColorTheme struct {
|
||||
Selected ColorAttr
|
||||
Header ColorAttr
|
||||
Border ColorAttr
|
||||
BorderLabel ColorAttr
|
||||
}
|
||||
|
||||
type Event struct {
|
||||
@ -441,6 +442,7 @@ var (
|
||||
ColBorder ColorPair
|
||||
ColPreview ColorPair
|
||||
ColPreviewBorder ColorPair
|
||||
ColBorderLabel ColorPair
|
||||
)
|
||||
|
||||
func EmptyTheme() *ColorTheme {
|
||||
@ -463,7 +465,9 @@ func EmptyTheme() *ColorTheme {
|
||||
Cursor: ColorAttr{colUndefined, AttrUndefined},
|
||||
Selected: ColorAttr{colUndefined, AttrUndefined},
|
||||
Header: ColorAttr{colUndefined, AttrUndefined},
|
||||
Border: ColorAttr{colUndefined, AttrUndefined}}
|
||||
Border: ColorAttr{colUndefined, AttrUndefined},
|
||||
BorderLabel: ColorAttr{colUndefined, AttrUndefined},
|
||||
}
|
||||
}
|
||||
|
||||
func NoColorTheme() *ColorTheme {
|
||||
@ -486,7 +490,9 @@ func NoColorTheme() *ColorTheme {
|
||||
Cursor: ColorAttr{colDefault, AttrRegular},
|
||||
Selected: ColorAttr{colDefault, AttrRegular},
|
||||
Header: ColorAttr{colDefault, AttrRegular},
|
||||
Border: ColorAttr{colDefault, AttrRegular}}
|
||||
Border: ColorAttr{colDefault, AttrRegular},
|
||||
BorderLabel: ColorAttr{colDefault, AttrRegular},
|
||||
}
|
||||
}
|
||||
|
||||
func errorExit(message string) {
|
||||
@ -514,7 +520,9 @@ func init() {
|
||||
Cursor: ColorAttr{colRed, AttrUndefined},
|
||||
Selected: ColorAttr{colMagenta, AttrUndefined},
|
||||
Header: ColorAttr{colCyan, AttrUndefined},
|
||||
Border: ColorAttr{colBlack, AttrUndefined}}
|
||||
Border: ColorAttr{colBlack, AttrUndefined},
|
||||
BorderLabel: ColorAttr{colWhite, AttrUndefined},
|
||||
}
|
||||
Dark256 = &ColorTheme{
|
||||
Colored: true,
|
||||
Input: ColorAttr{colDefault, AttrUndefined},
|
||||
@ -534,7 +542,9 @@ func init() {
|
||||
Cursor: ColorAttr{161, AttrUndefined},
|
||||
Selected: ColorAttr{168, AttrUndefined},
|
||||
Header: ColorAttr{109, AttrUndefined},
|
||||
Border: ColorAttr{59, AttrUndefined}}
|
||||
Border: ColorAttr{59, AttrUndefined},
|
||||
BorderLabel: ColorAttr{145, AttrUndefined},
|
||||
}
|
||||
Light256 = &ColorTheme{
|
||||
Colored: true,
|
||||
Input: ColorAttr{colDefault, AttrUndefined},
|
||||
@ -554,7 +564,9 @@ func init() {
|
||||
Cursor: ColorAttr{161, AttrUndefined},
|
||||
Selected: ColorAttr{168, AttrUndefined},
|
||||
Header: ColorAttr{31, AttrUndefined},
|
||||
Border: ColorAttr{145, AttrUndefined}}
|
||||
Border: ColorAttr{145, AttrUndefined},
|
||||
BorderLabel: ColorAttr{59, AttrUndefined},
|
||||
}
|
||||
}
|
||||
|
||||
func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||
@ -590,6 +602,7 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
|
||||
theme.Selected = o(baseTheme.Selected, theme.Selected)
|
||||
theme.Header = o(baseTheme.Header, theme.Header)
|
||||
theme.Border = o(baseTheme.Border, theme.Border)
|
||||
theme.BorderLabel = o(baseTheme.BorderLabel, theme.BorderLabel)
|
||||
|
||||
initPalette(theme)
|
||||
}
|
||||
@ -622,6 +635,7 @@ func initPalette(theme *ColorTheme) {
|
||||
ColInfo = pair(theme.Info, theme.Bg)
|
||||
ColHeader = pair(theme.Header, theme.Bg)
|
||||
ColBorder = pair(theme.Border, theme.Bg)
|
||||
ColBorderLabel = pair(theme.BorderLabel, theme.Bg)
|
||||
ColPreview = pair(theme.PreviewFg, theme.PreviewBg)
|
||||
ColPreviewBorder = pair(theme.Border, theme.PreviewBg)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user