mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-14 19:55:49 -07:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d226d841a1 | ||
|
c6d83047e5 | ||
|
46dabccdf1 | ||
|
cd9517b679 | ||
|
cd6677ba1d | ||
|
9c1a47acf7 | ||
|
0c280a3ce1 | ||
|
53e8b6e705 | ||
|
ad33165fa7 | ||
|
2055db61c8 | ||
|
d2c662e54f | ||
|
d24b58ef3f | ||
|
06ae9b0f3b | ||
|
2a9c1c06a4 |
37
CHANGELOG.md
37
CHANGELOG.md
@@ -1,6 +1,43 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
0.62.0
|
||||||
|
------
|
||||||
|
- Relaxed the `--color` option syntax to allow whitespace-separated entries (in addition to commas), making multi-line definitions easier to write and read
|
||||||
|
```sh
|
||||||
|
# seoul256-light
|
||||||
|
fzf --style full --color='
|
||||||
|
fg:#616161 fg+:#616161
|
||||||
|
bg:#ffffff bg+:#e9e9e9 alt-bg:#f1f1f1
|
||||||
|
hl:#719872 hl+:#719899
|
||||||
|
pointer:#e12672 marker:#e17899
|
||||||
|
header:#719872
|
||||||
|
spinner:#719899 info:#727100
|
||||||
|
prompt:#0099bd query:#616161
|
||||||
|
border:#e1e1e1
|
||||||
|
'
|
||||||
|
```
|
||||||
|
- Added `alt-bg` color to create striped lines to visually separate rows
|
||||||
|
```sh
|
||||||
|
fzf --color bg:237,alt-bg:238,current-bg:236 --highlight-line
|
||||||
|
|
||||||
|
declare -f | perl -0777 -pe 's/^}\n/}\0/gm' |
|
||||||
|
bat --plain --language bash --color always |
|
||||||
|
fzf --read0 --ansi --reverse --multi \
|
||||||
|
--color bg:237,alt-bg:238,current-bg:236 --highlight-line
|
||||||
|
```
|
||||||
|
- [fish] Improvements in CTRL-R binding (@bitraid)
|
||||||
|
- You can trigger CTRL-R in the middle of a command to insert the selected item
|
||||||
|
- You can delete history items with SHIFT-DEL
|
||||||
|
- Bug fixes and improvements
|
||||||
|
- Fixed unnecessary 100ms delay after `reload` (#4364)
|
||||||
|
- Fixed `selected-bg` not applied to colored items (#4372)
|
||||||
|
|
||||||
|
0.61.3
|
||||||
|
------
|
||||||
|
- Reverted #4351 as it caused `tmux run-shell 'fzf --tmux'` to fail (#4559 #4560)
|
||||||
|
- More environment variables for child processes (#4356)
|
||||||
|
|
||||||
0.61.2
|
0.61.2
|
||||||
------
|
------
|
||||||
- Fixed panic when using header border without pointer/marker (@phanen)
|
- Fixed panic when using header border without pointer/marker (@phanen)
|
||||||
|
@@ -155,6 +155,7 @@ let g:fzf_layout = { 'window': '10new' }
|
|||||||
let g:fzf_colors =
|
let g:fzf_colors =
|
||||||
\ { 'fg': ['fg', 'Normal'],
|
\ { 'fg': ['fg', 'Normal'],
|
||||||
\ 'bg': ['bg', 'Normal'],
|
\ 'bg': ['bg', 'Normal'],
|
||||||
|
\ 'query': ['fg', 'Normal'],
|
||||||
\ 'hl': ['fg', 'Comment'],
|
\ 'hl': ['fg', 'Comment'],
|
||||||
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
|
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
|
||||||
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
|
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
|
||||||
|
2
install
2
install
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
set -u
|
set -u
|
||||||
|
|
||||||
version=0.61.2
|
version=0.62.0
|
||||||
auto_completion=
|
auto_completion=
|
||||||
key_bindings=
|
key_bindings=
|
||||||
update_config=2
|
update_config=2
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
$version="0.61.2"
|
$version="0.62.0"
|
||||||
|
|
||||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
|
|
||||||
|
2
main.go
2
main.go
@@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/junegunn/fzf/src/protector"
|
"github.com/junegunn/fzf/src/protector"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "0.61"
|
var version = "0.62"
|
||||||
var revision = "devel"
|
var revision = "devel"
|
||||||
|
|
||||||
//go:embed shell/key-bindings.bash
|
//go:embed shell/key-bindings.bash
|
||||||
|
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf\-tmux 1 "Apr 2025" "fzf 0.61.2" "fzf\-tmux - open fzf in tmux split pane"
|
.TH fzf\-tmux 1 "May 2025" "fzf 0.62.0" "fzf\-tmux - open fzf in tmux split pane"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf\-tmux - open fzf in tmux split pane
|
fzf\-tmux - open fzf in tmux split pane
|
||||||
|
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
..
|
..
|
||||||
.TH fzf 1 "Apr 2025" "fzf 0.61.2" "fzf - a command-line fuzzy finder"
|
.TH fzf 1 "May 2025" "fzf 0.62.0" "fzf - a command-line fuzzy finder"
|
||||||
|
|
||||||
.SH NAME
|
.SH NAME
|
||||||
fzf - a command-line fuzzy finder
|
fzf - a command-line fuzzy finder
|
||||||
@@ -242,7 +242,7 @@ Apply a style preset [default|minimal|full[:BORDER_STYLE]]
|
|||||||
.TP
|
.TP
|
||||||
.BI "\-\-color=" "[BASE_SCHEME][,COLOR_NAME[:ANSI_COLOR][:ANSI_ATTRIBUTES]]..."
|
.BI "\-\-color=" "[BASE_SCHEME][,COLOR_NAME[:ANSI_COLOR][:ANSI_ATTRIBUTES]]..."
|
||||||
Color configuration. The name of the base color scheme is followed by custom
|
Color configuration. The name of the base color scheme is followed by custom
|
||||||
color mappings.
|
color mappings. Each entry is separated by a comma and/or whitespaces.
|
||||||
|
|
||||||
.RS
|
.RS
|
||||||
.B BASE SCHEME:
|
.B BASE SCHEME:
|
||||||
@@ -270,6 +270,7 @@ color mappings.
|
|||||||
\fBcurrent\-bg (bg+) \fRBackground (current line)
|
\fBcurrent\-bg (bg+) \fRBackground (current line)
|
||||||
\fBgutter \fRGutter on the left
|
\fBgutter \fRGutter on the left
|
||||||
\fBcurrent\-hl (hl+) \fRHighlighted substrings (current line)
|
\fBcurrent\-hl (hl+) \fRHighlighted substrings (current line)
|
||||||
|
\fBalt\-bg \fRAlternate background color to create striped lines
|
||||||
\fBquery (input\-fg) \fRQuery string
|
\fBquery (input\-fg) \fRQuery string
|
||||||
\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)
|
||||||
@@ -337,7 +338,19 @@ color mappings.
|
|||||||
# Seoul256 theme with 24-bit colors
|
# Seoul256 theme with 24-bit colors
|
||||||
fzf \-\-color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
|
fzf \-\-color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
|
||||||
\-\-color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
|
\-\-color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
|
||||||
\-\-color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'\fR
|
\-\-color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'
|
||||||
|
|
||||||
|
# Seoul256 light theme with 24-bit colors, each entry separated by whitespaces
|
||||||
|
fzf \-\-style full \-\-color='
|
||||||
|
fg:#616161 fg+:#616161
|
||||||
|
bg:#ffffff bg+:#e9e9e9 alt-bg:#f1f1f1
|
||||||
|
hl:#719872 hl+:#719899
|
||||||
|
pointer:#e12672 marker:#e17899
|
||||||
|
header:#719872
|
||||||
|
spinner:#719899 info:#727100
|
||||||
|
prompt:#0099bd query:#616161
|
||||||
|
border:#e1e1e1
|
||||||
|
'\fR
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.B "\-\-no\-color"
|
.B "\-\-no\-color"
|
||||||
@@ -1279,10 +1292,20 @@ fzf exports the following environment variables to its child processes.
|
|||||||
.br
|
.br
|
||||||
.BR FZF_PROMPT " Prompt string"
|
.BR FZF_PROMPT " Prompt string"
|
||||||
.br
|
.br
|
||||||
|
.BR FZF_GHOST " Ghost string"
|
||||||
|
.br
|
||||||
|
.BR FZF_POINTER " Pointer string"
|
||||||
|
.br
|
||||||
.BR FZF_PREVIEW_LABEL " Preview label string"
|
.BR FZF_PREVIEW_LABEL " Preview label string"
|
||||||
.br
|
.br
|
||||||
.BR FZF_BORDER_LABEL " Border label string"
|
.BR FZF_BORDER_LABEL " Border label string"
|
||||||
.br
|
.br
|
||||||
|
.BR FZF_LIST_LABEL " List label string"
|
||||||
|
.br
|
||||||
|
.BR FZF_INPUT_LABEL " Input label string"
|
||||||
|
.br
|
||||||
|
.BR FZF_HEADER_LABEL " Header label string"
|
||||||
|
.br
|
||||||
.BR FZF_ACTION " The name of the last action performed"
|
.BR FZF_ACTION " The name of the last action performed"
|
||||||
.br
|
.br
|
||||||
.BR FZF_KEY " The name of the last key pressed"
|
.BR FZF_KEY " The name of the last key pressed"
|
||||||
|
@@ -14,12 +14,21 @@
|
|||||||
|
|
||||||
# Key bindings
|
# Key bindings
|
||||||
# ------------
|
# ------------
|
||||||
# For compatibility with fish versions down to 3.1.2, the script does not use:
|
# The oldest supported fish version is 3.1b1. To maintain compatibility, the
|
||||||
# - The -f/--function switch of command: set
|
# command substitution syntax $(cmd) should never be used, even behind a version
|
||||||
# - The process substitution syntax: $(cmd)
|
# check, otherwise the source command will fail on fish versions older than 3.4.0.
|
||||||
# - Ranges that omit start/end indexes: $var[$start..] $var[..$end] $var[..]
|
|
||||||
function fzf_key_bindings
|
function fzf_key_bindings
|
||||||
|
|
||||||
|
# Check fish version
|
||||||
|
set -l fish_ver (string match -r '^(\d+).(\d+)' $version 2> /dev/null; or echo 0\n0\n0)
|
||||||
|
if test \( "$fish_ver[2]" -lt 3 \) -o \( "$fish_ver[2]" -eq 3 -a "$fish_ver[3]" -lt 1 \)
|
||||||
|
echo "This script requires fish version 3.1b1 or newer." >&2
|
||||||
|
return 1
|
||||||
|
else if not type -q fzf
|
||||||
|
echo "fzf was not found in path." >&2
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
|
||||||
function __fzf_defaults
|
function __fzf_defaults
|
||||||
# $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
# $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
# $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS
|
||||||
@@ -135,22 +144,21 @@ function fzf_key_bindings
|
|||||||
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND"
|
||||||
set -lx FZF_DEFAULT_OPTS_FILE
|
set -lx FZF_DEFAULT_OPTS_FILE
|
||||||
|
|
||||||
if set -l result (eval (__fzfcmd) --walker-root=$dir --query=$fzf_query | string split0)
|
set -l result (eval (__fzfcmd) --walker-root=$dir --query=$fzf_query | string split0)
|
||||||
# Remove last token from commandline.
|
and commandline -rt -- (string join -- ' ' $prefix(string escape -- $result))' '
|
||||||
commandline -t ''
|
|
||||||
for i in $result
|
|
||||||
commandline -it -- $prefix(string escape -- $i)' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
commandline -f repaint
|
commandline -f repaint
|
||||||
end
|
end
|
||||||
|
|
||||||
function fzf-history-widget -d "Show command history"
|
function fzf-history-widget -d "Show command history"
|
||||||
set -l fzf_query (commandline | string escape)
|
set -l -- command_line (commandline)
|
||||||
|
set -l -- current_line (commandline -L)
|
||||||
|
set -l -- total_lines (count $command_line)
|
||||||
|
set -l -- fzf_query (string escape -- $command_line[$current_line])
|
||||||
|
|
||||||
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
|
set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \
|
||||||
'--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \
|
'--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \
|
||||||
|
'--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \
|
||||||
"--bind=ctrl-r:toggle-sort --highlight-line $FZF_CTRL_R_OPTS" \
|
"--bind=ctrl-r:toggle-sort --highlight-line $FZF_CTRL_R_OPTS" \
|
||||||
'--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c)
|
'--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c)
|
||||||
|
|
||||||
@@ -172,9 +180,13 @@ function fzf_key_bindings
|
|||||||
test -z "$fish_private_mode"; and builtin history merge
|
test -z "$fish_private_mode"; and builtin history merge
|
||||||
|
|
||||||
if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0)
|
if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0)
|
||||||
commandline -- (string replace -a -- \n\t \n $result[1])
|
if test "$total_lines" -eq 1
|
||||||
test (count $result) -gt 1; and for i in $result[2..-1]
|
commandline -- (string replace -a -- \n\t \n $result)
|
||||||
commandline -i -- (string replace -a -- \n\t \n \n$i)
|
else
|
||||||
|
set -l a (math $current_line - 1)
|
||||||
|
set -l b (math $current_line + 1)
|
||||||
|
commandline -- $command_line[1..$a] (string replace -a -- \n\t \n $result)
|
||||||
|
commandline -a -- '' $command_line[$b..-1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ func (r revision) compatible(other revision) bool {
|
|||||||
// Run starts fzf
|
// Run starts fzf
|
||||||
func Run(opts *Options) (int, error) {
|
func Run(opts *Options) (int, error) {
|
||||||
if opts.Filter == nil {
|
if opts.Filter == nil {
|
||||||
if opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 && len(os.Getenv("TMUX_PANE")) > 0 && opts.Tmux.index >= opts.Height.index {
|
if opts.Tmux != nil && len(os.Getenv("TMUX")) > 0 && opts.Tmux.index >= opts.Height.index {
|
||||||
return runTmux(os.Args, opts)
|
return runTmux(os.Args, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,6 +295,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
// Event coordination
|
// Event coordination
|
||||||
reading := true
|
reading := true
|
||||||
ticks := 0
|
ticks := 0
|
||||||
|
startTick := 0
|
||||||
var nextCommand *commandSpec
|
var nextCommand *commandSpec
|
||||||
var nextEnviron []string
|
var nextEnviron []string
|
||||||
eventBox.Watch(EvtReadNew)
|
eventBox.Watch(EvtReadNew)
|
||||||
@@ -321,6 +322,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
clearDenylist()
|
clearDenylist()
|
||||||
}
|
}
|
||||||
reading = true
|
reading = true
|
||||||
|
startTick = ticks
|
||||||
chunkList.Clear()
|
chunkList.Clear()
|
||||||
itemIndex = 0
|
itemIndex = 0
|
||||||
inputRevision.bumpMajor()
|
inputRevision.bumpMajor()
|
||||||
@@ -509,7 +511,7 @@ func Run(opts *Options) (int, error) {
|
|||||||
}
|
}
|
||||||
if delay && reading {
|
if delay && reading {
|
||||||
dur := util.DurWithin(
|
dur := util.DurWithin(
|
||||||
time.Duration(ticks)*coordinatorDelayStep,
|
time.Duration(ticks-startTick)*coordinatorDelayStep,
|
||||||
0, coordinatorDelayMax)
|
0, coordinatorDelayMax)
|
||||||
time.Sleep(dur)
|
time.Sleep(dur)
|
||||||
}
|
}
|
||||||
|
@@ -1184,7 +1184,12 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
|
|||||||
var err error
|
var err error
|
||||||
theme := dupeTheme(defaultTheme)
|
theme := dupeTheme(defaultTheme)
|
||||||
rrggbb := regexp.MustCompile("^#[0-9a-fA-F]{6}$")
|
rrggbb := regexp.MustCompile("^#[0-9a-fA-F]{6}$")
|
||||||
for _, str := range strings.Split(strings.ToLower(str), ",") {
|
comma := regexp.MustCompile(`[\s,]+`)
|
||||||
|
for _, str := range comma.Split(strings.ToLower(str), -1) {
|
||||||
|
str = strings.TrimSpace(str)
|
||||||
|
if len(str) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
switch str {
|
switch str {
|
||||||
case "dark":
|
case "dark":
|
||||||
theme = dupeTheme(tui.Dark256)
|
theme = dupeTheme(tui.Dark256)
|
||||||
@@ -1295,6 +1300,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) (*tui.ColorTheme, erro
|
|||||||
mergeAttr(&theme.Current)
|
mergeAttr(&theme.Current)
|
||||||
case "current-bg", "bg+":
|
case "current-bg", "bg+":
|
||||||
mergeAttr(&theme.DarkBg)
|
mergeAttr(&theme.DarkBg)
|
||||||
|
case "alt-bg":
|
||||||
|
mergeAttr(&theme.AltBg)
|
||||||
case "selected-fg":
|
case "selected-fg":
|
||||||
mergeAttr(&theme.SelectedFg)
|
mergeAttr(&theme.SelectedFg)
|
||||||
case "selected-bg":
|
case "selected-bg":
|
||||||
|
@@ -333,7 +333,7 @@ func TestColorSpec(t *testing.T) {
|
|||||||
t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
|
t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
|
||||||
}
|
}
|
||||||
|
|
||||||
customized, _ = parseTheme(theme, "fg:231,dark,bg:232")
|
customized, _ = parseTheme(theme, "fg:231,dark bg:232")
|
||||||
if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
|
if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
|
||||||
t.Errorf("color not customized")
|
t.Errorf("color not customized")
|
||||||
}
|
}
|
||||||
|
@@ -98,8 +98,7 @@ func runProxy(commandPrefix string, cmdBuilder func(temp string, needBash bool)
|
|||||||
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
validIdentifier := regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_]*$`)
|
||||||
for _, pairStr := range os.Environ() {
|
for _, pairStr := range os.Environ() {
|
||||||
pair := strings.SplitN(pairStr, "=", 2)
|
pair := strings.SplitN(pairStr, "=", 2)
|
||||||
// TMUX_PANE is never set inside a tmux popup, and should not be set so as to not be detected as a regular tmux pane
|
if validIdentifier.MatchString(pair[0]) {
|
||||||
if validIdentifier.MatchString(pair[0]) && pair[0] != "TMUX_PANE" {
|
|
||||||
exports = append(exports, fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1])))
|
exports = append(exports, fmt.Sprintf("export %s=%s", pair[0], escapeSingleQuote(pair[1])))
|
||||||
} else if strings.HasPrefix(pair[0], "BASH_FUNC_") && strings.HasSuffix(pair[0], "%%") {
|
} else if strings.HasPrefix(pair[0], "BASH_FUNC_") && strings.HasSuffix(pair[0], "%%") {
|
||||||
name := pair[0][10 : len(pair[0])-2]
|
name := pair[0][10 : len(pair[0])-2]
|
||||||
|
@@ -119,7 +119,7 @@ func minRank() Result {
|
|||||||
return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
|
return Result{item: &minItem, points: [4]uint16{math.MaxUint16, 0, 0, 0}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr, current bool) []colorOffset {
|
func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, theme *tui.ColorTheme, colBase tui.ColorPair, colMatch tui.ColorPair, attrNth tui.Attr) []colorOffset {
|
||||||
itemColors := result.item.Colors()
|
itemColors := result.item.Colors()
|
||||||
|
|
||||||
// No ANSI codes
|
// No ANSI codes
|
||||||
@@ -182,18 +182,10 @@ func (result *Result) colorOffsets(matchOffsets []Offset, nthOffsets []Offset, t
|
|||||||
fg := ansi.color.fg
|
fg := ansi.color.fg
|
||||||
bg := ansi.color.bg
|
bg := ansi.color.bg
|
||||||
if fg == -1 {
|
if fg == -1 {
|
||||||
if current {
|
fg = colBase.Fg()
|
||||||
fg = theme.Current.Color
|
|
||||||
} else {
|
|
||||||
fg = theme.Fg.Color
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if bg == -1 {
|
if bg == -1 {
|
||||||
if current {
|
bg = colBase.Bg()
|
||||||
bg = theme.DarkBg.Color
|
|
||||||
} else {
|
|
||||||
bg = theme.Bg.Color
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return tui.NewColorPair(fg, bg, ansi.color.attr).MergeAttr(base)
|
return tui.NewColorPair(fg, bg, ansi.color.attr).MergeAttr(base)
|
||||||
}
|
}
|
||||||
|
@@ -131,7 +131,7 @@ func TestColorOffset(t *testing.T) {
|
|||||||
|
|
||||||
colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
|
colBase := tui.NewColorPair(89, 189, tui.AttrUndefined)
|
||||||
colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
|
colMatch := tui.NewColorPair(99, 199, tui.AttrUndefined)
|
||||||
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined, true)
|
colors := item.colorOffsets(offsets, nil, tui.Dark256, colBase, colMatch, tui.AttrUndefined)
|
||||||
assert := func(idx int, b int32, e int32, c tui.ColorPair) {
|
assert := func(idx int, b int32, e int32, c tui.ColorPair) {
|
||||||
o := colors[idx]
|
o := colors[idx]
|
||||||
if o.offset[0] != b || o.offset[1] != e || o.color != c {
|
if o.offset[0] != b || o.offset[1] != e || o.color != c {
|
||||||
@@ -158,7 +158,7 @@ func TestColorOffset(t *testing.T) {
|
|||||||
|
|
||||||
nthOffsets := []Offset{{37, 39}, {42, 45}}
|
nthOffsets := []Offset{{37, 39}, {42, 45}}
|
||||||
for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} {
|
for _, attr := range []tui.Attr{tui.AttrRegular, tui.StrikeThrough} {
|
||||||
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr, true)
|
colors = item.colorOffsets(offsets, nthOffsets, tui.Dark256, colRegular, colUnderline, attr)
|
||||||
|
|
||||||
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
|
// [{[0 5] {1 5 0}} {[5 15] {1 5 8}} {[15 20] {1 5 0}}
|
||||||
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
|
// {[22 25] {2 6 1}} {[25 27] {2 6 9}} {[27 30] {-1 -1 8}}
|
||||||
|
@@ -1091,9 +1091,13 @@ func (t *Terminal) environImpl(forPreview bool) []string {
|
|||||||
env = append(env, "FZF_ACTION="+t.lastAction.Name())
|
env = append(env, "FZF_ACTION="+t.lastAction.Name())
|
||||||
env = append(env, "FZF_KEY="+t.lastKey)
|
env = append(env, "FZF_KEY="+t.lastKey)
|
||||||
env = append(env, "FZF_PROMPT="+string(t.promptString))
|
env = append(env, "FZF_PROMPT="+string(t.promptString))
|
||||||
|
env = append(env, "FZF_GHOST="+string(t.ghost))
|
||||||
|
env = append(env, "FZF_POINTER="+string(t.pointer))
|
||||||
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, "FZF_LIST_LABEL="+t.listLabelOpts.label)
|
||||||
|
env = append(env, "FZF_INPUT_LABEL="+t.inputLabelOpts.label)
|
||||||
|
env = append(env, "FZF_HEADER_LABEL="+t.headerLabelOpts.label)
|
||||||
if len(t.nthCurrent) > 0 {
|
if len(t.nthCurrent) > 0 {
|
||||||
env = append(env, "FZF_NTH="+RangesToString(t.nthCurrent))
|
env = append(env, "FZF_NTH="+RangesToString(t.nthCurrent))
|
||||||
}
|
}
|
||||||
@@ -1254,7 +1258,7 @@ func (t *Terminal) ansiLabelPrinter(str string, color *tui.ColorPair, fill bool)
|
|||||||
printFn := func(window tui.Window, limit int) {
|
printFn := func(window tui.Window, limit int) {
|
||||||
if offsets == nil {
|
if offsets == nil {
|
||||||
// tui.Col* are not initialized until renderer.Init()
|
// tui.Col* are not initialized until renderer.Init()
|
||||||
offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr, false)
|
offsets = result.colorOffsets(nil, nil, t.theme, *color, *color, t.nthAttr)
|
||||||
}
|
}
|
||||||
for limit > 0 {
|
for limit > 0 {
|
||||||
if length > limit {
|
if length > limit {
|
||||||
@@ -2787,17 +2791,28 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
_, selected := t.selected[item.Index()]
|
_, selected := t.selected[item.Index()]
|
||||||
label := ""
|
label := ""
|
||||||
extraWidth := 0
|
extraWidth := 0
|
||||||
|
alt := false
|
||||||
|
altBg := t.theme.AltBg
|
||||||
|
selectedBg := selected && t.theme.SelectedBg != t.theme.ListBg
|
||||||
if t.jumping != jumpDisabled {
|
if t.jumping != jumpDisabled {
|
||||||
if index < len(t.jumpLabels) {
|
if index < len(t.jumpLabels) {
|
||||||
// Striped
|
// Striped
|
||||||
current = index%2 == 0
|
if !altBg.IsColorDefined() {
|
||||||
|
altBg = t.theme.DarkBg
|
||||||
|
alt = index%2 == 0
|
||||||
|
} else {
|
||||||
|
alt = index%2 == 1
|
||||||
|
}
|
||||||
label = t.jumpLabels[index:index+1] + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
|
label = t.jumpLabels[index:index+1] + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
|
||||||
if t.pointerLen == 0 {
|
if t.pointerLen == 0 {
|
||||||
extraWidth = 1
|
extraWidth = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if current {
|
} else {
|
||||||
label = t.pointer
|
if current {
|
||||||
|
label = t.pointer
|
||||||
|
}
|
||||||
|
alt = !selectedBg && altBg.IsColorDefined() && index%2 == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid unnecessary redraw
|
// Avoid unnecessary redraw
|
||||||
@@ -2824,10 +2839,12 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
|
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
|
||||||
postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) {
|
postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) {
|
||||||
width += extraWidth
|
width += extraWidth
|
||||||
if (current || selected) && t.highlightLine {
|
if (current || selected || alt) && t.highlightLine {
|
||||||
color := tui.ColSelected
|
color := tui.ColSelected
|
||||||
if current {
|
if current {
|
||||||
color = tui.ColCurrent
|
color = tui.ColCurrent
|
||||||
|
} else if alt {
|
||||||
|
color = color.WithBg(altBg)
|
||||||
}
|
}
|
||||||
fillSpaces := maxWidth - width
|
fillSpaces := maxWidth - width
|
||||||
if wrapped {
|
if wrapped {
|
||||||
@@ -2925,6 +2942,10 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
|||||||
base = tui.ColNormal
|
base = tui.ColNormal
|
||||||
match = tui.ColMatch
|
match = tui.ColMatch
|
||||||
}
|
}
|
||||||
|
if alt {
|
||||||
|
base = base.WithBg(altBg)
|
||||||
|
match = match.WithBg(altBg)
|
||||||
|
}
|
||||||
finalLineNum = t.printHighlighted(result, base, match, false, true, line, maxLine, forceRedraw, preTask, postTask)
|
finalLineNum = t.printHighlighted(result, base, match, false, true, line, maxLine, forceRedraw, preTask, postTask)
|
||||||
}
|
}
|
||||||
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
|
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
|
||||||
@@ -3023,7 +3044,7 @@ func (t *Terminal) printHighlighted(result Result, colBase tui.ColorPair, colMat
|
|||||||
sort.Sort(ByOrder(nthOffsets))
|
sort.Sort(ByOrder(nthOffsets))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr, current)
|
allOffsets := result.colorOffsets(charOffsets, nthOffsets, t.theme, colBase, colMatch, t.nthAttr)
|
||||||
|
|
||||||
maxLines := 1
|
maxLines := 1
|
||||||
if t.canSpanMultiLines() {
|
if t.canSpanMultiLines() {
|
||||||
|
@@ -308,6 +308,12 @@ func (p ColorPair) WithAttr(attr Attr) ColorPair {
|
|||||||
return dup
|
return dup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p ColorPair) WithBg(bg ColorAttr) ColorPair {
|
||||||
|
dup := p
|
||||||
|
bgPair := ColorPair{colUndefined, bg.Color, bg.Attr}
|
||||||
|
return dup.Merge(bgPair)
|
||||||
|
}
|
||||||
|
|
||||||
func (p ColorPair) MergeAttr(other ColorPair) ColorPair {
|
func (p ColorPair) MergeAttr(other ColorPair) ColorPair {
|
||||||
return p.WithAttr(other.attr)
|
return p.WithAttr(other.attr)
|
||||||
}
|
}
|
||||||
@@ -328,6 +334,7 @@ type ColorTheme struct {
|
|||||||
Bg ColorAttr
|
Bg ColorAttr
|
||||||
ListFg ColorAttr
|
ListFg ColorAttr
|
||||||
ListBg ColorAttr
|
ListBg ColorAttr
|
||||||
|
AltBg ColorAttr
|
||||||
Nth ColorAttr
|
Nth ColorAttr
|
||||||
SelectedFg ColorAttr
|
SelectedFg ColorAttr
|
||||||
SelectedBg ColorAttr
|
SelectedBg ColorAttr
|
||||||
@@ -735,6 +742,7 @@ func EmptyTheme() *ColorTheme {
|
|||||||
Bg: ColorAttr{colUndefined, AttrUndefined},
|
Bg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
AltBg: 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},
|
||||||
@@ -780,6 +788,7 @@ func NoColorTheme() *ColorTheme {
|
|||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
ListFg: ColorAttr{colDefault, AttrUndefined},
|
ListFg: ColorAttr{colDefault, AttrUndefined},
|
||||||
ListBg: ColorAttr{colDefault, AttrUndefined},
|
ListBg: ColorAttr{colDefault, AttrUndefined},
|
||||||
|
AltBg: ColorAttr{colUndefined, 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},
|
||||||
@@ -825,6 +834,7 @@ func init() {
|
|||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
AltBg: 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},
|
||||||
@@ -864,6 +874,7 @@ func init() {
|
|||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
AltBg: 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},
|
||||||
@@ -903,6 +914,7 @@ func init() {
|
|||||||
Bg: ColorAttr{colDefault, AttrUndefined},
|
Bg: ColorAttr{colDefault, AttrUndefined},
|
||||||
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
ListFg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
ListBg: ColorAttr{colUndefined, AttrUndefined},
|
||||||
|
AltBg: 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},
|
||||||
|
@@ -1632,14 +1632,16 @@ class TestCore < TestInteractive
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_env_vars
|
def test_env_vars
|
||||||
def to_vars(lines)
|
def env_vars
|
||||||
lines.select { it.start_with?('FZF_') }.to_h do
|
return {} unless File.exist?(tempname)
|
||||||
key, val = it.split('=', 2)
|
|
||||||
|
File.readlines(tempname).select { it.start_with?('FZF_') }.to_h do
|
||||||
|
key, val = it.chomp.split('=', 2)
|
||||||
[key.to_sym, val]
|
[key.to_sym, val]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
tmux.send_keys %(seq 100 | #{FZF} --multi --reverse --preview-window up,99%,noborder --preview 'env | grep ^FZF_ | sort' --no-input --bind enter:show-input+refresh-preview,space:disable-search+refresh-preview), :Enter
|
tmux.send_keys %(seq 100 | #{FZF} --multi --reverse --preview-window 0 --preview 'env | grep ^FZF_ | sort > #{tempname}' --no-input --bind enter:show-input+refresh-preview,space:disable-search+refresh-preview), :Enter
|
||||||
expected = {
|
expected = {
|
||||||
FZF_TOTAL_COUNT: '100',
|
FZF_TOTAL_COUNT: '100',
|
||||||
FZF_MATCH_COUNT: '100',
|
FZF_MATCH_COUNT: '100',
|
||||||
@@ -1648,31 +1650,32 @@ class TestCore < TestInteractive
|
|||||||
FZF_KEY: '',
|
FZF_KEY: '',
|
||||||
FZF_POS: '1',
|
FZF_POS: '1',
|
||||||
FZF_QUERY: '',
|
FZF_QUERY: '',
|
||||||
FZF_PROMPT: '>',
|
FZF_POINTER: '>',
|
||||||
|
FZF_PROMPT: '> ',
|
||||||
FZF_INPUT_STATE: 'hidden'
|
FZF_INPUT_STATE: 'hidden'
|
||||||
}
|
}
|
||||||
tmux.until do |lines|
|
tmux.until do
|
||||||
assert_equal expected, to_vars(lines).slice(*expected.keys)
|
assert_equal expected, env_vars.slice(*expected.keys)
|
||||||
end
|
end
|
||||||
tmux.send_keys :Enter
|
tmux.send_keys :Enter
|
||||||
tmux.until do |lines|
|
tmux.until do
|
||||||
expected.merge!(FZF_INPUT_STATE: 'enabled', FZF_ACTION: 'show-input', FZF_KEY: 'enter')
|
expected.merge!(FZF_INPUT_STATE: 'enabled', FZF_ACTION: 'show-input', FZF_KEY: 'enter')
|
||||||
assert_equal expected, to_vars(lines).slice(*expected.keys)
|
assert_equal expected, env_vars.slice(*expected.keys)
|
||||||
end
|
end
|
||||||
tmux.send_keys :Tab, :Tab
|
tmux.send_keys :Tab, :Tab
|
||||||
tmux.until do |lines|
|
tmux.until do
|
||||||
expected.merge!(FZF_ACTION: 'toggle-down', FZF_KEY: 'tab', FZF_POS: '3', FZF_SELECT_COUNT: '2')
|
expected.merge!(FZF_ACTION: 'toggle-down', FZF_KEY: 'tab', FZF_POS: '3', FZF_SELECT_COUNT: '2')
|
||||||
assert_equal expected, to_vars(lines).slice(*expected.keys)
|
assert_equal expected, env_vars.slice(*expected.keys)
|
||||||
end
|
end
|
||||||
tmux.send_keys '99'
|
tmux.send_keys '99'
|
||||||
tmux.until do |lines|
|
tmux.until do
|
||||||
expected.merge!(FZF_ACTION: 'char', FZF_KEY: '9', FZF_QUERY: '99', FZF_MATCH_COUNT: '1', FZF_POS: '1')
|
expected.merge!(FZF_ACTION: 'char', FZF_KEY: '9', FZF_QUERY: '99', FZF_MATCH_COUNT: '1', FZF_POS: '1')
|
||||||
assert_equal expected, to_vars(lines).slice(*expected.keys)
|
assert_equal expected, env_vars.slice(*expected.keys)
|
||||||
end
|
end
|
||||||
tmux.send_keys :Space
|
tmux.send_keys :Space
|
||||||
tmux.until do |lines|
|
tmux.until do
|
||||||
expected.merge!(FZF_INPUT_STATE: 'disabled', FZF_ACTION: 'disable-search', FZF_KEY: 'space')
|
expected.merge!(FZF_INPUT_STATE: 'disabled', FZF_ACTION: 'disable-search', FZF_KEY: 'space')
|
||||||
assert_equal expected, to_vars(lines).slice(*expected.keys)
|
assert_equal expected, env_vars.slice(*expected.keys)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user