@ 261102.1

260602.1 · ae78a5c56d6586589f9587902f437385c176eddc

Allow bare put action in transform output

transform/bg-transform now permit bare `put`, inserting the key that triggered the action (`a:transform:echo put` puts `a`).

reading declarations

src/options.go

@@ -10,7 +10,6 @@ import ( 	"strconv" 	"strings" 	"time"-	"unicode"  	"github.com/junegunn/fzf/src/algo" 	"github.com/junegunn/fzf/src/tui"@@ -1734,10 +1733,10 @@ Loop: 	return masked } -func parseSingleActionList(str string) ([]*action, error) {+func parseSingleActionList(str string, putAllowed bool) ([]*action, error) { 	// We prepend a colon to satisfy argActionRegexp and remove it later 	masked := maskActionContents(":" + str)[1:]-	return parseActionList(masked, str, []*action{}, false)+	return parseActionList(masked, str, []*action{}, putAllowed) }  func parseActionList(masked string, original string, prevActions []*action, putAllowed bool) ([]*action, error) {@@ -2043,8 +2042,7 @@ func parseKeymap(keymap map[tui.Event][]*action, str string) error { 				} 				key = firstKey(keys) 			}-			putAllowed := key.Type == tui.Rune && unicode.IsGraphic(key.Char)-			keymap[key], err = parseActionList(pair[1], origPairStr[len(pair[0])+1:], keymap[key], putAllowed)+			keymap[key], err = parseActionList(pair[1], origPairStr[len(pair[0])+1:], keymap[key], key.Printable()) 			if err != nil { 				return err 			}

src/options_test.go

@@ -572,7 +572,7 @@ func TestValidateSign(t *testing.T) { }  func TestParseSingleActionList(t *testing.T) {-	actions, _ := parseSingleActionList("Execute@foo+bar,baz@+up+up+reload:down+down")+	actions, _ := parseSingleActionList("Execute@foo+bar,baz@+up+up+reload:down+down", false) 	if len(actions) != 4 { 		t.Errorf("Invalid number of actions parsed:%d", len(actions)) 	}@@ -588,7 +588,7 @@ func TestParseSingleActionList(t *testing.T) { }  func TestParseSingleActionListError(t *testing.T) {-	_, err := parseSingleActionList("change-query(foobar)baz")+	_, err := parseSingleActionList("change-query(foobar)baz", false) 	if err == nil { 		t.Errorf("Failed to detect error") 	}

src/server.go

@@ -240,7 +240,7 @@ Loop: 	} 	body = body[:contentLength] -	actions, err := parseSingleActionList(strings.Trim(string(body), "\r\n"))+	actions, err := parseSingleActionList(strings.Trim(string(body), "\r\n"), false) 	if err != nil { 		return bad(err.Error()) 	}

src/terminal.go

@@ -6973,7 +6973,8 @@ func (t *Terminal) Loop() error { 				}) 			case actTransform, actBgTransform: 				capture(false, func(body string) {-					if actions, err := parseSingleActionList(strings.Trim(body, "\r\n")); err == nil {+					// Allow 'put' if the triggering key is a printable character+					if actions, err := parseSingleActionList(strings.Trim(body, "\r\n"), event.Printable()); err == nil { 						// NOTE: We're not properly passing the return value here 						doActions(actions) 					}

src/tui/tui.go

@@ -4,6 +4,7 @@ import ( 	"strconv" 	"strings" 	"time"+	"unicode"  	"github.com/junegunn/fzf/src/util" 	"github.com/rivo/uniseg"@@ -252,6 +253,12 @@ func (e Event) Comparable() Event { 	return Event{e.Type, e.Char, nil} } +// Printable returns true if the event is a printable character that can be+// inserted into the query (e.g. via the 'put' action).+func (e Event) Printable() bool {+	return e.Type == Rune && unicode.IsGraphic(e.Char)+}+ func (e Event) KeyName() string { 	if me := e.MouseEvent; me != nil { 		return me.Name()

test/test_core.rb

@@ -971,6 +971,24 @@ class TestCore < TestInteractive     tmux.until { |lines| assert_includes lines[1], ' aabravo/aabravo' }   end +  def test_transform_put+    tmux.send_keys %(seq 1000 | #{FZF} --bind 'a:transform:echo put'), :Enter+    tmux.until { |lines| assert_equal 1000, lines.match_count }+    tmux.send_keys :a+    tmux.until { |lines| assert_equal '> a', lines.last }+    tmux.send_keys :b+    tmux.until { |lines| assert_equal '> ab', lines.last }+  end++  # The async callback runs in a later iteration, but 'put' must still insert+  # the key that triggered the bg-transform (snapshot of the scheduling event).+  def test_bg_transform_put+    tmux.send_keys %(seq 1000 | #{FZF} --bind 'a:bg-transform:sleep 0.5; echo put'), :Enter+    tmux.until { |lines| assert_equal 1000, lines.match_count }+    tmux.send_keys 'ab'+    tmux.until { |lines| assert_equal '> ba', lines.last }+  end+   def test_accept_non_empty     tmux.send_keys %(seq 1000 | #{fzf('--print-query --bind enter:accept-non-empty')}), :Enter     tmux.until { |lines| assert_equal 1000, lines.match_count }