2
0
mirror of https://github.com/junegunn/fzf synced 2024-11-14 18:12:53 +00:00

Add alternative execute notation that does not require closing char

This can be used to avoid parse errors that can happen when the command
contains the closing character. Since the command does not finish at
a certain character, the key binding should be the last one in the
group. Suggested by @tiziano88. (#265)

  e.g. fzf --bind "ctrl-m:execute=COMMAND..." --bind ctrl-j:accept
This commit is contained in:
Junegunn Choi 2015-06-15 23:00:38 +09:00
parent e720f56ea8
commit fa5b58968e
2 changed files with 11 additions and 5 deletions

View File

@ -412,7 +412,7 @@ func parseKeymap(keymap map[int]actionType, execmap map[int]string, toggleSort b
// Backreferences are not supported. // Backreferences are not supported.
// "~!@#$%^&*:;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|') // "~!@#$%^&*:;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|')
executeRegexp = regexp.MustCompile( executeRegexp = regexp.MustCompile(
":execute(\\([^)]*\\)|\\[[^\\]]*\\]|~[^~]*~|![^!]*!|@[^@]*@|\\#[^\\#]*\\#|\\$[^\\$]*\\$|%[^%]*%|\\^[^\\^]*\\^|&[^&]*&|\\*[^\\*]*\\*|:[^:]*:|;[^;]*;|/[^/]*/|\\|[^\\|]*\\|)") ":execute=.*|:execute(\\([^)]*\\)|\\[[^\\]]*\\]|~[^~]*~|![^!]*!|@[^@]*@|\\#[^\\#]*\\#|\\$[^\\$]*\\$|%[^%]*%|\\^[^\\^]*\\^|&[^&]*&|\\*[^\\*]*\\*|:[^:]*:|;[^;]*;|/[^/]*/|\\|[^\\|]*\\|)")
} }
masked := executeRegexp.ReplaceAllStringFunc(str, func(src string) string { masked := executeRegexp.ReplaceAllStringFunc(str, func(src string) string {
return ":execute(" + strings.Repeat(" ", len(src)-10) + ")" return ":execute(" + strings.Repeat(" ", len(src)-10) + ")"
@ -503,7 +503,11 @@ func parseKeymap(keymap map[int]actionType, execmap map[int]string, toggleSort b
default: default:
if isExecuteAction(act) { if isExecuteAction(act) {
keymap[key] = actExecute keymap[key] = actExecute
if pair[1][7] == '=' {
execmap[key] = pair[1][8:]
} else {
execmap[key] = pair[1][8 : len(act)-1] execmap[key] = pair[1][8 : len(act)-1]
}
} else { } else {
errorExit("unknown action: " + act) errorExit("unknown action: " + act)
} }
@ -518,8 +522,8 @@ func isExecuteAction(str string) bool {
} }
b := str[7] b := str[7]
e := str[len(str)-1] e := str[len(str)-1]
if b == e && strings.ContainsAny(string(b), "~!@#$%^&*:;/|") || if b == '=' || b == '(' && e == ')' || b == '[' && e == ']' ||
b == '(' && e == ')' || b == '[' && e == ']' { b == e && strings.ContainsAny(string(b), "~!@#$%^&*:;/|") {
return true return true
} }
return false return false

View File

@ -163,7 +163,8 @@ func TestBind(t *testing.T) {
parseKeymap(keymap, execmap, false, parseKeymap(keymap, execmap, false,
"ctrl-a:kill-line,ctrl-b:toggle-sort,c:page-up,alt-z:page-down,"+ "ctrl-a:kill-line,ctrl-b:toggle-sort,c:page-up,alt-z:page-down,"+
"f1:execute(ls {}),f2:execute/echo {}, {}, {}/,f3:execute[echo '({})'],f4:execute:less {}:,"+ "f1:execute(ls {}),f2:execute/echo {}, {}, {}/,f3:execute[echo '({})'],f4:execute:less {}:,"+
"alt-a:execute@echo (,),[,],/,:,;,%,{}@,alt-b:execute;echo (,),[,],/,:,@,%,{};") "alt-a:execute@echo (,),[,],/,:,;,%,{}@,alt-b:execute;echo (,),[,],/,:,@,%,{};"+
",X:execute=foobar,Y:execute(baz)")
if !toggleSort { if !toggleSort {
t.Errorf("toggleSort not set") t.Errorf("toggleSort not set")
} }
@ -181,6 +182,7 @@ func TestBind(t *testing.T) {
checkString("less {}", execmap[curses.F4]) checkString("less {}", execmap[curses.F4])
checkString("echo (,),[,],/,:,;,%,{}", execmap[curses.AltA]) checkString("echo (,),[,],/,:,;,%,{}", execmap[curses.AltA])
checkString("echo (,),[,],/,:,@,%,{}", execmap[curses.AltB]) checkString("echo (,),[,],/,:,@,%,{}", execmap[curses.AltB])
checkString("foobar,Y:execute(baz)", execmap[curses.AltZ+'X'])
for idx, char := range []rune{'~', '!', '@', '#', '$', '%', '^', '&', '*', '|', ':', ';', '/'} { for idx, char := range []rune{'~', '!', '@', '#', '$', '%', '^', '&', '*', '|', ':', ';', '/'} {
keymap, execmap, toggleSort = keymap, execmap, toggleSort =