Add placeholder expression for zero-based item index: {n} and {+n}

Close #1482
This commit is contained in:
Junegunn Choi 2019-02-19 01:12:57 +09:00
parent 315e568de0
commit 6c32148f90
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
3 changed files with 27 additions and 12 deletions

View File

@ -301,7 +301,9 @@ e.g. \fBfzf --multi --preview='head -10 {+}'\fR
When using a field index expression, leading and trailing whitespace is stripped When using a field index expression, leading and trailing whitespace is stripped
from the replacement string. To preserve the whitespace, use the \fBs\fR flag. from the replacement string. To preserve the whitespace, use the \fBs\fR flag.
Also, \fB{q}\fR is replaced to the current query string. Also, \fB{q}\fR is replaced to the current query string, and \fB{n}\fR is
replaced to zero-based ordinal index of the line. Use \fB{+n}\fR if you want
all index numbers when multiple lines are selected.
Note that you can escape a placeholder pattern by prepending a backslash. Note that you can escape a placeholder pattern by prepending a backslash.

View File

@ -24,7 +24,7 @@ import (
var placeholder *regexp.Regexp var placeholder *regexp.Regexp
func init() { func init() {
placeholder = regexp.MustCompile("\\\\?(?:{[+s]*[0-9,-.]*}|{q})") placeholder = regexp.MustCompile("\\\\?(?:{[+s]*[0-9,-.]*}|{q}|{\\+?n})")
} }
type jumpMode int type jumpMode int
@ -227,6 +227,7 @@ const (
type placeholderFlags struct { type placeholderFlags struct {
plus bool plus bool
preserveSpace bool preserveSpace bool
number bool
query bool query bool
} }
@ -1198,6 +1199,9 @@ func parsePlaceholder(match string) (bool, string, placeholderFlags) {
case 's': case 's':
flags.preserveSpace = true flags.preserveSpace = true
skipChars++ skipChars++
case 'n':
flags.number = true
skipChars++
case 'q': case 'q':
flags.query = true flags.query = true
default: default:
@ -1253,7 +1257,16 @@ func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, fo
if match == "{}" { if match == "{}" {
for idx, item := range items { for idx, item := range items {
replacements[idx] = quoteEntry(item.AsString(stripAnsi)) if flags.number {
n := int(item.text.Index)
if n < 0 {
replacements[idx] = ""
} else {
replacements[idx] = strconv.Itoa(n)
}
} else {
replacements[idx] = quoteEntry(item.AsString(stripAnsi))
}
} }
return strings.Join(replacements, " ") return strings.Join(replacements, " ")
} }
@ -1351,7 +1364,7 @@ func (t *Terminal) buildPlusList(template string, forcePlus bool) (bool, []*Item
// 2. or it contains {+} and we have more than one item already selected. // 2. or it contains {+} and we have more than one item already selected.
// To do so, we pass an empty Item instead of nil to trigger an update. // To do so, we pass an empty Item instead of nil to trigger an update.
if current == nil { if current == nil {
current = &Item{} current = &minItem
} }
var sels []*Item var sels []*Item

View File

@ -1400,21 +1400,21 @@ class TestGoFZF < TestBase
def test_preview_flags def test_preview_flags
tmux.send_keys %(seq 10 | sed 's/^/:: /; s/$/ /' | tmux.send_keys %(seq 10 | sed 's/^/:: /; s/$/ /' |
#{FZF} --multi --preview 'echo {{2}/{s2}/{+2}/{+s2}/{q}}'), :Enter #{FZF} --multi --preview 'echo {{2}/{s2}/{+2}/{+s2}/{q}/{n}/{+n}}'), :Enter
tmux.until { |lines| lines[1].include?('{1/1 /1/1 /}') } tmux.until { |lines| lines[1].include?('{1/1 /1/1 //0/0}') }
tmux.send_keys '123' tmux.send_keys '123'
tmux.until { |lines| lines[1].include?('{////123}') } tmux.until { |lines| lines[1].include?('{////123//}') }
tmux.send_keys 'C-u', '1' tmux.send_keys 'C-u', '1'
tmux.until { |lines| lines.match_count == 2 } tmux.until { |lines| lines.match_count == 2 }
tmux.until { |lines| lines[1].include?('{1/1 /1/1 /1}') } tmux.until { |lines| lines[1].include?('{1/1 /1/1 /1/0/0}') }
tmux.send_keys :BTab tmux.send_keys :BTab
tmux.until { |lines| lines[1].include?('{10/10 /1/1 /1}') } tmux.until { |lines| lines[1].include?('{10/10 /1/1 /1/9/0}') }
tmux.send_keys :BTab tmux.send_keys :BTab
tmux.until { |lines| lines[1].include?('{10/10 /1 10/1 10 /1}') } tmux.until { |lines| lines[1].include?('{10/10 /1 10/1 10 /1/9/0 9}') }
tmux.send_keys '2' tmux.send_keys '2'
tmux.until { |lines| lines[1].include?('{//1 10/1 10 /12}') } tmux.until { |lines| lines[1].include?('{//1 10/1 10 /12//0 9}') }
tmux.send_keys '3' tmux.send_keys '3'
tmux.until { |lines| lines[1].include?('{//1 10/1 10 /123}') } tmux.until { |lines| lines[1].include?('{//1 10/1 10 /123//0 9}') }
end end
def test_preview_q_no_match def test_preview_q_no_match