updated for version 7.4.191
Problem: Escaping a file name for shell commands can't be done without a
function.
Solution: Add the :S file name modifier.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 7d6708a..7b57e7f 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -5428,6 +5428,7 @@
< This results in a directory listing for the file under the
cursor. Example of use with |system()|: >
:call system("chmod +w -- " . shellescape(expand("%")))
+< See also |::S|.
shiftwidth() *shiftwidth()*
@@ -5910,14 +5911,16 @@
passed as stdin to the command. The string is written as-is,
you need to take care of using the correct line separators
yourself. Pipes are not used.
- Note: Use |shellescape()| to escape special characters in a
- command argument. Newlines in {expr} may cause the command to
- fail. The characters in 'shellquote' and 'shellxquote' may
- also cause trouble.
+ Note: Use |shellescape()| or |::S| with |expand()| or
+ |fnamemodify()| to escape special characters in a command
+ argument. Newlines in {expr} may cause the command to fail.
+ The characters in 'shellquote' and 'shellxquote' may also
+ cause trouble.
This is not to be used for interactive commands.
The result is a String. Example: >
:let files = system("ls " . shellescape(expand('%:h')))
+ :let files = system('ls ' . expand('%:h:S'))
< To make the result more system-independent, the shell output
is filtered to replace <CR> with <NL> for Macintosh, and
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 95e0950..9fb67a2 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -4757,8 +4757,9 @@
global or local to buffer |global-local|
{not in Vi}
Program to use for the ":make" command. See |:make_makeprg|.
- This option may contain '%' and '#' characters, which are expanded to
- the current and alternate file name. |:_%| |:_#|
+ This option may contain '%' and '#' characters (see |:_%| and |:_#|),
+ which are expanded to the current and alternate file name. Use |::S|
+ to escape file names in case they contain special characters.
Environment variables are expanded |:set_env|. See |option-backslash|
about including spaces and backslashes.
Note that a '|' must be escaped twice: once for ":set" and once for
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index d6bf938..f82dd1f 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -838,7 +838,7 @@
The alltests.py script seems to be used quite often, that's all.
Useful values for the 'makeprg' options therefore are:
setlocal makeprg=./alltests.py " Run a testsuite
- setlocal makeprg=python % " Run a single testcase
+ setlocal makeprg=python\ %:S " Run a single testcase
Also see http://vim.sourceforge.net/tip_view.php?tip_id=280.
@@ -1332,7 +1332,7 @@
Here is an alternative from Michael F. Lamb for Unix that filters the errors
first: >
:setl errorformat=%Z%f:%l:\ %m,%A%p^,%-G%*[^sl]%.%#
- :setl makeprg=javac\ %\ 2>&1\ \\\|\ vim-javac-filter
+ :setl makeprg=javac\ %:S\ 2>&1\ \\\|\ vim-javac-filter
You need to put the following in "vim-javac-filter" somewhere in your path
(e.g., in ~/bin) and make it executable: >
diff --git a/runtime/doc/usr_30.txt b/runtime/doc/usr_30.txt
index 52f4375..b2be512 100644
--- a/runtime/doc/usr_30.txt
+++ b/runtime/doc/usr_30.txt
@@ -128,7 +128,7 @@
You can include special Vim keywords in the command specification. The %
character expands to the name of the current file. So if you execute the
command: >
- :set makeprg=make\ %
+ :set makeprg=make\ %:S
When you are editing main.c, then ":make" executes the following command: >
@@ -137,7 +137,7 @@
This is not too useful, so you will refine the command a little and use the :r
(root) modifier: >
- :set makeprg=make\ %:r.o
+ :set makeprg=make\ %:r:S.o
Now the command executed is as follows: >
diff --git a/runtime/doc/usr_40.txt b/runtime/doc/usr_40.txt
index b1108a5..9d70648 100644
--- a/runtime/doc/usr_40.txt
+++ b/runtime/doc/usr_40.txt
@@ -209,7 +209,7 @@
separates the two commands. This also means that a | character can't be used
inside a map command. To include one, use <Bar> (five characters). Example:
>
- :map <F8> :write <Bar> !checkin %<CR>
+ :map <F8> :write <Bar> !checkin %:S<CR>
The same problem applies to the ":unmap" command, with the addition that you
have to watch out for trailing white space. These two commands are different:
diff --git a/runtime/doc/usr_42.txt b/runtime/doc/usr_42.txt
index a1cd533..1d16112 100644
--- a/runtime/doc/usr_42.txt
+++ b/runtime/doc/usr_42.txt
@@ -311,7 +311,7 @@
item with a bitmap. For example, define a new toolbar item with: >
:tmenu ToolBar.Compile Compile the current file
- :amenu ToolBar.Compile :!cc % -o %:r<CR>
+ :amenu ToolBar.Compile :!cc %:S -o %:r:S<CR>
Now you need to create the icon. For MS-Windows it must be in bitmap format,
with the name "Compile.bmp". For Unix XPM format is used, the file name is
diff --git a/runtime/doc/vi_diff.txt b/runtime/doc/vi_diff.txt
index 45fe7de..aadbf9b 100644
--- a/runtime/doc/vi_diff.txt
+++ b/runtime/doc/vi_diff.txt
@@ -540,7 +540,7 @@
Added :wnext command. Same as ":write" followed by ":next".
The ":w!" command always writes, also when the file is write protected. In Vi
-you would have to do ":!chmod +w %" and ":set noro".
+you would have to do ":!chmod +w %:S" and ":set noro".
When 'tildeop' has been set, "~" is an operator (must be followed by a
movement command).
diff --git a/src/eval.c b/src/eval.c
index 3be3813..85c4031 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -16950,7 +16950,7 @@
typval_T *rettv;
{
rettv->vval.v_string = vim_strsave_shellescape(
- get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]));
+ get_tv_string(&argvars[0]), non_zero_arg(&argvars[1]), TRUE);
rettv->v_type = VAR_STRING;
}
@@ -24355,6 +24355,17 @@
}
}
+ if (src[*usedlen] == ':' && src[*usedlen + 1] == 'S')
+ {
+ p = vim_strsave_shellescape(*fnamep, FALSE, FALSE);
+ if (p == NULL)
+ return -1;
+ vim_free(*bufp);
+ *bufp = *fnamep = p;
+ *fnamelen = (int)STRLEN(p);
+ *usedlen += 2;
+ }
+
return valid;
}
diff --git a/src/misc2.c b/src/misc2.c
index a9d7a82..8f8b2d9 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1369,12 +1369,14 @@
* Escape a newline, depending on the 'shell' option.
* When "do_special" is TRUE also replace "!", "%", "#" and things starting
* with "<" like "<cfile>".
+ * When "do_newline" is FALSE do not escape newline unless it is csh shell.
* Returns the result in allocated memory, NULL if we have run out.
*/
char_u *
-vim_strsave_shellescape(string, do_special)
+vim_strsave_shellescape(string, do_special, do_newline)
char_u *string;
int do_special;
+ int do_newline;
{
unsigned length;
char_u *p;
@@ -1403,7 +1405,8 @@
# endif
if (*p == '\'')
length += 3; /* ' => '\'' */
- if (*p == '\n' || (*p == '!' && (csh_like || do_special)))
+ if ((*p == '\n' && (csh_like || do_newline))
+ || (*p == '!' && (csh_like || do_special)))
{
++length; /* insert backslash */
if (csh_like && do_special)
@@ -1454,7 +1457,8 @@
++p;
continue;
}
- if (*p == '\n' || (*p == '!' && (csh_like || do_special)))
+ if ((*p == '\n' && (csh_like || do_newline))
+ || (*p == '!' && (csh_like || do_special)))
{
*d++ = '\\';
if (csh_like && do_special)
diff --git a/src/normal.c b/src/normal.c
index 73505a6..b8c6fc2 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -5790,7 +5790,7 @@
{
/* Escape the argument properly for a shell command */
ptr = vim_strnsave(ptr, n);
- p = vim_strsave_shellescape(ptr, TRUE);
+ p = vim_strsave_shellescape(ptr, TRUE, TRUE);
vim_free(ptr);
if (p == NULL)
{
diff --git a/src/proto/misc2.pro b/src/proto/misc2.pro
index 16c5918..544e669 100644
--- a/src/proto/misc2.pro
+++ b/src/proto/misc2.pro
@@ -32,7 +32,7 @@
char_u *vim_strsave_escaped __ARGS((char_u *string, char_u *esc_chars));
char_u *vim_strsave_escaped_ext __ARGS((char_u *string, char_u *esc_chars, int cc, int bsl));
int csh_like_shell __ARGS((void));
-char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special));
+char_u *vim_strsave_shellescape __ARGS((char_u *string, int do_special, int do_newline));
char_u *vim_strsave_up __ARGS((char_u *string));
char_u *vim_strnsave_up __ARGS((char_u *string, int len));
void vim_strup __ARGS((char_u *p));
diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak
index e76ecb0..d7f503f 100644
--- a/src/testdir/Make_amiga.mak
+++ b/src/testdir/Make_amiga.mak
@@ -35,7 +35,7 @@
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test97.out test98.out \
test99.out test100.out test101.out test102.out test103.out \
- test104.out
+ test104.out test105.out
.SUFFIXES: .in .out
@@ -156,3 +156,4 @@
test102.out: test102.in
test103.out: test103.in
test104.out: test104.in
+test105.out: test105.in
diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak
index 5855359..d26fe89 100644
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -33,7 +33,8 @@
test84.out test85.out test86.out test87.out test88.out \
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test98.out test99.out \
- test100.out test101.out test102.out test103.out test104.out
+ test100.out test101.out test102.out test103.out test104.out \
+ test105.out
SCRIPTS32 = test50.out test70.out
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
index 4b93279..0523ae4 100644
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -53,7 +53,8 @@
test84.out test85.out test86.out test87.out test88.out \
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test98.out test99.out \
- test100.out test101.out test102.out test103.out test104.out
+ test100.out test101.out test102.out test103.out test104.out \
+ test105.out
SCRIPTS32 = test50.out test70.out
diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak
index 7e37df7..65c0946 100644
--- a/src/testdir/Make_os2.mak
+++ b/src/testdir/Make_os2.mak
@@ -35,7 +35,8 @@
test81.out test82.out test83.out test84.out test88.out \
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test98.out test99.out \
- test100.out test101.out test102.out test103.out test104.out
+ test100.out test101.out test102.out test103.out test104.out \
+ test105.out
.SUFFIXES: .in .out
diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms
index f3483da..de3fb48 100644
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -4,7 +4,7 @@
# Authors: Zoltan Arpadffy, <arpadffy@polarhome.com>
# Sandor Kopanyi, <sandor.kopanyi@mailbox.hu>
#
-# Last change: 2013 Nov 21
+# Last change: 2014 Feb 23
#
# This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64.
# Edit the lines in the Configuration section below to select.
@@ -79,7 +79,8 @@
test82.out test83.out test84.out test88.out test89.out \
test90.out test91.out test92.out test93.out test94.out \
test95.out test96.out test97.out test98.out test99.out \
- test100.out test101.out test102.out test103.out test104.out
+ test100.out test101.out test102.out test103.out test104.out \
+ test105.out
# Known problems:
# Test 30: a problem around mac format - unknown reason
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index bd29836..d86a7b0 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -31,7 +31,7 @@
test89.out test90.out test91.out test92.out test93.out \
test94.out test95.out test96.out test97.out test98.out \
test99.out test100.out test101.out test102.out test103.out \
- test104.out
+ test104.out test105.out
SCRIPTS_GUI = test16.out
diff --git a/src/testdir/test105.in b/src/testdir/test105.in
new file mode 100644
index 0000000..284f3bf
--- /dev/null
+++ b/src/testdir/test105.in
@@ -0,0 +1,45 @@
+Test filename modifiers vim: set ft=vim :
+
+STARTTEST
+:source small.vim
+:%delete _
+:set shell=sh
+:set shellslash
+:let tab="\t"
+:command -nargs=1 Put :let expr=<q-args> | $put =expr.tab.strtrans(string(eval(expr)))
+:let $HOME=fnamemodify('.', ':p:h:h:h')
+:Put fnamemodify('.', ':p' )[-1:]
+:Put fnamemodify('.', ':p:h' )[-1:]
+:Put fnamemodify('test.out', ':p' )[-1:]
+:Put fnamemodify('test.out', ':.' )
+:Put fnamemodify('../testdir/a', ':.' )
+:Put fnamemodify('test.out', ':~' )
+:Put fnamemodify('../testdir/a', ':~' )
+:Put fnamemodify('../testdir/a', ':t' )
+:Put fnamemodify('.', ':p:t' )
+:Put fnamemodify('test.out', ':p:t' )
+:Put fnamemodify('test.out', ':p:e' )
+:Put fnamemodify('test.out', ':p:t:e' )
+:Put fnamemodify('abc.fb2.tar.gz', ':r' )
+:Put fnamemodify('abc.fb2.tar.gz', ':r:r' )
+:Put fnamemodify('abc.fb2.tar.gz', ':r:r:r' )
+:Put substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(src/testdir/.*\)', '\1', '')
+:Put fnamemodify('abc.fb2.tar.gz', ':e' )
+:Put fnamemodify('abc.fb2.tar.gz', ':e:e' )
+:Put fnamemodify('abc.fb2.tar.gz', ':e:e:e' )
+:Put fnamemodify('abc.fb2.tar.gz', ':e:e:e:e')
+:Put fnamemodify('abc.fb2.tar.gz', ':e:e:r' )
+:Put fnamemodify('abc def', ':S' )
+:Put fnamemodify('abc" "def', ':S' )
+:Put fnamemodify('abc"%"def', ':S' )
+:Put fnamemodify('abc'' ''def', ':S' )
+:Put fnamemodify('abc''%''def', ':S' )
+:Put fnamemodify("abc\ndef", ':S' )
+:set shell=tcsh
+:Put fnamemodify("abc\ndef", ':S' )
+:$put ='vim: ts=8'
+:1 delete _
+:w! test.out
+:qa!
+ENDTEST
+
diff --git a/src/testdir/test105.ok b/src/testdir/test105.ok
new file mode 100644
index 0000000..0681597
--- /dev/null
+++ b/src/testdir/test105.ok
@@ -0,0 +1,29 @@
+fnamemodify('.', ':p' )[-1:] '/'
+fnamemodify('.', ':p:h' )[-1:] 'r'
+fnamemodify('test.out', ':p' )[-1:] 't'
+fnamemodify('test.out', ':.' ) 'test.out'
+fnamemodify('../testdir/a', ':.' ) 'a'
+fnamemodify('test.out', ':~' ) '~/src/testdir/test.out'
+fnamemodify('../testdir/a', ':~' ) '~/src/testdir/a'
+fnamemodify('../testdir/a', ':t' ) 'a'
+fnamemodify('.', ':p:t' ) ''
+fnamemodify('test.out', ':p:t' ) 'test.out'
+fnamemodify('test.out', ':p:e' ) 'out'
+fnamemodify('test.out', ':p:t:e' ) 'out'
+fnamemodify('abc.fb2.tar.gz', ':r' ) 'abc.fb2.tar'
+fnamemodify('abc.fb2.tar.gz', ':r:r' ) 'abc.fb2'
+fnamemodify('abc.fb2.tar.gz', ':r:r:r' ) 'abc'
+substitute(fnamemodify('abc.fb2.tar.gz', ':p:r:r'), '.*\(src/testdir/.*\)', '\1', '') 'src/testdir/abc.fb2'
+fnamemodify('abc.fb2.tar.gz', ':e' ) 'gz'
+fnamemodify('abc.fb2.tar.gz', ':e:e' ) 'tar.gz'
+fnamemodify('abc.fb2.tar.gz', ':e:e:e' ) 'fb2.tar.gz'
+fnamemodify('abc.fb2.tar.gz', ':e:e:e:e') 'fb2.tar.gz'
+fnamemodify('abc.fb2.tar.gz', ':e:e:r' ) 'tar'
+fnamemodify('abc def', ':S' ) '''abc def'''
+fnamemodify('abc" "def', ':S' ) '''abc" "def'''
+fnamemodify('abc"%"def', ':S' ) '''abc"%"def'''
+fnamemodify('abc'' ''def', ':S' ) '''abc''\'''' ''\''''def'''
+fnamemodify('abc''%''def', ':S' ) '''abc''\''''%''\''''def'''
+fnamemodify("abc\ndef", ':S' ) '''abc^@def'''
+fnamemodify("abc\ndef", ':S' ) '''abc\^@def'''
+vim: ts=8
diff --git a/src/version.c b/src/version.c
index 1459a3b..9c9586b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -739,6 +739,8 @@
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 191,
+/**/
190,
/**/
189,