diff options
-rw-r--r-- | src/nvim/eval/funcs.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 33 | ||||
-rw-r--r-- | src/nvim/ex_getln.h | 5 | ||||
-rw-r--r-- | src/nvim/ex_session.c | 2 | ||||
-rw-r--r-- | src/nvim/normal.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_cmdline.vim | 6 |
6 files changed, 35 insertions, 15 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 2775fd4778..6466e06010 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -2467,7 +2467,7 @@ static void f_fmod(typval_T *argvars, typval_T *rettv, FunPtr fptr) /// "fnameescape({string})" function static void f_fnameescape(typval_T *argvars, typval_T *rettv, FunPtr fptr) { - rettv->vval.v_string = vim_strsave_fnameescape(tv_get_string(&argvars[0]), false); + rettv->vval.v_string = vim_strsave_fnameescape(tv_get_string(&argvars[0]), VSE_NONE); rettv->v_type = VAR_STRING; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 32977569c3..a5783f4ced 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4334,6 +4334,7 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o { int i; char_u *p; + const int vse_what = xp->xp_context == EXPAND_BUFFERS ? VSE_BUFFER : VSE_NONE; /* * May change home directory back to "~" @@ -4365,10 +4366,10 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o #endif } #ifdef BACKSLASH_IN_FILENAME - p = (char_u *)vim_strsave_fnameescape((const char *)files[i], false); + p = (char_u *)vim_strsave_fnameescape((const char *)files[i], vse_what); #else p = (char_u *)vim_strsave_fnameescape((const char *)files[i], - xp->xp_shell); + xp->xp_shell ? VSE_SHELL : vse_what); #endif xfree(files[i]); files[i] = p; @@ -4400,25 +4401,30 @@ void ExpandEscape(expand_T *xp, char_u *str, int numfiles, char_u **files, int o } } -/// Escape special characters in a file name for use as a command argument +/// Escape special characters in "fname", depending on "what": /// /// @param[in] fname File name to escape. -/// @param[in] shell What to escape for: if false, escapes for VimL command, -/// if true then it escapes for a shell command. +/// @param[in] what What to escape for: +/// - VSE_NONE: for when used as a file name argument after a Vim command. +/// - VSE_SHELL: for a shell command. +/// - VSE_BUFFER: for the ":buffer" command. /// /// @return [allocated] escaped file name. -char *vim_strsave_fnameescape(const char *const fname, const bool shell FUNC_ATTR_UNUSED) +char *vim_strsave_fnameescape(const char *const fname, const int what) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { #ifdef BACKSLASH_IN_FILENAME # define PATH_ESC_CHARS " \t\n*?[{`%#'\"|!<" +# define BUFFER_ESC_CHARS ((char_u *)" \t\n*?[`%#'\"|!<") char_u buf[sizeof(PATH_ESC_CHARS)]; int j = 0; - // Don't escape '[', '{' and '!' if they are in 'isfname'. - for (const char *s = PATH_ESC_CHARS; *s != NUL; s++) { - if ((*s != '[' && *s != '{' && *s != '!') || !vim_isfilec(*s)) { - buf[j++] = *s; + // Don't escape '[', '{' and '!' if they are in 'isfname' and for the + // ":buffer" command. + for (const char *p = what == VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS; + *p != NUL; p++) { + if ((*p != '[' && *p != '{' && *p != '!') || !vim_isfilec(*p)) { + buf[j++] = *p; } } buf[j] = NUL; @@ -4427,9 +4433,12 @@ char *vim_strsave_fnameescape(const char *const fname, const bool shell FUNC_ATT #else # define PATH_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<") # define SHELL_ESC_CHARS ((char_u *)" \t\n*?[{`$\\%#'\"|!<>();&") +# define BUFFER_ESC_CHARS ((char_u *)" \t\n*?[`$\\%#'\"|!<") char *p = - (char *)vim_strsave_escaped((const char_u *)fname, (shell ? SHELL_ESC_CHARS : PATH_ESC_CHARS)); - if (shell && csh_like_shell()) { + (char *)vim_strsave_escaped((const char_u *)fname, + what == VSE_SHELL ? SHELL_ESC_CHARS + : what == VSE_BUFFER ? BUFFER_ESC_CHARS : PATH_ESC_CHARS); + if (what == VSE_SHELL && csh_like_shell()) { // For csh and similar shells need to put two backslashes before '!'. // One is taken by Vim, one by the shell. char *s = (char *)vim_strsave_escaped((const char_u *)p, diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h index 5da9febe71..1cc6faf87c 100644 --- a/src/nvim/ex_getln.h +++ b/src/nvim/ex_getln.h @@ -34,6 +34,11 @@ #define WILD_BUFLASTUSED 0x1000 #define BUF_DIFF_FILTER 0x2000 +// flags used by vim_strsave_fnameescape() +#define VSE_NONE 0 +#define VSE_SHELL 1 ///< escape for a shell command +#define VSE_BUFFER 2 ///< escape for a ":buffer" command + /// Present history tables typedef enum { HIST_DEFAULT = -2, ///< Default (current) history. diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index d18ef3a188..a7f4080b22 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -285,7 +285,7 @@ static char *ses_escape_fname(char *name, unsigned *flagp) } // Escape special characters. - p = vim_strsave_fnameescape(sname, false); + p = vim_strsave_fnameescape(sname, VSE_NONE); xfree(sname); return p; } diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 9696130070..0eb8a8f59b 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -4321,7 +4321,7 @@ static void nv_ident(cmdarg_T *cap) ptr = vim_strnsave(ptr, n); if (kp_ex) { // Escape the argument properly for an Ex command - p = (char_u *)vim_strsave_fnameescape((const char *)ptr, false); + p = (char_u *)vim_strsave_fnameescape((const char *)ptr, VSE_NONE); } else { // Escape the argument properly for a shell command p = vim_strsave_shellescape(ptr, true, true); diff --git a/src/nvim/testdir/test_cmdline.vim b/src/nvim/testdir/test_cmdline.vim index 93b5e4d1cf..e42510c17f 100644 --- a/src/nvim/testdir/test_cmdline.vim +++ b/src/nvim/testdir/test_cmdline.vim @@ -900,6 +900,12 @@ func Test_cmdline_complete_various() call feedkeys(":unlet one two\<C-A>\<C-B>\"\<CR>", 'xt') call assert_equal("\"unlet one two", @:) + " completion for the :buffer command with curlies + edit \{someFile} + call feedkeys(":buf someFile\<C-A>\<C-B>\"\<CR>", 'xt') + call assert_equal("\"buf {someFile}", @:) + bwipe {someFile} + " completion for the :bdelete command call feedkeys(":bdel a b c\<C-A>\<C-B>\"\<CR>", 'xt') call assert_equal("\"bdel a b c", @:) |