From 21d664d670182a7937f3fc783cac11fa1c2afab4 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Thu, 25 May 2017 19:09:04 +0900 Subject: [PATCH 1/6] Update extra bash completion example --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b7c1fa..93c7628 100644 --- a/README.md +++ b/README.md @@ -374,8 +374,8 @@ On bash, fuzzy completion is enabled only for a predefined set of commands commands as well like follows. ```sh -# There are also _fzf_path_completion and _fzf_dir_completion -complete -F _fzf_file_completion -o default -o bashdefault doge +complete -F _fzf_path_completion -o default -o bashdefault ag +complete -F _fzf_dir_completion -o default -o bashdefault tree ``` Vim plugin From 8aab0fc1894facf9ac51132ff8a832b18bc115ac Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Sun, 28 May 2017 21:06:06 -0400 Subject: [PATCH 2/6] [vim] Replace s:fzf_shellescape and s:shellesc with fzf#shellescape (#916) --- plugin/fzf.vim | 44 ++++++++++++++++++++++++-------------------- test/fzf.vader | 18 ++++++++++++++++++ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/plugin/fzf.vim b/plugin/fzf.vim index e82ef11..fbfcd1d 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -44,20 +44,28 @@ if s:is_win let &shellslash = shellslash endtry endfunction - - function! s:fzf_shellescape(path) - return substitute(s:fzf_call('shellescape', a:path), '[^\\]\zs\\"$', '\\\\"', '') - endfunction else function! s:fzf_call(fn, ...) return call(a:fn, a:000) endfunction - - function! s:fzf_shellescape(path) - return shellescape(a:path) - endfunction endif +function! s:shellesc_cmd(arg) + let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g') + let escaped = substitute(escaped, '%', '%%', 'g') + let escaped = substitute(escaped, '"', '\\^&', 'g') + let escaped = substitute(escaped, '\\\+\(\\^\)', '\\\\\1', 'g') + return '^"'.substitute(escaped, '[^\\]\zs\\$', '\\\\', '').'^"' +endfunction + +function! fzf#shellescape(arg, ...) + let shell = get(a:000, 0, &shell) + if shell =~# 'cmd.exe$' + return s:shellesc_cmd(a:arg) + endif + return s:fzf_call('shellescape', a:arg) +endfunction + function! s:fzf_getcwd() return s:fzf_call('getcwd') endfunction @@ -108,7 +116,7 @@ function! s:fzf_exec() throw 'fzf executable not found' endif endif - return s:is_win ? s:exec : s:shellesc(s:exec) + return s:is_win ? s:exec : fzf#shellescape(s:exec) endfunction function! s:tmux_enabled() @@ -128,10 +136,6 @@ function! s:tmux_enabled() return s:tmux endfunction -function! s:shellesc(arg) - return '"'.substitute(a:arg, '"', '\\"', 'g').'"' -endfunction - function! s:escape(path) let escaped_chars = '$%#''"' @@ -250,7 +254,7 @@ endfunction function! s:evaluate_opts(options) return type(a:options) == type([]) ? - \ join(map(copy(a:options), 's:fzf_shellescape(v:val)')) : a:options + \ join(map(copy(a:options), 'fzf#shellescape(v:val)')) : a:options endfunction " [name string,] [opts dict,] [fullscreen boolean] @@ -297,7 +301,7 @@ function! fzf#wrap(...) if !isdirectory(dir) call mkdir(dir, 'p') endif - let history = s:is_win ? s:fzf_shellescape(dir.'\'.name) : s:escape(dir.'/'.name) + let history = s:is_win ? fzf#shellescape(dir.'\'.name) : s:escape(dir.'/'.name) let opts.options = join(['--history', history, opts.options]) endif @@ -349,7 +353,7 @@ try if !has_key(dict, 'source') && !empty($FZF_DEFAULT_COMMAND) let temps.source = s:fzf_tempname().(s:is_win ? '.bat' : '') call writefile((s:is_win ? ['@echo off'] : []) + split($FZF_DEFAULT_COMMAND, "\n"), temps.source) - let dict.source = (empty($SHELL) ? &shell : $SHELL) . (s:is_win ? ' /c ' : ' ') . s:shellesc(temps.source) + let dict.source = (empty($SHELL) ? &shell : $SHELL) . (s:is_win ? ' /c ' : ' ') . fzf#shellescape(temps.source) endif if has_key(dict, 'source') @@ -360,7 +364,7 @@ try elseif type == 3 let temps.input = s:fzf_tempname() call writefile(source, temps.input) - let prefix = (s:is_win ? 'type ' : 'cat ').s:shellesc(temps.input).'|' + let prefix = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input).'|' else throw 'Invalid source type' endif @@ -424,7 +428,7 @@ function! s:fzf_tmux(dict) endif endfor return printf('LINES=%d COLUMNS=%d %s %s %s --', - \ &lines, &columns, s:shellesc(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-')) + \ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-')) endfunction function! s:splittable(dict) @@ -493,7 +497,7 @@ function! s:execute(dict, command, use_height, temps) abort if has('unix') && !a:use_height silent! !clear 2> /dev/null endif - let escaped = escape(substitute(a:command, '\n', '\\n', 'g'), '%#!') + let escaped = (a:use_height || s:is_win) ? a:command : escape(substitute(a:command, '\n', '\\n', 'g'), '%#!') if has('gui_running') let Launcher = get(a:dict, 'launcher', get(g:, 'Fzf_launcher', get(g:, 'fzf_launcher', s:launcher))) let fmt = type(Launcher) == 2 ? call(Launcher, []) : Launcher @@ -502,7 +506,7 @@ function! s:execute(dict, command, use_height, temps) abort endif let command = printf(fmt, escaped) else - let command = a:use_height ? a:command : escaped + let command = escaped endif if s:is_win let batchfile = s:fzf_tempname().'.bat' diff --git a/test/fzf.vader b/test/fzf.vader index c6f899f..64a5c7b 100644 --- a/test/fzf.vader +++ b/test/fzf.vader @@ -147,6 +147,24 @@ Execute (fzf#wrap): let opts = fzf#wrap({}) Assert opts.options =~ '^--color=fg:' +Execute (fzf#shellescape with sh): + AssertEqual '''''', fzf#shellescape('', 'sh') + AssertEqual '''""''', fzf#shellescape('""', 'sh') + AssertEqual '''foobar>''', fzf#shellescape('foobar>', 'sh') + AssertEqual '''\"''', fzf#shellescape('\"', 'sh') + AssertEqual '''echo ''\''''a''\'''' && echo ''\''''b''\''''''', fzf#shellescape('echo ''a'' && echo ''b''', 'sh') + +Execute (fzf#shellescape with cmd.exe): + AssertEqual '^"^"', fzf#shellescape('', 'cmd.exe') + AssertEqual '^"\^"\^"^"', fzf#shellescape('""', 'cmd.exe') + AssertEqual '^"foobar^>^"', fzf#shellescape('foobar>', 'cmd.exe') + AssertEqual '^"\\\^"\\^"', fzf#shellescape('\\\\\\\\"\', 'cmd.exe') + AssertEqual '^"echo ''a'' ^&^& echo ''b''^"', fzf#shellescape('echo ''a'' && echo ''b''', 'cmd.exe') + + AssertEqual '^"C:\Program Files ^(x86^)\\^"', fzf#shellescape('C:\Program Files (x86)\', 'cmd.exe') + AssertEqual '^"C:/Program Files ^(x86^)/^"', fzf#shellescape('C:/Program Files (x86)/', 'cmd.exe') + " AssertEqual '^"%%USERPROFILE%%^", fzf#shellescape('%USERPROFILE%', 'cmd.exe') + Execute (Cleanup): unlet g:dir Restore From 669a6fee40a2d946ab35561c47e76d6a2216948c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 30 May 2017 20:56:01 -0400 Subject: [PATCH 3/6] [vim] Use utf-8 for cmd.exe (#929) --- plugin/fzf.vim | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/plugin/fzf.vim b/plugin/fzf.vim index fbfcd1d..81aff37 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -44,10 +44,22 @@ if s:is_win let &shellslash = shellslash endtry endfunction + + " Use utf-8 for fzf.vim commands + " Return array of shell commands for cmd.exe + function! s:wrap_cmds(cmds) + return ['@echo off', 'for /f "tokens=4" %%a in (''chcp'') do set origchcp=%%a', 'chcp 65001 > nul'] + + \ (type(a:cmds) == type([]) ? a:cmds : [a:cmds]) + + \ ['chcp %origchcp% > nul'] + endfunction else function! s:fzf_call(fn, ...) return call(a:fn, a:000) endfunction + + function! s:wrap_cmds(cmds) + return a:cmds + endfunction endif function! s:shellesc_cmd(arg) @@ -352,7 +364,7 @@ try if !has_key(dict, 'source') && !empty($FZF_DEFAULT_COMMAND) let temps.source = s:fzf_tempname().(s:is_win ? '.bat' : '') - call writefile((s:is_win ? ['@echo off'] : []) + split($FZF_DEFAULT_COMMAND, "\n"), temps.source) + call writefile(s:wrap_cmds(split($FZF_DEFAULT_COMMAND, "\n")), temps.source) let dict.source = (empty($SHELL) ? &shell : $SHELL) . (s:is_win ? ' /c ' : ' ') . fzf#shellescape(temps.source) endif @@ -510,7 +522,7 @@ function! s:execute(dict, command, use_height, temps) abort endif if s:is_win let batchfile = s:fzf_tempname().'.bat' - call writefile(['@echo off', command], batchfile) + call writefile(s:wrap_cmds(command), batchfile) let command = batchfile if has('nvim') let s:dict = a:dict From 0665fe04138866fcdd659dcae221672bf1f5f325 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 31 May 2017 10:02:04 +0900 Subject: [PATCH 4/6] [vim] Remove unnecessary ternary expression Related: https://github.com/junegunn/fzf.vim/issues/378 --- plugin/fzf.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/fzf.vim b/plugin/fzf.vim index 81aff37..2917568 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -128,7 +128,7 @@ function! s:fzf_exec() throw 'fzf executable not found' endif endif - return s:is_win ? s:exec : fzf#shellescape(s:exec) + return fzf#shellescape(s:exec) endfunction function! s:tmux_enabled() From 076f49d447093944b0ba91c4c60b57a9126869ea Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 31 May 2017 10:03:23 +0900 Subject: [PATCH 5/6] [vim] Make sure to delete temporary batchfile on Windows --- plugin/fzf.vim | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin/fzf.vim b/plugin/fzf.vim index 2917568..8c8ff85 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -524,6 +524,7 @@ function! s:execute(dict, command, use_height, temps) abort let batchfile = s:fzf_tempname().'.bat' call writefile(s:wrap_cmds(command), batchfile) let command = batchfile + let a:temps.batchfile = batchfile if has('nvim') let s:dict = a:dict let s:temps = a:temps From 35d407021c468f6faf0d99358d3fca1720d4edc9 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Wed, 31 May 2017 23:59:11 +0900 Subject: [PATCH 6/6] [vim] Replace invalid s:escape calls with fzf#shellescape --- plugin/fzf.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/fzf.vim b/plugin/fzf.vim index 8c8ff85..8bdeb3b 100644 --- a/plugin/fzf.vim +++ b/plugin/fzf.vim @@ -313,7 +313,7 @@ function! fzf#wrap(...) if !isdirectory(dir) call mkdir(dir, 'p') endif - let history = s:is_win ? fzf#shellescape(dir.'\'.name) : s:escape(dir.'/'.name) + let history = fzf#shellescape(dir.'/'.name) let opts.options = join(['--history', history, opts.options]) endif @@ -553,7 +553,7 @@ function! s:execute_tmux(dict, command, temps) abort let command = a:command if s:pushd(a:dict) " -c '#{pane_current_path}' is only available on tmux 1.9 or above - let command = 'cd '.s:escape(a:dict.dir).' && '.command + let command = join(['cd', fzf#shellescape(a:dict.dir), '&&', command]) endif call system(command)