mirror of
https://github.com/junegunn/fzf.git
synced 2025-08-15 20:23:50 -07:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
c0d407f7ce | ||
|
461115afde | ||
|
bae1965231 | ||
|
b89c77ec9a | ||
|
1ca5f09d7b | ||
|
d79902ae59 | ||
|
77568e114f |
@@ -1,6 +1,13 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.60.2
|
||||
------
|
||||
- Template for `--with-nth` and `--accept-nth` now supports `{n}` which evaluates to the zero-based ordinal index of the item
|
||||
- Fixed a regression that caused the last field in the "nth" expression to be trimmed when a regular expression delimiter is used
|
||||
- Thanks to @phanen for the fix
|
||||
- Fixed 'jump' action when the pointer is an empty string
|
||||
|
||||
0.60.1
|
||||
------
|
||||
- Bug fixes and minor improvements
|
||||
|
2
install
2
install
@@ -2,7 +2,7 @@
|
||||
|
||||
set -u
|
||||
|
||||
version=0.60.1
|
||||
version=0.60.2
|
||||
auto_completion=
|
||||
key_bindings=
|
||||
update_config=2
|
||||
|
@@ -1,4 +1,4 @@
|
||||
$version="0.60.1"
|
||||
$version="0.60.2"
|
||||
|
||||
$fzf_base=Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
|
||||
|
@@ -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 "Feb 2025" "fzf 0.60.1" "fzf\-tmux - open fzf in tmux split pane"
|
||||
.TH fzf\-tmux 1 "Feb 2025" "fzf 0.60.2" "fzf\-tmux - open fzf in tmux split pane"
|
||||
|
||||
.SH NAME
|
||||
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
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf 1 "Feb 2025" "fzf 0.60.1" "fzf - a command-line fuzzy finder"
|
||||
.TH fzf 1 "Feb 2025" "fzf 0.60.2" "fzf - a command-line fuzzy finder"
|
||||
|
||||
.SH NAME
|
||||
fzf - a command-line fuzzy finder
|
||||
@@ -122,7 +122,9 @@ fields.
|
||||
.BI "\-\-with\-nth=" "N[,..] or TEMPLATE"
|
||||
Transform the presentation of each line using the field index expressions.
|
||||
For advanced transformation, you can provide a template containing field index
|
||||
expressions in curly braces.
|
||||
expressions in curly braces. When you use a template, the trailing delimiter is
|
||||
stripped from each expression, giving you more control over the output.
|
||||
\fB{n}\fR in template evaluates to the zero-based ordinal index of the line.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
@@ -130,13 +132,16 @@ e.g.
|
||||
echo foo bar baz | fzf --with-nth 2..
|
||||
|
||||
# Use template to rearrange fields
|
||||
echo foo,bar,baz | fzf --delimiter , --with-nth '{1},{3},{2},{1..2}'
|
||||
echo foo,bar,baz | fzf --delimiter , --with-nth '{n},{1},{3},{2},{1..2}'
|
||||
.RE
|
||||
.TP
|
||||
.BI "\-\-accept\-nth=" "N[,..] or TEMPLATE"
|
||||
Define which fields to print on accept. The last delimiter is stripped from the
|
||||
output. For advanced transformation, you can provide a template containing
|
||||
field index expressions in curly braces.
|
||||
field index expressions in curly braces. When you use a template, the trailing
|
||||
delimiter is stripped from each expression, giving you more control over the
|
||||
output. \fB{n}\fR in template evaluates to the zero-based ordinal index of the
|
||||
line.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
@@ -144,7 +149,7 @@ e.g.
|
||||
echo foo bar baz | fzf --accept-nth 2
|
||||
|
||||
# Template
|
||||
echo foo bar baz | fzf --accept-nth '1st: {1}, 2nd: {2}, 3rd: {3}'
|
||||
echo foo bar baz | fzf --accept-nth 'Index: {n}, 1st: {1}, 2nd: {2}, 3rd: {3}'
|
||||
.RE
|
||||
.TP
|
||||
.B "+s, \-\-no\-sort"
|
||||
@@ -1719,6 +1724,9 @@ e.g.
|
||||
\fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all+accept'\fR
|
||||
\fBfzf \-\-multi \-\-bind 'ctrl\-a:select\-all' \-\-bind 'ctrl\-a:+accept'\fR
|
||||
|
||||
Any action after a terminal action that exits fzf, such as \fBaccept\fR or
|
||||
\fBabort\fR, is ignored.
|
||||
|
||||
.SS ACTION ARGUMENT
|
||||
|
||||
An action denoted with \fB(...)\fR suffix takes an argument.
|
||||
|
@@ -128,7 +128,7 @@ func Run(opts *Options) (int, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
transformed := nthTransformer(tokens)
|
||||
transformed := nthTransformer(tokens, itemIndex)
|
||||
if len(header) < opts.HeaderLines {
|
||||
header = append(header, transformed)
|
||||
eventBox.Set(EvtHeader, header)
|
||||
|
@@ -544,8 +544,8 @@ type Options struct {
|
||||
Case Case
|
||||
Normalize bool
|
||||
Nth []Range
|
||||
WithNth func(Delimiter) func([]Token) string
|
||||
AcceptNth func(Delimiter) func([]Token) string
|
||||
WithNth func(Delimiter) func([]Token, int32) string
|
||||
AcceptNth func(Delimiter) func([]Token, int32) string
|
||||
Delimiter Delimiter
|
||||
Sort int
|
||||
Track trackOption
|
||||
@@ -769,30 +769,31 @@ func splitNth(str string) ([]Range, error) {
|
||||
return ranges, nil
|
||||
}
|
||||
|
||||
func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) {
|
||||
func nthTransformer(str string) (func(Delimiter) func([]Token, int32) string, error) {
|
||||
// ^[0-9,-.]+$"
|
||||
if match, _ := regexp.MatchString("^[0-9,-.]+$", str); match {
|
||||
nth, err := splitNth(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func(Delimiter) func([]Token) string {
|
||||
return func(tokens []Token) string {
|
||||
return func(Delimiter) func([]Token, int32) string {
|
||||
return func(tokens []Token, index int32) string {
|
||||
return JoinTokens(Transform(tokens, nth))
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// {...} {...} ...
|
||||
placeholder := regexp.MustCompile("{[0-9,-.]+}")
|
||||
placeholder := regexp.MustCompile("{[0-9,-.]+}|{n}")
|
||||
indexes := placeholder.FindAllStringIndex(str, -1)
|
||||
if indexes == nil {
|
||||
return nil, errors.New("template should include at least 1 placeholder: " + str)
|
||||
}
|
||||
|
||||
type NthParts struct {
|
||||
str string
|
||||
nth []Range
|
||||
str string
|
||||
index bool
|
||||
nth []Range
|
||||
}
|
||||
|
||||
parts := make([]NthParts, len(indexes))
|
||||
@@ -801,7 +802,10 @@ func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) {
|
||||
if idx < index[0] {
|
||||
parts = append(parts, NthParts{str: str[idx:index[0]]})
|
||||
}
|
||||
if nth, err := splitNth(str[index[0]+1 : index[1]-1]); err == nil {
|
||||
expr := str[index[0]+1 : index[1]-1]
|
||||
if expr == "n" {
|
||||
parts = append(parts, NthParts{index: true})
|
||||
} else if nth, err := splitNth(expr); err == nil {
|
||||
parts = append(parts, NthParts{nth: nth})
|
||||
}
|
||||
idx = index[1]
|
||||
@@ -810,12 +814,16 @@ func nthTransformer(str string) (func(Delimiter) func([]Token) string, error) {
|
||||
parts = append(parts, NthParts{str: str[idx:]})
|
||||
}
|
||||
|
||||
return func(delimiter Delimiter) func([]Token) string {
|
||||
return func(tokens []Token) string {
|
||||
return func(delimiter Delimiter) func([]Token, int32) string {
|
||||
return func(tokens []Token, index int32) string {
|
||||
str := ""
|
||||
for _, holder := range parts {
|
||||
if holder.nth != nil {
|
||||
str += StripLastDelimiter(JoinTokens(Transform(tokens, holder.nth)), delimiter)
|
||||
} else if holder.index {
|
||||
if index >= 0 {
|
||||
str += strconv.Itoa(int(index))
|
||||
}
|
||||
} else {
|
||||
str += holder.str
|
||||
}
|
||||
|
@@ -305,7 +305,7 @@ type Terminal struct {
|
||||
nthAttr tui.Attr
|
||||
nth []Range
|
||||
nthCurrent []Range
|
||||
acceptNth func([]Token) string
|
||||
acceptNth func([]Token, int32) string
|
||||
tabstop int
|
||||
margin [4]sizeSpec
|
||||
padding [4]sizeSpec
|
||||
@@ -1576,7 +1576,7 @@ func (t *Terminal) output() bool {
|
||||
if t.acceptNth != nil {
|
||||
transform = func(item *Item) string {
|
||||
tokens := Tokenize(item.AsString(t.ansi), t.delimiter)
|
||||
transformed := t.acceptNth(tokens)
|
||||
transformed := t.acceptNth(tokens, item.Index())
|
||||
return StripLastDelimiter(transformed, t.delimiter)
|
||||
}
|
||||
}
|
||||
@@ -2755,11 +2755,15 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
||||
item := result.item
|
||||
_, selected := t.selected[item.Index()]
|
||||
label := ""
|
||||
extraWidth := 0
|
||||
if t.jumping != jumpDisabled {
|
||||
if index < len(t.jumpLabels) {
|
||||
// Striped
|
||||
current = index%2 == 0
|
||||
label = t.jumpLabels[index:index+1] + strings.Repeat(" ", t.pointerLen-1)
|
||||
label = t.jumpLabels[index:index+1] + strings.Repeat(" ", util.Max(0, t.pointerLen-1))
|
||||
if t.pointerLen == 0 {
|
||||
extraWidth = 1
|
||||
}
|
||||
}
|
||||
} else if current {
|
||||
label = t.pointer
|
||||
@@ -2788,6 +2792,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
|
||||
|
||||
maxWidth := t.window.Width() - (t.pointerLen + t.markerLen + 1)
|
||||
postTask := func(lineNum int, width int, wrapped bool, forceRedraw bool) {
|
||||
width += extraWidth
|
||||
if (current || selected) && t.highlightLine {
|
||||
color := tui.ColSelected
|
||||
if current {
|
||||
|
@@ -225,7 +225,9 @@ func StripLastDelimiter(str string, delimiter Delimiter) string {
|
||||
locs := delimiter.regex.FindAllStringIndex(str, -1)
|
||||
if len(locs) > 0 {
|
||||
lastLoc := locs[len(locs)-1]
|
||||
str = str[:lastLoc[0]]
|
||||
if lastLoc[1] == len(str) {
|
||||
str = str[:lastLoc[0]]
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.TrimRightFunc(str, unicode.IsSpace)
|
||||
|
@@ -827,6 +827,24 @@ class TestCore < TestInteractive
|
||||
tmux.until { |lines| assert(lines.any? { it.include?('jump cancelled at 3') }) }
|
||||
end
|
||||
|
||||
def test_jump_no_pointer
|
||||
tmux.send_keys "seq 100 | #{FZF} --pointer= --jump-labels 12345 --bind ctrl-j:jump", :Enter
|
||||
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||
tmux.send_keys 'C-j'
|
||||
tmux.until { |lines| assert_equal '5 5', lines[-7] }
|
||||
tmux.send_keys 'C-c'
|
||||
tmux.until { |lines| assert_equal ' 5', lines[-7] }
|
||||
end
|
||||
|
||||
def test_jump_no_pointer_no_marker
|
||||
tmux.send_keys "seq 100 | #{FZF} --pointer= --marker= --jump-labels 12345 --bind ctrl-j:jump", :Enter
|
||||
tmux.until { |lines| assert_equal 100, lines.match_count }
|
||||
tmux.send_keys 'C-j'
|
||||
tmux.until { |lines| assert_equal '55', lines[-7] }
|
||||
tmux.send_keys 'C-c'
|
||||
tmux.until { |lines| assert_equal '5', lines[-7] }
|
||||
end
|
||||
|
||||
def test_pointer
|
||||
tmux.send_keys "seq 10 | #{fzf("--pointer '>>'")}", :Enter
|
||||
# Assert that specified pointer is displayed
|
||||
@@ -1773,12 +1791,21 @@ class TestCore < TestInteractive
|
||||
end
|
||||
end
|
||||
|
||||
def test_accept_nth_template
|
||||
tmux.send_keys %(echo "foo ,bar,baz" | #{FZF} -d, --accept-nth '1st: {1}, 3rd: {3}, 2nd: {2}' --sync --bind start:accept > #{tempname}), :Enter
|
||||
def test_accept_nth_regex_delimiter_strip_last
|
||||
tmux.send_keys %((echo "foo:,bar:,baz"; echo "foo:,bar:,baz:,qux:,") | #{FZF} --multi --delimiter='[:,]+' --accept-nth 2.. --sync --bind 'load:select-all+accept' > #{tempname}), :Enter
|
||||
wait do
|
||||
assert_path_exists tempname
|
||||
# Last delimiter and the whitespaces are removed
|
||||
assert_equal ['1st: foo, 3rd: baz, 2nd: bar'], File.readlines(tempname, chomp: true)
|
||||
assert_equal ['bar:,baz', 'bar:,baz:,qux'], File.readlines(tempname, chomp: true)
|
||||
end
|
||||
end
|
||||
|
||||
def test_accept_nth_template
|
||||
tmux.send_keys %(echo "foo ,bar,baz" | #{FZF} -d, --accept-nth '[{n}] 1st: {1}, 3rd: {3}, 2nd: {2}' --sync --bind start:accept > #{tempname}), :Enter
|
||||
wait do
|
||||
assert_path_exists tempname
|
||||
# Last delimiter and the whitespaces are removed
|
||||
assert_equal ['[0] 1st: foo, 3rd: baz, 2nd: bar'], File.readlines(tempname, chomp: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user