m/fzf
1
0
mirror of https://github.com/junegunn/fzf.git synced 2025-11-15 14:53:47 -05:00

Compare commits

..

11 Commits

Author SHA1 Message Date
Junegunn Choi
e03ac3136e 0.33.0 2022-08-29 07:23:14 +09:00
Junegunn Choi
6fb41a202a Add --scheme=[default|path|history] option to choose scoring scheme
Close #2909
Close #2930
2022-08-28 22:22:39 +09:00
Emil Vanherp
4bef330ce1 Add support for ANSI strike-through (#2932)
Close #2932

Co-authored-by: Emil Vanherp <emil@vanherp.me>
2022-08-26 09:27:49 +09:00
Junegunn Choi
8a5f719964 ADVANCED: fzf-git.sh 2022-08-25 17:54:35 +09:00
Charlie Vieth
209d5e8e90 ansi: speed up escape sequence parsing (#2927) 2022-08-25 14:02:08 +09:00
Junegunn Choi
9d041aa582 Update README 2022-08-23 13:29:41 +09:00
Junegunn Choi
6532b3e655 [completion] Remove extra trailing slash on directory completion
Fix #2931
2022-08-22 22:29:51 +09:00
Junegunn Choi
c1c355160d Support border-{up,down} as the synonyms for border-{top,bottom} 2022-08-20 00:11:17 +09:00
Junegunn Choi
83515d5610 Update ANSI test cases 2022-08-13 22:40:37 +09:00
Junegunn Choi
aa10dccf90 Support colon delimiter in ANSI escape sequences
# Both should work
    printf "\e[38;5;208mOption 1\e[m\nOption 2" | fzf --ansi
    printf "\e[38:5:208mOption 1\e[m\nOption 2" | fzf --ansi

This change makes ANSI parsing slightly slower.

    cpu: Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz

    Before:
      BenchmarkNextAnsiEscapeSequence-12            992.22 MB/s
      BenchmarkExtractColor-12                      174.35 MB/s

    After:
      BenchmarkNextAnsiEscapeSequence-12            925.05 MB/s
      BenchmarkExtractColor-12                      163.33 MB/s

Fix #2913
2022-08-13 22:30:50 +09:00
Junegunn Choi
f4fd53211a Reformat comments adhere to gofmt 2022-08-12 22:11:15 +09:00
29 changed files with 264 additions and 157 deletions

View File

@@ -22,7 +22,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@f6164bd8c8acb4a71fb2791a8b6c4024ff038dab # v2
with:
go-version: 1.18
go-version: 1.19
- name: Setup Ruby
uses: ruby/setup-ruby@ebaea52cb20fea395b0904125276395e37183dac

View File

@@ -1,7 +1,7 @@
Advanced fzf examples
======================
*(Last update: 2021/05/22)*
*(Last update: 2022/08/25)*
<!-- vim-markdown-toc GFM -->
@@ -496,9 +496,17 @@ pods() {
Key bindings for git objects
----------------------------
I have [blogged](https://junegunn.kr/2016/07/fzf-git) about my fzf+git key
bindings a few years ago. I'm going to show them here again, because they are
seriously useful.
Oftentimes, you want to put the identifiers of various Git object to the
command-line. For example, it is common to write commands like these:
```sh
git checkout [SOME_COMMIT_HASH or BRANCH or TAG]
git diff [SOME_COMMIT_HASH or BRANCH or TAG] [SOME_COMMIT_HASH or BRANCH or TAG]
```
[fzf-git.sh](https://github.com/junegunn/fzf-git.sh) project defines a set of
fzf-based key bindings for Git objects. I strongly recommend that you check
them out because they are seriously useful.
### Files listed in `git status`
@@ -518,9 +526,6 @@ seriously useful.
![image](https://user-images.githubusercontent.com/700826/113473765-91692080-94a6-11eb-8d38-ed4d41f27ac1.png)
The full source code can be found [here](https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236).
Color themes
------------

View File

@@ -1,6 +1,31 @@
CHANGELOG
=========
0.33.0
------
- Added `--scheme=[default|path|history]` option to choose scoring scheme
- (Experimental)
- We updated the scoring algorithm in 0.32.0, however we have learned that
this new scheme (`default`) is not always giving the optimal result
- `path`: Additional bonus point is only given the the characters after
path separator. You might want to choose this scheme if you have many
files with spaces in their paths.
- `history`: No additional bonus points are given so that we give more
weight to the chronological ordering. This is equivalent to the scoring
scheme before 0.32.0. This also sets `--tiebreak=index`.
- ANSI color sequences with colon delimiters are now supported.
```sh
printf "\e[38;5;208mOption 1\e[m\nOption 2" | fzf --ansi
printf "\e[38:5:208mOption 1\e[m\nOption 2" | fzf --ansi
```
- Support `border-{up,down}` as the synonyms for `border-{top,bottom}` in
`--preview-window`
- Added support for ANSI `strikethrough`
```sh
printf "\e[9mdeleted" | fzf --ansi
fzf --color fg+:strikethrough
```
0.32.1
------
- Fixed incorrect ordering of `--tiebreak=chunk`

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2013-2021 Junegunn Choi
Copyright (c) 2013-2022 Junegunn Choi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -627,10 +627,7 @@ fzf --height 40% --layout reverse --info inline --border \
See the man page (`man fzf`) for the full list of options.
For more advanced examples, see [Key bindings for git with fzf][fzf-git]
([code](https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236)).
[fzf-git]: https://junegunn.kr/2016/07/fzf-git/
More advanced examples can be found [here](https://github.com/junegunn/fzf/blob/master/ADVANCED.md).
----

2
go.mod
View File

@@ -1,7 +1,7 @@
module github.com/junegunn/fzf
require (
github.com/gdamore/tcell v1.4.0
github.com/gdamore/tcell/v2 v2.5.3
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-runewidth v0.0.13
github.com/mattn/go-shellwords v1.0.12

10
go.sum
View File

@@ -1,13 +1,11 @@
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/gdamore/tcell/v2 v2.5.3 h1:b9XQrT6QGbgI7JvZOJXFNczOQeIYbo8BfeSMzt2sAV0=
github.com/gdamore/tcell/v2 v2.5.3/go.mod h1:wSkrPaXoiIWZqW/g7Px4xc79di6FTcpB8tvaKJ6uGBo=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
@@ -19,11 +17,13 @@ github.com/saracen/walker v0.1.2/go.mod h1:0oKYMsKVhSJ+ful4p/XbjvXbMgLEkLITZaxoz
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM=
golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

View File

@@ -2,7 +2,7 @@
set -u
version=0.32.1
version=0.33.0
auto_completion=
key_bindings=
update_config=2

View File

@@ -1,4 +1,4 @@
$version="0.32.1"
$version="0.33.0"
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition

View File

@@ -5,7 +5,7 @@ import (
"github.com/junegunn/fzf/src/protector"
)
var version string = "0.32"
var version string = "0.33"
var revision string = "devel"
func main() {

View File

@@ -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
THE SOFTWARE.
..
.TH fzf-tmux 1 "Aug 2022" "fzf 0.32.1" "fzf-tmux - open fzf in tmux split pane"
.TH fzf-tmux 1 "Aug 2022" "fzf 0.33.0" "fzf-tmux - open fzf in tmux split pane"
.SH NAME
fzf-tmux - open fzf in tmux split pane

View File

@@ -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
THE SOFTWARE.
..
.TH fzf 1 "Aug 2022" "fzf 0.32.1" "fzf - a command-line fuzzy finder"
.TH fzf 1 "Aug 2022" "fzf 0.33.0" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -51,6 +51,18 @@ Case-sensitive match
.B "--literal"
Do not normalize latin script letters for matching.
.TP
.BI "--scheme=" SCHEME
Choose scoring scheme tailored for different types of input.
.br
.BR default " Generic scoring scheme designed to work well with any type of input"
.br
.BR path " Scoring scheme for paths (additional bonus point only after path separator)
.br
.BR history " Scoring scheme for command history (no additional bonus points).
Sets \fB--tiebreak=index\fR as well.
.br
.TP
.BI "--algo=" TYPE
Fuzzy matching algorithm (default: v2)
@@ -189,21 +201,21 @@ Choose the layout (default: default)
A synonym for \fB--layout=reverse\fB
.TP
.BI "--border" [=STYLE]
.BI "--border" [=BORDER_OPT]
Draw border around the finder
.br
.BR rounded " Border with rounded corners (default)"
.BR rounded " Border with rounded corners (default)"
.br
.BR sharp " Border with sharp corners"
.BR sharp " Border with sharp corners"
.br
.BR horizontal " Horizontal lines above and below the finder"
.BR horizontal " Horizontal lines above and below the finder"
.br
.BR vertical " Vertical lines on each side of the finder"
.BR vertical " Vertical lines on each side of the finder"
.br
.BR top
.BR top " (up)"
.br
.BR bottom
.BR bottom " (down)"
.br
.BR left
.br
@@ -378,6 +390,7 @@ color mappings.
\fBreverse\fR
\fBdim\fR
\fBitalic\fR
\fBstrikethrough\fR
.B EXAMPLES:

View File

@@ -181,7 +181,7 @@ __fzf_generic_path_completion() {
[[ -z "$dir" ]] && dir='.'
[[ "$dir" != "/" ]] && dir="${dir/%\//}"
matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $2" __fzf_comprun "$4" -q "$leftover" | while read -r item; do
printf "%q$3 " "$item"
printf "%q " "${item%$3}$3"
done)
matches=${matches% }
[[ -z "$3" ]] && [[ "$__fzf_nospace_commands" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "

View File

@@ -146,7 +146,8 @@ __fzf_generic_path_completion() {
[ -z "$dir" ] && dir='.'
[ "$dir" != "/" ] && dir="${dir/%\//}"
matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
echo -n "${(q)item}$suffix "
item="${item%$suffix}$suffix"
echo -n "${(q)item} "
done)
matches=${matches% }
if [ -n "$matches" ]; then

View File

@@ -50,7 +50,7 @@ __fzf_cd__() {
__fzf_history__() {
local output opts script
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m --read0"
opts="--height ${FZF_TMUX_HEIGHT:-40%} --bind=ctrl-z:ignore $FZF_DEFAULT_OPTS -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m --read0"
script='BEGIN { getc; $/ = "\n\t"; $HISTCOUNT = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCOUNT - $. . "\t$_" if !$seen{$_}++'
output=$(
builtin fc -lnr -2147483648 |

View File

@@ -53,7 +53,7 @@ function fzf_key_bindings
function fzf-history-widget -d "Show command history"
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
begin
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS --tiebreak=index --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS +m"
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS +m"
set -l FISH_MAJOR (echo $version | cut -f1 -d.)
set -l FISH_MINOR (echo $version | cut -f2 -d.)

View File

@@ -98,7 +98,7 @@ fzf-history-widget() {
local selected num
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
selected=( $(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --scheme=history --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
local ret=$?
if [ -n "$selected" ]; then
num=$selected[1]

View File

@@ -80,6 +80,7 @@ Scoring criteria
import (
"bytes"
"fmt"
"os"
"strings"
"unicode"
"unicode/utf8"
@@ -89,7 +90,8 @@ import (
var DEBUG bool
const delimiterChars = "/,:;|"
var delimiterChars = "/,:;|"
const whiteChars = " \t\n\v\f\r\x85\xA0"
func indexAt(index int, max int, forward bool) int {
@@ -120,12 +122,6 @@ const (
// in web2 dictionary and my file system.
bonusBoundary = scoreMatch / 2
// Extra bonus for word boundary after whitespace character or beginning of the string
bonusBoundaryWhite = bonusBoundary + 2
// Extra bonus for word boundary after slash, colon, semi-colon, and comma
bonusBoundaryDelimiter = bonusBoundary + 1
// Although bonus point for non-word characters is non-contextual, we need it
// for computing bonus points for consecutive chunks starting with a non-word
// character.
@@ -149,6 +145,16 @@ const (
bonusFirstCharMultiplier = 2
)
var (
// Extra bonus for word boundary after whitespace character or beginning of the string
bonusBoundaryWhite int16 = bonusBoundary + 2
// Extra bonus for word boundary after slash, colon, semi-colon, and comma
bonusBoundaryDelimiter int16 = bonusBoundary + 1
initialCharClass charClass = charWhite
)
type charClass int
const (
@@ -161,6 +167,29 @@ const (
charNumber
)
func Init(scheme string) bool {
switch scheme {
case "default":
bonusBoundaryWhite = bonusBoundary + 2
bonusBoundaryDelimiter = bonusBoundary + 1
case "path":
bonusBoundaryWhite = bonusBoundary
bonusBoundaryDelimiter = bonusBoundary + 1
if os.PathSeparator == '/' {
delimiterChars = "/"
} else {
delimiterChars = string([]rune{os.PathSeparator, '/'})
}
initialCharClass = charDelimiter
case "history":
bonusBoundaryWhite = bonusBoundary
bonusBoundaryDelimiter = bonusBoundary
default:
return false
}
return true
}
func posArray(withPos bool, len int) *[]int {
if withPos {
pos := make([]int, 0, len)
@@ -407,7 +436,7 @@ func FuzzyMatchV2(caseSensitive bool, normalize bool, forward bool, input *util.
// Phase 2. Calculate bonus for each point
maxScore, maxScorePos := int16(0), 0
pidx, lastIdx := 0, 0
pchar0, pchar, prevH0, prevClass, inGap := pattern[0], pattern[0], int16(0), charWhite, false
pchar0, pchar, prevH0, prevClass, inGap := pattern[0], pattern[0], int16(0), initialCharClass, false
Tsub := T[idx:]
H0sub, C0sub, Bsub := H0[idx:][:len(Tsub)], C0[idx:][:len(Tsub)], B[idx:][:len(Tsub)]
for off, char := range Tsub {
@@ -910,8 +939,8 @@ func EqualMatch(caseSensitive bool, normalize bool, forward bool, text *util.Cha
match = runesStr == string(pattern)
}
if match {
return Result{trimmedLen, trimmedLen + lenPattern, (scoreMatch+bonusBoundaryWhite)*lenPattern +
(bonusFirstCharMultiplier-1)*bonusBoundaryWhite}, nil
return Result{trimmedLen, trimmedLen + lenPattern, (scoreMatch+int(bonusBoundaryWhite))*lenPattern +
(bonusFirstCharMultiplier-1)*int(bonusBoundaryWhite)}, nil
}
return Result{-1, -1, 0}, nil
}

View File

@@ -45,29 +45,29 @@ func TestFuzzyMatch(t *testing.T) {
assertMatch(t, fn, false, forward, "fooBarbaz1", "oBZ", 2, 9,
scoreMatch*3+bonusCamel123+scoreGapStart+scoreGapExtension*3)
assertMatch(t, fn, false, forward, "foo bar baz", "fbb", 0, 9,
scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+
bonusBoundaryWhite*2+2*scoreGapStart+4*scoreGapExtension)
scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
int(bonusBoundaryWhite)*2+2*scoreGapStart+4*scoreGapExtension)
assertMatch(t, fn, false, forward, "/AutomatorDocument.icns", "rdoc", 9, 13,
scoreMatch*4+bonusCamel123+bonusConsecutive*2)
assertMatch(t, fn, false, forward, "/man1/zshcompctl.1", "zshc", 6, 10,
scoreMatch*4+bonusBoundaryDelimiter*bonusFirstCharMultiplier+bonusBoundaryDelimiter*3)
scoreMatch*4+int(bonusBoundaryDelimiter)*bonusFirstCharMultiplier+int(bonusBoundaryDelimiter)*3)
assertMatch(t, fn, false, forward, "/.oh-my-zsh/cache", "zshc", 8, 13,
scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*2+scoreGapStart+bonusBoundaryDelimiter)
scoreMatch*4+bonusBoundary*bonusFirstCharMultiplier+bonusBoundary*2+scoreGapStart+int(bonusBoundaryDelimiter))
assertMatch(t, fn, false, forward, "ab0123 456", "12356", 3, 10,
scoreMatch*5+bonusConsecutive*3+scoreGapStart+scoreGapExtension)
assertMatch(t, fn, false, forward, "abc123 456", "12356", 3, 10,
scoreMatch*5+bonusCamel123*bonusFirstCharMultiplier+bonusCamel123*2+bonusConsecutive+scoreGapStart+scoreGapExtension)
assertMatch(t, fn, false, forward, "foo/bar/baz", "fbb", 0, 9,
scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+
bonusBoundaryDelimiter*2+2*scoreGapStart+4*scoreGapExtension)
scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
int(bonusBoundaryDelimiter)*2+2*scoreGapStart+4*scoreGapExtension)
assertMatch(t, fn, false, forward, "fooBarBaz", "fbb", 0, 7,
scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+
scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
bonusCamel123*2+2*scoreGapStart+2*scoreGapExtension)
assertMatch(t, fn, false, forward, "foo barbaz", "fbb", 0, 8,
scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite+
scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite)+
scoreGapStart*2+scoreGapExtension*3)
assertMatch(t, fn, false, forward, "fooBar Baz", "foob", 0, 4,
scoreMatch*4+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite*3)
scoreMatch*4+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite)*3)
assertMatch(t, fn, false, forward, "xFoo-Bar Baz", "foo-b", 1, 6,
scoreMatch*5+bonusCamel123*bonusFirstCharMultiplier+bonusCamel123*2+
bonusNonWord+bonusBoundary)
@@ -75,14 +75,14 @@ func TestFuzzyMatch(t *testing.T) {
assertMatch(t, fn, true, forward, "fooBarbaz", "oBz", 2, 9,
scoreMatch*3+bonusCamel123+scoreGapStart+scoreGapExtension*3)
assertMatch(t, fn, true, forward, "Foo/Bar/Baz", "FBB", 0, 9,
scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryDelimiter*2+
scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryDelimiter)*2+
scoreGapStart*2+scoreGapExtension*4)
assertMatch(t, fn, true, forward, "FooBarBaz", "FBB", 0, 7,
scoreMatch*3+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusCamel123*2+
scoreMatch*3+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+bonusCamel123*2+
scoreGapStart*2+scoreGapExtension*2)
assertMatch(t, fn, true, forward, "FooBar Baz", "FooB", 0, 4,
scoreMatch*4+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite*2+
util.Max(bonusCamel123, bonusBoundaryWhite))
scoreMatch*4+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite)*2+
util.Max(bonusCamel123, int(bonusBoundaryWhite)))
// Consecutive bonus updated
assertMatch(t, fn, true, forward, "foo-bar", "o-ba", 2, 6,
@@ -98,10 +98,10 @@ func TestFuzzyMatch(t *testing.T) {
func TestFuzzyMatchBackward(t *testing.T) {
assertMatch(t, FuzzyMatchV1, false, true, "foobar fb", "fb", 0, 4,
scoreMatch*2+bonusBoundaryWhite*bonusFirstCharMultiplier+
scoreMatch*2+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+
scoreGapStart+scoreGapExtension)
assertMatch(t, FuzzyMatchV1, false, false, "foobar fb", "fb", 7, 9,
scoreMatch*2+bonusBoundaryWhite*bonusFirstCharMultiplier+bonusBoundaryWhite)
scoreMatch*2+int(bonusBoundaryWhite)*bonusFirstCharMultiplier+int(bonusBoundaryWhite))
}
func TestExactMatchNaive(t *testing.T) {
@@ -114,9 +114,9 @@ func TestExactMatchNaive(t *testing.T) {
assertMatch(t, ExactMatchNaive, false, dir, "/AutomatorDocument.icns", "rdoc", 9, 13,
scoreMatch*4+bonusCamel123+bonusConsecutive*2)
assertMatch(t, ExactMatchNaive, false, dir, "/man1/zshcompctl.1", "zshc", 6, 10,
scoreMatch*4+bonusBoundaryDelimiter*(bonusFirstCharMultiplier+3))
scoreMatch*4+int(bonusBoundaryDelimiter)*(bonusFirstCharMultiplier+3))
assertMatch(t, ExactMatchNaive, false, dir, "/.oh-my-zsh/cache", "zsh/c", 8, 13,
scoreMatch*5+bonusBoundary*(bonusFirstCharMultiplier+3)+bonusBoundaryDelimiter)
scoreMatch*5+bonusBoundary*(bonusFirstCharMultiplier+3)+int(bonusBoundaryDelimiter))
}
}
@@ -128,7 +128,7 @@ func TestExactMatchNaiveBackward(t *testing.T) {
}
func TestPrefixMatch(t *testing.T) {
score := scoreMatch*3 + bonusBoundaryWhite*bonusFirstCharMultiplier + bonusBoundaryWhite*2
score := scoreMatch*3 + int(bonusBoundaryWhite)*bonusFirstCharMultiplier + int(bonusBoundaryWhite)*2
for _, dir := range []bool{true, false} {
assertMatch(t, PrefixMatch, true, dir, "fooBarbaz", "Foo", -1, -1, 0)
@@ -159,7 +159,7 @@ func TestSuffixMatch(t *testing.T) {
// Only when the pattern doesn't end with a space
assertMatch(t, SuffixMatch, false, dir, "fooBarbaz ", "baz ", 6, 10,
scoreMatch*4+bonusConsecutive*2+bonusBoundaryWhite)
scoreMatch*4+bonusConsecutive*2+int(bonusBoundaryWhite))
}
}

View File

@@ -55,6 +55,9 @@ func (s *ansiState) ToString() string {
if s.attr&tui.Reverse > 0 {
ret += "7;"
}
if s.attr&tui.StrikeThrough > 0 {
ret += "9;"
}
ret += toAnsiString(s.fg, 30) + toAnsiString(s.bg, 40)
return "\x1b[" + strings.TrimSuffix(ret, ";") + "m"
@@ -85,7 +88,7 @@ func isPrint(c uint8) bool {
}
func matchOperatingSystemCommand(s string) int {
// `\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)`
// `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
// ^ match starting here
//
i := 5 // prefix matched in nextAnsiEscapeSequence()
@@ -103,30 +106,37 @@ func matchOperatingSystemCommand(s string) int {
}
func matchControlSequence(s string) int {
// `\x1b[\\[()][0-9;?]*[a-zA-Z@]`
// ^ match starting here
// `\x1b[\\[()][0-9;:?]*[a-zA-Z@]`
// ^ match starting here
//
i := 2 // prefix matched in nextAnsiEscapeSequence()
for ; i < len(s) && (isNumeric(s[i]) || s[i] == ';' || s[i] == '?'); i++ {
}
if i < len(s) {
for ; i < len(s); i++ {
c := s[i]
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '@' {
return i + 1
switch c {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';', ':', '?':
// ok
default:
if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '@' {
return i + 1
}
return -1
}
}
return -1
}
func isCtrlSeqStart(c uint8) bool {
return c == '\\' || c == '[' || c == '(' || c == ')'
switch c {
case '\\', '[', '(', ')':
return true
}
return false
}
// nextAnsiEscapeSequence returns the ANSI escape sequence and is equivalent to
// calling FindStringIndex() on the below regex (which was originally used):
//
// "(?:\x1b[\\[()][0-9;?]*[a-zA-Z@]|\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
//
// "(?:\x1b[\\[()][0-9;:?]*[a-zA-Z@]|\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)"
func nextAnsiEscapeSequence(s string) (int, int) {
// fast check for ANSI escape sequences
i := 0
@@ -154,16 +164,16 @@ Loop:
return i - n, i + 1
}
case '\x1b':
// match: `\x1b[\\[()][0-9;?]*[a-zA-Z@]`
// match: `\x1b[\\[()][0-9;:?]*[a-zA-Z@]`
if i+2 < len(s) && isCtrlSeqStart(s[i+1]) {
if j := matchControlSequence(s[i:]); j != -1 {
return i, i + j
}
}
// match: `\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)`
// match: `\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)`
if i+5 < len(s) && s[i+1] == ']' && isNumeric(s[i+2]) &&
s[i+3] == ';' && isPrint(s[i+4]) {
(s[i+3] == ';' || s[i+3] == ':') && isPrint(s[i+4]) {
if j := matchOperatingSystemCommand(s[i:]); j != -1 {
return i, i + j
@@ -280,9 +290,20 @@ func extractColor(str string, state *ansiState, proc func(string, *ansiState) bo
return trimmed, nil, state
}
func parseAnsiCode(s string) (int, string) {
func parseAnsiCode(s string, delimiter byte) (int, byte, string) {
var remaining string
if i := strings.IndexByte(s, ';'); i >= 0 {
i := -1
if delimiter == 0 {
// Faster than strings.IndexAny(";:")
i = strings.IndexByte(s, ';')
if i < 0 {
i = strings.IndexByte(s, ':')
}
} else {
i = strings.IndexByte(s, delimiter)
}
if i >= 0 {
delimiter = s[i]
remaining = s[i+1:]
s = s[:i]
}
@@ -294,14 +315,14 @@ func parseAnsiCode(s string) (int, string) {
for _, ch := range []byte(s) {
ch -= '0'
if ch > 9 {
return -1, remaining
return -1, delimiter, remaining
}
code = code*10 + int(ch)
}
return code, remaining
return code, delimiter, remaining
}
return -1, remaining
return -1, delimiter, remaining
}
func interpretCode(ansiCode string, prevState *ansiState) ansiState {
@@ -329,9 +350,10 @@ func interpretCode(ansiCode string, prevState *ansiState) ansiState {
state256 := 0
ptr := &state.fg
var delimiter byte = 0
for len(ansiCode) != 0 {
var num int
if num, ansiCode = parseAnsiCode(ansiCode); num != -1 {
if num, delimiter, ansiCode = parseAnsiCode(ansiCode, delimiter); num != -1 {
switch state256 {
case 0:
switch num {
@@ -357,6 +379,8 @@ func interpretCode(ansiCode string, prevState *ansiState) ansiState {
state.attr = state.attr | tui.Blink
case 7:
state.attr = state.attr | tui.Reverse
case 9:
state.attr = state.attr | tui.StrikeThrough
case 23: // tput rmso
state.attr = state.attr &^ tui.Italic
case 24: // tput rmul

View File

@@ -15,14 +15,14 @@ import (
// testing nextAnsiEscapeSequence().
//
// References:
// - https://github.com/gnachman/iTerm2
// - https://web.archive.org/web/20090204053813/http://ascii-table.com/ansi-escape-sequences.php
// (archived from http://ascii-table.com/ansi-escape-sequences.php)
// - https://web.archive.org/web/20090227051140/http://ascii-table.com/ansi-escape-sequences-vt-100.php
// (archived from http://ascii-table.com/ansi-escape-sequences-vt-100.php)
// - http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
// - https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
var ansiRegexReference = regexp.MustCompile("(?:\x1b[\\[()][0-9;]*[a-zA-Z@]|\x1b][0-9];[[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)")
// - https://github.com/gnachman/iTerm2
// - https://web.archive.org/web/20090204053813/http://ascii-table.com/ansi-escape-sequences.php
// (archived from http://ascii-table.com/ansi-escape-sequences.php)
// - https://web.archive.org/web/20090227051140/http://ascii-table.com/ansi-escape-sequences-vt-100.php
// (archived from http://ascii-table.com/ansi-escape-sequences-vt-100.php)
// - http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html
// - https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
var ansiRegexReference = regexp.MustCompile("(?:\x1b[\\[()][0-9;:]*[a-zA-Z@]|\x1b][0-9][;:][[:print:]]+(?:\x1b\\\\|\x07)|\x1b.|[\x0e\x0f]|.\x08)")
func testParserReference(t testing.TB, str string) {
t.Helper()
@@ -358,6 +358,7 @@ func TestAnsiCodeStringConversion(t *testing.T) {
assert("\x1b[31m", &ansiState{fg: 4, bg: 4, lbg: -1}, "\x1b[31;44m")
assert("\x1b[1;2;31m", &ansiState{fg: 2, bg: -1, attr: tui.Reverse, lbg: -1}, "\x1b[1;2;7;31;49m")
assert("\x1b[38;5;100;48;5;200m", nil, "\x1b[38;5;100;48;5;200m")
assert("\x1b[38:5:100:48:5:200m", nil, "\x1b[38;5;100;48;5;200m")
assert("\x1b[48;5;100;38;5;200m", nil, "\x1b[38;5;200;48;5;100m")
assert("\x1b[48;5;100;38;2;10;20;30;1m", nil, "\x1b[1;38;2;10;20;30;48;5;100m")
assert("\x1b[48;5;100;38;2;10;20;30;7m",
@@ -377,7 +378,7 @@ func TestParseAnsiCode(t *testing.T) {
{"-2", "", -1},
}
for _, x := range tests {
n, s := parseAnsiCode(x.In)
n, _, s := parseAnsiCode(x.In, 0)
if n != x.N || s != x.Exp {
t.Fatalf("%q: got: (%d %q) want: (%d %q)", x.In, n, s, x.N, x.Exp)
}
@@ -385,9 +386,9 @@ func TestParseAnsiCode(t *testing.T) {
}
// kernel/bpf/preload/iterators/README
const ansiBenchmarkString = "\x1b[38;5;81m\x1b[01;31m\x1b[Kkernel/\x1b[0m\x1b[38;5;81mbpf/" +
"\x1b[0m\x1b[38;5;81mpreload/\x1b[0m\x1b[38;5;81miterators/" +
"\x1b[0m\x1b[38;5;149mMakefile\x1b[m\x1b[K\x1b[0m"
const ansiBenchmarkString = "\x1b[38;5;81m\x1b[01;31m\x1b[Kkernel/\x1b[0m\x1b[38:5:81mbpf/" +
"\x1b[0m\x1b[38:5:81mpreload/\x1b[0m\x1b[38;5;81miterators/" +
"\x1b[0m\x1b[38:5:149mMakefile\x1b[m\x1b[K\x1b[0m"
func BenchmarkNextAnsiEscapeSequence(b *testing.B) {
b.SetBytes(int64(len(ansiBenchmarkString)))

View File

@@ -1,28 +1,4 @@
/*
Package fzf implements fzf, a command-line fuzzy finder.
The MIT License (MIT)
Copyright (c) 2013-2021 Junegunn Choi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
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
THE SOFTWARE.
*/
// Package fzf implements fzf, a command-line fuzzy finder.
package fzf
import (

View File

@@ -21,9 +21,9 @@ const usage = `usage: fzf [options]
-x, --extended Extended-search mode
(enabled by default; +x or --no-extended to disable)
-e, --exact Enable Exact-match
--algo=TYPE Fuzzy matching algorithm: [v1|v2] (default: v2)
-i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
--scheme=SCHEME Scoring scheme [default|path|history]
--literal Do not normalize latin script letters before matching
-n, --nth=N[,..] Comma-separated list of field index expressions
for limiting search scope. Each can be a non-zero
@@ -194,6 +194,7 @@ func (a previewOpts) sameContentLayout(b previewOpts) bool {
type Options struct {
Fuzzy bool
FuzzyAlgo algo.Algo
Scheme string
Extended bool
Phony bool
Case Case
@@ -259,6 +260,7 @@ func defaultOptions() *Options {
return &Options{
Fuzzy: true,
FuzzyAlgo: algo.FuzzyMatchV2,
Scheme: "default",
Extended: true,
Phony: false,
Case: CaseSmart,
@@ -441,6 +443,15 @@ func parseAlgo(str string) algo.Algo {
return algo.FuzzyMatchV2
}
func processScheme(opts *Options) {
if !algo.Init(opts.Scheme) {
errorExit("invalid scoring scheme (expected: default|path|history)")
}
if opts.Scheme == "history" {
opts.Criteria = []criterion{byScore}
}
}
func parseBorder(str string, optional bool) tui.BorderShape {
switch str {
case "rounded":
@@ -700,6 +711,8 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
cattr.Attr |= tui.Blink
case "reverse":
cattr.Attr |= tui.Reverse
case "strikethrough":
cattr.Attr |= tui.StrikeThrough
case "black":
cattr.Color = tui.Color(0)
case "red":
@@ -1228,9 +1241,9 @@ func parsePreviewWindow(opts *previewOpts, input string) {
opts.border = tui.BorderHorizontal
case "border-vertical":
opts.border = tui.BorderVertical
case "border-top":
case "border-up", "border-top":
opts.border = tui.BorderTop
case "border-bottom":
case "border-down", "border-bottom":
opts.border = tui.BorderBottom
case "border-left":
opts.border = tui.BorderLeft
@@ -1343,6 +1356,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Normalize = true
case "--algo":
opts.FuzzyAlgo = parseAlgo(nextString(allArgs, &i, "algorithm required (v1|v2)"))
case "--scheme":
opts.Scheme = strings.ToLower(nextString(allArgs, &i, "scoring scheme required (default|path|history)"))
case "--expect":
for k, v := range parseKeyChords(nextString(allArgs, &i, "key names required"), "key names required") {
opts.Expect[k] = v
@@ -1549,6 +1564,8 @@ func parseOptions(opts *Options, allArgs []string) {
default:
if match, value := optString(arg, "--algo="); match {
opts.FuzzyAlgo = parseAlgo(value)
} else if match, value := optString(arg, "--scheme="); match {
opts.Scheme = strings.ToLower(value)
} else if match, value := optString(arg, "-q", "--query="); match {
opts.Query = value
} else if match, value := optString(arg, "-f", "--filter="); match {
@@ -1750,6 +1767,10 @@ func postProcessOptions(opts *Options) {
theme.Cursor = boldify(theme.Cursor)
theme.Spinner = boldify(theme.Spinner)
}
if opts.Scheme != "default" {
processScheme(opts)
}
}
func expectsArbitraryString(opt string) bool {

View File

@@ -25,14 +25,14 @@ import (
// import "github.com/pkg/profile"
/*
Placeholder regex is used to extract placeholders from fzf's template
strings. Acts as input validation for parsePlaceholder function.
Describes the syntax, but it is fairly lenient.
Placeholder regex is used to extract placeholders from fzf's template
strings. Acts as input validation for parsePlaceholder function.
Describes the syntax, but it is fairly lenient.
The following pseudo regex has been reverse engineered from the
implementation. It is overly strict, but better describes whats possible.
As such it is not useful for validation, but rather to generate test
cases for example.
The following pseudo regex has been reverse engineered from the
implementation. It is overly strict, but better describes whats possible.
As such it is not useful for validation, but rather to generate test
cases for example.
\\?(?: # escaped type
{\+?s?f?RANGE(?:,RANGE)*} # token type

View File

@@ -421,10 +421,10 @@ func TestPowershellCommands(t *testing.T) {
}
/*
Test typical valid placeholders and parsing of them.
Test typical valid placeholders and parsing of them.
Also since the parser assumes the input is matched with `placeholder` regex,
the regex is tested here as well.
Also since the parser assumes the input is matched with `placeholder` regex,
the regex is tested here as well.
*/
func TestParsePlaceholder(t *testing.T) {
// give, want pairs

View File

@@ -14,16 +14,17 @@ func (a Attr) Merge(b Attr) Attr {
const (
AttrUndefined = Attr(0)
AttrRegular = Attr(1 << 7)
AttrClear = Attr(1 << 8)
AttrRegular = Attr(1 << 8)
AttrClear = Attr(1 << 9)
Bold = Attr(1)
Dim = Attr(1 << 1)
Italic = Attr(1 << 2)
Underline = Attr(1 << 3)
Blink = Attr(1 << 4)
Blink2 = Attr(1 << 5)
Reverse = Attr(1 << 6)
Bold = Attr(1)
Dim = Attr(1 << 1)
Italic = Attr(1 << 2)
Underline = Attr(1 << 3)
Blink = Attr(1 << 4)
Blink2 = Attr(1 << 5)
Reverse = Attr(1 << 6)
StrikeThrough = Attr(1 << 7)
)
func (r *FullscreenRenderer) Init() {}

View File

@@ -856,6 +856,9 @@ func attrCodes(attr Attr) []string {
if (attr & Reverse) > 0 {
codes = append(codes, "7")
}
if (attr & StrikeThrough) > 0 {
codes = append(codes, "9")
}
return codes
}

View File

@@ -8,8 +8,8 @@ import (
"runtime"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/encoding"
"github.com/gdamore/tcell/v2"
"github.com/gdamore/tcell/v2/encoding"
"github.com/mattn/go-runewidth"
"github.com/rivo/uniseg"
@@ -19,12 +19,20 @@ func HasFullscreenRenderer() bool {
return true
}
func (p ColorPair) style() tcell.Style {
style := tcell.StyleDefault
return style.Foreground(tcell.Color(p.Fg())).Background(tcell.Color(p.Bg()))
func asTcellColor(color Color) tcell.Color {
value := uint64(tcell.ColorValid) + uint64(color)
if color.is24() {
value = value | uint64(tcell.ColorIsRGB)
}
return tcell.Color(value)
}
type Attr tcell.Style
func (p ColorPair) style() tcell.Style {
style := tcell.StyleDefault
return style.Foreground(asTcellColor(p.Fg())).Background(asTcellColor(p.Bg()))
}
type Attr int32
type TcellWindow struct {
color bool
@@ -72,12 +80,13 @@ func (w *TcellWindow) FinishFill() {
}
const (
Bold Attr = Attr(tcell.AttrBold)
Dim = Attr(tcell.AttrDim)
Blink = Attr(tcell.AttrBlink)
Reverse = Attr(tcell.AttrReverse)
Underline = Attr(tcell.AttrUnderline)
Italic = Attr(tcell.AttrItalic)
Bold Attr = Attr(tcell.AttrBold)
Dim = Attr(tcell.AttrDim)
Blink = Attr(tcell.AttrBlink)
Reverse = Attr(tcell.AttrReverse)
Underline = Attr(tcell.AttrUnderline)
StrikeThrough = Attr(tcell.AttrStrikeThrough)
Italic = Attr(tcell.AttrItalic)
)
const (
@@ -561,6 +570,7 @@ func (w *TcellWindow) printString(text string, pair ColorPair) {
style = style.
Reverse(a&Attr(tcell.AttrReverse) != 0).
Underline(a&Attr(tcell.AttrUnderline) != 0).
StrikeThrough(a&Attr(tcell.AttrStrikeThrough) != 0).
Italic(a&Attr(tcell.AttrItalic) != 0).
Blink(a&Attr(tcell.AttrBlink) != 0).
Dim(a&Attr(tcell.AttrDim) != 0)
@@ -612,6 +622,7 @@ func (w *TcellWindow) fillString(text string, pair ColorPair) FillReturn {
Dim(a&Attr(tcell.AttrDim) != 0).
Reverse(a&Attr(tcell.AttrReverse) != 0).
Underline(a&Attr(tcell.AttrUnderline) != 0).
StrikeThrough(a&Attr(tcell.AttrStrikeThrough) != 0).
Italic(a&Attr(tcell.AttrItalic) != 0)
gr := uniseg.NewGraphemes(text)

View File

@@ -5,7 +5,7 @@ package tui
import (
"testing"
"github.com/gdamore/tcell"
"github.com/gdamore/tcell/v2"
"github.com/junegunn/fzf/src/util"
)