There is no simple way to prepare a file name parameter for bufnr() so
that it reliably finds a specific buffer.
The file name can contain file-pattern characters that can lead to more
than one match, or a match attempt in buflist_findpat() can find a match
on the wrong buffer.
:let buf = bufnr('[my]_testfile')
can match does not match
m_testfile [my]_testfile
y_testfile
According to ':he bufname()', to force a single full match, embed the
filename in '^' and '$'. Also, the file-pattern characters and special
characters need to be escaped:
:let buf = bufnr('^'. escape(fname, '*?\,{}[]^$%#') .'$')
But for some character combinations, the escaped characters do not match:
:echo '^'. escape('test\{,}name', '*?\,{}[]^$%#') .'$'
^test\\\{\,\}name$
In the escaped filename, '\\\{\,\}' is treated as the file-pattern
'\\\{n,m\}', equivalent to '\{n,m}' in a regex (':he file-pattern').
But the '\,' in the middle is syntactically incorrect, and the whole
pattern is rejected. A literal match also fails. Unless a buffer named
'^test\\\{\,\}name$' exists, which would be a false match.
According to ':he file-pattern', the only construct with magic escaped
characters is '\\\{n,m\}'.
But file_pat_to_reg_pat() knows more, at least when '\' is allowed as a
directory separator. E.g.:
'\*' used as '\.*'
'\?' used as '\.'
...
All functions that use an {expr} as in bufname() have this problem:
bufname()
bufnr()
bufwinnr()
getbufline()
getbufvar()
setbufvar()
Suggested solution:
Add a {literal} parameter to bufnr(), which forces a literal match as in
bufexists().
When a full path is used in the {expr} parameter, a match is also unique.
In all other functions, the result of bufnr() can be used.
---
runtime/doc/eval.txt | 8 ++++++--
src/eval.c | 17 +++++++++++++----
2 files changed, 19 insertions(+), 6 deletions(-)
Index: b/runtime/doc/eval.txt
===================================================================
--- a/runtime/doc/eval.txt 2015-08-04 22:23:36.705032764 +0200
+++ b/runtime/doc/eval.txt 2015-08-04 22:28:32.096557318 +0200
@@ -1763,7 +1763,8 @@ bufexists( {expr}) Number TRUE if buffe
buflisted( {expr}) Number TRUE if buffer {expr} is listed
bufloaded( {expr}) Number TRUE if buffer {expr} is loaded
bufname( {expr}) String Name of the buffer {expr}
-bufnr( {expr}) Number Number of the buffer {expr}
+bufnr( {expr} [, {create} [, {literal}]])
+ Number Number of the buffer {expr}
bufwinnr( {expr}) Number window number of buffer {expr}
byte2line( {byte}) Number line number at byte count {byte}
byteidx( {expr}, {nr}) Number byte index of {nr}'th char in {expr}
@@ -2293,10 +2294,13 @@ bufname({expr})
*bufname()*
Obsolete name: buffer_name().
*bufnr()*
-bufnr({expr} [, {create}])
+bufnr({expr} [, {create} [, {literal}]])
The result is the number of a buffer, as it is displayed by
the ":ls" command. For the use of {expr}, see |bufname()|
above.
+ If the {literal} argument is present and not zero, {expr} is
+ used as in |bufexists()|. Use this to prevent expansion of
+ pattern wildcards in {expr}.
If the buffer doesn't exist, -1 is returned. Or, if the
{create} argument is present and not zero, a new, unlisted,
buffer is created and its number is returned.
Index: b/src/eval.c
===================================================================
--- a/src/eval.c 2015-08-04 22:24:36.704935227 +0200
+++ b/src/eval.c 2015-08-04 22:28:32.100557312 +0200
@@ -8083,7 +8083,7 @@ static struct fst
{"buflisted", 1, 1, f_buflisted},
{"bufloaded", 1, 1, f_bufloaded},
{"bufname", 1, 1, f_bufname},
- {"bufnr", 1, 2, f_bufnr},
+ {"bufnr", 1, 3, f_bufnr},
{"bufwinnr", 1, 1, f_bufwinnr},
{"byte2line", 1, 1, f_byte2line},
{"byteidx", 2, 2, f_byteidx},
@@ -9388,9 +9388,18 @@ f_bufnr(argvars, rettv)
char_u *name;
(void)get_tv_number(&argvars[0]); /* issue errmsg if type error */
- ++emsg_off;
- buf = get_buf_tv(&argvars[0], FALSE);
- --emsg_off;
+
+ if (argvars[1].v_type != VAR_UNKNOWN
+ && argvars[2].v_type != VAR_UNKNOWN
+ && get_tv_number_chk(&argvars[2], &error) != 0
+ && !error)
+ buf = find_buffer(&argvars[0]);
+ else
+ {
+ ++emsg_off;
+ buf = get_buf_tv(&argvars[0], FALSE);
+ --emsg_off;
+ }
/* If the buffer isn't found and the second argument is not zero create a
* new buffer. */
--
Olaf Dabrunz (oda <at> fctrace.org)
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.