aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer_defs.h1
-rw-r--r--src/nvim/charset.c46
-rw-r--r--src/nvim/eval.lua2
-rw-r--r--src/nvim/eval/funcs.c76
-rw-r--r--src/nvim/ex_cmds.c10
-rw-r--r--src/nvim/ex_cmds2.c31
-rw-r--r--src/nvim/ex_docmd.c4
-rw-r--r--src/nvim/fileio.c2
-rw-r--r--src/nvim/getchar.c3
-rw-r--r--src/nvim/mbyte.c4
-rw-r--r--src/nvim/memline.c49
-rw-r--r--src/nvim/message.c7
-rw-r--r--src/nvim/misc1.c4
-rw-r--r--src/nvim/option.c4
-rw-r--r--src/nvim/os/signal.c4
-rw-r--r--src/nvim/quickfix.c18
-rw-r--r--src/nvim/screen.c2
-rw-r--r--src/nvim/testdir/runtest.vim3
-rw-r--r--src/nvim/testdir/test_display.vim41
-rw-r--r--src/nvim/testdir/test_functions.vim6
-rw-r--r--src/nvim/testdir/test_put.vim26
-rw-r--r--src/nvim/testdir/test_quickfix.vim40
-rw-r--r--src/nvim/testdir/test_swap.vim60
-rw-r--r--src/nvim/testdir/test_syntax.vim98
-rw-r--r--src/nvim/testdir/test_window_cmd.vim4
25 files changed, 401 insertions, 144 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 5e5a20e8f2..1223f2bdab 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -91,6 +91,7 @@ typedef struct {
#define BF_READERR 0x40 // got errors while reading the file
#define BF_DUMMY 0x80 // dummy buffer, only used internally
#define BF_PRESERVED 0x100 // ":preserve" was used
+#define BF_SYN_SET 0x200 // 'syntax' option was set
// Mask to check for flags that prevent normal writing
#define BF_WRITE_MASK (BF_NOTEDITED + BF_NEW + BF_READERR)
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index f9d5adbc12..fb158f377a 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -509,7 +509,7 @@ char_u* str_foldcase(char_u *str, int orglen, char_u *buf, int buflen)
// Does NOT work for multi-byte characters, c must be <= 255.
// Also doesn't work for the first byte of a multi-byte, "c" must be a
// character!
-static char_u transchar_buf[11];
+static char_u transchar_charbuf[11];
/// Translate a character into a printable one, leaving printable ASCII intact
///
@@ -520,11 +520,17 @@ static char_u transchar_buf[11];
/// @return translated character into a static buffer.
char_u *transchar(int c)
{
+ return transchar_buf(curbuf, c);
+}
+
+char_u *transchar_buf(const buf_T *buf, int c)
+ FUNC_ATTR_NONNULL_ALL
+{
int i = 0;
if (IS_SPECIAL(c)) {
// special key code, display as ~@ char
- transchar_buf[0] = '~';
- transchar_buf[1] = '@';
+ transchar_charbuf[0] = '~';
+ transchar_charbuf[1] = '@';
i = 2;
c = K_SECOND(c);
}
@@ -532,14 +538,14 @@ char_u *transchar(int c)
if ((!chartab_initialized && (((c >= ' ') && (c <= '~'))))
|| ((c <= 0xFF) && vim_isprintc_strict(c))) {
// printable character
- transchar_buf[i] = (char_u)c;
- transchar_buf[i + 1] = NUL;
+ transchar_charbuf[i] = (char_u)c;
+ transchar_charbuf[i + 1] = NUL;
} else if (c <= 0xFF) {
- transchar_nonprint(transchar_buf + i, c);
+ transchar_nonprint(buf, transchar_charbuf + i, c);
} else {
- transchar_hex((char *)transchar_buf + i, c);
+ transchar_hex((char *)transchar_charbuf + i, c);
}
- return transchar_buf;
+ return transchar_charbuf;
}
/// Like transchar(), but called with a byte instead of a character
@@ -548,13 +554,13 @@ char_u *transchar(int c)
///
/// @param[in] c Byte to translate.
///
-/// @return pointer to translated character in transchar_buf.
+/// @return pointer to translated character in transchar_charbuf.
char_u *transchar_byte(const int c)
FUNC_ATTR_WARN_UNUSED_RESULT
{
if (c >= 0x80) {
- transchar_nonprint(transchar_buf, c);
- return transchar_buf;
+ transchar_nonprint(curbuf, transchar_charbuf, c);
+ return transchar_charbuf;
}
return transchar(c);
}
@@ -563,16 +569,18 @@ char_u *transchar_byte(const int c)
///
/// @warning Does not work for multi-byte characters, c must be <= 255.
///
-/// @param[out] buf Buffer to store result in, must be able to hold at least
-/// 5 bytes (conversion result + NUL).
+/// @param[in] buf Required to check the file format
+/// @param[out] charbuf Buffer to store result in, must be able to hold
+/// at least 5 bytes (conversion result + NUL).
/// @param[in] c Character to convert. NUL is assumed to be NL according to
/// `:h NL-used-for-NUL`.
-void transchar_nonprint(char_u *buf, int c)
+void transchar_nonprint(const buf_T *buf, char_u *charbuf, int c)
+ FUNC_ATTR_NONNULL_ALL
{
if (c == NL) {
// we use newline in place of a NUL
c = NUL;
- } else if ((c == CAR) && (get_fileformat(curbuf) == EOL_MAC)) {
+ } else if ((c == CAR) && (get_fileformat(buf) == EOL_MAC)) {
// we use CR in place of NL in this case
c = NL;
}
@@ -580,14 +588,14 @@ void transchar_nonprint(char_u *buf, int c)
if (dy_flags & DY_UHEX || c > 0x7f) {
// 'display' has "uhex"
- transchar_hex((char *)buf, c);
+ transchar_hex((char *)charbuf, c);
} else {
// 0x00 - 0x1f and 0x7f
- buf[0] = '^';
+ charbuf[0] = '^';
// DEL displayed as ^?
- buf[1] = (char_u)(c ^ 0x40);
+ charbuf[1] = (char_u)(c ^ 0x40);
- buf[2] = NUL;
+ charbuf[2] = NUL;
}
}
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 372c950825..11f6a350e4 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -371,7 +371,7 @@ return {
tolower={args=1},
toupper={args=1},
tr={args=3},
- trim={args={1,2}},
+ trim={args={1,3}},
trunc={args=1, func="float_op_wrapper", data="&trunc"},
type={args=1},
undofile={args=1},
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 6c3802143f..861743eb7d 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -10823,52 +10823,72 @@ static void f_trim(typval_T *argvars, typval_T *rettv, FunPtr fptr)
const char_u *prev;
const char_u *p;
int c1;
+ int dir = 0;
rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = NULL;
if (head == NULL) {
- rettv->vval.v_string = NULL;
return;
}
if (argvars[1].v_type == VAR_STRING) {
mask = (const char_u *)tv_get_string_buf_chk(&argvars[1], buf2);
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ bool error = false;
+ // leading or trailing characters to trim
+ dir = (int)tv_get_number_chk(&argvars[2], &error);
+ if (error) {
+ return;
+ }
+ if (dir < 0 || dir > 2) {
+ emsgf(_(e_invarg2), tv_get_string(&argvars[2]));
+ return;
+ }
+ }
}
- while (*head != NUL) {
- c1 = PTR2CHAR(head);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ if (dir == 0 || dir == 1) {
+ // Trim leading characters
+ while (*head != NUL) {
+ c1 = PTR2CHAR(head);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
}
- if (*p == NUL) {
- break;
- }
+ MB_PTR_ADV(head);
}
- MB_PTR_ADV(head);
}
- for (tail = head + STRLEN(head); tail > head; tail = prev) {
- prev = tail;
- MB_PTR_BACK(head, prev);
- c1 = PTR2CHAR(prev);
- if (mask == NULL) {
- if (c1 > ' ' && c1 != 0xa0) {
- break;
- }
- } else {
- for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
- if (c1 == PTR2CHAR(p)) {
+ tail = head + STRLEN(head);
+ if (dir == 0 || dir == 2) {
+ // Trim trailing characters
+ for (; tail > head; tail = prev) {
+ prev = tail;
+ MB_PTR_BACK(head, prev);
+ c1 = PTR2CHAR(prev);
+ if (mask == NULL) {
+ if (c1 > ' ' && c1 != 0xa0) {
+ break;
+ }
+ } else {
+ for (p = mask; *p != NUL; MB_PTR_ADV(p)) {
+ if (c1 == PTR2CHAR(p)) {
+ break;
+ }
+ }
+ if (*p == NUL) {
break;
}
- }
- if (*p == NUL) {
- break;
}
}
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index bb4e92efc0..3669cbbd2d 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -135,7 +135,7 @@ void do_ascii(const exarg_T *const eap)
char buf1[20];
if (vim_isprintc_strict(c) && (c < ' ' || c > '~')) {
char_u buf3[7];
- transchar_nonprint(buf3, c);
+ transchar_nonprint(curbuf, buf3, c);
vim_snprintf(buf1, sizeof(buf1), " <%s>", (char *)buf3);
} else {
buf1[0] = NUL;
@@ -2240,11 +2240,9 @@ int do_ecmd(
goto theend;
}
- /*
- * if the file was changed we may not be allowed to abandon it
- * - if we are going to re-edit the same file
- * - or if we are the only window on this file and if ECMD_HIDE is FALSE
- */
+ // If the file was changed we may not be allowed to abandon it:
+ // - if we are going to re-edit the same file
+ // - or if we are the only window on this file and if ECMD_HIDE is FALSE
if ( ((!other_file && !(flags & ECMD_OLDBUF))
|| (curbuf->b_nwindows == 1
&& !(flags & (ECMD_HIDE | ECMD_ADDBUF))))
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 3e169f7a4e..503fd8e0d0 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2058,6 +2058,10 @@ void ex_listdo(exarg_T *eap)
// Don't do syntax HL autocommands. Skipping the syntax file is a
// great speed improvement.
save_ei = au_event_disable(",Syntax");
+
+ FOR_ALL_BUFFERS(buf) {
+ buf->b_flags &= ~BF_SYN_SET;
+ }
}
if (eap->cmdidx == CMD_windo
@@ -2252,9 +2256,32 @@ void ex_listdo(exarg_T *eap)
}
if (save_ei != NULL) {
+ buf_T *bnext;
+ aco_save_T aco;
+
au_event_restore(save_ei);
- apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
- curbuf->b_fname, true, curbuf);
+
+ for (buf_T *buf = firstbuf; buf != NULL; buf = bnext) {
+ bnext = buf->b_next;
+ if (buf->b_nwindows > 0 && (buf->b_flags & BF_SYN_SET)) {
+ buf->b_flags &= ~BF_SYN_SET;
+
+ // buffer was opened while Syntax autocommands were disabled,
+ // need to trigger them now.
+ if (buf == curbuf) {
+ apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn,
+ curbuf->b_fname, true, curbuf);
+ } else {
+ aucmd_prepbuf(&aco, buf);
+ apply_autocmds(EVENT_SYNTAX, buf->b_p_syn,
+ buf->b_fname, true, buf);
+ aucmd_restbuf(&aco);
+ }
+
+ // start over, in case autocommands messed things up.
+ bnext = firstbuf;
+ }
+ }
}
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index b4c634292c..71ac542323 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -7138,14 +7138,14 @@ static void ex_resize(exarg_T *eap)
n = atol((char *)eap->arg);
if (cmdmod.split & WSP_VERT) {
if (*eap->arg == '-' || *eap->arg == '+') {
- n += curwin->w_width;
+ n += wp->w_width;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very wide
n = Columns;
}
win_setwidth_win(n, wp);
} else {
if (*eap->arg == '-' || *eap->arg == '+') {
- n += curwin->w_height;
+ n += wp->w_height;
} else if (n == 0 && eap->arg[0] == NUL) { // default is very high
n = Rows-1;
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 1b4a89fb6c..ad856b588a 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3593,7 +3593,7 @@ restore_backup:
* the backup file our 'original' file.
*/
if (*p_pm && dobackup) {
- char *org = modname((char *)fname, (char *)p_pm, FALSE);
+ char *const org = modname((char *)fname, (char *)p_pm, false);
if (backup != NULL) {
/*
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index cbd9582f8b..456979be00 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -4204,7 +4204,6 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
{
char_u *str = strstart;
int c;
- int modifiers;
// :map xx <Nop>
if (*str == NUL && what == 1) {
@@ -4231,7 +4230,7 @@ int put_escstr(FILE *fd, char_u *strstart, int what)
* when they are read back.
*/
if (c == K_SPECIAL && what != 2) {
- modifiers = 0x0;
+ int modifiers = 0;
if (str[1] == KS_MODIFIER) {
modifiers = str[2];
str += 3;
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index e67be60aa6..6d188c6cd0 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -512,7 +512,7 @@ int utf_ptr2cells(const char_u *p)
{
int c;
- /* Need to convert to a wide character. */
+ // Need to convert to a character number.
if (*p >= 0x80) {
c = utf_ptr2char(p);
/* An illegal byte is displayed as <xx>. */
@@ -582,7 +582,7 @@ size_t mb_string2cells_len(const char_u *str, size_t size)
return clen;
}
-/// Convert a UTF-8 byte sequence to a wide character
+/// Convert a UTF-8 byte sequence to a character number.
///
/// If the sequence is illegal or truncated by a NUL then the first byte is
/// returned.
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 2a75f13cc2..57ed0d6588 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1360,7 +1360,7 @@ recover_names (
* Try finding a swap file by simply adding ".swp" to the file name.
*/
if (*dirp == NUL && file_count + num_files == 0 && fname != NULL) {
- char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", TRUE);
+ char_u *swapname = (char_u *)modname((char *)fname_res, ".swp", true);
if (swapname != NULL) {
if (os_path_exists(swapname)) {
files = xmalloc(sizeof(char_u *));
@@ -1638,10 +1638,11 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
// May also add the file name with a dot prepended, for swap file in same
// dir as original file.
if (prepend_dot) {
- names[num_names] = (char_u *)modname((char *)path, ".sw?", TRUE);
- if (names[num_names] == NULL)
+ names[num_names] = (char_u *)modname((char *)path, ".sw?", true);
+ if (names[num_names] == NULL) {
return num_names;
- ++num_names;
+ }
+ num_names++;
}
// Form the normal swap file name pattern by appending ".sw?".
@@ -2422,17 +2423,17 @@ int ml_replace(linenr_T lnum, char_u *line, bool copy)
return ml_replace_buf(curbuf, lnum, line, copy);
}
-/*
- * Replace line lnum, with buffering, in current buffer.
- *
- * If "copy" is TRUE, make a copy of the line, otherwise the line has been
- * copied to allocated memory already.
- *
- * Check: The caller of this function should probably also call
- * changed_lines(), unless update_screen(NOT_VALID) is used.
- *
- * return FAIL for failure, OK otherwise
- */
+// Replace line "lnum", with buffering, in current buffer.
+//
+// If "copy" is true, make a copy of the line, otherwise the line has been
+// copied to allocated memory already.
+// If "copy" is false the "line" may be freed to add text properties!
+// Do not use it after calling ml_replace().
+//
+// Check: The caller of this function should probably also call
+// changed_lines(), unless update_screen(NOT_VALID) is used.
+//
+// return FAIL for failure, OK otherwise
int ml_replace_buf(buf_T *buf, linenr_T lnum, char_u *line, bool copy)
{
if (line == NULL) /* just checking... */
@@ -3193,6 +3194,12 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
char_u *fname_res = fname;
#ifdef HAVE_READLINK
char_u fname_buf[MAXPATHL];
+
+ // Expand symlink in the file name, so that we put the swap file with the
+ // actual file instead of with the symlink.
+ if (resolve_symlink(fname, fname_buf) == OK) {
+ fname_res = fname_buf;
+ }
#endif
int len = (int)STRLEN(dir_name);
@@ -3201,20 +3208,14 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
&& len > 1
&& s[-1] == s[-2]) { // Ends with '//', Use Full path
r = NULL;
- if ((s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname)) != NULL) {
- r = (char_u *)modname((char *)s, ".swp", FALSE);
+ s = (char_u *)make_percent_swname((char *)dir_name, (char *)fname_res);
+ if (s != NULL) {
+ r = (char_u *)modname((char *)s, ".swp", false);
xfree(s);
}
return r;
}
-#ifdef HAVE_READLINK
- /* Expand symlink in the file name, so that we put the swap file with the
- * actual file instead of with the symlink. */
- if (resolve_symlink(fname, fname_buf) == OK)
- fname_res = fname_buf;
-#endif
-
// Prepend a '.' to the swap file name for the current directory.
r = (char_u *)modname((char *)fname_res, ".swp",
dir_name[0] == '.' && dir_name[1] == NUL);
diff --git a/src/nvim/message.c b/src/nvim/message.c
index e4f47917ec..6cd5616acf 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1621,7 +1621,7 @@ const char *str2special(const char **const sp, const bool replace_spaces,
// Check for an illegal byte.
if (MB_BYTE2LEN((uint8_t)(*str)) > len) {
- transchar_nonprint((char_u *)buf, c);
+ transchar_nonprint(curbuf, (char_u *)buf, c);
*sp = str + 1;
return buf;
}
@@ -1886,6 +1886,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
// wait-return prompt later. Needed when scrolling, resetting
// need_wait_return after some prompt, and then outputting something
// without scrolling
+ // Not needed when only using CR to move the cursor.
bool overflow = false;
if (ui_has(kUIMessages)) {
int count = msg_ext_visible + (msg_ext_overwrite ? 0 : 1);
@@ -1897,7 +1898,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
overflow = msg_scrolled != 0;
}
- if (overflow && !msg_scrolled_ign) {
+ if (overflow && !msg_scrolled_ign && strcmp(str, "\r") != 0) {
need_wait_return = true;
}
msg_didany = true; // remember that something was outputted
@@ -1999,7 +2000,7 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr,
|| (*s == TAB && msg_col <= 7)
|| (utf_ptr2cells(s) > 1
&& msg_col <= 2))
- : (msg_col + t_col >= Columns - 1
+ : ((*s != '\r' && msg_col + t_col >= Columns - 1)
|| (*s == TAB
&& msg_col + t_col >= ((Columns - 1) & ~7))
|| (utf_ptr2cells(s) > 1
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index 6dafbafb3e..1cd9ff2c4d 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -983,7 +983,7 @@ void preserve_exit(void)
FOR_ALL_BUFFERS(buf) {
if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
- mch_errmsg((uint8_t *)"Vim: preserving files...\n");
+ mch_errmsg("Vim: preserving files...\r\n");
ui_flush();
ml_sync_all(false, false, true); // preserve all swap files
break;
@@ -992,7 +992,7 @@ void preserve_exit(void)
ml_close_all(false); // close all memfiles, without deleting
- mch_errmsg("Vim: Finished.\n");
+ mch_errmsg("Vim: Finished.\r\n");
getout(1);
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 6ae9378236..484d9da3a1 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -3438,6 +3438,7 @@ ambw_end:
// recursively, to avoid endless recurrence.
apply_autocmds(EVENT_SYNTAX, curbuf->b_p_syn, curbuf->b_fname,
value_changed || syn_recursive == 1, curbuf);
+ curbuf->b_flags |= BF_SYN_SET;
syn_recursive--;
} else if (varp == &(curbuf->b_p_ft)) {
// 'filetype' is set, trigger the FileType autocommand
@@ -7269,7 +7270,8 @@ unsigned int get_bkc_value(buf_T *buf)
}
/// Return the current end-of-line type: EOL_DOS, EOL_UNIX or EOL_MAC.
-int get_fileformat(buf_T *buf)
+int get_fileformat(const buf_T *buf)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
int c = *buf->b_p_ff;
diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c
index bfe230b521..bc774b8ebc 100644
--- a/src/nvim/os/signal.c
+++ b/src/nvim/os/signal.c
@@ -161,8 +161,8 @@ static void deadly_signal(int signum)
WLOG("got signal %d (%s)", signum, signal_name(signum));
- snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\n",
- signal_name(signum));
+ snprintf((char *)IObuff, sizeof(IObuff), "Vim: Caught deadly signal '%s'\r\n",
+ signal_name(signum));
// Preserve files and exit.
preserve_exit();
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 5ade59d224..4d3d0f5fdf 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -5068,6 +5068,20 @@ static void vgr_jump_to_match(qf_info_T *qi, int forceit, int *redraw_for_dummy,
}
}
+// Return true if "buf" had an existing swap file, the current swap file does
+// not end in ".swp".
+static bool existing_swapfile(const buf_T *buf)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL) {
+ const char_u *const fname = buf->b_ml.ml_mfp->mf_fname;
+ const size_t len = STRLEN(fname);
+
+ return fname[len - 1] != 'p' || fname[len - 2] != 'w';
+ }
+ return false;
+}
+
// ":vimgrep {pattern} file(s)"
// ":vimgrepadd {pattern} file(s)"
// ":lvimgrep {pattern} file(s)"
@@ -5225,7 +5239,9 @@ void ex_vimgrep(exarg_T *eap)
if (!found_match) {
wipe_dummy_buffer(buf, dirname_start);
buf = NULL;
- } else if (buf != first_match_buf || (flags & VGR_NOJUMP)) {
+ } else if (buf != first_match_buf
+ || (flags & VGR_NOJUMP)
+ || existing_swapfile(buf)) {
unload_dummy_buffer(buf, dirname_start);
// Keeping the buffer, remove the dummy flag.
buf->b_flags &= ~BF_DUMMY;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 1191886888..9f450888a2 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -3634,7 +3634,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow,
mb_utf8 = false; // don't draw as UTF-8
}
} else if (c != NUL) {
- p_extra = transchar(c);
+ p_extra = transchar_buf(wp->w_buffer, c);
if (n_extra == 0) {
n_extra = byte2cells(c) - 1;
}
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 765ba2cbb6..b02514143c 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -78,6 +78,9 @@ set encoding=utf-8
let s:test_script_fname = expand('%')
au! SwapExists * call HandleSwapExists()
func HandleSwapExists()
+ if exists('g:ignoreSwapExists')
+ return
+ endif
" Ignore finding a swap file for the test script (the user might be
" editing it and do ":make test_name") and the output file.
" Report finding another swap file and chose 'q' to avoid getting stuck.
diff --git a/src/nvim/testdir/test_display.vim b/src/nvim/testdir/test_display.vim
index e853b046dc..66b016c8b2 100644
--- a/src/nvim/testdir/test_display.vim
+++ b/src/nvim/testdir/test_display.vim
@@ -185,6 +185,47 @@ func Test_scroll_CursorLineNr_update()
call delete(filename)
endfunc
+" check a long file name does not result in the hit-enter prompt
+func Test_edit_long_file_name()
+ CheckScreendump
+
+ let longName = 'x'->repeat(&columns)
+ call writefile([], longName)
+ let buf = RunVimInTerminal('-N -u NONE ' .. longName, #{rows: 8})
+
+ call VerifyScreenDump(buf, 'Test_long_file_name_1', {})
+
+ call term_sendkeys(buf, ":q\<cr>")
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete(longName)
+endfunc
+
+func Test_unprintable_fileformats()
+ CheckScreendump
+
+ call writefile(["unix\r", "two"], 'Xunix.txt')
+ call writefile(["mac\r", "two"], 'Xmac.txt')
+ let lines =<< trim END
+ edit Xunix.txt
+ split Xmac.txt
+ edit ++ff=mac
+ END
+ let filename = 'Xunprintable'
+ call writefile(lines, filename)
+ let buf = RunVimInTerminal('-S '.filename, #{rows: 9, cols: 50})
+ call VerifyScreenDump(buf, 'Test_display_unprintable_01', {})
+ call term_sendkeys(buf, "\<C-W>\<C-W>\<C-L>")
+ call VerifyScreenDump(buf, 'Test_display_unprintable_02', {})
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('Xunix.txt')
+ call delete('Xmac.txt')
+ call delete(filename)
+endfunc
+
" Test for scrolling that modifies buffer during visual block
func Test_visual_block_scroll()
" See test/functional/legacy/visual_mode_spec.lua
diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim
index 8fa70a5313..00f0126582 100644
--- a/src/nvim/testdir/test_functions.vim
+++ b/src/nvim/testdir/test_functions.vim
@@ -1083,6 +1083,12 @@ func Test_trim()
call assert_equal("", trim("", ""))
call assert_equal("a", trim("a", ""))
call assert_equal("", trim("", "a"))
+ call assert_equal("vim", trim(" vim ", " ", 0))
+ call assert_equal("vim ", trim(" vim ", " ", 1))
+ call assert_equal(" vim", trim(" vim ", " ", 2))
+ call assert_fails('call trim(" vim ", " ", [])', 'E745:')
+ call assert_fails('call trim(" vim ", " ", -1)', 'E475:')
+ call assert_fails('call trim(" vim ", " ", 3)', 'E475:')
let chars = join(map(range(1, 0x20) + [0xa0], {n -> nr2char(n)}), '')
call assert_equal("x", trim(chars . "x" . chars))
diff --git a/src/nvim/testdir/test_put.vim b/src/nvim/testdir/test_put.vim
index 884ada7e88..15745d5619 100644
--- a/src/nvim/testdir/test_put.vim
+++ b/src/nvim/testdir/test_put.vim
@@ -22,12 +22,21 @@ endfunc
func Test_put_char_block2()
new
- let a = [ getreg('a'), getregtype('a') ]
call setreg('a', ' one ', 'v')
call setline(1, ['Line 1', '', 'Line 3', ''])
" visually select the first 3 lines and put register a over it
exe "norm! ggl\<c-v>2j2l\"ap"
- call assert_equal(['L one 1', '', 'L one 3', ''], getline(1,4))
+ call assert_equal(['L one 1', '', 'L one 3', ''], getline(1, 4))
+ " clean up
+ bw!
+endfunc
+
+func Test_put_lines()
+ new
+ let a = [ getreg('a'), getregtype('a') ]
+ call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
+ exe 'norm! gg"add"AddG""p'
+ call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1, '$'))
" clean up
bw!
call setreg('a', a[0], a[1])
@@ -42,21 +51,10 @@ func Test_put_expr()
exec "4norm! \"=\<cr>P"
norm! j0.
norm! j0.
- call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1,'$'))
+ call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1, '$'))
bw!
endfunc
-func Test_put_lines()
- new
- let a = [ getreg('a'), getregtype('a') ]
- call setline(1, ['Line 1', 'Line2', 'Line 3', ''])
- exe 'norm! gg"add"AddG""p'
- call assert_equal(['Line 3', '', 'Line 1', 'Line2'], getline(1,'$'))
- " clean up
- bw!
- call setreg('a', a[0], a[1])
-endfunc
-
func Test_put_fails_when_nomodifiable()
new
setlocal nomodifiable
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index f9e79919e9..d46233991c 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -1,8 +1,7 @@
" Test for the quickfix commands.
-if !has('quickfix')
- finish
-endif
+source check.vim
+CheckFeature quickfix
set encoding=utf-8
@@ -2568,6 +2567,41 @@ func Test_vimgrep_incsearch()
set noincsearch
endfunc
+" Test vimgrep without swap file
+func Test_vimgrep_without_swap_file()
+ let lines =<< trim [SCRIPT]
+ vimgrep grep test_c*
+ call writefile(['done'], 'Xresult')
+ qall!
+ [SCRIPT]
+ call writefile(lines, 'Xscript')
+ if RunVim([], [], '--clean -n -S Xscript Xscript')
+ call assert_equal(['done'], readfile('Xresult'))
+ endif
+ call delete('Xscript')
+ call delete('Xresult')
+endfunc
+
+func Test_vimgrep_existing_swapfile()
+ call writefile(['match apple with apple'], 'Xapple')
+ call writefile(['swapfile'], '.Xapple.swp')
+ let g:foundSwap = 0
+ let g:ignoreSwapExists = 1
+ augroup grep
+ au SwapExists * let foundSwap = 1 | let v:swapchoice = 'e'
+ augroup END
+ vimgrep apple Xapple
+ call assert_equal(1, g:foundSwap)
+ call assert_match('.Xapple.swo', swapname(''))
+
+ call delete('Xapple')
+ call delete('Xapple.swp')
+ augroup grep
+ au! SwapExists
+ augroup END
+ unlet g:ignoreSwapExists
+endfunc
+
func XfreeTests(cchar)
call s:setup_commands(a:cchar)
diff --git a/src/nvim/testdir/test_swap.vim b/src/nvim/testdir/test_swap.vim
index e072e9ed7f..f27920d20f 100644
--- a/src/nvim/testdir/test_swap.vim
+++ b/src/nvim/testdir/test_swap.vim
@@ -1,5 +1,7 @@
" Tests for the swap feature
+source check.vim
+
func s:swapname()
return trim(execute('swapname'))
endfunc
@@ -305,3 +307,61 @@ func Test_swap_recover_ext()
augroup END
augroup! test_swap_recover_ext
endfunc
+
+" Test for selecting 'q' in the attention prompt
+func Test_swap_prompt_splitwin()
+ CheckRunVimInTerminal
+
+ call writefile(['foo bar'], 'Xfile1')
+ edit Xfile1
+ preserve " should help to make sure the swap file exists
+
+ let buf = RunVimInTerminal('', {'rows': 20})
+ call term_sendkeys(buf, ":set nomore\n")
+ call term_sendkeys(buf, ":set noruler\n")
+ call term_sendkeys(buf, ":split Xfile1\n")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^\[O\]pen Read-Only, (E)dit anyway, (R)ecover, (Q)uit, (A)bort: $', term_getline(buf, 20))})
+ call term_sendkeys(buf, "q")
+ call term_wait(buf)
+ call term_sendkeys(buf, ":\<CR>")
+ call WaitForAssert({-> assert_match('^:$', term_getline(buf, 20))})
+ call term_sendkeys(buf, ":echomsg winnr('$')\<CR>")
+ call term_wait(buf)
+ call WaitForAssert({-> assert_match('^1$', term_getline(buf, 20))})
+ call StopVimInTerminal(buf)
+ %bwipe!
+ call delete('Xfile1')
+endfunc
+
+func Test_swap_symlink()
+ if !has("unix")
+ return
+ endif
+
+ call writefile(['text'], 'Xtestfile')
+ silent !ln -s -f Xtestfile Xtestlink
+
+ set dir=.
+
+ " Test that swap file uses the name of the file when editing through a
+ " symbolic link (so that editing the file twice is detected)
+ edit Xtestlink
+ call assert_match('Xtestfile\.swp$', s:swapname())
+ bwipe!
+
+ call mkdir('Xswapdir')
+ exe 'set dir=' . getcwd() . '/Xswapdir//'
+
+ " Check that this also works when 'directory' ends with '//'
+ edit Xtestlink
+ call assert_match('Xtestfile\.swp$', s:swapname())
+ bwipe!
+
+ set dir&
+ call delete('Xtestfile')
+ call delete('Xtestlink')
+ call delete('Xswapdir', 'rf')
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 2404f113d9..2617aa3945 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -475,6 +475,40 @@ func Test_bg_detection()
hi Normal ctermbg=NONE
endfunc
+func Test_syntax_hangs()
+ if !has('reltime') || !has('float') || !has('syntax')
+ return
+ endif
+
+ " This pattern takes a long time to match, it should timeout.
+ new
+ call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
+ let start = reltime()
+ set nolazyredraw redrawtime=101
+ syn match Error /\%#=1a*.*X\@<=b*/
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ " second time syntax HL is disabled
+ let start = reltime()
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed < 0.1)
+
+ " after CTRL-L the timeout flag is reset
+ let start = reltime()
+ exe "normal \<C-L>"
+ redraw
+ let elapsed = reltimefloat(reltime(start))
+ call assert_true(elapsed > 0.1)
+ call assert_true(elapsed < 1.0)
+
+ set redrawtime&
+ bwipe!
+endfunc
+
func Test_synstack_synIDtrans()
new
setfiletype c
@@ -550,38 +584,42 @@ func Test_syn_wrong_z_one()
bwipe!
endfunc
-func Test_syntax_hangs()
- if !has('reltime') || !has('float') || !has('syntax')
- return
- endif
+func Test_syntax_after_bufdo()
+ call writefile(['/* aaa comment */'], 'Xaaa.c')
+ call writefile(['/* bbb comment */'], 'Xbbb.c')
+ call writefile(['/* ccc comment */'], 'Xccc.c')
+ call writefile(['/* ddd comment */'], 'Xddd.c')
+
+ let bnr = bufnr('%')
+ new Xaaa.c
+ badd Xbbb.c
+ badd Xccc.c
+ badd Xddd.c
+ exe "bwipe " . bnr
+ let l = []
+ bufdo call add(l, bufnr('%'))
+ call assert_equal(4, len(l))
- " This pattern takes a long time to match, it should timeout.
- new
- call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
- let start = reltime()
- set nolazyredraw redrawtime=101
- syn match Error /\%#=1a*.*X\@<=b*/
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed > 0.1)
- call assert_true(elapsed < 1.0)
-
- " second time syntax HL is disabled
- let start = reltime()
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed < 0.1)
-
- " after CTRL-L the timeout flag is reset
- let start = reltime()
- exe "normal \<C-L>"
- redraw
- let elapsed = reltimefloat(reltime(start))
- call assert_true(elapsed > 0.1)
- call assert_true(elapsed < 1.0)
+ syntax on
- set redrawtime&
- bwipe!
+ " This used to only enable syntax HL in the last buffer.
+ bufdo tab split
+ tabrewind
+ for tab in range(1, 4)
+ norm fm
+ call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
+ tabnext
+ endfor
+
+ bwipe! Xaaa.c
+ bwipe! Xbbb.c
+ bwipe! Xccc.c
+ bwipe! Xddd.c
+ syntax off
+ call delete('Xaaa.c')
+ call delete('Xbbb.c')
+ call delete('Xccc.c')
+ call delete('Xddd.c')
endfunc
func Test_syntax_foldlevel()
diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim
index 9f47ee2904..500e3ff088 100644
--- a/src/nvim/testdir/test_window_cmd.vim
+++ b/src/nvim/testdir/test_window_cmd.vim
@@ -879,6 +879,10 @@ func Test_window_resize()
exe other_winnr .. 'resize 10'
call assert_equal(10, winheight(other_winnr))
call assert_equal(&lines - 10 - 3, winheight(0))
+ exe other_winnr .. 'resize +1'
+ exe other_winnr .. 'resize +1'
+ call assert_equal(12, winheight(other_winnr))
+ call assert_equal(&lines - 10 - 3 -2, winheight(0))
%bwipe!
endfunc