aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/buffer.c37
-rw-r--r--src/nvim/buffer_defs.h5
-rw-r--r--src/nvim/eval.c3
-rw-r--r--src/nvim/eval/typval_encode.c.h2
-rw-r--r--src/nvim/fileio.c32
-rw-r--r--src/nvim/main.c60
-rw-r--r--src/nvim/main.h34
-rw-r--r--src/nvim/ops.c10
-rw-r--r--src/nvim/option.c31
-rw-r--r--src/nvim/regexp_nfa.c17
-rw-r--r--src/nvim/search.c17
-rw-r--r--src/nvim/spell.c2
-rw-r--r--src/nvim/syntax.c75
-rw-r--r--src/nvim/terminal.c12
-rw-r--r--src/nvim/testdir/summarize.vim2
-rw-r--r--src/nvim/testdir/test_autocmd.vim4
-rw-r--r--src/nvim/testdir/test_filetype.vim31
-rw-r--r--src/nvim/testdir/test_increment.vim36
-rw-r--r--src/nvim/testdir/test_regexp_utf8.vim19
-rw-r--r--src/nvim/testdir/test_syntax.vim85
-rw-r--r--src/nvim/testdir/test_tagjump.vim69
-rw-r--r--src/nvim/testdir/test_textobjects.vim11
22 files changed, 474 insertions, 120 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 3ce39feda5..29712e9f52 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -3084,28 +3084,29 @@ fileinfo(
}
vim_snprintf_add((char *)buffer, IOSIZE, "\"%s%s%s%s%s%s",
- curbufIsChanged() ? (shortmess(SHM_MOD)
- ? " [+]" : _(" [Modified]")) : " ",
- (curbuf->b_flags & BF_NOTEDITED)
- && !bt_dontwrite(curbuf)
- ? _("[Not edited]") : "",
- (curbuf->b_flags & BF_NEW)
- && !bt_dontwrite(curbuf)
- ? _("[New file]") : "",
- (curbuf->b_flags & BF_READERR) ? _("[Read errors]") : "",
- curbuf->b_p_ro ? (shortmess(SHM_RO) ? _("[RO]")
- : _("[readonly]")) : "",
- (curbufIsChanged() || (curbuf->b_flags & BF_WRITE_MASK)
- || curbuf->b_p_ro) ?
- " " : "");
- /* With 32 bit longs and more than 21,474,836 lines multiplying by 100
- * causes an overflow, thus for large numbers divide instead. */
- if (curwin->w_cursor.lnum > 1000000L)
+ curbufIsChanged()
+ ? (shortmess(SHM_MOD) ? " [+]" : _(" [Modified]")) : " ",
+ (curbuf->b_flags & BF_NOTEDITED) && !bt_dontwrite(curbuf)
+ ? _("[Not edited]") : "",
+ (curbuf->b_flags & BF_NEW) && !bt_dontwrite(curbuf)
+ ? new_file_message() : "",
+ (curbuf->b_flags & BF_READERR)
+ ? _("[Read errors]") : "",
+ curbuf->b_p_ro
+ ? (shortmess(SHM_RO) ? _("[RO]") : _("[readonly]")) : "",
+ (curbufIsChanged()
+ || (curbuf->b_flags & BF_WRITE_MASK)
+ || curbuf->b_p_ro)
+ ? " " : "");
+ // With 32 bit longs and more than 21,474,836 lines multiplying by 100
+ // causes an overflow, thus for large numbers divide instead.
+ if (curwin->w_cursor.lnum > 1000000L) {
n = (int)(((long)curwin->w_cursor.lnum) /
((long)curbuf->b_ml.ml_line_count / 100L));
- else
+ } else {
n = (int)(((long)curwin->w_cursor.lnum * 100L) /
(long)curbuf->b_ml.ml_line_count);
+ }
if (curbuf->b_ml.ml_flags & ML_EMPTY) {
vim_snprintf_add((char *)buffer, IOSIZE, "%s", _(no_lines_msg));
} else if (p_ru) {
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index d696eedbb7..550f8a5e40 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -373,6 +373,10 @@ struct stl_hlrec {
#define SYNSPL_TOP 1 // spell check toplevel text
#define SYNSPL_NOTOP 2 // don't spell check toplevel text
+// values for b_syn_foldlevel: how to compute foldlevel on a line
+#define SYNFLD_START 0 // use level of item at start of line
+#define SYNFLD_MINIMUM 1 // use lowest local minimum level on line
+
// avoid #ifdefs for when b_spell is not available
# define B_SPELL(buf) ((buf)->b_spell)
@@ -398,6 +402,7 @@ typedef struct {
int b_syn_error; // TRUE when error occurred in HL
bool b_syn_slow; // true when 'redrawtime' reached
int b_syn_ic; // ignore case for :syn cmds
+ int b_syn_foldlevel; // how to compute foldlevel on a line
int b_syn_spell; // SYNSPL_ values
garray_T b_syn_patterns; // table for syntax patterns
garray_T b_syn_clusters; // table for syntax clusters
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 66cd0e09c6..b7e827e86b 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -8137,9 +8137,6 @@ void set_argv_var(char **argv, int argc)
list_T *l = tv_list_alloc(argc);
int i;
- if (l == NULL) {
- getout(1);
- }
tv_list_set_lock(l, VAR_FIXED);
for (i = 0; i < argc; i++) {
tv_list_append_string(l, (const char *const)argv[i], -1);
diff --git a/src/nvim/eval/typval_encode.c.h b/src/nvim/eval/typval_encode.c.h
index 0aa64b1d5f..91c948ce7e 100644
--- a/src/nvim/eval/typval_encode.c.h
+++ b/src/nvim/eval/typval_encode.c.h
@@ -364,7 +364,7 @@ static int _TYPVAL_ENCODE_CONVERT_ONE_VALUE(
_TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(tv->vval.v_list, lv_copyID, copyID,
kMPConvList);
TYPVAL_ENCODE_CONV_LIST_START(tv, tv_list_len(tv->vval.v_list));
- assert(saved_copyID != copyID && saved_copyID != copyID - 1);
+ assert(saved_copyID != copyID);
_mp_push(*mpstack, ((MPConvStackVal) {
.type = kMPConvList,
.tv = tv,
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index f29304867a..20f0cdccc3 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -569,20 +569,21 @@ readfile(
return FAIL;
}
}
- if (dir_of_file_exists(fname))
- filemess(curbuf, sfname, (char_u *)_("[New File]"), 0);
- else
- filemess(curbuf, sfname,
- (char_u *)_("[New DIRECTORY]"), 0);
- /* Even though this is a new file, it might have been
- * edited before and deleted. Get the old marks. */
+ if (dir_of_file_exists(fname)) {
+ filemess(curbuf, sfname, (char_u *)new_file_message(), 0);
+ } else {
+ filemess(curbuf, sfname, (char_u *)_("[New DIRECTORY]"), 0);
+ }
+ // Even though this is a new file, it might have been
+ // edited before and deleted. Get the old marks.
check_marks_read();
- /* Set forced 'fileencoding'. */
- if (eap != NULL)
+ // Set forced 'fileencoding'.
+ if (eap != NULL) {
set_forced_fenc(eap);
+ }
apply_autocmds_exarg(EVENT_BUFNEWFILE, sfname, sfname,
- FALSE, curbuf, eap);
- /* remember the current fileformat */
+ false, curbuf, eap);
+ // remember the current fileformat
save_file_ff(curbuf);
if (aborting()) /* autocmds may abort script processing */
@@ -2203,6 +2204,11 @@ static void check_marks_read(void)
curbuf->b_marks_read = true;
}
+char *new_file_message(void)
+{
+ return shortmess(SHM_NEW) ? _("[New]") : _("[New File]");
+}
+
/*
* buf_write() - write to file "fname" lines "start" through "end"
*
@@ -3513,8 +3519,8 @@ restore_backup:
STRCAT(IObuff, _("[Device]"));
c = TRUE;
} else if (newfile) {
- STRCAT(IObuff, shortmess(SHM_NEW) ? _("[New]") : _("[New File]"));
- c = TRUE;
+ STRCAT(IObuff, new_file_message());
+ c = true;
}
if (no_eol) {
msg_add_eol();
diff --git a/src/nvim/main.c b/src/nvim/main.c
index b3a903cbe3..ae64046d07 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -84,44 +84,11 @@
#endif
#include "nvim/api/vim.h"
-// Maximum number of commands from + or -c arguments.
-#define MAX_ARG_CMDS 10
-
// values for "window_layout"
#define WIN_HOR 1 // "-o" horizontally split windows
#define WIN_VER 2 // "-O" vertically split windows
#define WIN_TABS 3 // "-p" windows on tab pages
-// Struct for various parameters passed between main() and other functions.
-typedef struct {
- int argc;
- char **argv;
-
- char *use_vimrc; // vimrc from -u argument
-
- int n_commands; // no. of commands from + or -c
- char *commands[MAX_ARG_CMDS]; // commands from + or -c arg
- char_u cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
- int n_pre_commands; // no. of commands from --cmd
- char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
-
- int edit_type; // type of editing to do
- char_u *tagname; // tag from -t argument
- char_u *use_ef; // 'errorfile' from -q argument
-
- bool input_isatty; // stdin is a terminal
- bool output_isatty; // stdout is a terminal
- bool err_isatty; // stderr is a terminal
- int no_swap_file; // "-n" argument used
- int use_debug_break_level;
- int window_count; // number of windows to use
- int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS
-
- int diff_mode; // start with 'diff' set
-
- char *listen_addr; // --listen {address}
-} mparm_T;
-
// Values for edit_type.
#define EDIT_NONE 0 // no edit type yet
#define EDIT_FILE 1 // file name argument[s] given, use argument list
@@ -188,7 +155,7 @@ bool event_teardown(void)
/// Performs early initialization.
///
/// Needed for unit tests. Must be called after `time_init()`.
-void early_init(void)
+void early_init(mparm_T *paramp)
{
env_init();
fs_init();
@@ -222,7 +189,7 @@ void early_init(void)
// msg_outtrans_len_attr().
// First find out the home directory, needed to expand "~" in options.
init_homedir(); // find real value of $HOME
- set_init_1();
+ set_init_1(paramp != NULL ? paramp->clean : false);
log_init();
TIME_MSG("inits 1");
@@ -265,9 +232,17 @@ int main(int argc, char **argv)
init_startuptime(&params);
+ // Need to find "--clean" before actually parsing arguments.
+ for (int i = 1; i < params.argc; i++) {
+ if (STRICMP(params.argv[i], "--clean") == 0) {
+ params.clean = true;
+ break;
+ }
+ }
+
event_init();
- early_init();
+ early_init(&params);
set_argv_var(argv, argc); // set v:argv
@@ -291,6 +266,12 @@ int main(int argc, char **argv)
fname = get_fname(&params, cwd);
}
+ // Recovery mode without a file name: List swap files.
+ // In this case, no UI is needed.
+ if (recoverymode && fname == NULL) {
+ headless_mode = true;
+ }
+
TIME_MSG("expanding arguments");
if (params.diff_mode && params.window_count == -1)
@@ -862,6 +843,7 @@ static void command_line_scan(mparm_T *parmp)
argv_idx += 11;
} else if (STRNICMP(argv[0] + argv_idx, "clean", 5) == 0) {
parmp->use_vimrc = "NONE";
+ parmp->clean = true;
set_option_value("shadafile", 0L, "NONE", 0);
} else {
if (argv[0][argv_idx])
@@ -978,7 +960,6 @@ static void command_line_scan(mparm_T *parmp)
case 'r': // "-r" recovery mode
case 'L': { // "-L" recovery mode
recoverymode = 1;
- headless_mode = true;
break;
}
case 's': {
@@ -1277,9 +1258,8 @@ static void init_params(mparm_T *paramp, int argc, char **argv)
/// Initialize global startuptime file if "--startuptime" passed as an argument.
static void init_startuptime(mparm_T *paramp)
{
- for (int i = 1; i < paramp->argc; i++) {
- if (STRICMP(paramp->argv[i], "--startuptime") == 0
- && i + 1 < paramp->argc) {
+ for (int i = 1; i < paramp->argc - 1; i++) {
+ if (STRICMP(paramp->argv[i], "--startuptime") == 0) {
time_fd = os_fopen(paramp->argv[i + 1], "a");
time_start("--- NVIM STARTING ---");
break;
diff --git a/src/nvim/main.h b/src/nvim/main.h
index 86d25fe657..61252f2bce 100644
--- a/src/nvim/main.h
+++ b/src/nvim/main.h
@@ -4,8 +4,42 @@
#include "nvim/normal.h"
#include "nvim/event/loop.h"
+// Maximum number of commands from + or -c arguments.
+#define MAX_ARG_CMDS 10
+
extern Loop main_loop;
+// Struct for various parameters passed between main() and other functions.
+typedef struct {
+ int argc;
+ char **argv;
+
+ char *use_vimrc; // vimrc from -u argument
+ bool clean; // --clean argument
+
+ int n_commands; // no. of commands from + or -c
+ char *commands[MAX_ARG_CMDS]; // commands from + or -c arg
+ char_u cmds_tofree[MAX_ARG_CMDS]; // commands that need free()
+ int n_pre_commands; // no. of commands from --cmd
+ char *pre_commands[MAX_ARG_CMDS]; // commands from --cmd argument
+
+ int edit_type; // type of editing to do
+ char_u *tagname; // tag from -t argument
+ char_u *use_ef; // 'errorfile' from -q argument
+
+ bool input_isatty; // stdin is a terminal
+ bool output_isatty; // stdout is a terminal
+ bool err_isatty; // stderr is a terminal
+ int no_swap_file; // "-n" argument used
+ int use_debug_break_level;
+ int window_count; // number of windows to use
+ int window_layout; // 0, WIN_HOR, WIN_VER or WIN_TABS
+
+ int diff_mode; // start with 'diff' set
+
+ char *listen_addr; // --listen {address}
+} mparm_T;
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "main.h.generated.h"
#endif
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index eb32a1dd9b..e905029dae 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4671,17 +4671,23 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
int maxlen = 0;
pos_T startpos;
pos_T endpos;
+ colnr_T save_coladd = 0;
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX"
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal"
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
+ if (virtual_active()) {
+ save_coladd = pos->coladd;
+ pos->coladd = 0;
+ }
+
curwin->w_cursor = *pos;
ptr = ml_get(pos->lnum);
col = pos->col;
- if (*ptr == NUL) {
+ if (*ptr == NUL || col + !!save_coladd >= (int)STRLEN(ptr)) {
goto theend;
}
@@ -4976,6 +4982,8 @@ theend:
curwin->w_cursor = save_cursor;
} else if (did_change) {
curwin->w_set_curswant = true;
+ } else if (virtual_active()) {
+ curwin->w_cursor.coladd = save_coladd;
}
return did_change;
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 96f8e1529a..d789ad3587 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -524,11 +524,17 @@ char *get_lib_dir(void)
///
/// Windows: Uses "…/nvim-data" for kXDGDataHome to avoid storing
/// configuration and data files in the same path. #4403
-static void set_runtimepath_default(void)
+///
+/// If "clean_arg" is true, Nvim was started with --clean.
+static void set_runtimepath_default(bool clean_arg)
{
size_t rtp_size = 0;
- char *const data_home = stdpaths_get_xdg_var(kXDGDataHome);
- char *const config_home = stdpaths_get_xdg_var(kXDGConfigHome);
+ char *const data_home = clean_arg
+ ? NULL
+ : stdpaths_get_xdg_var(kXDGDataHome);
+ char *const config_home = clean_arg
+ ? NULL
+ : stdpaths_get_xdg_var(kXDGConfigHome);
char *const vimruntime = vim_getenv("VIMRUNTIME");
char *const libdir = get_lib_dir();
char *const data_dirs = stdpaths_get_xdg_var(kXDGDataDirs);
@@ -622,7 +628,8 @@ static void set_runtimepath_default(void)
/// Initialize the options, first part.
///
/// Called only once from main(), just after creating the first buffer.
-void set_init_1(void)
+/// If "clean_arg" is true, Nvim was started with --clean.
+void set_init_1(bool clean_arg)
{
int opt_idx;
@@ -765,7 +772,7 @@ void set_init_1(void)
true);
// Set default for &runtimepath. All necessary expansions are performed in
// this function.
- set_runtimepath_default();
+ set_runtimepath_default(clean_arg);
/*
* Set all the options (except the terminal options) to their default
@@ -2538,8 +2545,8 @@ static bool valid_filetype(const char_u *val)
return valid_name(val, ".-_");
}
-/// Return true if "val" is a valid 'spellang' value.
-bool valid_spellang(const char_u *val)
+/// Return true if "val" is a valid 'spelllang' value.
+bool valid_spelllang(const char_u *val)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return valid_name(val, ".-_,@");
@@ -3071,7 +3078,7 @@ ambw_end:
const bool is_spellfile = varp == &(curwin->w_s->b_p_spf);
if ((is_spellfile && !valid_spellfile(*varp))
- || (!is_spellfile && !valid_spellang(*varp))) {
+ || (!is_spellfile && !valid_spelllang(*varp))) {
errmsg = e_invarg;
} else {
errmsg = did_set_spell_option(is_spellfile);
@@ -5469,9 +5476,6 @@ static int put_setstring(FILE *fd, char *cmd, char *name,
// replace home directory in the whole option value into "buf"
buf = xmalloc(size);
- if (buf == NULL) {
- goto fail;
- }
home_replace(NULL, *valuep, buf, size, false);
// If the option value is longer than MAXPATHL, we need to append
@@ -5479,10 +5483,7 @@ static int put_setstring(FILE *fd, char *cmd, char *name,
// can be expanded when read back.
if (size >= MAXPATHL && (flags & P_COMMA) != 0
&& vim_strchr(*valuep, ',') != NULL) {
- part = xmalloc(size);
- if (part == NULL) {
- goto fail;
- }
+ part = xmalloc(size);
// write line break to clear the option, e.g. ':set rtp='
if (put_eol(fd) == FAIL) {
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 2ca5f42e51..387732fdee 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -4960,7 +4960,7 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
int c2_len = PTR2LEN(s2);
int c2 = PTR2CHAR(s2);
- if ((c1 != c2 && (!rex.reg_ic || mb_tolower(c1) != mb_tolower(c2)))
+ if ((c1 != c2 && (!rex.reg_ic || utf_fold(c1) != utf_fold(c2)))
|| c1_len != c2_len) {
match = false;
break;
@@ -5682,11 +5682,11 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
break;
}
if (rex.reg_ic) {
- int curc_low = mb_tolower(curc);
+ int curc_low = utf_fold(curc);
int done = false;
for (; c1 <= c2; c1++) {
- if (mb_tolower(c1) == curc_low) {
+ if (utf_fold(c1) == curc_low) {
result = result_if_matched;
done = TRUE;
break;
@@ -5698,8 +5698,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
}
} else if (state->c < 0 ? check_char_class(state->c, curc)
: (curc == state->c
- || (rex.reg_ic && mb_tolower(curc)
- == mb_tolower(state->c)))) {
+ || (rex.reg_ic
+ && utf_fold(curc) == utf_fold(state->c)))) {
result = result_if_matched;
break;
}
@@ -6106,7 +6106,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
result = (c == curc);
if (!result && rex.reg_ic) {
- result = mb_tolower(c) == mb_tolower(curc);
+ result = utf_fold(c) == utf_fold(curc);
}
// If rex.reg_icombine is not set only skip over the character
@@ -6260,8 +6260,9 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
// Checking if the required start character matches is
// cheaper than adding a state that won't match.
c = PTR2CHAR(reginput + clen);
- if (c != prog->regstart && (!rex.reg_ic || mb_tolower(c)
- != mb_tolower(prog->regstart))) {
+ if (c != prog->regstart
+ && (!rex.reg_ic
+ || utf_fold(c) != utf_fold(prog->regstart))) {
#ifdef REGEXP_DEBUG
fprintf(log_fd,
" Skipping start state, regstart does not match\n");
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 23086c629b..b105d99d7c 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -2326,9 +2326,9 @@ int findsent(Direction dir, long count)
func = decl;
while (count--) {
- /*
- * if on an empty line, skip up to a non-empty line
- */
+ const pos_T prev_pos = pos;
+
+ // if on an empty line, skip up to a non-empty line
if (gchar_pos(&pos) == NUL) {
do {
if ((*func)(&pos) == -1) {
@@ -2411,6 +2411,17 @@ found:
while (!noskip && ((c = gchar_pos(&pos)) == ' ' || c == '\t'))
if (incl(&pos) == -1)
break;
+
+ if (equalpos(prev_pos, pos)) {
+ // didn't actually move, advance one character and try again
+ if ((*func)(&pos) == -1) {
+ if (count) {
+ return FAIL;
+ }
+ break;
+ }
+ count++;
+ }
}
setpcmark();
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 180073ade1..4d8da1ba14 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -2007,7 +2007,7 @@ char_u *did_set_spelllang(win_T *wp)
region = NULL;
len = (int)STRLEN(lang);
- if (!valid_spellang(lang)) {
+ if (!valid_spelllang(lang)) {
continue;
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index f3b05c3961..4aa7c21ce4 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -121,6 +121,8 @@ static int hl_attr_table[] =
{ HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERCURL, HL_ITALIC, HL_INVERSE,
HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 };
+static char e_illegal_arg[] = N_("E390: Illegal argument: %s");
+
// The patterns that are being searched for are stored in a syn_pattern.
// A match item consists of one pattern.
// A start/end item consists of n start patterns and m end patterns.
@@ -3045,7 +3047,7 @@ static void syn_cmd_conceal(exarg_T *eap, int syncing)
} else if (STRNICMP(arg, "off", 3) == 0 && next - arg == 3) {
curwin->w_s->b_syn_conceal = false;
} else {
- EMSG2(_("E390: Illegal argument: %s"), arg);
+ EMSG2(_(e_illegal_arg), arg);
}
}
@@ -3073,7 +3075,42 @@ static void syn_cmd_case(exarg_T *eap, int syncing)
} else if (STRNICMP(arg, "ignore", 6) == 0 && next - arg == 6) {
curwin->w_s->b_syn_ic = true;
} else {
- EMSG2(_("E390: Illegal argument: %s"), arg);
+ EMSG2(_(e_illegal_arg), arg);
+ }
+}
+
+/// Handle ":syntax foldlevel" command.
+static void syn_cmd_foldlevel(exarg_T *eap, int syncing)
+{
+ char_u *arg = eap->arg;
+ char_u *arg_end;
+
+ eap->nextcmd = find_nextcmd(arg);
+ if (eap->skip)
+ return;
+
+ if (*arg == NUL) {
+ switch (curwin->w_s->b_syn_foldlevel) {
+ case SYNFLD_START: MSG(_("syntax foldlevel start")); break;
+ case SYNFLD_MINIMUM: MSG(_("syntax foldlevel minimum")); break;
+ default: break;
+ }
+ return;
+ }
+
+ arg_end = skiptowhite(arg);
+ if (STRNICMP(arg, "start", 5) == 0 && arg_end - arg == 5) {
+ curwin->w_s->b_syn_foldlevel = SYNFLD_START;
+ } else if (STRNICMP(arg, "minimum", 7) == 0 && arg_end - arg == 7) {
+ curwin->w_s->b_syn_foldlevel = SYNFLD_MINIMUM;
+ } else {
+ EMSG2(_(e_illegal_arg), arg);
+ return;
+ }
+
+ arg = skipwhite(arg_end);
+ if (*arg != NUL) {
+ EMSG2(_(e_illegal_arg), arg);
}
}
@@ -3105,7 +3142,7 @@ static void syn_cmd_spell(exarg_T *eap, int syncing)
} else if (STRNICMP(arg, "default", 7) == 0 && next - arg == 7) {
curwin->w_s->b_syn_spell = SYNSPL_DEFAULT;
} else {
- EMSG2(_("E390: Illegal argument: %s"), arg);
+ EMSG2(_(e_illegal_arg), arg);
return;
}
@@ -3161,6 +3198,7 @@ void syntax_clear(synblock_T *block)
block->b_syn_error = false; // clear previous error
block->b_syn_slow = false; // clear previous timeout
block->b_syn_ic = false; // Use case, by default
+ block->b_syn_foldlevel = SYNFLD_START;
block->b_syn_spell = SYNSPL_DEFAULT; // default spell checking
block->b_syn_containedin = false;
block->b_syn_conceal = false;
@@ -5485,6 +5523,7 @@ static struct subcommand subcommands[] =
{ "cluster", syn_cmd_cluster },
{ "conceal", syn_cmd_conceal },
{ "enable", syn_cmd_enable },
+ { "foldlevel", syn_cmd_foldlevel },
{ "include", syn_cmd_include },
{ "iskeyword", syn_cmd_iskeyword },
{ "keyword", syn_cmd_keyword },
@@ -5763,6 +5802,17 @@ int syn_get_stack_item(int i)
return CUR_STATE(i).si_id;
}
+static int syn_cur_foldlevel(void)
+{
+ int level = 0;
+ for (int i = 0; i < current_state.ga_len; i++) {
+ if (CUR_STATE(i).si_flags & HL_FOLD) {
+ level++;
+ }
+ }
+ return level;
+}
+
/*
* Function called to get folding level for line "lnum" in window "wp".
*/
@@ -5776,9 +5826,22 @@ int syn_get_foldlevel(win_T *wp, long lnum)
&& !wp->w_s->b_syn_slow) {
syntax_start(wp, lnum);
- for (int i = 0; i < current_state.ga_len; ++i) {
- if (CUR_STATE(i).si_flags & HL_FOLD) {
- ++level;
+ // Start with the fold level at the start of the line.
+ level = syn_cur_foldlevel();
+
+ if (wp->w_s->b_syn_foldlevel == SYNFLD_MINIMUM) {
+ // Find the lowest fold level that is followed by a higher one.
+ int cur_level = level;
+ int low_level = cur_level;
+ while (!current_finished) {
+ (void)syn_current_attr(false, false, NULL, false);
+ cur_level = syn_cur_foldlevel();
+ if (cur_level < low_level) {
+ low_level = cur_level;
+ } else if (cur_level > low_level) {
+ level = low_level;
+ }
+ current_col++;
}
}
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index a096b77ac6..6a13341a89 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -489,7 +489,17 @@ static int terminal_execute(VimState *state, int key)
terminal_send_key(s->term, key);
}
- return curbuf->handle == s->term->buf_handle;
+ if (curbuf->terminal == NULL) {
+ return 0;
+ }
+ if (s->term != curbuf->terminal) {
+ invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
+ invalidate_terminal(curbuf->terminal,
+ curbuf->terminal->cursor.row,
+ curbuf->terminal->cursor.row + 1);
+ s->term = curbuf->terminal;
+ }
+ return 1;
}
void terminal_destroy(Terminal *term)
diff --git a/src/nvim/testdir/summarize.vim b/src/nvim/testdir/summarize.vim
index 4e4135287b..7f8f758a71 100644
--- a/src/nvim/testdir/summarize.vim
+++ b/src/nvim/testdir/summarize.vim
@@ -28,7 +28,7 @@ if 1
" This uses the :s command to just fetch and process the output of the
" tests, it doesn't actually replace anything.
" And it uses "silent" to avoid reporting the number of matches.
- silent %s/^Executed\s\+\zs\d\+\ze\s\+tests\?/\=Count(submatch(0),'executed')/egn
+ silent %s/Executed\s\+\zs\d\+\ze\s\+tests\?/\=Count(submatch(0),'executed')/egn
silent %s/^SKIPPED \zs.*/\=Count(submatch(0), 'skipped')/egn
silent %s/^\(\d\+\)\s\+FAILED:/\=Count(submatch(1), 'failed')/egn
diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim
index 5217aa7339..d116246ef3 100644
--- a/src/nvim/testdir/test_autocmd.vim
+++ b/src/nvim/testdir/test_autocmd.vim
@@ -1252,6 +1252,10 @@ func Test_TextYankPost()
call assert_equal(
\{'regcontents': ['foo'], 'inclusive': v:false, 'regname': '', 'operator': 'y', 'visual': v:false, 'regtype': 'V'},
\g:event)
+ norm Vy
+ call assert_equal(
+ \{'regcontents': ['foo'], 'inclusive': v:true, 'regname': '', 'operator': 'y', 'visual': v:true, 'regtype': 'V'},
+ \g:event)
call feedkeys("\<C-V>y", 'x')
call assert_equal(
\{'regcontents': ['f'], 'inclusive': v:true, 'regname': '', 'operator': 'y', 'visual': v:true, 'regtype': "\x161"},
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index ffd2cee80f..9303fac927 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -131,7 +131,7 @@ let s:filename_checks = {
\ 'def': ['file.def'],
\ 'denyhosts': ['denyhosts.conf'],
\ 'desc': ['file.desc'],
- \ 'desktop': ['file.desktop', '.directory'],
+ \ 'desktop': ['file.desktop', '.directory', 'file.directory'],
\ 'dictconf': ['dict.conf', '.dictrc'],
\ 'dictdconf': ['dictd.conf'],
\ 'diff': ['file.diff', 'file.rej'],
@@ -329,7 +329,7 @@ let s:filename_checks = {
\ 'pccts': ['file.g'],
\ 'pdf': ['file.pdf'],
\ 'perl': ['file.plx', 'file.al', 'file.psgi', 'gitolite.rc', '.gitolite.rc', 'example.gitolite.rc'],
- \ 'perl6': ['file.p6', 'file.pm6', 'file.pl6'],
+ \ 'perl6': ['file.p6', 'file.pm6', 'file.pl6', 'file.raku', 'file.rakumod'],
\ 'pf': ['pf.conf'],
\ 'pfmain': ['main.cf'],
\ 'php': ['file.php', 'file.php9', 'file.phtml', 'file.ctp'],
@@ -360,7 +360,7 @@ let s:filename_checks = {
\ 'protocols': ['/etc/protocols'],
\ 'psf': ['file.psf'],
\ 'pyrex': ['file.pyx', 'file.pxd'],
- \ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi'],
+ \ 'python': ['file.py', 'file.pyw', '.pythonstartup', '.pythonrc', 'file.ptl', 'file.pyi', 'SConstruct'],
\ 'quake': ['anybaseq2/file.cfg', 'anyid1/file.cfg', 'quake3/file.cfg'],
\ 'radiance': ['file.rad', 'file.mat'],
\ 'ratpoison': ['.ratpoisonrc', 'ratpoisonrc'],
@@ -427,8 +427,8 @@ let s:filename_checks = {
\ 'sqr': ['file.sqr', 'file.sqi'],
\ 'squid': ['squid.conf'],
\ 'srec': ['file.s19', 'file.s28', 'file.s37', 'file.mot', 'file.srec'],
- \ 'sshconfig': ['ssh_config', '/.ssh/config'],
- \ 'sshdconfig': ['sshd_config'],
+ \ 'sshconfig': ['ssh_config', '/.ssh/config', '/etc/ssh/ssh_config.d/file.conf', 'any/etc/ssh/ssh_config.d/file.conf'],
+ \ 'sshdconfig': ['sshd_config', '/etc/ssh/sshd_config.d/file.conf', 'any/etc/ssh/sshd_config.d/file.conf'],
\ 'st': ['file.st'],
\ 'stata': ['file.ado', 'file.do', 'file.imata', 'file.mata'],
\ 'stp': ['file.stp'],
@@ -439,7 +439,7 @@ let s:filename_checks = {
\ 'swiftgyb': ['file.swift.gyb'],
\ 'sil': ['file.sil'],
\ 'sysctl': ['/etc/sysctl.conf', '/etc/sysctl.d/file.conf'],
- \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.mount', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile'],
+ \ 'systemd': ['any/systemd/file.automount', 'any/systemd/file.dnssd', 'any/systemd/file.link', 'any/systemd/file.mount', 'any/systemd/file.netdev', 'any/systemd/file.network', 'any/systemd/file.nspawn', 'any/systemd/file.path', 'any/systemd/file.service', 'any/systemd/file.slice', 'any/systemd/file.socket', 'any/systemd/file.swap', 'any/systemd/file.target', 'any/systemd/file.timer', '/etc/systemd/some.conf.d/file.conf', '/etc/systemd/system/some.d/file.conf', '/etc/systemd/system/some.d/.#file', '/etc/systemd/system/.#otherfile', '/home/user/.config/systemd/user/some.d/mine.conf', '/home/user/.config/systemd/user/some.d/.#file', '/home/user/.config/systemd/user/.#otherfile'],
\ 'systemverilog': ['file.sv', 'file.svh'],
\ 'tags': ['tags'],
\ 'tak': ['file.tak'],
@@ -606,9 +606,19 @@ let s:script_checks = {
\ 'yaml': [['%YAML 1.2']],
\ }
-func Test_script_detection()
+" Various forms of "env" optional arguments.
+let s:script_env_checks = {
+ \ 'perl': [['#!/usr/bin/env VAR=val perl']],
+ \ 'scala': [['#!/usr/bin/env VAR=val VVAR=vval scala']],
+ \ 'awk': [['#!/usr/bin/env VAR=val -i awk']],
+ \ 'scheme': [['#!/usr/bin/env VAR=val --ignore-environment scheme']],
+ \ 'python': [['#!/usr/bin/env VAR=val -S python -w -T']],
+ \ 'wml': [['#!/usr/bin/env VAR=val --split-string wml']],
+ \ }
+
+func Run_script_detection(test_dict)
filetype on
- for [ft, files] in items(s:script_checks)
+ for [ft, files] in items(a:test_dict)
for file in files
call writefile(file, 'Xtest')
split Xtest
@@ -620,6 +630,11 @@ func Test_script_detection()
filetype off
endfunc
+func Test_script_detection()
+ call Run_script_detection(s:script_checks)
+ call Run_script_detection(s:script_env_checks)
+endfunc
+
func Test_setfiletype_completion()
call feedkeys(":setfiletype java\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"setfiletype java javacc javascript javascriptreact', @:)
diff --git a/src/nvim/testdir/test_increment.vim b/src/nvim/testdir/test_increment.vim
index ab11d943d9..f81f8edbde 100644
--- a/src/nvim/testdir/test_increment.vim
+++ b/src/nvim/testdir/test_increment.vim
@@ -779,4 +779,40 @@ func Test_increment_empty_line()
bwipe!
endfunc
+func Test_normal_increment_with_virtualedit()
+ set virtualedit=all
+
+ call setline(1, ["\<TAB>1"])
+ exec "norm! 0\<C-A>"
+ call assert_equal("\<TAB>2", getline(1))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+
+ call setline(1, ["\<TAB>1"])
+ exec "norm! 0l\<C-A>"
+ call assert_equal("\<TAB>2", getline(1))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+
+ call setline(1, ["\<TAB>1"])
+ exec "norm! 07l\<C-A>"
+ call assert_equal("\<TAB>2", getline(1))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+
+ call setline(1, ["\<TAB>1"])
+ exec "norm! 0w\<C-A>"
+ call assert_equal("\<TAB>2", getline(1))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+
+ call setline(1, ["\<TAB>1"])
+ exec "norm! 0wl\<C-A>"
+ call assert_equal("\<TAB>1", getline(1))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["\<TAB>1"])
+ exec "norm! 0w30l\<C-A>"
+ call assert_equal("\<TAB>1", getline(1))
+ call assert_equal([0, 1, 3, 29], getpos('.'))
+
+ set virtualedit&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_regexp_utf8.vim b/src/nvim/testdir/test_regexp_utf8.vim
index ecd0e8d56b..f48458566b 100644
--- a/src/nvim/testdir/test_regexp_utf8.vim
+++ b/src/nvim/testdir/test_regexp_utf8.vim
@@ -332,4 +332,23 @@ func Test_ambiwidth()
set regexpengine& ambiwidth&
endfunc
+func Run_regexp_ignore_case()
+ call assert_equal('iIİ', substitute('iIİ', '\([iIİ]\)', '\1', 'g'))
+
+ call assert_equal('iIx', substitute('iIİ', '\c\([İ]\)', 'x', 'g'))
+ call assert_equal('xxİ', substitute('iIİ', '\(i\c\)', 'x', 'g'))
+ call assert_equal('iIx', substitute('iIİ', '\(İ\c\)', 'x', 'g'))
+ call assert_equal('iIx', substitute('iIİ', '\c\(\%u0130\)', 'x', 'g'))
+ call assert_equal('iIx', substitute('iIİ', '\c\([\u0130]\)', 'x', 'g'))
+ call assert_equal('iIx', substitute('iIİ', '\c\([\u012f-\u0131]\)', 'x', 'g'))
+endfunc
+
+func Test_regexp_ignore_case()
+ set regexpengine=1
+ call Run_regexp_ignore_case()
+ set regexpengine=2
+ call Run_regexp_ignore_case()
+ set regexpengine&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_syntax.vim b/src/nvim/testdir/test_syntax.vim
index 6cada1503f..85ee42420e 100644
--- a/src/nvim/testdir/test_syntax.vim
+++ b/src/nvim/testdir/test_syntax.vim
@@ -153,7 +153,7 @@ endfunc
func Test_syntax_completion()
call feedkeys(":syn \<C-A>\<C-B>\"\<CR>", 'tx')
- call assert_equal('"syn case clear cluster conceal enable include iskeyword keyword list manual match off on region reset spell sync', @:)
+ call assert_equal('"syn case clear cluster conceal enable foldlevel include iskeyword keyword list manual match off on region reset spell sync', @:)
call feedkeys(":syn case \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syn case ignore match', @:)
@@ -579,3 +579,86 @@ func Test_syntax_hangs()
set redrawtime&
bwipe!
endfunc
+
+func Test_syntax_foldlevel()
+ new
+ call setline(1, [
+ \ 'void f(int a)',
+ \ '{',
+ \ ' if (a == 1) {',
+ \ ' a = 0;',
+ \ ' } else if (a == 2) {',
+ \ ' a = 1;',
+ \ ' } else {',
+ \ ' a = 2;',
+ \ ' }',
+ \ ' if (a > 0) {',
+ \ ' if (a == 1) {',
+ \ ' a = 0;',
+ \ ' } /* missing newline */ } /* end of outer if */ else {',
+ \ ' a = 1;',
+ \ ' }',
+ \ ' if (a == 1)',
+ \ ' {',
+ \ ' a = 0;',
+ \ ' }',
+ \ ' else if (a == 2)',
+ \ ' {',
+ \ ' a = 1;',
+ \ ' }',
+ \ ' else',
+ \ ' {',
+ \ ' a = 2;',
+ \ ' }',
+ \ '}',
+ \ ])
+ setfiletype c
+ syntax on
+ set foldmethod=syntax
+
+ call assert_fails('syn foldlevel start start', 'E390')
+ call assert_fails('syn foldlevel not_an_option', 'E390')
+
+ set foldlevel=1
+
+ syn foldlevel start
+ redir @c
+ syn foldlevel
+ redir END
+ call assert_equal("\nsyntax foldlevel start", @c)
+ syn sync fromstart
+ let a = map(range(3,9), 'foldclosed(v:val)')
+ call assert_equal([3,3,3,3,3,3,3], a) " attached cascade folds together
+ let a = map(range(10,15), 'foldclosed(v:val)')
+ call assert_equal([10,10,10,10,10,10], a) " over-attached 'else' hidden
+ let a = map(range(16,27), 'foldclosed(v:val)')
+ let unattached_results = [-1,17,17,17,-1,21,21,21,-1,25,25,25]
+ call assert_equal(unattached_results, a) " unattached cascade folds separately
+
+ syn foldlevel minimum
+ redir @c
+ syn foldlevel
+ redir END
+ call assert_equal("\nsyntax foldlevel minimum", @c)
+ syn sync fromstart
+ let a = map(range(3,9), 'foldclosed(v:val)')
+ call assert_equal([3,3,5,5,7,7,7], a) " attached cascade folds separately
+ let a = map(range(10,15), 'foldclosed(v:val)')
+ call assert_equal([10,10,10,13,13,13], a) " over-attached 'else' visible
+ let a = map(range(16,27), 'foldclosed(v:val)')
+ call assert_equal(unattached_results, a) " unattached cascade folds separately
+
+ set foldlevel=2
+
+ syn foldlevel start
+ syn sync fromstart
+ let a = map(range(11,14), 'foldclosed(v:val)')
+ call assert_equal([11,11,11,-1], a) " over-attached 'else' hidden
+
+ syn foldlevel minimum
+ syn sync fromstart
+ let a = map(range(11,14), 'foldclosed(v:val)')
+ call assert_equal([11,11,-1,-1], a) " over-attached 'else' visible
+
+ quit!
+endfunc
diff --git a/src/nvim/testdir/test_tagjump.vim b/src/nvim/testdir/test_tagjump.vim
index 5fd71d8bfc..6abe5b7c89 100644
--- a/src/nvim/testdir/test_tagjump.vim
+++ b/src/nvim/testdir/test_tagjump.vim
@@ -255,8 +255,52 @@ func Test_tagjump_etags()
ta foo
call assert_equal('void foo() {}', getline('.'))
+ " Test for including another tags file
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ "void foo() {}\x7ffoo\x011,0",
+ \ "\x0c",
+ \ "Xnonexisting,include",
+ \ "\x0c",
+ \ "Xtags2,include"
+ \ ], 'Xtags')
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ "int main(int argc, char **argv)\x7fmain\x012,14",
+ \ ], 'Xtags2')
+ tag main
+ call assert_equal(2, line('.'))
+
+ " corrupted tag line
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,8",
+ \ "int main"
+ \ ], 'Xtags', 'b')
+ call assert_fails('tag foo', 'E426:')
+
+ " invalid line number
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ "void foo() {}\x7ffoo\x0abc,0",
+ \ ], 'Xtags')
+ call assert_fails('tag foo', 'E426:')
+
+ " invalid tag name
+ call writefile([
+ \ "\x0c",
+ \ "Xmain.c,64",
+ \ ";;;;\x7f1,0",
+ \ ], 'Xtags')
+ call assert_fails('tag foo', 'E426:')
+
call delete('Xtags')
+ call delete('Xtags2')
call delete('Xmain.c')
+ set tags&
bwipe!
endfunc
@@ -531,4 +575,29 @@ func Test_tagline()
set tags&
endfunc
+" Test for the 'taglength' option
+func Test_tag_length()
+ set tags=Xtags
+ call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
+ \ "tame\tXfile1\t1;",
+ \ "tape\tXfile2\t1;"], 'Xtags')
+ call writefile(['tame'], 'Xfile1')
+ call writefile(['tape'], 'Xfile2')
+
+ " Jumping to the tag 'tape', should instead jump to 'tame'
+ new
+ set taglength=2
+ tag tape
+ call assert_equal('Xfile1', @%)
+ " Tag search should jump to the right tag
+ enew
+ tag /^tape$
+ call assert_equal('Xfile2', @%)
+
+ call delete('Xtags')
+ call delete('Xfile1')
+ call delete('Xfile2')
+ set tags& taglength&
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/testdir/test_textobjects.vim b/src/nvim/testdir/test_textobjects.vim
index b20c4df311..7863317eb0 100644
--- a/src/nvim/testdir/test_textobjects.vim
+++ b/src/nvim/testdir/test_textobjects.vim
@@ -290,5 +290,16 @@ func! Test_sentence_with_cursor_on_delimiter()
normal! 17|yas
call assert_equal("A '([sentence.])' ", @")
+ " don't get stuck on a quote at the start of a sentence
+ %delete _
+ call setline(1, ['A sentence.', '"A sentence"?', 'A sentence!'])
+ normal gg))
+ call assert_equal(3, getcurpos()[1])
+
+ %delete _
+ call setline(1, ['A sentence.', "'A sentence'?", 'A sentence!'])
+ normal gg))
+ call assert_equal(3, getcurpos()[1])
+
%delete _
endfunc