diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/buffer_defs.h | 3 | ||||
-rw-r--r-- | src/nvim/eval.c | 4 | ||||
-rw-r--r-- | src/nvim/event/libuv_process.h | 5 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 29 | ||||
-rw-r--r-- | src/nvim/file_search.c | 30 | ||||
-rw-r--r-- | src/nvim/fold.c | 24 | ||||
-rw-r--r-- | src/nvim/getchar.c | 71 | ||||
-rw-r--r-- | src/nvim/memline.c | 2 | ||||
-rw-r--r-- | src/nvim/memory.c | 7 | ||||
-rw-r--r-- | src/nvim/ops.c | 49 | ||||
-rw-r--r-- | src/nvim/option.c | 2 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 14 | ||||
-rw-r--r-- | src/nvim/terminal.c | 1 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_alot.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_fold.vim | 16 | ||||
-rw-r--r-- | src/nvim/testdir/test_glob2regpat.vim | 30 | ||||
-rw-r--r-- | src/nvim/testdir/test_mapping.vim | 100 | ||||
-rw-r--r-- | src/nvim/testdir/test_marks.vim | 26 | ||||
-rw-r--r-- | src/nvim/testdir/test_nested_function.vim | 32 | ||||
-rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 10 | ||||
-rw-r--r-- | src/nvim/testdir/test_writefile.vim | 16 | ||||
-rw-r--r-- | src/nvim/version.c | 12 | ||||
-rw-r--r-- | src/nvim/window.c | 41 |
24 files changed, 387 insertions, 142 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index a1b5633c32..3e9767adde 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -825,8 +825,7 @@ struct tabpage_S { frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots dictitem_T tp_winvar; ///< variable for "t:" Dictionary dict_T *tp_vars; ///< internal variables, local to tab page - char_u *localdir; ///< Absolute path of local directory or - ///< NULL + char_u *tp_localdir; ///< Absolute path of local CWD or NULL }; /* diff --git a/src/nvim/eval.c b/src/nvim/eval.c index bcad6df337..7ca3d89665 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10901,7 +10901,7 @@ static void f_getcwd(typval_T *argvars, typval_T *rettv, FunPtr fptr) } case kCdScopeTab: // FALLTHROUGH assert(tp); - from = tp->localdir; + from = tp->tp_localdir; if (from) { break; } @@ -12015,7 +12015,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv, FunPtr fptr) break; case kCdScopeTab: assert(tp); - rettv->vval.v_number = tp->localdir ? 1 : 0; + rettv->vval.v_number = tp->tp_localdir ? 1 : 0; break; case kCdScopeGlobal: // The global scope never has a local directory diff --git a/src/nvim/event/libuv_process.h b/src/nvim/event/libuv_process.h index aaaa896e10..1132ce79ca 100644 --- a/src/nvim/event/libuv_process.h +++ b/src/nvim/event/libuv_process.h @@ -14,8 +14,9 @@ typedef struct libuv_process { static inline LibuvProcess libuv_process_init(Loop *loop, void *data) { - LibuvProcess rv; - rv.process = process_init(loop, kProcessTypeUv, data); + LibuvProcess rv = { + .process = process_init(loop, kProcessTypeUv, data) + }; return rv; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 340b7d442b..c7cb875b88 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6949,24 +6949,27 @@ void free_cd_dir(void) /// @param scope Scope of the function call (global, tab or window). void post_chdir(CdScope scope) { - // The local directory of the current window is always overwritten. + // Always overwrite the window-local CWD. xfree(curwin->w_localdir); curwin->w_localdir = NULL; - // Overwrite the local directory of the current tab page for `cd` and `tcd` + // Overwrite the tab-local CWD for :cd, :tcd. if (scope >= kCdScopeTab) { - xfree(curtab->localdir); - curtab->localdir = NULL; + xfree(curtab->tp_localdir); + curtab->tp_localdir = NULL; } if (scope < kCdScopeGlobal) { - // If still in global directory, need to remember current directory as - // global directory. + // If still in global directory, set CWD as the global directory. if (globaldir == NULL && prev_dir != NULL) { globaldir = vim_strsave(prev_dir); } } + char cwd[MAXPATHL]; + if (os_dirname((char_u *)cwd, MAXPATHL) != OK) { + return; + } switch (scope) { case kCdScopeGlobal: // We are now in the global directory, no need to remember its name. @@ -6974,23 +6977,17 @@ void post_chdir(CdScope scope) globaldir = NULL; break; case kCdScopeTab: - // Remember this local directory for the tab page. - if (os_dirname(NameBuff, MAXPATHL) == OK) { - curtab->localdir = vim_strsave(NameBuff); - } + curtab->tp_localdir = (char_u *)xstrdup(cwd); break; case kCdScopeWindow: - // Remember this local directory for the window. - if (os_dirname(NameBuff, MAXPATHL) == OK) { - curwin->w_localdir = vim_strsave(NameBuff); - } + curwin->w_localdir = (char_u *)xstrdup(cwd); break; case kCdScopeInvalid: - // We should never get here assert(false); } - shorten_fnames(TRUE); + shorten_fnames(true); + do_autocmd_dirchanged(cwd, scope); } /// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`. diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 79a39c6503..b73d9944ce 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1519,7 +1519,7 @@ theend: return file_name; } -static void do_autocmd_dirchanged(char_u *new_dir, CdScope scope) +void do_autocmd_dirchanged(char *new_dir, CdScope scope) { static bool recursive = false; @@ -1550,10 +1550,11 @@ static void do_autocmd_dirchanged(char_u *new_dir, CdScope scope) } dict_add_nr_str(dict, "scope", 0L, (char_u *)buf); - dict_add_nr_str(dict, "cwd", 0L, new_dir); + dict_add_nr_str(dict, "cwd", 0L, (char_u *)new_dir); dict_set_keys_readonly(dict); - apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, new_dir, false, NULL); + apply_autocmds(EVENT_DIRCHANGED, (char_u *)buf, (char_u *)new_dir, false, + NULL); dict_clear(dict); @@ -1565,14 +1566,25 @@ static void do_autocmd_dirchanged(char_u *new_dir, CdScope scope) /// @return OK or FAIL int vim_chdirfile(char_u *fname) { - char_u dir[MAXPATHL]; + char dir[MAXPATHL]; STRLCPY(dir, fname, MAXPATHL); - *path_tail_with_sep(dir) = NUL; - if (os_chdir((char *)dir) != 0) { + *path_tail_with_sep((char_u *)dir) = NUL; + + if (os_dirname(NameBuff, sizeof(NameBuff)) != OK) { + NameBuff[0] = NUL; + } + + if (os_chdir(dir) != 0) { return FAIL; } - do_autocmd_dirchanged(dir, kCdScopeWindow); + +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(dir); +#endif + if (!strequal(dir, (char *)NameBuff)) { + do_autocmd_dirchanged(dir, kCdScopeWindow); + } return OK; } @@ -1587,10 +1599,6 @@ int vim_chdir(char_u *new_dir, CdScope scope) } int r = os_chdir((char *)dir_name); - if (r == 0) { - do_autocmd_dirchanged(dir_name, scope); - } - xfree(dir_name); return r; } diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 1423463800..7c0283971e 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -29,6 +29,7 @@ #include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/undo.h" +#include "nvim/ops.h" /* local declarations. {{{1 */ /* typedef fold_T {{{2 */ @@ -1593,29 +1594,32 @@ static void foldCreateMarkers(linenr_T start, linenr_T end) /* * Add "marker[markerlen]" in 'commentstring' to line "lnum". */ -static void foldAddMarker(linenr_T lnum, char_u *marker, size_t markerlen) +static void foldAddMarker(linenr_T lnum, const char_u *marker, size_t markerlen) { char_u *cms = curbuf->b_p_cms; char_u *line; char_u *newline; char_u *p = (char_u *)strstr((char *)curbuf->b_p_cms, "%s"); + bool line_is_comment = false; - /* Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end */ + // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end line = ml_get(lnum); size_t line_len = STRLEN(line); if (u_save(lnum - 1, lnum + 1) == OK) { + // Check if the line ends with an unclosed comment + skip_comment(line, false, false, &line_is_comment); newline = xmalloc(line_len + markerlen + STRLEN(cms) + 1); STRCPY(newline, line); - if (p == NULL) + // Append the marker to the end of the line + if (p == NULL || line_is_comment) { STRLCPY(newline + line_len, marker, markerlen + 1); - else { + } else { STRCPY(newline + line_len, cms); memcpy(newline + line_len + (p - cms), marker, markerlen); STRCPY(newline + line_len + (p - cms) + markerlen, p + 2); } - - ml_replace(lnum, newline, FALSE); + ml_replace(lnum, newline, false); } } @@ -2535,10 +2539,10 @@ static void foldSplit(garray_T *gap, int i, linenr_T top, linenr_T bot) * 1 2 3 * 1 2 3 * top 2 3 4 5 - * 2 3 4 5 - * bot 2 3 4 5 - * 3 5 6 - * 3 5 6 + * 2 3 4 5 + * bot 2 3 4 5 + * 3 5 6 + * 3 5 6 * * 1: not changed * 2: truncate to stop above "top" diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 6d1fab138c..bae8ae6d91 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1913,59 +1913,30 @@ static int vgetorpeek(int advance) if ((mp == NULL || max_mlen >= mp_match_len) && keylen != KEYLEN_PART_MAP) { - // When no matching mapping found or found a non-matching mapping - // that matches at least what the matching mapping matched: - // Check if we have a terminal code, when: - // mapping is allowed, - // keys have not been mapped, - // and not an ESC sequence, not in insert mode, - // and when not timed out. - if ((no_mapping == 0 || allow_keys != 0) - && (typebuf.tb_maplen == 0 - || (p_remap && typebuf.tb_noremap[ - typebuf.tb_off] == RM_YES)) - && !timedout) { - keylen = 0; - } else - keylen = 0; - if (keylen == 0) { /* no matching terminal code */ - /* When there was a matching mapping and no - * termcode could be replaced after another one, - * use that mapping (loop around). If there was - * no mapping use the character from the - * typeahead buffer right here. */ - if (mp == NULL) { - /* - * get a character: 2. from the typeahead buffer - */ - c = typebuf.tb_buf[typebuf.tb_off] & 255; - if (advance) { /* remove chars from tb_buf */ - cmd_silent = (typebuf.tb_silent > 0); - if (typebuf.tb_maplen > 0) - KeyTyped = FALSE; - else { - KeyTyped = TRUE; - /* write char to script file(s) */ - gotchars(typebuf.tb_buf - + typebuf.tb_off, 1); - } - KeyNoremap = typebuf.tb_noremap[ - typebuf.tb_off]; - del_typebuf(1, 0); + // No matching mapping found or found a non-matching mapping that + // matches at least what the matching mapping matched + keylen = 0; + // If there was no mapping, use the character from the typeahead + // buffer right here. Otherwise, use the mapping (loop around). + if (mp == NULL) { + // get a character: 2. from the typeahead buffer + c = typebuf.tb_buf[typebuf.tb_off] & 255; + if (advance) { // remove chars from tb_buf + cmd_silent = (typebuf.tb_silent > 0); + if (typebuf.tb_maplen > 0) { + KeyTyped = false; + } else { + KeyTyped = true; + // write char to script file(s) + gotchars(typebuf.tb_buf + typebuf.tb_off, 1); } - break; /* got character, break for loop */ + KeyNoremap = typebuf.tb_noremap[typebuf.tb_off]; + del_typebuf(1, 0); } - } - if (keylen > 0) { /* full matching terminal code */ - continue; /* try mapping again */ - } - - /* Partial match: get some more characters. When a - * matching mapping was found use that one. */ - if (mp == NULL || keylen < 0) - keylen = KEYLEN_PART_KEY; - else + break; // got character, break for loop + } else { keylen = mp_match_len; + } } /* complete match */ diff --git a/src/nvim/memline.c b/src/nvim/memline.c index b67f550358..1a315fce8b 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -2318,7 +2318,7 @@ ml_append_int ( * * return FAIL for failure, OK otherwise */ -int ml_replace(linenr_T lnum, char_u *line, int copy) +int ml_replace(linenr_T lnum, char_u *line, bool copy) { if (line == NULL) /* just checking... */ return FAIL; diff --git a/src/nvim/memory.c b/src/nvim/memory.c index b593936d7b..58c01fbe7a 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -475,6 +475,13 @@ void *xmemdup(const void *data, size_t len) return memcpy(xmalloc(len), data, len); } +/// Returns true if strings `a` and `b` are equal. Arguments may be NULL. +bool strequal(const char *a, const char *b) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return (a == NULL && b == NULL) || (a && b && strcmp(a, b) == 0); +} + /* * Avoid repeating the error message many times (they take 1 second each). * Did_outofmem_msg is reset when a character is read. diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 530193bd41..1e4d392754 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -3438,43 +3438,47 @@ dis_msg ( os_breakcheck(); } -/* - * If "process" is TRUE and the line begins with a comment leader (possibly - * after some white space), return a pointer to the text after it. Put a boolean - * value indicating whether the line ends with an unclosed comment in - * "is_comment". - * line - line to be processed, - * process - if FALSE, will only check whether the line ends with an unclosed - * comment, - * include_space - whether to also skip space following the comment leader, - * is_comment - will indicate whether the current line ends with an unclosed - * comment. - */ -static char_u *skip_comment(char_u *line, int process, int include_space, int *is_comment) +/// If \p "process" is true and the line begins with a comment leader (possibly +/// after some white space), return a pointer to the text after it. +/// Put a boolean value indicating whether the line ends with an unclosed +/// comment in "is_comment". +/// +/// @param line - line to be processed +/// @param process - if false, will only check whether the line ends +/// with an unclosed comment, +/// @param include_space - whether to skip space following the comment leader +/// @param[out] is_comment - whether the current line ends with an unclosed +/// comment. +char_u *skip_comment( + char_u *line, bool process, bool include_space, bool *is_comment +) { char_u *comment_flags = NULL; int lead_len; int leader_offset = get_last_leader_offset(line, &comment_flags); - *is_comment = FALSE; + *is_comment = false; if (leader_offset != -1) { /* Let's check whether the line ends with an unclosed comment. * If the last comment leader has COM_END in flags, there's no comment. */ while (*comment_flags) { if (*comment_flags == COM_END - || *comment_flags == ':') + || *comment_flags == ':') { break; - ++comment_flags; + } + comment_flags++; + } + if (*comment_flags != COM_END) { + *is_comment = true; } - if (*comment_flags != COM_END) - *is_comment = TRUE; } - if (process == FALSE) + if (process == false) { return line; + } - lead_len = get_leader_len(line, &comment_flags, FALSE, include_space); + lead_len = get_leader_len(line, &comment_flags, false, include_space); if (lead_len == 0) return line; @@ -3496,8 +3500,9 @@ static char_u *skip_comment(char_u *line, int process, int include_space, int *i * starting with a closing part of a three-part comment. That's good, * because we don't want to remove those as this would be annoying. */ - if (*comment_flags == ':' || *comment_flags == NUL) + if (*comment_flags == ':' || *comment_flags == NUL) { line += lead_len; + } return line; } @@ -3531,7 +3536,7 @@ int do_join(size_t count, int *comments = NULL; int remove_comments = (use_formatoptions == TRUE) && has_format_option(FO_REMOVE_COMS); - int prev_was_comment; + bool prev_was_comment; if (save_undo && u_save(curwin->w_cursor.lnum - 1, curwin->w_cursor.lnum + (linenr_T)count) == FAIL) { diff --git a/src/nvim/option.c b/src/nvim/option.c index 9a39581ec5..2fae4aa848 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1491,7 +1491,7 @@ do_set ( new_value_alloced = true; if (newval == NULL) { newval = empty_option; - } else if (!(options[opt_idx].flags | P_NO_DEF_EXP)) { + } else if (!(options[opt_idx].flags & P_NO_DEF_EXP)) { s = option_expand(opt_idx, newval); if (s == NULL) { s = newval; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 40a8066f75..7f5e5a481b 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -4214,11 +4214,15 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title, return retval; } -static int qf_set_properties(qf_info_T *qi, dict_T *what) +static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) { dictitem_T *di; int retval = FAIL; + int newlist = false; + if (action == ' ' || qi->qf_curlist == qi->qf_listcount) { + newlist = true; + } int qf_idx = qi->qf_curlist; // default is the current list if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL) { // Use the specified quickfix/location list @@ -4230,6 +4234,12 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what) } else { return FAIL; } + newlist = false; // use the specified list + } + + if (newlist) { + qf_new_list(qi, NULL); + qf_idx = qi->qf_curlist; } if ((di = dict_find(what, (char_u *)"title", -1)) != NULL) { @@ -4260,7 +4270,7 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, } if (what != NULL) { - retval = qf_set_properties(qi, what); + retval = qf_set_properties(qi, what, action); } else { retval = qf_add_entries(qi, list, title, action); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index cec7fc84a5..bd925a8106 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -238,6 +238,7 @@ Terminal *terminal_open(TerminalOptions opts) set_option_value((uint8_t *)"wrap", false, NULL, OPT_LOCAL); set_option_value((uint8_t *)"number", false, NULL, OPT_LOCAL); set_option_value((uint8_t *)"relativenumber", false, NULL, OPT_LOCAL); + set_option_value((uint8_t *)"list", false, NULL, OPT_LOCAL); buf_set_term_title(curbuf, (char *)curbuf->b_ffname); RESET_BINDING(curwin); // Reset cursor in current window. diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 740a10f153..9f9ecbc6c9 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -24,7 +24,6 @@ SCRIPTS ?= \ test64.out \ test73.out \ test79.out \ - test_marks.out \ # Tests using runtest.vim. # Keep test_alot*.res as the last one, sort the others. @@ -44,8 +43,10 @@ NEW_TESTS ?= \ test_increment_dbcs.res \ test_lambda.res \ test_langmap.res \ + test_marks.res \ test_match.res \ test_matchadd_conceal.res \ + test_nested_function.res \ test_quickfix.res \ test_signs.res \ test_syntax.res \ @@ -55,6 +56,7 @@ NEW_TESTS ?= \ test_viml.res \ test_visual.res \ test_window_id.res \ + test_writefile.res \ test_alot.res SCRIPTS_GUI := test16.out diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim index 3d3aa3449e..8aa0f417d1 100644 --- a/src/nvim/testdir/test_alot.vim +++ b/src/nvim/testdir/test_alot.vim @@ -16,6 +16,7 @@ source test_lambda.vim source test_match.vim source test_matchadd_conceal_utf8.vim source test_menu.vim +source test_mapping.vim source test_messages.vim source test_options.vim source test_partial.vim diff --git a/src/nvim/testdir/test_fold.vim b/src/nvim/testdir/test_fold.vim index 1f835b876f..7cb9faa75f 100644 --- a/src/nvim/testdir/test_fold.vim +++ b/src/nvim/testdir/test_fold.vim @@ -96,6 +96,22 @@ func! Test_indent_fold2() bw! endfunc +func Test_folds_marker_in_comment() + new + call setline(1, ['" foo', 'bar', 'baz']) + setl fen fdm=marker + setl com=sO:\"\ -,mO:\"\ \ ,eO:\"\",:\" cms=\"%s + norm! zf2j + setl nofen + :1y + call assert_equal(['" foo{{{'], getreg(0,1,1)) + :+2y + call assert_equal(['baz"}}}'], getreg(0,1,1)) + + set foldmethod& + bwipe! +endfunc + func Test_manual_fold_with_filter() if !executable('cat') return diff --git a/src/nvim/testdir/test_glob2regpat.vim b/src/nvim/testdir/test_glob2regpat.vim new file mode 100644 index 0000000000..fdf17946b6 --- /dev/null +++ b/src/nvim/testdir/test_glob2regpat.vim @@ -0,0 +1,30 @@ +" Test glob2regpat() + +func Test_invalid() + call assert_fails('call glob2regpat(1.33)', 'E806:') + call assert_fails('call glob2regpat("}")', 'E219:') + call assert_fails('call glob2regpat("{")', 'E220:') +endfunc + +func Test_valid() + call assert_equal('^foo\.', glob2regpat('foo.*')) + call assert_equal('^foo.$', glob2regpat('foo?')) + call assert_equal('\.vim$', glob2regpat('*.vim')) + call assert_equal('^[abc]$', glob2regpat('[abc]')) + call assert_equal('^foo bar$', glob2regpat('foo\ bar')) + call assert_equal('^foo,bar$', glob2regpat('foo,bar')) + call assert_equal('^\(foo\|bar\)$', glob2regpat('{foo,bar}')) + call assert_equal('.*', glob2regpat('**')) + + if exists('+shellslash') + call assert_equal('^foo[\/].$', glob2regpat('foo\?')) + call assert_equal('^\(foo[\/]\|bar\|foobar\)$', glob2regpat('{foo\,bar,foobar}')) + call assert_equal('^[\/]\(foo\|bar[\/]\)$', glob2regpat('\{foo,bar\}')) + call assert_equal('^[\/][\/]\(foo\|bar[\/][\/]\)$', glob2regpat('\\{foo,bar\\}')) + else + call assert_equal('^foo?$', glob2regpat('foo\?')) + call assert_equal('^\(foo,bar\|foobar\)$', glob2regpat('{foo\,bar,foobar}')) + call assert_equal('^{foo,bar}$', glob2regpat('\{foo,bar\}')) + call assert_equal('^\\\(foo\|bar\\\)$', glob2regpat('\\{foo,bar\\}')) + endif +endfunc diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim new file mode 100644 index 0000000000..d937565ce5 --- /dev/null +++ b/src/nvim/testdir/test_mapping.vim @@ -0,0 +1,100 @@ +" Tests for mappings and abbreviations + +if !has('multi_byte') + finish +endif + +func Test_abbreviation() + " abbreviation with 0x80 should work + inoreab чкпр vim + call feedkeys("Goчкпр \<Esc>", "xt") + call assert_equal('vim ', getline('$')) + iunab чкпр + set nomodified +endfunc + +func Test_map_ctrl_c_insert() + " mapping of ctrl-c in Insert mode + set cpo-=< cpo-=k + inoremap <c-c> <ctrl-c> + cnoremap <c-c> dummy + cunmap <c-c> + call feedkeys("GoTEST2: CTRL-C |\<C-C>A|\<Esc>", "xt") + call assert_equal('TEST2: CTRL-C |<ctrl-c>A|', getline('$')) + unmap! <c-c> + set nomodified +endfunc + +func Test_map_ctrl_c_visual() + " mapping of ctrl-c in Visual mode + vnoremap <c-c> :<C-u>$put ='vmap works' + call feedkeys("GV\<C-C>\<CR>", "xt") + call assert_equal('vmap works', getline('$')) + vunmap <c-c> + set nomodified +endfunc + +func Test_map_langmap() + " langmap should not get remapped in insert mode + inoremap { FAIL_ilangmap + set langmap=+{ langnoremap + call feedkeys("Go+\<Esc>", "xt") + call assert_equal('+', getline('$')) + + " Insert-mode expr mapping with langmap + inoremap <expr> { "FAIL_iexplangmap" + call feedkeys("Go+\<Esc>", "xt") + call assert_equal('+', getline('$')) + iunmap <expr> { + + " langmap should not get remapped in Command-line mode + cnoremap { FAIL_clangmap + call feedkeys(":call append(line('$'), '+')\<CR>", "xt") + call assert_equal('+', getline('$')) + cunmap { + + " Command-line mode expr mapping with langmap + cnoremap <expr> { "FAIL_cexplangmap" + call feedkeys(":call append(line('$'), '+')\<CR>", "xt") + call assert_equal('+', getline('$')) + cunmap { + set nomodified +endfunc + +func Test_map_feedkeys() + " issue #212 (feedkeys insert mapping at current position) + nnoremap . :call feedkeys(".", "in")<cr> + call setline('$', ['a b c d', 'a b c d']) + $-1 + call feedkeys("0qqdw.ifoo\<Esc>qj0@q\<Esc>", "xt") + call assert_equal(['fooc d', 'fooc d'], getline(line('$') - 1, line('$'))) + unmap . + set nomodified +endfunc + +func Test_map_cursor() + " <c-g>U<cursor> works only within a single line + imapclear + imap ( ()<c-g>U<left> + call feedkeys("G2o\<Esc>ki\<CR>Test1: text with a (here some more text\<Esc>k.", "xt") + call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 2)) + call assert_equal('Test1: text with a (here some more text)', getline(line('$') - 1)) + + " test undo + call feedkeys("G2o\<Esc>ki\<CR>Test2: text wit a (here some more text [und undo]\<C-G>u\<Esc>k.u", "xt") + call assert_equal('', getline(line('$') - 2)) + call assert_equal('Test2: text wit a (here some more text [und undo])', getline(line('$') - 1)) + set nomodified + imapclear +endfunc + +" This isn't actually testing a mapping, but similar use of CTRL-G U as above. +func Test_break_undo() + :set whichwrap=<,>,[,] + call feedkeys("G4o2k", "xt") + exe ":norm! iTest3: text with a (parenthesis here\<C-G>U\<Right>new line here\<esc>\<up>\<up>." + call assert_equal('new line here', getline(line('$') - 3)) + call assert_equal('Test3: text with a (parenthesis here', getline(line('$') - 2)) + call assert_equal('new line here', getline(line('$') - 1)) + set nomodified +endfunc diff --git a/src/nvim/testdir/test_marks.vim b/src/nvim/testdir/test_marks.vim new file mode 100644 index 0000000000..d00b1ddc88 --- /dev/null +++ b/src/nvim/testdir/test_marks.vim @@ -0,0 +1,26 @@ + +" Test that a deleted mark is restored after delete-undo-redo-undo. +function! Test_Restore_DelMark() + enew! + call append(0, [" textline A", " textline B", " textline C"]) + normal! 2gg + set nocp viminfo+=nviminfo + exe "normal! i\<C-G>u\<Esc>" + exe "normal! maddu\<C-R>u" + let pos = getpos("'a") + call assert_equal(2, pos[1]) + call assert_equal(1, pos[2]) + enew! +endfunction + +" Test that CTRL-A and CTRL-X updates last changed mark '[, ']. +function! Test_Incr_Marks() + enew! + call append(0, ["123 123 123", "123 123 123", "123 123 123"]) + normal! gg + execute "normal! \<C-A>`[v`]rAjwvjw\<C-X>`[v`]rX" + call assert_equal("AAA 123 123", getline(1)) + call assert_equal("123 XXXXXXX", getline(2)) + call assert_equal("XXX 123 123", getline(3)) + enew! +endfunction diff --git a/src/nvim/testdir/test_nested_function.vim b/src/nvim/testdir/test_nested_function.vim new file mode 100644 index 0000000000..f881730529 --- /dev/null +++ b/src/nvim/testdir/test_nested_function.vim @@ -0,0 +1,32 @@ +"Tests for nested functions +" +function! NestedFunc() + fu! Func1() + let g:text .= 'Func1 ' + endfunction + call Func1() + fu! s:func2() + let g:text .= 's:func2 ' + endfunction + call s:func2() + fu! s:_func3() + let g:text .= 's:_func3 ' + endfunction + call s:_func3() + let fn = 'Func4' + fu! {fn}() + let g:text .= 'Func4 ' + endfunction + call {fn}() + let fn = 'func5' + fu! s:{fn}() + let g:text .= 's:func5' + endfunction + call s:{fn}() +endfunction + +function! Test_nested_functions() + let g:text = '' + call NestedFunc() + call assert_equal('Func1 s:func2 s:_func3 Func4 s:func5', g:text) +endfunction diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 044c288ce0..1f4a39b853 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -1508,6 +1508,16 @@ function Xproperty_tests(cchar) call assert_equal('Sample', w:quickfix_title) Xclose + " Tests for action argument + silent! Xolder 999 + let qfnr = g:Xgetlist({'all':1}).nr + call g:Xsetlist([], 'r', {'title' : 'N1'}) + call assert_equal('N1', g:Xgetlist({'all':1}).title) + call g:Xsetlist([], ' ', {'title' : 'N2'}) + call assert_equal(qfnr + 1, g:Xgetlist({'all':1}).nr) + call g:Xsetlist([], ' ', {'title' : 'N3'}) + call assert_equal('N2', g:Xgetlist({'nr':2, 'title':1}).title) + " Invalid arguments call assert_fails('call g:Xgetlist([])', 'E715') call assert_fails('call g:Xsetlist([], "a", [])', 'E715') diff --git a/src/nvim/testdir/test_writefile.vim b/src/nvim/testdir/test_writefile.vim new file mode 100644 index 0000000000..d820c580ac --- /dev/null +++ b/src/nvim/testdir/test_writefile.vim @@ -0,0 +1,16 @@ + +function! Test_WriteFile() + let f = tempname() + call writefile(["over","written"], f, "b") + call writefile(["hello","world"], f, "b") + call writefile(["!", "good"], f, "a") + call writefile(["morning"], f, "ab") + call writefile(["", "vimmers"], f, "ab") + let l = readfile(f) + call assert_equal("hello", l[0]) + call assert_equal("world!", l[1]) + call assert_equal("good", l[2]) + call assert_equal("morning", l[3]) + call assert_equal("vimmers", l[4]) + call delete(f) +endfunction diff --git a/src/nvim/version.c b/src/nvim/version.c index 0ed6137d35..13b8247044 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -135,7 +135,7 @@ static int included_patches[] = { // 2308 NA // 2307, // 2306, - // 2305, + 2305, // 2304 NA // 2303, // 2302 NA @@ -176,7 +176,7 @@ static int included_patches[] = { // 2267 NA // 2266, 2265, - // 2264, + 2264, // 2263, // 2262 NA // 2261 NA @@ -232,7 +232,7 @@ static int included_patches[] = { // 2211 NA // 2210 NA // 2209, - // 2208, + 2208, // 2207 NA // 2206 NA 2205, @@ -244,7 +244,7 @@ static int included_patches[] = { // 2199 NA // 2198 NA 2197, - // 2196, + 2196, // 2195 NA 2194, // 2193 NA @@ -253,9 +253,9 @@ static int included_patches[] = { // 2190, // 2189, 2188, - // 2187, + 2187, // 2186 NA - // 2185, + 2185, // 2184, 2183, // 2182 NA diff --git a/src/nvim/window.c b/src/nvim/window.c index bae7c2e7dc..6c9d3554f1 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3003,8 +3003,7 @@ void free_tabpage(tabpage_T *tp) hash_init(&tp->tp_vars->dv_hashtab); unref_var_dict(tp->tp_vars); - - xfree(tp->localdir); // Free tab-local working directory + xfree(tp->tp_localdir); xfree(tp); } @@ -3030,7 +3029,7 @@ int win_new_tabpage(int after, char_u *filename) return FAIL; } - newtp->localdir = tp->localdir ? vim_strsave(tp->localdir) : NULL; + newtp->tp_localdir = tp->tp_localdir ? vim_strsave(tp->tp_localdir) : NULL; curtab = newtp; @@ -3627,28 +3626,38 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, curwin->w_cursor.coladd = 0; changed_line_abv_curs(); /* assume cursor position needs updating */ - // The new directory is either the local directory of the window, of the tab - // or NULL. - char_u *new_dir = curwin->w_localdir ? curwin->w_localdir : curtab->localdir; + // New directory is either the local directory of the window, tab or NULL. + char *new_dir = (char *)(curwin->w_localdir + ? curwin->w_localdir : curtab->tp_localdir); + + char cwd[MAXPATHL]; + if (os_dirname((char_u *)cwd, MAXPATHL) != OK) { + cwd[0] = NUL; + } if (new_dir) { // Window/tab has a local directory: Save current directory as global - // directory (unless that was done already) and change to the local - // directory. + // (unless that was done already) and change to the local directory. if (globaldir == NULL) { - char_u cwd[MAXPATHL]; - - if (os_dirname(cwd, MAXPATHL) == OK) { - globaldir = vim_strsave(cwd); + if (cwd[0] != NUL) { + globaldir = (char_u *)xstrdup(cwd); } } - if (os_chdir((char *)new_dir) == 0) { + if (os_chdir(new_dir) == 0) { + if (!p_acd && !strequal(new_dir, cwd)) { + do_autocmd_dirchanged(new_dir, curwin->w_localdir + ? kCdScopeWindow : kCdScopeTab); + } shorten_fnames(true); } } else if (globaldir != NULL) { - /* Window doesn't have a local directory and we are not in the global - * directory: Change to the global directory. */ - ignored = os_chdir((char *)globaldir); + // Window doesn't have a local directory and we are not in the global + // directory: Change to the global directory. + if (os_chdir((char *)globaldir) == 0) { + if (!p_acd && !strequal((char *)globaldir, cwd)) { + do_autocmd_dirchanged((char *)globaldir, kCdScopeGlobal); + } + } xfree(globaldir); globaldir = NULL; shorten_fnames(TRUE); |