diff --git a/runtime/defaults.vim b/runtime/defaults.vim index 45a5393d32..023d640208 100644 --- a/runtime/defaults.vim +++ b/runtime/defaults.vim @@ -1,7 +1,7 @@ " The default vimrc file. " " Maintainer: Bram Moolenaar -" Last change: 2016 Aug 20 +" Last change: 2016 Aug 21 " " This is loaded if no vimrc file was found. " Except when Vim is run with "-u NONE" or "-C". @@ -107,9 +107,9 @@ if !exists(":DiffOrig") \ | wincmd p | diffthis endif -if has('langmap') && exists('+langnoremap') +if has('langmap') && exists('+langremap') " Prevent that the langmap option applies to characters that result from a - " mapping. If unset (default), this may break plugins (but it's backward + " mapping. If set (default), this may break plugins (but it's backward " compatible). - set langnoremap + set nolangremap endif diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt index b98c18b02c..f2444c017f 100644 --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -87,14 +87,21 @@ In the GUI tab pages line you can use the right mouse button to open menu. Execute {cmd} and when it opens a new window open a new tab page instead. Doesn't work for |:diffsplit|, |:diffpatch|, |:execute| and |:normal|. - When [count] is omitted the tab page appears after the current - one. - When [count] is specified the new tab page comes after tab - page [count]. Use ":0tab cmd" to get the new tab page as the - first one. + If [count] is given the new tab page appears after the tab + page [count] otherwise the new tab page will appear after the + current one. Examples: > - :tab split " opens current buffer in new tab page - :tab help gt " opens tab page with help for "gt" + :tab split " opens current buffer in new tab page + :tab help gt " opens tab page with help for "gt" + :.tab help gt " as above + :+tab help " opens tab page with help after the next + " tab page + :-tab help " opens tab page with help before the + " current one + :0tab help " opens tab page with help before the + " first one + :$tab help " opens tab page with help after the last + " one CTRL-W gf Open a new tab page and edit the file name under the cursor. See |CTRL-W_gf|. @@ -141,10 +148,11 @@ something else. given, then they become hidden. But modified buffers are never abandoned, so changes cannot get lost. > :tabonly " close all tab pages except the current + " one :{count}tabo[nly][!] Close all tab pages except the {count}th one. > - :.tabonly " one + :.tabonly " as above :-tabonly " close all tab pages except the previous " one :+tabonly " close all tab pages except the next one diff --git a/src/evalfunc.c b/src/evalfunc.c index f786c462d6..36c068b6e8 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -3587,8 +3587,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) use_string = TRUE; } - if (((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) - || is_funcref)) + if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref) { name = s; trans_name = trans_function_name(&name, FALSE, @@ -3597,7 +3596,8 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref) s = NULL; } - if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))) + if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)) + || (is_funcref && trans_name == NULL)) EMSG2(_(e_invarg2), s); /* Don't check an autoload name for existence here. */ else if (trans_name != NULL && (is_funcref @@ -11518,7 +11518,11 @@ f_submatch(typval_T *argvars, typval_T *rettv) no = (int)get_tv_number_chk(&argvars[0], &error); if (error) return; - error = FALSE; + if (no < 0 || no >= NSUBEXP) + { + EMSGN(_("E935: invalid submatch number: %d"), no); + return; + } if (argvars[1].v_type != VAR_UNKNOWN) retList = (int)get_tv_number_chk(&argvars[1], &error); if (error) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index e727ecc186..5c79e95941 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -8392,6 +8392,60 @@ ex_drop(exarg_T *eap) } #endif +#if defined(FEAT_QUICKFIX) || defined(FEAT_EVAL) || defined(PROTO) +/* + * Skip over the pattern argument of ":vimgrep /pat/[g][j]". + * Put the start of the pattern in "*s", unless "s" is NULL. + * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP. + * If "s" is not NULL terminate the pattern with a NUL. + * Return a pointer to the char just past the pattern plus flags. + */ + char_u * +skip_vimgrep_pat(char_u *p, char_u **s, int *flags) +{ + int c; + + if (vim_isIDc(*p)) + { + /* ":vimgrep pattern fname" */ + if (s != NULL) + *s = p; + p = skiptowhite(p); + if (s != NULL && *p != NUL) + *p++ = NUL; + } + else + { + /* ":vimgrep /pattern/[g][j] fname" */ + if (s != NULL) + *s = p + 1; + c = *p; + p = skip_regexp(p + 1, c, TRUE, NULL); + if (*p != c) + return NULL; + + /* Truncate the pattern. */ + if (s != NULL) + *p = NUL; + ++p; + + /* Find the flags */ + while (*p == 'g' || *p == 'j') + { + if (flags != NULL) + { + if (*p == 'g') + *flags |= VGR_GLOBAL; + else + *flags |= VGR_NOJUMP; + } + ++p; + } + } + return p; +} +#endif + #if defined(FEAT_EVAL) || defined(PROTO) /* * List v:oldfiles in a nice way. diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 85fc29cd70..dbccca2186 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -1865,9 +1865,7 @@ do_one_cmd( /* * 2. Handle command modifiers. */ - p = ea.cmd; - if (VIM_ISDIGIT(*ea.cmd)) - p = skipwhite(skipdigits(ea.cmd)); + p = skip_range(ea.cmd, NULL); switch (*p) { /* When adding an entry, also modify cmd_exists(). */ @@ -1999,10 +1997,19 @@ do_one_cmd( case 't': if (checkforcmd(&p, "tab", 3)) { #ifdef FEAT_WINDOWS - if (vim_isdigit(*ea.cmd)) - cmdmod.tab = atoi((char *)ea.cmd) + 1; - else + long tabnr = get_address(&ea, &ea.cmd, ADDR_TABS, + ea.skip, FALSE); + if (tabnr == MAXLNUM) cmdmod.tab = tabpage_index(curtab) + 1; + else + { + if (tabnr < 0 || tabnr > LAST_TAB_NR) + { + errormsg = (char_u *)_(e_invrange); + goto doend; + } + cmdmod.tab = tabnr + 1; + } ea.cmd = p; #endif continue; diff --git a/src/macros.h b/src/macros.h index 28f43a3627..aec1425594 100644 --- a/src/macros.h +++ b/src/macros.h @@ -135,7 +135,7 @@ do { \ if (*p_langmap \ && (condition) \ - && (!p_lnr || (p_lnr && typebuf_maplen() == 0)) \ + && (p_lrm || (!p_lrm && KeyTyped)) \ && !KeyStuffed \ && (c) >= 0) \ { \ @@ -150,7 +150,7 @@ do { \ if (*p_langmap \ && (condition) \ - && (!p_lnr || (p_lnr && typebuf_maplen() == 0)) \ + && (p_lrm || (!p_lrm && KeyTyped)) \ && !KeyStuffed \ && (c) >= 0 && (c) < 256) \ c = langmap_mapchar[c]; \ diff --git a/src/option.c b/src/option.c index 44a56a2c6e..9da21fe985 100644 --- a/src/option.c +++ b/src/option.c @@ -1739,6 +1739,13 @@ static struct vimoption options[] = (char_u *)&p_lnr, PV_NONE, #else (char_u *)NULL, PV_NONE, +#endif + {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, + {"langremap", "lrm", P_BOOL|P_VI_DEF, +#ifdef FEAT_LANGMAP + (char_u *)&p_lrm, PV_NONE, +#else + (char_u *)NULL, PV_NONE, #endif {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT}, {"laststatus", "ls", P_NUM|P_VI_DEF|P_RALL, @@ -7989,6 +7996,15 @@ set_bool_option( compatible_set(); } +#ifdef FEAT_LANGMAP + if ((int *)varp == &p_lrm) + /* 'langremap' -> !'langnoremap' */ + p_lnr = !p_lrm; + else if ((int *)varp == &p_lnr) + /* 'langnoremap' -> !'langremap' */ + p_lrm = !p_lnr; +#endif + #ifdef FEAT_PERSISTENT_UNDO /* 'undofile' */ else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) diff --git a/src/option.h b/src/option.h index ecca9efd58..1947431531 100644 --- a/src/option.h +++ b/src/option.h @@ -616,6 +616,7 @@ EXTERN char_u *p_km; /* 'keymodel' */ #ifdef FEAT_LANGMAP EXTERN char_u *p_langmap; /* 'langmap'*/ EXTERN int p_lnr; /* 'langnoremap' */ +EXTERN int p_lrm; /* 'langremap' */ #endif #if defined(FEAT_MENU) && defined(FEAT_MULTI_LANG) EXTERN char_u *p_lm; /* 'langmenu' */ diff --git a/src/proto/ex_cmds.pro b/src/proto/ex_cmds.pro index 324608f33e..63f25b50f4 100644 --- a/src/proto/ex_cmds.pro +++ b/src/proto/ex_cmds.pro @@ -65,5 +65,6 @@ char_u *get_sign_name(expand_T *xp, int idx); void set_context_in_sign_cmd(expand_T *xp, char_u *arg); void ex_smile(exarg_T *eap); void ex_drop(exarg_T *eap); +char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags); void ex_oldfiles(exarg_T *eap); /* vim: set ft=c : */ diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro index 99f5edeefd..d48eb25326 100644 --- a/src/proto/quickfix.pro +++ b/src/proto/quickfix.pro @@ -26,9 +26,8 @@ void ex_cc(exarg_T *eap); void ex_cnext(exarg_T *eap); void ex_cfile(exarg_T *eap); void ex_vimgrep(exarg_T *eap); -char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags); -int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict); int get_errorlist(win_T *wp, int qf_idx, list_T *list); +int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict); int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T *what); void ex_cbuffer(exarg_T *eap); void ex_cexpr(exarg_T *eap); diff --git a/src/quickfix.c b/src/quickfix.c index 2fa6ed98a9..f808da4995 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4318,58 +4318,6 @@ theend: vim_regfree(regmatch.regprog); } -/* - * Skip over the pattern argument of ":vimgrep /pat/[g][j]". - * Put the start of the pattern in "*s", unless "s" is NULL. - * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP. - * If "s" is not NULL terminate the pattern with a NUL. - * Return a pointer to the char just past the pattern plus flags. - */ - char_u * -skip_vimgrep_pat(char_u *p, char_u **s, int *flags) -{ - int c; - - if (vim_isIDc(*p)) - { - /* ":vimgrep pattern fname" */ - if (s != NULL) - *s = p; - p = skiptowhite(p); - if (s != NULL && *p != NUL) - *p++ = NUL; - } - else - { - /* ":vimgrep /pattern/[g][j] fname" */ - if (s != NULL) - *s = p + 1; - c = *p; - p = skip_regexp(p + 1, c, TRUE, NULL); - if (*p != c) - return NULL; - - /* Truncate the pattern. */ - if (s != NULL) - *p = NUL; - ++p; - - /* Find the flags */ - while (*p == 'g' || *p == 'j') - { - if (flags != NULL) - { - if (*p == 'g') - *flags |= VGR_GLOBAL; - else - *flags |= VGR_NOJUMP; - } - ++p; - } - } - return p; -} - /* * Restore current working directory to "dirname_start" if they differ, taking * into account whether it is set locally or globally. diff --git a/src/term.c b/src/term.c index 8d7f168a03..a521b7c062 100644 --- a/src/term.c +++ b/src/term.c @@ -4945,7 +4945,7 @@ check_termcode( button = getdigits(&p); mouse_code = 0; - switch( button ) + switch (button) { case 4: mouse_code = MOUSE_LEFT; break; case 1: mouse_code = MOUSE_RIGHT; break; @@ -4953,7 +4953,7 @@ check_termcode( default: return -1; } - switch( action ) + switch (action) { case 31: /* Initial press */ if (*p++ != ';') @@ -5102,9 +5102,11 @@ check_termcode( else if (orig_num_clicks == 4) modifiers |= MOD_MASK_4CLICK; - /* Work out our pseudo mouse event */ + /* Work out our pseudo mouse event. Note that MOUSE_RELEASE gets + * added, then it's not mouse up/down. */ key_name[0] = (int)KS_EXTRA; - if (wheel_code != 0) + if (wheel_code != 0 + && (wheel_code & MOUSE_RELEASE) != MOUSE_RELEASE) { if (wheel_code & MOUSE_CTRL) modifiers |= MOD_MASK_CTRL; diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index a7ad65eef4..b23b4490bb 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -198,6 +198,11 @@ func Test_substitute_expr() call assert_equal('--', substitute('xxx', 'x*', {-> '-' . Recurse() . '-'}, '')) endfunc +func Test_invalid_submatch() + " This was causing invalid memory access in Vim-7.4.2232 and older + call assert_fails("call substitute('x', '.', {-> submatch(10)}, '')", 'E935:') +endfunc + func Test_substitute_expr_arg() call assert_equal('123456789-123456789=', substitute('123456789', \ '\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', @@ -237,6 +242,7 @@ func Test_funcref() call assert_equal(1, OneByRef()) let OneByRef = funcref('One') call assert_equal(2, OneByRef()) + call assert_fails('echo funcref("{")', 'E475:') endfunc func Test_setmatches() diff --git a/src/testdir/test_mapping.vim b/src/testdir/test_mapping.vim index a1281eb4d3..66b81cecf8 100644 --- a/src/testdir/test_mapping.vim +++ b/src/testdir/test_mapping.vim @@ -35,29 +35,73 @@ func Test_map_ctrl_c_visual() endfunc func Test_map_langmap() - " langmap should not get remapped in insert mode - inoremap { FAIL_ilangmap - set langmap=+{ langnoremap + if !has('langmap') + return + endif + + " check langmap applies in normal mode + set langmap=+- nolangremap + new + call setline(1, ['a', 'b', 'c']) + 2 + call assert_equal('b', getline('.')) + call feedkeys("+", "xt") + call assert_equal('a', getline('.')) + + " check no remapping + map x + + 2 + call feedkeys("x", "xt") + call assert_equal('c', getline('.')) + + " check with remapping + set langremap + 2 + call feedkeys("x", "xt") + call assert_equal('a', getline('.')) + + unmap x + bwipe! + + " 'langnoremap' follows 'langremap' and vise versa + set langremap + set langnoremap + call assert_equal(0, &langremap) + set langremap + call assert_equal(0, &langnoremap) + set nolangremap + call assert_equal(1, &langnoremap) + + " langmap should not apply in insert mode, 'langremap' doesn't matter + set langmap=+{ nolangremap + call feedkeys("Go+\", "xt") + call assert_equal('+', getline('$')) + set langmap=+{ langremap call feedkeys("Go+\", "xt") call assert_equal('+', getline('$')) - " Insert-mode expr mapping with langmap - inoremap { "FAIL_iexplangmap" - call feedkeys("Go+\", "xt") - call assert_equal('+', getline('$')) - iunmap { - - " langmap should not get remapped in Command-line mode - cnoremap { FAIL_clangmap + " langmap used for register name in insert mode. + call setreg('a', 'aaaa') + call setreg('b', 'bbbb') + call setreg('c', 'cccc') + set langmap=ab langremap + call feedkeys("Go\a\", "xt") + call assert_equal('bbbb', getline('$')) + call feedkeys("Go\\a\", "xt") + call assert_equal('bbbb', getline('$')) + " mapping does not apply + imap c a + call feedkeys("Go\c\", "xt") + call assert_equal('cccc', getline('$')) + imap a c + call feedkeys("Go\a\", "xt") + call assert_equal('bbbb', getline('$')) + + " langmap should not apply in Command-line mode + set langmap=+{ nolangremap call feedkeys(":call append(line('$'), '+')\", "xt") call assert_equal('+', getline('$')) - cunmap { - " Command-line mode expr mapping with langmap - cnoremap { "FAIL_cexplangmap" - call feedkeys(":call append(line('$'), '+')\", "xt") - call assert_equal('+', getline('$')) - cunmap { set nomodified endfunc diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim index e6b85d6e14..f1c41e967b 100644 --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -186,4 +186,36 @@ function Test_tabpage_with_autocmd() bw! endfunction +function Test_tabpage_with_tab_modifier() + for n in range(4) + tabedit + endfor + + function s:check_tab(pre_nr, cmd, post_nr) + exec 'tabnext ' . a:pre_nr + exec a:cmd + call assert_equal(a:post_nr, tabpagenr()) + call assert_equal('help', &filetype) + helpclose + endfunc + + call s:check_tab(1, 'tab help', 2) + call s:check_tab(1, '3tab help', 4) + call s:check_tab(1, '.tab help', 2) + call s:check_tab(1, '.+1tab help', 3) + call s:check_tab(1, '0tab help', 1) + call s:check_tab(2, '+tab help', 4) + call s:check_tab(2, '+2tab help', 5) + call s:check_tab(4, '-tab help', 4) + call s:check_tab(4, '-2tab help', 3) + call s:check_tab(3, '$tab help', 6) + call assert_fails('99tab help', 'E16:') + call assert_fails('+99tab help', 'E16:') + call assert_fails('-99tab help', 'E16:') + + delfunction s:check_tab + tabonly! + bw! +endfunction + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 1e24cebd4c..d08a2e6866 100644 --- a/src/version.c +++ b/src/version.c @@ -778,6 +778,20 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2239, +/**/ + 2238, +/**/ + 2237, +/**/ + 2236, +/**/ + 2235, +/**/ + 2234, +/**/ + 2233, /**/ 2232, /**/