aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer_defs.h3
-rw-r--r--src/nvim/eval.c4
-rw-r--r--src/nvim/event/libuv_process.h5
-rw-r--r--src/nvim/ex_docmd.c29
-rw-r--r--src/nvim/file_search.c30
-rw-r--r--src/nvim/fold.c24
-rw-r--r--src/nvim/getchar.c71
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/memory.c7
-rw-r--r--src/nvim/ops.c49
-rw-r--r--src/nvim/option.c2
-rw-r--r--src/nvim/quickfix.c14
-rw-r--r--src/nvim/terminal.c1
-rw-r--r--src/nvim/testdir/Makefile4
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_fold.vim16
-rw-r--r--src/nvim/testdir/test_glob2regpat.vim30
-rw-r--r--src/nvim/testdir/test_mapping.vim100
-rw-r--r--src/nvim/testdir/test_marks.vim26
-rw-r--r--src/nvim/testdir/test_nested_function.vim32
-rw-r--r--src/nvim/testdir/test_quickfix.vim10
-rw-r--r--src/nvim/testdir/test_writefile.vim16
-rw-r--r--src/nvim/version.c12
-rw-r--r--src/nvim/window.c41
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);