diff --git a/CHANGELOG.md b/CHANGELOG.md index a305ecc7..7609316f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG ========= +0.24.4 +------ +- Added `change-prompt` action + ```sh + fzf --prompt 'foo> ' --bind $'a:change-prompt:\x1b[31mbar> ' + ``` +- Bug fixes and improvements + 0.24.3 ------ - Added `--padding` option diff --git a/man/man1/fzf-tmux.1 b/man/man1/fzf-tmux.1 index 25465424..7f0cda19 100644 --- a/man/man1/fzf-tmux.1 +++ b/man/man1/fzf-tmux.1 @@ -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 "Nov 2020" "fzf 0.24.3" "fzf-tmux - open fzf in tmux split pane" +.TH fzf-tmux 1 "Dec 2020" "fzf 0.24.3" "fzf-tmux - open fzf in tmux split pane" .SH NAME fzf-tmux - open fzf in tmux split pane diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index 0efa4750..f779ad5e 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -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 "Nov 2020" "fzf 0.24.4" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Dec 2020" "fzf 0.24.4" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -761,6 +761,7 @@ A key or an event can be bound to one or more of the following actions. \fBbackward-word\fR \fIalt-b shift-left\fR \fBbeginning-of-line\fR \fIctrl-a home\fR \fBcancel\fR (clear query string if not empty, abort fzf otherwise) + \fBchange-prompt(...)\fR (change prompt to the given string) \fBclear-screen\fR \fIctrl-l\fR \fBclear-selection\fR (clear multi-selection) \fBclear-query\fR (clear query string) @@ -816,42 +817,51 @@ A key or an event can be bound to one or more of the following actions. Multiple actions can be chained using \fB+\fR separator. e.g. - \fBfzf --bind 'ctrl-a:select-all+accept'\fR + \fBfzf --multi --bind 'ctrl-a:select-all+accept'\fR + \fBfzf --multi --bind 'ctrl-a:select-all' --bind 'ctrl-a:+accept'\fR -.SS COMMAND EXECUTION +.SS ACTION ARGUMENT -With \fBexecute(...)\fR action, you can execute arbitrary commands without -leaving fzf. For example, you can turn fzf into a simple file browser by -binding \fBenter\fR key to \fBless\fR command like follows. +An action denoted with \fB(...)\fR suffix takes an argument. - \fBfzf --bind "enter:execute(less {})"\fR - -You can use the same placeholder expressions as in \fB--preview\fR. +e.g. + \fBfzf --bind 'ctrl-a:change-prompt(NewPrompt> )'\fR + \fBfzf --bind 'ctrl-v:preview(cat {})' --preview-window hidden\fR -If the command contains parentheses, fzf may fail to parse the expression. In +If the argument contains parentheses, fzf may fail to parse the expression. In that case, you can use any of the following alternative notations to avoid parse errors. - \fBexecute[...]\fR - \fBexecute~...~\fR - \fBexecute!...!\fR - \fBexecute@...@\fR - \fBexecute#...#\fR - \fBexecute$...$\fR - \fBexecute%...%\fR - \fBexecute^...^\fR - \fBexecute&...&\fR - \fBexecute*...*\fR - \fBexecute;...;\fR - \fBexecute/.../\fR - \fBexecute|...|\fR - \fBexecute:...\fR + \fBaction-name[...]\fR + \fBaction-name~...~\fR + \fBaction-name!...!\fR + \fBaction-name@...@\fR + \fBaction-name#...#\fR + \fBaction-name$...$\fR + \fBaction-name%...%\fR + \fBaction-name^...^\fR + \fBaction-name&...&\fR + \fBaction-name*...*\fR + \fBaction-name;...;\fR + \fBaction-name/.../\fR + \fBaction-name|...|\fR + \fBaction-name:...\fR .RS The last one is the special form that frees you from parse errors as it does not expect the closing character. The catch is that it should be the last one in the comma-separated list of key-action pairs. .RE +.SS COMMAND EXECUTION + +With \fBexecute(...)\fR action, you can execute arbitrary commands without +leaving fzf. For example, you can turn fzf into a simple file browser by +binding \fBenter\fR key to \fBless\fR command like follows. + + \fBfzf --bind "enter:execute(less {})"\fR + +You can use the same placeholder expressions as in \fB--preview\fR. + fzf switches to the alternate screen when executing a command. However, if the command is expected to complete quickly, and you are not interested in its output, you might want to use \fBexecute-silent\fR instead, which silently diff --git a/src/options.go b/src/options.go index 0a6dcf99..b3fb78cf 100644 --- a/src/options.go +++ b/src/options.go @@ -735,7 +735,7 @@ func init() { // Backreferences are not supported. // "~!@#$%^&*;/|".each_char.map { |c| Regexp.escape(c) }.map { |c| "#{c}[^#{c}]*#{c}" }.join('|') executeRegexp = regexp.MustCompile( - `(?si)[:+](execute(?:-multi|-silent)?|reload|preview):.+|[:+](execute(?:-multi|-silent)?|reload|preview)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`) + `(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`) } func parseKeymap(keymap map[int][]action, str string) { @@ -749,6 +749,8 @@ func parseKeymap(keymap map[int][]action, str string) { prefix = symbol + "reload" } else if strings.HasPrefix(src[1:], "preview") { prefix = symbol + "preview" + } else if strings.HasPrefix(src[1:], "change-prompt") { + prefix = symbol + "change-prompt" } else if src[len(prefix)] == '-' { c := src[len(prefix)+1] if c == 's' || c == 'S' { @@ -922,6 +924,8 @@ func parseKeymap(keymap map[int][]action, str string) { offset = len("reload") case actPreview: offset = len("preview") + case actChangePrompt: + offset = len("change-prompt") case actExecuteSilent: offset = len("execute-silent") case actExecuteMulti: @@ -961,6 +965,8 @@ func isExecuteAction(str string) actionType { return actReload case "preview": return actPreview + case "change-prompt": + return actChangePrompt case "execute": return actExecute case "execute-silent": diff --git a/src/terminal.go b/src/terminal.go index 14a90d51..08535484 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -214,6 +214,7 @@ const ( actBackwardDeleteCharEOF actBackwardWord actCancel + actChangePrompt actClearScreen actClearQuery actClearSelection @@ -2223,6 +2224,9 @@ func (t *Terminal) Loop() { } case actPrintQuery: req(reqPrintQuery) + case actChangePrompt: + t.prompt, t.promptLen = t.parsePrompt(a.a) + req(reqPrompt) case actPreview: togglePreview(true) refreshPreview(a.a) diff --git a/test/test_go.rb b/test/test_go.rb index 3ff118c1..13b1ee47 100755 --- a/test/test_go.rb +++ b/test/test_go.rb @@ -1823,6 +1823,15 @@ class TestGoFZF < TestBase tmux.until { |lines| lines.item_count == 100 } tmux.until { |lines| lines[1]&.include?('[200]') } end + + def test_change_prompt + tmux.send_keys "#{FZF} --bind 'a:change-prompt(a> ),b:change-prompt:b> ' --query foo", :Enter + tmux.until { |lines| assert_equal '> foo', lines[-1] } + tmux.send_keys 'a' + tmux.until { |lines| assert_equal 'a> foo', lines[-1] } + tmux.send_keys 'b' + tmux.until { |lines| assert_equal 'c> foo', lines[-1] } + end end module TestShell