aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/buffer.c12
-rw-r--r--src/nvim/api/private/helpers.c8
-rw-r--r--src/nvim/buffer_defs.h10
-rw-r--r--src/nvim/channel.c1
-rw-r--r--src/nvim/channel.h2
-rw-r--r--src/nvim/charset.c1
-rw-r--r--src/nvim/diff.c17
-rw-r--r--src/nvim/edit.c4
-rw-r--r--src/nvim/eval.c36
-rw-r--r--src/nvim/eval.lua1
-rw-r--r--src/nvim/eval/funcs.c37
-rw-r--r--src/nvim/eval/typval.h4
-rw-r--r--src/nvim/ex_cmds.c23
-rw-r--r--src/nvim/ex_cmds.lua39
-rw-r--r--src/nvim/ex_cmds_defs.h59
-rw-r--r--src/nvim/ex_docmd.c6
-rw-r--r--src/nvim/ex_getln.c2
-rw-r--r--src/nvim/extmark.c14
-rw-r--r--src/nvim/fold.c6
-rw-r--r--src/nvim/getchar.h4
-rw-r--r--src/nvim/globals.h537
-rw-r--r--src/nvim/indent_c.c9
-rw-r--r--src/nvim/lua/executor.c152
-rw-r--r--src/nvim/lua/treesitter.c5
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/marktree.c6
-rw-r--r--src/nvim/mbyte.c126
-rw-r--r--src/nvim/mouse.c11
-rw-r--r--src/nvim/move.c2
-rw-r--r--src/nvim/msgpack_rpc/channel.h2
-rw-r--r--src/nvim/normal.c8
-rw-r--r--src/nvim/ops.c58
-rw-r--r--src/nvim/option.c31
-rw-r--r--src/nvim/options.lua5
-rw-r--r--src/nvim/os/shell.c1
-rw-r--r--src/nvim/screen.c32
-rw-r--r--src/nvim/sign.c210
-rw-r--r--src/nvim/testdir/test_diffmode.vim10
-rw-r--r--src/nvim/testdir/test_filetype.vim1
-rw-r--r--src/nvim/testdir/test_messages.vim31
-rw-r--r--src/nvim/testdir/test_number.vim11
-rw-r--r--src/nvim/testdir/test_options.vim8
-rw-r--r--src/nvim/testdir/test_restricted.vim103
-rw-r--r--src/nvim/testdir/test_search.vim6
-rw-r--r--src/nvim/testdir/test_signs.vim413
-rw-r--r--src/nvim/testdir/test_timers.vim4
-rw-r--r--src/nvim/tui/tui.c1
-rw-r--r--src/nvim/version.c4
-rw-r--r--src/nvim/viml/parser/expressions.h4
-rw-r--r--src/nvim/window.c22
-rw-r--r--src/tree_sitter/api.h37
-rw-r--r--src/tree_sitter/array.h28
-rw-r--r--src/tree_sitter/atomic.h4
-rw-r--r--src/tree_sitter/bits.h2
-rw-r--r--src/tree_sitter/language.h14
-rw-r--r--src/tree_sitter/lexer.c13
-rw-r--r--src/tree_sitter/lexer.h2
-rw-r--r--src/tree_sitter/parser.c61
-rw-r--r--src/tree_sitter/query.c218
-rw-r--r--src/tree_sitter/stack.c2
-rw-r--r--src/tree_sitter/subtree.c13
-rw-r--r--src/tree_sitter/subtree.h4
62 files changed, 1741 insertions, 757 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 645fb653e5..7578f0fbc5 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -1123,7 +1123,7 @@ ArrayOf(Integer) nvim_buf_get_extmark_by_id(Buffer buffer, Integer ns_id,
}
if (!ns_initialized((uint64_t)ns_id)) {
- api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
+ api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
return rv;
}
@@ -1190,7 +1190,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start,
}
if (!ns_initialized((uint64_t)ns_id)) {
- api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
+ api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
return rv;
}
Integer limit = -1;
@@ -1280,7 +1280,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id,
}
if (!ns_initialized((uint64_t)ns_id)) {
- api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
+ api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
return 0;
}
@@ -1308,7 +1308,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer id,
if (id >= 0) {
id_num = (uint64_t)id;
} else {
- api_set_error(err, kErrorTypeValidation, _("Invalid mark id"));
+ api_set_error(err, kErrorTypeValidation, "Invalid mark id");
return 0;
}
@@ -1337,7 +1337,7 @@ Boolean nvim_buf_del_extmark(Buffer buffer,
return false;
}
if (!ns_initialized((uint64_t)ns_id)) {
- api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
+ api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
return false;
}
@@ -1655,7 +1655,7 @@ Integer nvim__buf_add_decoration(Buffer buffer, Integer ns_id, String hl_group,
}
if (!ns_initialized((uint64_t)ns_id)) {
- api_set_error(err, kErrorTypeValidation, _("Invalid ns_id"));
+ api_set_error(err, kErrorTypeValidation, "Invalid ns_id");
return 0;
}
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index a1745ef777..a458762cc6 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1544,7 +1544,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
*col = MAXCOL;
return true;
} else if (id < 0) {
- api_set_error(err, kErrorTypeValidation, _("Mark id must be positive"));
+ api_set_error(err, kErrorTypeValidation, "Mark id must be positive");
return false;
}
@@ -1554,7 +1554,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
*col = extmark.col;
return true;
} else {
- api_set_error(err, kErrorTypeValidation, _("No mark with requested id"));
+ api_set_error(err, kErrorTypeValidation, "No mark with requested id");
return false;
}
@@ -1565,7 +1565,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
|| pos.items[0].type != kObjectTypeInteger
|| pos.items[1].type != kObjectTypeInteger) {
api_set_error(err, kErrorTypeValidation,
- _("Position must have 2 integer elements"));
+ "Position must have 2 integer elements");
return false;
}
Integer pos_row = pos.items[0].data.integer;
@@ -1575,7 +1575,7 @@ bool extmark_get_index_from_obj(buf_T *buf, Integer ns_id, Object obj, int
return true;
} else {
api_set_error(err, kErrorTypeValidation,
- _("Position must be a mark id Integer or position Array"));
+ "Position must be a mark id Integer or position Array");
return false;
}
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 9cdf36e4ed..1f943b25b6 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -166,11 +166,11 @@ typedef struct {
char_u *wo_briopt;
# define w_p_briopt w_onebuf_opt.wo_briopt /* 'breakindentopt' */
int wo_diff;
-# define w_p_diff w_onebuf_opt.wo_diff /* 'diff' */
- long wo_fdc;
-# define w_p_fdc w_onebuf_opt.wo_fdc /* 'foldcolumn' */
- int wo_fdc_save;
-# define w_p_fdc_save w_onebuf_opt.wo_fdc_save /* 'foldenable' saved for diff mode */
+# define w_p_diff w_onebuf_opt.wo_diff // 'diff'
+ char_u *wo_fdc;
+# define w_p_fdc w_onebuf_opt.wo_fdc // 'foldcolumn'
+ char_u *wo_fdc_save;
+# define w_p_fdc_save w_onebuf_opt.wo_fdc_save // 'fdc' saved for diff mode
int wo_fen;
# define w_p_fen w_onebuf_opt.wo_fen /* 'foldenable' */
int wo_fen_save;
diff --git a/src/nvim/channel.c b/src/nvim/channel.c
index c66a0682e3..5eb29a7290 100644
--- a/src/nvim/channel.c
+++ b/src/nvim/channel.c
@@ -19,7 +19,6 @@
#include "nvim/ascii.h"
static bool did_stdio = false;
-PMap(uint64_t) *channels = NULL;
/// next free id for a job or rpc channel
/// 1 is reserved for stdio channel
diff --git a/src/nvim/channel.h b/src/nvim/channel.h
index c733e276be..9d26852ce5 100644
--- a/src/nvim/channel.h
+++ b/src/nvim/channel.h
@@ -85,7 +85,7 @@ struct Channel {
bool callback_scheduled;
};
-EXTERN PMap(uint64_t) *channels;
+EXTERN PMap(uint64_t) *channels INIT(= NULL);
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "channel.h.generated.h"
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 0f9e2e23c0..f9d5adbc12 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1570,6 +1570,7 @@ char_u* skiptohex(char_u *q)
///
/// @return Pointer to the next whitespace or NUL character.
char_u *skiptowhite(const char_u *p)
+ FUNC_ATTR_NONNULL_ALL
{
while (*p != ' ' && *p != '\t' && *p != NUL) {
p++;
diff --git a/src/nvim/diff.c b/src/nvim/diff.c
index 04309444d9..f8b7592d0b 100644
--- a/src/nvim/diff.c
+++ b/src/nvim/diff.c
@@ -1385,11 +1385,18 @@ void diff_win_options(win_T *wp, int addbuf)
curbuf = curwin->w_buffer;
if (!wp->w_p_diff) {
- wp->w_p_fdc_save = wp->w_p_fdc;
wp->w_p_fen_save = wp->w_p_fen;
wp->w_p_fdl_save = wp->w_p_fdl;
+
+ if (wp->w_p_diff_saved) {
+ free_string_option(wp->w_p_fdc_save);
+ }
+ wp->w_p_fdc_save = vim_strsave(wp->w_p_fdc);
}
- wp->w_p_fdc = diff_foldcolumn;
+ xfree(wp->w_p_fdc);
+ wp->w_p_fdc = (char_u *)xstrdup("2");
+ assert(diff_foldcolumn >= 0 && diff_foldcolumn <= 9);
+ snprintf((char *)wp->w_p_fdc, STRLEN(wp->w_p_fdc) + 1, "%d", diff_foldcolumn);
wp->w_p_fen = true;
wp->w_p_fdl = 0;
foldUpdateAll(wp);
@@ -1443,9 +1450,9 @@ void ex_diffoff(exarg_T *eap)
wp->w_p_fdm = vim_strsave(*wp->w_p_fdm_save
? wp->w_p_fdm_save
: (char_u *)"manual");
- if (wp->w_p_fdc == diff_foldcolumn) {
- wp->w_p_fdc = wp->w_p_fdc_save;
- }
+ free_string_option(wp->w_p_fdc);
+ wp->w_p_fdc = vim_strsave(wp->w_p_fdc_save);
+
if (wp->w_p_fdl == 0) {
wp->w_p_fdl = wp->w_p_fdl_save;
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 3e57bc8599..f938607f17 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -4083,7 +4083,7 @@ static int ins_compl_get_exp(pos_T *ini)
type = CTRL_X_PATH_DEFINES;
else if (*e_cpt == ']' || *e_cpt == 't') {
type = CTRL_X_TAGS;
- vim_snprintf((char *)IObuff, IOSIZE, _("Scanning tags."));
+ vim_snprintf((char *)IObuff, IOSIZE, "%s", _("Scanning tags."));
(void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
} else {
type = -1;
@@ -6215,7 +6215,7 @@ comp_textwidth (
if (cmdwin_type != 0) {
textwidth -= 1;
}
- textwidth -= curwin->w_p_fdc;
+ textwidth -= win_fdccol_count(curwin);
textwidth -= win_signcol_count(curwin);
if (curwin->w_p_nu || curwin->w_p_rnu)
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 74a5edc0df..ca0e078e4a 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -8114,10 +8114,16 @@ void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
bool callback_from_typval(Callback *const callback, typval_T *const arg)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
+ int r = OK;
+
if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL) {
callback->data.partial = arg->vval.v_partial;
callback->data.partial->pt_refcount++;
callback->type = kCallbackPartial;
+ } else if (arg->v_type == VAR_STRING
+ && arg->vval.v_string != NULL
+ && ascii_isdigit(*arg->vval.v_string)) {
+ r = FAIL;
} else if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING) {
char_u *name = arg->vval.v_string;
func_ref(name);
@@ -8126,6 +8132,10 @@ bool callback_from_typval(Callback *const callback, typval_T *const arg)
} else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0) {
callback->type = kCallbackNone;
} else {
+ r = FAIL;
+ }
+
+ if (r == FAIL) {
EMSG(_("E921: Invalid callback argument"));
return false;
}
@@ -9459,6 +9469,27 @@ void set_selfdict(typval_T *rettv, dict_T *selfdict)
}
}
+// Turn a typeval into a string. Similar to tv_get_string_buf() but uses
+// string() on Dict, List, etc.
+static const char *tv_stringify(typval_T *varp, char *buf)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (varp->v_type == VAR_LIST
+ || varp->v_type == VAR_DICT
+ || varp->v_type == VAR_FUNC
+ || varp->v_type == VAR_PARTIAL
+ || varp->v_type == VAR_FLOAT) {
+ typval_T tmp;
+
+ f_string(varp, &tmp, NULL);
+ const char *const res = tv_get_string_buf(&tmp, buf);
+ tv_clear(varp);
+ *varp = tmp;
+ return res;
+ }
+ return tv_get_string_buf(varp, buf);
+}
+
// Find variable "name" in the list of variables.
// Return a pointer to it if found, NULL if not found.
// Careful: "a:0" variables don't have a name.
@@ -10349,7 +10380,10 @@ void ex_execute(exarg_T *eap)
}
if (!eap->skip) {
- const char *const argstr = tv_get_string(&rettv);
+ char buf[NUMBUFLEN];
+ const char *const argstr = eap->cmdidx == CMD_execute
+ ? tv_get_string_buf(&rettv, buf)
+ : tv_stringify(&rettv, buf);
const size_t len = strlen(argstr);
ga_grow(&ga, len + 2);
if (!GA_EMPTY(&ga)) {
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua
index 4654f8cef6..d3e769a7ef 100644
--- a/src/nvim/eval.lua
+++ b/src/nvim/eval.lua
@@ -102,6 +102,7 @@ return {
exists={args=1},
exp={args=1, func="float_op_wrapper", data="&exp"},
expand={args={1, 3}},
+ expandcmd={args=1},
extend={args={2, 3}},
feedkeys={args={1, 2}},
file_readable={args=1, func='f_filereadable'}, -- obsolete
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index bd57cec794..6d67279e64 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -2103,6 +2103,31 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, FunPtr fptr)
menu_get((char_u *)tv_get_string(&argvars[0]), modes, rettv->vval.v_list);
}
+// "expandcmd()" function
+// Expand all the special characters in a command string.
+static void f_expandcmd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+{
+ char_u *errormsg = NULL;
+
+ rettv->v_type = VAR_STRING;
+ char_u *cmdstr = (char_u *)xstrdup(tv_get_string(&argvars[0]));
+
+ exarg_T eap = {
+ .cmd = cmdstr,
+ .arg = cmdstr,
+ .usefilter = false,
+ .nextcmd = NULL,
+ .cmdidx = CMD_USER,
+ };
+ eap.argt |= NOSPC;
+
+ expand_filename(&eap, &cmdstr, &errormsg);
+ if (errormsg != NULL && *errormsg != NUL) {
+ EMSG(errormsg);
+ }
+ rettv->vval.v_string = cmdstr;
+}
+
/*
* "extend(list, list [, idx])" function
* "extend(dict, dict [, action])" function
@@ -4292,7 +4317,7 @@ static void f_histadd(typval_T *argvars, typval_T *rettv, FunPtr fptr)
HistoryType histype;
rettv->vval.v_number = false;
- if (check_restricted() || check_secure()) {
+ if (check_secure()) {
return;
}
const char *str = tv_get_string_chk(&argvars[0]); // NULL on type error
@@ -5272,7 +5297,6 @@ static void f_list2str(typval_T *argvars, typval_T *rettv, FunPtr fptr)
});
ga_append(&ga, NUL);
- rettv->v_type = VAR_STRING;
rettv->vval.v_string = ga.ga_data;
}
@@ -7755,8 +7779,7 @@ static void f_setbufline(typval_T *argvars, typval_T *rettv, FunPtr fptr)
*/
static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
- if (check_restricted()
- || check_secure()
+ if (check_secure()
|| !tv_check_str_or_nr(&argvars[0])) {
return;
}
@@ -8260,7 +8283,7 @@ static void f_settabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = 0;
- if (check_restricted() || check_secure()) {
+ if (check_secure()) {
return;
}
@@ -9558,7 +9581,7 @@ static void f_stridx(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/*
* "string()" function
*/
-static void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr)
+void f_string(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->v_type = VAR_STRING;
rettv->vval.v_string = (char_u *)encode_tv2string(&argvars[0], NULL);
@@ -10981,7 +11004,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
rettv->vval.v_number = -1;
- if (check_restricted() || check_secure()) {
+ if (check_secure()) {
return;
}
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 008453b87f..5afdedff75 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -33,7 +33,7 @@ typedef double float_T;
enum { DO_NOT_FREE_CNT = (INT_MAX / 2) };
/// Additional values for tv_list_alloc() len argument
-enum {
+enum ListLenSpecials {
/// List length is not known in advance
///
/// To be used when there is neither a way to know how many elements will be
@@ -49,7 +49,7 @@ enum {
///
/// To be used when it looks impractical to determine list length.
kListLenMayKnow = -3,
-} ListLenSpecials;
+};
/// Maximal possible value of varnumber_T variable
#define VARNUMBER_MAX INT64_MAX
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index bc6821f60f..a2c4435014 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3008,18 +3008,18 @@ void ex_z(exarg_T *eap)
ex_no_reprint = true;
}
-/*
- * Check if the restricted flag is set.
- * If so, give an error message and return TRUE.
- * Otherwise, return FALSE.
- */
-int check_restricted(void)
+// Check if the restricted flag is set.
+// If so, give an error message and return true.
+// Otherwise, return false.
+bool check_restricted(void)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
if (restricted) {
- EMSG(_("E145: Shell commands not allowed in restricted mode"));
- return TRUE;
+ EMSG(_("E145: Shell commands and some functionality not allowed"
+ " in restricted mode"));
+ return true;
}
- return FALSE;
+ return false;
}
/*
@@ -4482,8 +4482,9 @@ prepare_tagpreview (
curwin->w_p_wfh = TRUE;
RESET_BINDING(curwin); /* don't take over 'scrollbind'
and 'cursorbind' */
- curwin->w_p_diff = FALSE; /* no 'diff' */
- curwin->w_p_fdc = 0; /* no 'foldcolumn' */
+ curwin->w_p_diff = false; // no 'diff'
+ set_string_option_direct((char_u *)"fdc", -1, // no 'foldcolumn'
+ (char_u *)"0", OPT_FREE, SID_NONE);
return true;
}
}
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index f7aa8a994a..252af409c0 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -24,6 +24,7 @@ local SBOXOK = 0x80000
local CMDWIN = 0x100000
local MODIFY = 0x200000
local EXFLAGS = 0x400000
+local RESTRICT = 0x800000
local FILES = bit.bor(XFILE, EXTRA)
local WORD1 = bit.bor(EXTRA, NOSPC)
local FILE1 = bit.bor(FILES, NOSPC)
@@ -1582,19 +1583,19 @@ return {
},
{
command='lua',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_lua',
},
{
command='luado',
- flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_luado',
},
{
command='luafile',
- flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_luafile',
},
@@ -1924,13 +1925,13 @@ return {
},
{
command='perl',
- flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, SBOXOK, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_script_ni',
},
{
command='perldo',
- flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, DFLALL, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_ni',
},
@@ -2056,67 +2057,67 @@ return {
},
{
command='python',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_python',
},
{
command='pydo',
- flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pydo',
},
{
command='pyfile',
- flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pyfile',
},
{
command='py3',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_python3',
},
{
command='py3do',
- flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pydo3',
},
{
command='python3',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_python3',
},
{
command='py3file',
- flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_py3file',
},
{
command='pyx',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pyx',
},
{
command='pyxdo',
- flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pyxdo',
},
{
command='pythonx',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pyx',
},
{
command='pyxfile',
- flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_pyxfile',
},
@@ -2242,19 +2243,19 @@ return {
},
{
command='ruby',
- flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_ruby',
},
{
command='rubydo',
- flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, DFLALL, EXTRA, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_rubydo',
},
{
command='rubyfile',
- flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN),
+ flags=bit.bor(RANGE, FILE1, NEEDARG, CMDWIN, RESTRICT),
addr_type=ADDR_LINES,
func='ex_rubyfile',
},
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index d25d81658c..1f0560ae48 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -36,35 +36,36 @@
// 4. Add documentation in ../doc/xxx.txt. Add a tag for both the short and
// long name of the command.
-#define RANGE 0x001 /* allow a linespecs */
-#define BANG 0x002 /* allow a ! after the command name */
-#define EXTRA 0x004 /* allow extra args after command name */
-#define XFILE 0x008 /* expand wildcards in extra part */
-#define NOSPC 0x010 /* no spaces allowed in the extra part */
-#define DFLALL 0x020 /* default file range is 1,$ */
-#define WHOLEFOLD 0x040 /* extend range to include whole fold also
- when less than two numbers given */
-#define NEEDARG 0x080 /* argument required */
-#define TRLBAR 0x100 /* check for trailing vertical bar */
-#define REGSTR 0x200 /* allow "x for register designation */
-#define COUNT 0x400 /* allow count in argument, after command */
-#define NOTRLCOM 0x800 /* no trailing comment allowed */
-#define ZEROR 0x1000 /* zero line number allowed */
-#define USECTRLV 0x2000 /* do not remove CTRL-V from argument */
-#define NOTADR 0x4000 /* number before command is not an address */
-#define EDITCMD 0x8000 /* allow "+command" argument */
-#define BUFNAME 0x10000 /* accepts buffer name */
-#define BUFUNL 0x20000 /* accepts unlisted buffer too */
-#define ARGOPT 0x40000 /* allow "++opt=val" argument */
-#define SBOXOK 0x80000 /* allowed in the sandbox */
-#define CMDWIN 0x100000 /* allowed in cmdline window; when missing
- * disallows editing another buffer when
- * curbuf_lock is set */
-#define MODIFY 0x200000 /* forbidden in non-'modifiable' buffer */
-#define EXFLAGS 0x400000 /* allow flags after count in argument */
-#define FILES (XFILE | EXTRA) /* multiple extra files allowed */
-#define WORD1 (EXTRA | NOSPC) /* one extra word allowed */
-#define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */
+#define RANGE 0x001 // allow a linespecs
+#define BANG 0x002 // allow a ! after the command name
+#define EXTRA 0x004 // allow extra args after command name
+#define XFILE 0x008 // expand wildcards in extra part
+#define NOSPC 0x010 // no spaces allowed in the extra part
+#define DFLALL 0x020 // default file range is 1,$
+#define WHOLEFOLD 0x040 // extend range to include whole fold also
+ // when less than two numbers given
+#define NEEDARG 0x080 // argument required
+#define TRLBAR 0x100 // check for trailing vertical bar
+#define REGSTR 0x200 // allow "x for register designation
+#define COUNT 0x400 // allow count in argument, after command
+#define NOTRLCOM 0x800 // no trailing comment allowed
+#define ZEROR 0x1000 // zero line number allowed
+#define USECTRLV 0x2000 // do not remove CTRL-V from argument
+#define NOTADR 0x4000 // number before command is not an address
+#define EDITCMD 0x8000 // allow "+command" argument
+#define BUFNAME 0x10000 // accepts buffer name
+#define BUFUNL 0x20000 // accepts unlisted buffer too
+#define ARGOPT 0x40000 // allow "++opt=val" argument
+#define SBOXOK 0x80000 // allowed in the sandbox
+#define CMDWIN 0x100000 // allowed in cmdline window; when missing
+ // disallows editing another buffer when
+ // curbuf_lock is set
+#define MODIFY 0x200000 // forbidden in non-'modifiable' buffer
+#define EXFLAGS 0x400000 // allow flags after count in argument
+#define RESTRICT 0x800000L // forbidden in restricted mode
+#define FILES (XFILE | EXTRA) // multiple extra files allowed
+#define WORD1 (EXTRA | NOSPC) // one extra word allowed
+#define FILE1 (FILES | NOSPC) // 1 file allowed, defaults to current file
// values for cmd_addr_type
#define ADDR_LINES 0
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 28ecaf684a..abe394dc3a 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1783,10 +1783,14 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (!ea.skip) {
if (sandbox != 0 && !(ea.argt & SBOXOK)) {
- /* Command not allowed in sandbox. */
+ // Command not allowed in sandbox.
errormsg = (char_u *)_(e_sandbox);
goto doend;
}
+ if (restricted != 0 && (ea.argt & RESTRICT)) {
+ errormsg = (char_u *)_("E981: Command not allowed in restricted mode");
+ goto doend;
+ }
if (!MODIFIABLE(curbuf) && (ea.argt & MODIFY)
// allow :put in terminals
&& (!curbuf->terminal || ea.cmdidx != CMD_put)) {
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index 1c3c212aef..c9f36ccd61 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2701,7 +2701,7 @@ static bool color_cmdline(CmdlineInfo *colored_ccline)
goto color_cmdline_error;
}
if (tv.v_type != VAR_LIST) {
- PRINT_ERRMSG(_("E5400: Callback should return list"));
+ PRINT_ERRMSG("%s", _("E5400: Callback should return list"));
goto color_cmdline_error;
}
if (tv.vval.v_list == NULL) {
diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c
index d00943c1be..e77b556024 100644
--- a/src/nvim/extmark.c
+++ b/src/nvim/extmark.c
@@ -86,7 +86,7 @@ uint64_t extmark_set(buf_T *buf, uint64_t ns_id, uint64_t id,
extmark_del(buf, ns_id, id);
} else {
// TODO(bfredl): we need to do more if "revising" a decoration mark.
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
old_pos = marktree_lookup(buf->b_marktree, old_mark, itr);
assert(itr->node);
if (old_pos.row == row && old_pos.col == col) {
@@ -119,7 +119,7 @@ revised:
static bool extmark_setraw(buf_T *buf, uint64_t mark, int row, colnr_T col)
{
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
mtpos_t pos = marktree_lookup(buf->b_marktree, mark, itr);
if (pos.row == -1) {
return false;
@@ -147,7 +147,7 @@ bool extmark_del(buf_T *buf, uint64_t ns_id, uint64_t id)
return false;
}
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
mtpos_t pos = marktree_lookup(buf->b_marktree, mark, itr);
assert(pos.row >= 0);
marktree_del_itr(buf->b_marktree, itr, false);
@@ -207,7 +207,7 @@ bool extmark_clear(buf_T *buf, uint64_t ns_id,
delete_set = map_new(uint64_t, uint64_t)();
}
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
marktree_itr_get(buf->b_marktree, l_row, l_col, itr);
while (true) {
mtmark_t mark = marktree_itr_current(itr);
@@ -276,7 +276,7 @@ ExtmarkArray extmark_get(buf_T *buf, uint64_t ns_id,
int64_t amount, bool reverse)
{
ExtmarkArray array = KV_INITIAL_VALUE;
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
// Find all the marks
marktree_itr_get_ext(buf->b_marktree, (mtpos_t){ l_row, l_col },
itr, reverse, false, NULL);
@@ -396,7 +396,7 @@ void u_extmark_copy(buf_T *buf,
ExtmarkUndoObject undo;
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
marktree_itr_get(buf->b_marktree, l_row, l_col, itr);
while (true) {
mtmark_t mark = marktree_itr_current(itr);
@@ -738,7 +738,7 @@ void clear_virttext(VirtText *text)
VirtText *extmark_find_virttext(buf_T *buf, int row, uint64_t ns_id)
{
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
marktree_itr_get(buf->b_marktree, row, 0, itr);
while (true) {
mtmark_t mark = marktree_itr_current(itr);
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 331d7f9e29..c14a64fa38 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1465,10 +1465,10 @@ static void foldMarkAdjustRecurse(garray_T *gap, linenr_T line1, linenr_T line2,
* Get the lowest 'foldlevel' value that makes the deepest nested fold in the
* current window open.
*/
-int getDeepestNesting(void)
+int getDeepestNesting(win_T *wp)
{
- checkupdate(curwin);
- return getDeepestNestingRecurse(&curwin->w_folds);
+ checkupdate(wp);
+ return getDeepestNestingRecurse(&wp->w_folds);
}
static int getDeepestNestingRecurse(garray_T *gap)
diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h
index 01f60ccf49..f0b52079aa 100644
--- a/src/nvim/getchar.h
+++ b/src/nvim/getchar.h
@@ -10,12 +10,12 @@
/// Values for "noremap" argument of ins_typebuf()
///
/// Also used for map->m_noremap and menu->noremap[].
-enum {
+enum RemapValues {
REMAP_YES = 0, ///< Allow remapping.
REMAP_NONE = -1, ///< No remapping.
REMAP_SCRIPT = -2, ///< Remap script-local mappings only.
REMAP_SKIP = -3, ///< No remapping for first char.
-} RemapValues;
+};
// Argument for flush_buffers().
typedef enum {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 323c6cf9c3..ccf704fe76 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -120,24 +120,20 @@ typedef off_t off_T;
# endif
#endif
-/*
- * When vgetc() is called, it sets mod_mask to the set of modifiers that are
- * held down based on the MOD_MASK_* symbols that are read first.
- */
-EXTERN int mod_mask INIT(= 0x0); /* current key modifiers */
+// When vgetc() is called, it sets mod_mask to the set of modifiers that are
+// held down based on the MOD_MASK_* symbols that are read first.
+EXTERN int mod_mask INIT(= 0x0); // current key modifiers
EXTERN bool lua_attr_active INIT(= false);
-/*
- * Cmdline_row is the row where the command line starts, just below the
- * last window.
- * When the cmdline gets longer than the available space the screen gets
- * scrolled up. After a CTRL-D (show matches), after hitting ':' after
- * "hit return", and for the :global command, the command line is
- * temporarily moved. The old position is restored with the next call to
- * update_screen().
- */
+// Cmdline_row is the row where the command line starts, just below the
+// last window.
+// When the cmdline gets longer than the available space the screen gets
+// scrolled up. After a CTRL-D (show matches), after hitting ':' after
+// "hit return", and for the :global command, the command line is
+// temporarily moved. The old position is restored with the next call to
+// update_screen().
EXTERN int cmdline_row;
EXTERN int redraw_cmdline INIT(= false); // cmdline must be redrawn
@@ -149,42 +145,38 @@ EXTERN int cmdline_was_last_drawn INIT(= false); // cmdline was last drawn
EXTERN int exec_from_reg INIT(= false); // executing register
-/*
- * When '$' is included in 'cpoptions' option set:
- * When a change command is given that deletes only part of a line, a dollar
- * is put at the end of the changed text. dollar_vcol is set to the virtual
- * column of this '$'. -1 is used to indicate no $ is being displayed.
- */
+// When '$' is included in 'cpoptions' option set:
+// When a change command is given that deletes only part of a line, a dollar
+// is put at the end of the changed text. dollar_vcol is set to the virtual
+// column of this '$'. -1 is used to indicate no $ is being displayed.
EXTERN colnr_T dollar_vcol INIT(= -1);
-/*
- * Variables for Insert mode completion.
- */
+// Variables for Insert mode completion.
-/* Length in bytes of the text being completed (this is deleted to be replaced
- * by the match.) */
+// Length in bytes of the text being completed (this is deleted to be replaced
+// by the match.)
EXTERN int compl_length INIT(= 0);
-/* Set when character typed while looking for matches and it means we should
- * stop looking for matches. */
-EXTERN int compl_interrupted INIT(= FALSE);
+// Set when character typed while looking for matches and it means we should
+// stop looking for matches.
+EXTERN int compl_interrupted INIT(= false);
// Set when doing something for completion that may call edit() recursively,
// which is not allowed. Also used to disable folding during completion
EXTERN int compl_busy INIT(= false);
-/* List of flags for method of completion. */
+// List of flags for method of completion.
EXTERN int compl_cont_status INIT(= 0);
-# define CONT_ADDING 1 /* "normal" or "adding" expansion */
-# define CONT_INTRPT (2 + 4) /* a ^X interrupted the current expansion */
- /* it's set only iff N_ADDS is set */
-# define CONT_N_ADDS 4 /* next ^X<> will add-new or expand-current */
-# define CONT_S_IPOS 8 /* next ^X<> will set initial_pos?
- * if so, word-wise-expansion will set SOL */
-# define CONT_SOL 16 /* pattern includes start of line, just for
- * word-wise expansion, not set for ^X^L */
-# define CONT_LOCAL 32 /* for ctrl_x_mode 0, ^X^P/^X^N do a local
- * expansion, (eg use complete=.) */
+# define CONT_ADDING 1 // "normal" or "adding" expansion
+# define CONT_INTRPT (2 + 4) // a ^X interrupted the current expansion
+ // it's set only iff N_ADDS is set
+# define CONT_N_ADDS 4 // next ^X<> will add-new or expand-current
+# define CONT_S_IPOS 8 // next ^X<> will set initial_pos?
+ // if so, word-wise-expansion will set SOL
+# define CONT_SOL 16 // pattern includes start of line, just for
+ // word-wise expansion, not set for ^X^L
+# define CONT_LOCAL 32 // for ctrl_x_mode 0, ^X^P/^X^N do a local
+ // expansion, (eg use complete=.)
// state for putting characters in the message area
EXTERN int cmdmsg_rl INIT(= false); // cmdline is drawn right to left
@@ -200,49 +192,49 @@ EXTERN bool msg_scrolled_ign INIT(= false);
EXTERN bool msg_did_scroll INIT(= false);
-EXTERN char_u *keep_msg INIT(= NULL); /* msg to be shown after redraw */
-EXTERN int keep_msg_attr INIT(= 0); /* highlight attr for keep_msg */
-EXTERN int keep_msg_more INIT(= FALSE); /* keep_msg was set by msgmore() */
-EXTERN int need_fileinfo INIT(= FALSE); /* do fileinfo() after redraw */
-EXTERN int msg_scroll INIT(= FALSE); /* msg_start() will scroll */
-EXTERN int msg_didout INIT(= FALSE); /* msg_outstr() was used in line */
-EXTERN int msg_didany INIT(= FALSE); /* msg_outstr() was used at all */
-EXTERN int msg_nowait INIT(= FALSE); /* don't wait for this msg */
-EXTERN int emsg_off INIT(= 0); /* don't display errors for now,
- unless 'debug' is set. */
-EXTERN int info_message INIT(= FALSE); /* printing informative message */
-EXTERN int msg_hist_off INIT(= FALSE); /* don't add messages to history */
-EXTERN int need_clr_eos INIT(= FALSE); /* need to clear text before
- displaying a message. */
-EXTERN int emsg_skip INIT(= 0); /* don't display errors for
- expression that is skipped */
-EXTERN int emsg_severe INIT(= FALSE); /* use message of next of several
- emsg() calls for throw */
-EXTERN int did_endif INIT(= FALSE); /* just had ":endif" */
-EXTERN dict_T vimvardict; /* Dictionary with v: variables */
-EXTERN dict_T globvardict; /* Dictionary with g: variables */
-EXTERN int did_emsg; /* set by emsg() when the message
- is displayed or thrown */
+EXTERN char_u *keep_msg INIT(= NULL); // msg to be shown after redraw
+EXTERN int keep_msg_attr INIT(= 0); // highlight attr for keep_msg
+EXTERN int keep_msg_more INIT(= false); // keep_msg was set by msgmore()
+EXTERN int need_fileinfo INIT(= false); // do fileinfo() after redraw
+EXTERN int msg_scroll INIT(= false); // msg_start() will scroll
+EXTERN int msg_didout INIT(= false); // msg_outstr() was used in line
+EXTERN int msg_didany INIT(= false); // msg_outstr() was used at all
+EXTERN int msg_nowait INIT(= false); // don't wait for this msg
+EXTERN int emsg_off INIT(= 0); // don't display errors for now,
+ // unless 'debug' is set.
+EXTERN int info_message INIT(= false); // printing informative message
+EXTERN int msg_hist_off INIT(= false); // don't add messages to history
+EXTERN int need_clr_eos INIT(= false); // need to clear text before
+ // displaying a message.
+EXTERN int emsg_skip INIT(= 0); // don't display errors for
+ // expression that is skipped
+EXTERN int emsg_severe INIT(= false); // use message of next of several
+ // emsg() calls for throw
+EXTERN int did_endif INIT(= false); // just had ":endif"
+EXTERN dict_T vimvardict; // Dictionary with v: variables
+EXTERN dict_T globvardict; // Dictionary with g: variables
+EXTERN int did_emsg; // set by emsg() when the message
+ // is displayed or thrown
EXTERN bool called_vim_beep; // set if vim_beep() is called
-EXTERN int did_emsg_syntax; /* did_emsg set because of a
- syntax error */
-EXTERN int called_emsg; /* always set by emsg() */
-EXTERN int ex_exitval INIT(= 0); /* exit value for ex mode */
-EXTERN int emsg_on_display INIT(= FALSE); /* there is an error message */
-EXTERN int rc_did_emsg INIT(= FALSE); /* vim_regcomp() called emsg() */
-
-EXTERN int no_wait_return INIT(= 0); /* don't wait for return for now */
-EXTERN int need_wait_return INIT(= 0); /* need to wait for return later */
-EXTERN int did_wait_return INIT(= FALSE); /* wait_return() was used and
- nothing written since then */
-EXTERN int need_maketitle INIT(= TRUE); /* call maketitle() soon */
+EXTERN int did_emsg_syntax; // did_emsg set because of a
+ // syntax error
+EXTERN int called_emsg; // always set by emsg()
+EXTERN int ex_exitval INIT(= 0); // exit value for ex mode
+EXTERN int emsg_on_display INIT(= false); // there is an error message
+EXTERN int rc_did_emsg INIT(= false); // vim_regcomp() called emsg()
+
+EXTERN int no_wait_return INIT(= 0); // don't wait for return for now
+EXTERN int need_wait_return INIT(= 0); // need to wait for return later
+EXTERN int did_wait_return INIT(= false); // wait_return() was used and
+ // nothing written since then
+EXTERN int need_maketitle INIT(= true); // call maketitle() soon
EXTERN int quit_more INIT(= false); // 'q' hit at "--more--" msg
EXTERN int ex_keep_indent INIT(= false); // getexmodeline(): keep indent
EXTERN int vgetc_busy INIT(= 0); // when inside vgetc() then > 0
-EXTERN int didset_vim INIT(= FALSE); /* did set $VIM ourselves */
-EXTERN int didset_vimruntime INIT(= FALSE); /* idem for $VIMRUNTIME */
+EXTERN int didset_vim INIT(= false); // did set $VIM ourselves
+EXTERN int didset_vimruntime INIT(= false); // idem for $VIMRUNTIME
/// Lines left before a "more" message. Ex mode needs to be able to reset this
/// after you type something.
@@ -250,8 +242,8 @@ EXTERN int lines_left INIT(= -1); // lines left for listing
EXTERN int msg_no_more INIT(= false); // don't use more prompt, truncate
// messages
-EXTERN char_u *sourcing_name INIT( = NULL); /* name of error message source */
-EXTERN linenr_T sourcing_lnum INIT(= 0); /* line number of the source file */
+EXTERN char_u *sourcing_name INIT(= NULL); // name of error message source
+EXTERN linenr_T sourcing_lnum INIT(= 0); // line number of the source file
EXTERN int ex_nesting_level INIT(= 0); // nesting level
EXTERN int debug_break_level INIT(= -1); // break below this level
@@ -282,11 +274,11 @@ EXTERN int check_cstack INIT(= false);
/// commands).
EXTERN int trylevel INIT(= 0);
-/// When "force_abort" is TRUE, always skip commands after an error message,
+/// When "force_abort" is true, always skip commands after an error message,
/// even after the outermost ":endif", ":endwhile" or ":endfor" or for a
-/// function without the "abort" flag. It is set to TRUE when "trylevel" is
+/// function without the "abort" flag. It is set to true when "trylevel" is
/// non-zero (and ":silent!" was not used) or an exception is being thrown at
-/// the time an error is detected. It is set to FALSE when "trylevel" gets
+/// the time an error is detected. It is set to false when "trylevel" gets
/// zero again and there was no error or interrupt or throw.
EXTERN int force_abort INIT(= false);
@@ -357,41 +349,38 @@ EXTERN int provider_call_nesting INIT(= 0);
EXTERN int t_colors INIT(= 256); // int value of T_CCO
-/*
- * When highlight_match is TRUE, highlight a match, starting at the cursor
- * position. Search_match_lines is the number of lines after the match (0 for
- * a match within one line), search_match_endcol the column number of the
- * character just after the match in the last line.
- */
-EXTERN int highlight_match INIT(= FALSE); /* show search match pos */
-EXTERN linenr_T search_match_lines; /* lines of of matched string */
-EXTERN colnr_T search_match_endcol; /* col nr of match end */
-
-EXTERN int no_smartcase INIT(= FALSE); /* don't use 'smartcase' once */
-
-EXTERN int need_check_timestamps INIT(= FALSE); /* need to check file
- timestamps asap */
-EXTERN int did_check_timestamps INIT(= FALSE); /* did check timestamps
- recently */
-EXTERN int no_check_timestamps INIT(= 0); /* Don't check timestamps */
-
-EXTERN int autocmd_busy INIT(= FALSE); /* Is apply_autocmds() busy? */
-EXTERN int autocmd_no_enter INIT(= FALSE); /* *Enter autocmds disabled */
-EXTERN int autocmd_no_leave INIT(= FALSE); /* *Leave autocmds disabled */
-EXTERN int modified_was_set; /* did ":set modified" */
-EXTERN int did_filetype INIT(= FALSE); /* FileType event found */
-EXTERN int keep_filetype INIT(= FALSE); /* value for did_filetype when
- starting to execute
- autocommands */
+// When highlight_match is true, highlight a match, starting at the cursor
+// position. Search_match_lines is the number of lines after the match (0 for
+// a match within one line), search_match_endcol the column number of the
+// character just after the match in the last line.
+EXTERN int highlight_match INIT(= false); // show search match pos
+EXTERN linenr_T search_match_lines; // lines of of matched string
+EXTERN colnr_T search_match_endcol; // col nr of match end
+
+EXTERN int no_smartcase INIT(= false); // don't use 'smartcase' once
+
+EXTERN int need_check_timestamps INIT(= false); // need to check file
+ // timestamps asap
+EXTERN int did_check_timestamps INIT(= false); // did check timestamps
+ // recently
+EXTERN int no_check_timestamps INIT(= 0); // Don't check timestamps
+
+EXTERN int autocmd_busy INIT(= false); // Is apply_autocmds() busy?
+EXTERN int autocmd_no_enter INIT(= false); // *Enter autocmds disabled
+EXTERN int autocmd_no_leave INIT(= false); // *Leave autocmds disabled
+EXTERN int modified_was_set; // did ":set modified"
+EXTERN int did_filetype INIT(= false); // FileType event found
+// value for did_filetype when starting to execute autocommands
+EXTERN int keep_filetype INIT(= false);
// When deleting the current buffer, another one must be loaded.
// If we know which one is preferred, au_new_curbuf is set to it.
EXTERN bufref_T au_new_curbuf INIT(= { NULL, 0, 0 });
-// When deleting a buffer/window and autocmd_busy is TRUE, do not free the
+// When deleting a buffer/window and autocmd_busy is true, do not free the
// buffer/window. but link it in the list starting with
// au_pending_free_buf/ap_pending_free_win, using b_next/w_next.
-// Free the buffer/window when autocmd_busy is being set to FALSE.
+// Free the buffer/window when autocmd_busy is being set to false.
EXTERN buf_T *au_pending_free_buf INIT(= NULL);
EXTERN win_T *au_pending_free_win INIT(= NULL);
@@ -399,31 +388,27 @@ EXTERN win_T *au_pending_free_win INIT(= NULL);
EXTERN int mouse_grid;
EXTERN int mouse_row;
EXTERN int mouse_col;
-EXTERN bool mouse_past_bottom INIT(= false); /* mouse below last line */
-EXTERN bool mouse_past_eol INIT(= false); /* mouse right of line */
-EXTERN int mouse_dragging INIT(= 0); /* extending Visual area with
- mouse dragging */
+EXTERN bool mouse_past_bottom INIT(= false); // mouse below last line
+EXTERN bool mouse_past_eol INIT(= false); // mouse right of line
+EXTERN int mouse_dragging INIT(= 0); // extending Visual area with
+ // mouse dragging
-/* The root of the menu hierarchy. */
+// The root of the menu hierarchy.
EXTERN vimmenu_T *root_menu INIT(= NULL);
-/*
- * While defining the system menu, sys_menu is TRUE. This avoids
- * overruling of menus that the user already defined.
- */
-EXTERN int sys_menu INIT(= FALSE);
-
-/* While redrawing the screen this flag is set. It means the screen size
- * ('lines' and 'rows') must not be changed. */
-EXTERN int updating_screen INIT(= FALSE);
-
-/*
- * All windows are linked in a list. firstwin points to the first entry,
- * lastwin to the last entry (can be the same as firstwin) and curwin to the
- * currently active window.
- */
-EXTERN win_T *firstwin; /* first window */
-EXTERN win_T *lastwin; /* last window */
-EXTERN win_T *prevwin INIT(= NULL); /* previous window */
+// While defining the system menu, sys_menu is true. This avoids
+// overruling of menus that the user already defined.
+EXTERN int sys_menu INIT(= false);
+
+// While redrawing the screen this flag is set. It means the screen size
+// ('lines' and 'rows') must not be changed.
+EXTERN int updating_screen INIT(= 0);
+
+// All windows are linked in a list. firstwin points to the first entry,
+// lastwin to the last entry (can be the same as firstwin) and curwin to the
+// currently active window.
+EXTERN win_T *firstwin; // first window
+EXTERN win_T *lastwin; // last window
+EXTERN win_T *prevwin INIT(= NULL); // previous window
# define ONE_WINDOW (firstwin == lastwin)
# define FOR_ALL_FRAMES(frp, first_frame) \
for (frp = first_frame; frp != NULL; frp = frp->fr_next) // NOLINT
@@ -439,33 +424,27 @@ EXTERN win_T *prevwin INIT(= NULL); /* previous window */
for (win_T *wp = ((tp) == curtab) \
? firstwin : (tp)->tp_firstwin; wp != NULL; wp = wp->w_next)
-EXTERN win_T *curwin; /* currently active window */
+EXTERN win_T *curwin; // currently active window
-EXTERN win_T *aucmd_win; /* window used in aucmd_prepbuf() */
-EXTERN int aucmd_win_used INIT(= FALSE); /* aucmd_win is being used */
+EXTERN win_T *aucmd_win; // window used in aucmd_prepbuf()
+EXTERN int aucmd_win_used INIT(= false); // aucmd_win is being used
-/*
- * The window layout is kept in a tree of frames. topframe points to the top
- * of the tree.
- */
-EXTERN frame_T *topframe; /* top of the window frame tree */
+// The window layout is kept in a tree of frames. topframe points to the top
+// of the tree.
+EXTERN frame_T *topframe; // top of the window frame tree
-/*
- * Tab pages are alternative topframes. "first_tabpage" points to the first
- * one in the list, "curtab" is the current one.
- */
+// Tab pages are alternative topframes. "first_tabpage" points to the first
+// one in the list, "curtab" is the current one.
EXTERN tabpage_T *first_tabpage;
EXTERN tabpage_T *lastused_tabpage;
EXTERN tabpage_T *curtab;
-EXTERN int redraw_tabline INIT(= FALSE); /* need to redraw tabline */
+EXTERN int redraw_tabline INIT(= false); // need to redraw tabline
// Iterates over all tabs in the tab list
# define FOR_ALL_TABS(tp) for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next)
-/*
- * All buffers are linked in a list. 'firstbuf' points to the first entry,
- * 'lastbuf' to the last entry and 'curbuf' to the currently active buffer.
- */
+// All buffers are linked in a list. 'firstbuf' points to the first entry,
+// 'lastbuf' to the last entry and 'curbuf' to the currently active buffer.
EXTERN buf_T *firstbuf INIT(= NULL); // first buffer
EXTERN buf_T *lastbuf INIT(= NULL); // last buffer
EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer
@@ -481,23 +460,19 @@ EXTERN buf_T *curbuf INIT(= NULL); // currently active buffer
for (sign = buf->b_signlist; sign != NULL; sign = sign->next) // NOLINT
-/*
- * List of files being edited (global argument list). curwin->w_alist points
- * to this when the window is using the global argument list.
- */
-EXTERN alist_T global_alist; /* global argument list */
+// List of files being edited (global argument list). curwin->w_alist points
+// to this when the window is using the global argument list.
+EXTERN alist_T global_alist; // global argument list
EXTERN int max_alist_id INIT(= 0); ///< the previous argument list id
EXTERN bool arg_had_last INIT(= false); // accessed last file in
// global_alist
-EXTERN int ru_col; /* column for ruler */
-EXTERN int ru_wid; /* 'rulerfmt' width of ruler when non-zero */
-EXTERN int sc_col; /* column for shown command */
+EXTERN int ru_col; // column for ruler
+EXTERN int ru_wid; // 'rulerfmt' width of ruler when non-zero
+EXTERN int sc_col; // column for shown command
-//
// When starting or exiting some things are done differently (e.g. screen
// updating).
-//
// First NO_SCREEN, then NO_BUFFERS, then 0 when startup finished.
EXTERN int starting INIT(= NO_SCREEN);
@@ -546,98 +521,78 @@ EXTERN int VIsual_select INIT(= false);
EXTERN int VIsual_reselect;
/// Type of Visual mode.
EXTERN int VIsual_mode INIT(= 'v');
-/// TRUE when redoing Visual.
+/// true when redoing Visual.
EXTERN int redo_VIsual_busy INIT(= false);
/// When pasting text with the middle mouse button in visual mode with
/// restart_edit set, remember where it started so we can set Insstart.
EXTERN pos_T where_paste_started;
-/*
- * This flag is used to make auto-indent work right on lines where only a
- * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
- * reset when any other editing is done on the line. If an <ESC> or <RETURN>
- * is received, and did_ai is TRUE, the line is truncated.
- */
+// This flag is used to make auto-indent work right on lines where only a
+// <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
+// reset when any other editing is done on the line. If an <ESC> or <RETURN>
+// is received, and did_ai is true, the line is truncated.
EXTERN bool did_ai INIT(= false);
-/*
- * Column of first char after autoindent. 0 when no autoindent done. Used
- * when 'backspace' is 0, to avoid backspacing over autoindent.
- */
+// Column of first char after autoindent. 0 when no autoindent done. Used
+// when 'backspace' is 0, to avoid backspacing over autoindent.
EXTERN colnr_T ai_col INIT(= 0);
-/*
- * This is a character which will end a start-middle-end comment when typed as
- * the first character on a new line. It is taken from the last character of
- * the "end" comment leader when the COM_AUTO_END flag is given for that
- * comment end in 'comments'. It is only valid when did_ai is TRUE.
- */
+// This is a character which will end a start-middle-end comment when typed as
+// the first character on a new line. It is taken from the last character of
+// the "end" comment leader when the COM_AUTO_END flag is given for that
+// comment end in 'comments'. It is only valid when did_ai is true.
EXTERN int end_comment_pending INIT(= NUL);
-/*
- * This flag is set after a ":syncbind" to let the check_scrollbind() function
- * know that it should not attempt to perform scrollbinding due to the scroll
- * that was a result of the ":syncbind." (Otherwise, check_scrollbind() will
- * undo some of the work done by ":syncbind.") -ralston
- */
-EXTERN int did_syncbind INIT(= FALSE);
-
-/*
- * This flag is set when a smart indent has been performed. When the next typed
- * character is a '{' the inserted tab will be deleted again.
- */
+// This flag is set after a ":syncbind" to let the check_scrollbind() function
+// know that it should not attempt to perform scrollbinding due to the scroll
+// that was a result of the ":syncbind." (Otherwise, check_scrollbind() will
+// undo some of the work done by ":syncbind.") -ralston
+EXTERN int did_syncbind INIT(= false);
+
+// This flag is set when a smart indent has been performed. When the next typed
+// character is a '{' the inserted tab will be deleted again.
EXTERN bool did_si INIT(= false);
-/*
- * This flag is set after an auto indent. If the next typed character is a '}'
- * one indent will be removed.
- */
+// This flag is set after an auto indent. If the next typed character is a '}'
+// one indent will be removed.
EXTERN bool can_si INIT(= false);
-/*
- * This flag is set after an "O" command. If the next typed character is a '{'
- * one indent will be removed.
- */
+// This flag is set after an "O" command. If the next typed character is a '{'
+// one indent will be removed.
EXTERN bool can_si_back INIT(= false);
// w_cursor before formatting text.
EXTERN pos_T saved_cursor INIT(= { 0, 0, 0 });
-/*
- * Stuff for insert mode.
- */
-EXTERN pos_T Insstart; /* This is where the latest
- * insert/append mode started. */
+// Stuff for insert mode.
+EXTERN pos_T Insstart; // This is where the latest
+ // insert/append mode started.
// This is where the latest insert/append mode started. In contrast to
// Insstart, this won't be reset by certain keys and is needed for
// op_insert(), to detect correctly where inserting by the user started.
EXTERN pos_T Insstart_orig;
-/*
- * Stuff for VREPLACE mode.
- */
-EXTERN int orig_line_count INIT(= 0); /* Line count when "gR" started */
-EXTERN int vr_lines_changed INIT(= 0); /* #Lines changed by "gR" so far */
+// Stuff for VREPLACE mode.
+EXTERN int orig_line_count INIT(= 0); // Line count when "gR" started
+EXTERN int vr_lines_changed INIT(= 0); // #Lines changed by "gR" so far
// increase around internal delete/replace
EXTERN int inhibit_delete_count INIT(= 0);
-/*
- * These flags are set based upon 'fileencoding'.
- * Note that "enc_utf8" is also set for "unicode", because the characters are
- * internally stored as UTF-8 (to avoid trouble with NUL bytes).
- */
-# define DBCS_JPN 932 /* japan */
-# define DBCS_JPNU 9932 /* euc-jp */
-# define DBCS_KOR 949 /* korea */
-# define DBCS_KORU 9949 /* euc-kr */
-# define DBCS_CHS 936 /* chinese */
-# define DBCS_CHSU 9936 /* euc-cn */
-# define DBCS_CHT 950 /* taiwan */
-# define DBCS_CHTU 9950 /* euc-tw */
-# define DBCS_2BYTE 1 /* 2byte- */
+// These flags are set based upon 'fileencoding'.
+// Note that "enc_utf8" is also set for "unicode", because the characters are
+// internally stored as UTF-8 (to avoid trouble with NUL bytes).
+# define DBCS_JPN 932 // japan
+# define DBCS_JPNU 9932 // euc-jp
+# define DBCS_KOR 949 // korea
+# define DBCS_KORU 9949 // euc-kr
+# define DBCS_CHS 936 // chinese
+# define DBCS_CHSU 9936 // euc-cn
+# define DBCS_CHT 950 // taiwan
+# define DBCS_CHTU 9950 // euc-tw
+# define DBCS_2BYTE 1 // 2byte-
# define DBCS_DEBUG -1
// mbyte flags that used to depend on 'encoding'. These are now deprecated, as
@@ -678,40 +633,40 @@ EXTERN int u_sync_once INIT(= 0); // Call u_sync() once when evaluating
EXTERN bool force_restart_edit INIT(= false); // force restart_edit after
// ex_normal returns
-EXTERN int restart_edit INIT(= 0); /* call edit when next cmd finished */
-EXTERN int arrow_used; /* Normally FALSE, set to TRUE after
- * hitting cursor key in insert mode.
- * Used by vgetorpeek() to decide when
- * to call u_sync() */
-EXTERN int ins_at_eol INIT(= FALSE); /* put cursor after eol when
- restarting edit after CTRL-O */
+EXTERN int restart_edit INIT(= 0); // call edit when next cmd finished
+EXTERN int arrow_used; // Normally false, set to true after
+ // hitting cursor key in insert mode.
+ // Used by vgetorpeek() to decide when
+ // to call u_sync()
+EXTERN int ins_at_eol INIT(= false); // put cursor after eol when
+ // restarting edit after CTRL-O
EXTERN char_u *edit_submode INIT(= NULL); // msg for CTRL-X submode
EXTERN char_u *edit_submode_pre INIT(= NULL); // prepended to edit_submode
EXTERN char_u *edit_submode_extra INIT(= NULL); // appended to edit_submode
EXTERN hlf_T edit_submode_highl; // highl. method for extra info
-EXTERN int no_abbr INIT(= TRUE); /* TRUE when no abbreviations loaded */
+EXTERN int no_abbr INIT(= true); // true when no abbreviations loaded
EXTERN int mapped_ctrl_c INIT(= 0); // Modes where CTRL-C is mapped.
-EXTERN cmdmod_T cmdmod; /* Ex command modifiers */
+EXTERN cmdmod_T cmdmod; // Ex command modifiers
EXTERN int msg_silent INIT(= 0); // don't print messages
EXTERN int emsg_silent INIT(= 0); // don't print error messages
EXTERN bool emsg_noredir INIT(= false); // don't redirect error messages
EXTERN bool cmd_silent INIT(= false); // don't echo the command line
-/* Values for swap_exists_action: what to do when swap file already exists */
-#define SEA_NONE 0 /* don't use dialog */
-#define SEA_DIALOG 1 /* use dialog when possible */
-#define SEA_QUIT 2 /* quit editing the file */
-#define SEA_RECOVER 3 /* recover the file */
+// Values for swap_exists_action: what to do when swap file already exists
+#define SEA_NONE 0 // don't use dialog
+#define SEA_DIALOG 1 // use dialog when possible
+#define SEA_QUIT 2 // quit editing the file
+#define SEA_RECOVER 3 // recover the file
EXTERN int swap_exists_action INIT(= SEA_NONE);
-/* For dialog when swap file already
- * exists. */
-EXTERN int swap_exists_did_quit INIT(= FALSE);
-/* Selected "quit" at the dialog. */
+// For dialog when swap file already
+// exists.
+EXTERN int swap_exists_did_quit INIT(= false);
+// Selected "quit" at the dialog.
EXTERN char_u IObuff[IOSIZE]; ///< Buffer for sprintf, I/O, etc.
EXTERN char_u NameBuff[MAXPATHL]; ///< Buffer for expanding file names
@@ -724,11 +679,11 @@ IOSIZE
#endif
];
-/* When non-zero, postpone redrawing. */
+// When non-zero, postpone redrawing.
EXTERN int RedrawingDisabled INIT(= 0);
-EXTERN int readonlymode INIT(= FALSE); /* Set to TRUE for "view" */
-EXTERN int recoverymode INIT(= FALSE); /* Set to TRUE for "-r" option */
+EXTERN int readonlymode INIT(= false); // Set to true for "view"
+EXTERN int recoverymode INIT(= false); // Set to true for "-r" option
// typeahead buffer
EXTERN typebuf_T typebuf INIT(= { NULL, NULL, 0, 0, 0, 0, 0, 0, 0 });
@@ -738,7 +693,7 @@ EXTERN int ex_normal_lock INIT(= 0); // forbid use of ex_normal()
EXTERN int ignore_script INIT(= false); // ignore script input
EXTERN int stop_insert_mode; // for ":stopinsert" and 'insertmode'
EXTERN bool KeyTyped; // true if user typed current char
-EXTERN int KeyStuffed; // TRUE if current char from stuffbuf
+EXTERN int KeyStuffed; // true if current char from stuffbuf
EXTERN int maptick INIT(= 0); // tick for each non-mapped char
EXTERN int must_redraw INIT(= 0); // type of redraw necessary
@@ -754,15 +709,15 @@ EXTERN FILE *scriptout INIT(= NULL); ///< Stream to write script to.
// volatile because it is used in a signal handler.
EXTERN volatile int got_int INIT(= false); // set to true when interrupt
// signal occurred
-EXTERN int bangredo INIT(= FALSE); /* set to TRUE with ! command */
-EXTERN int searchcmdlen; /* length of previous search cmd */
-EXTERN int reg_do_extmatch INIT(= 0); /* Used when compiling regexp:
- * REX_SET to allow \z\(...\),
- * REX_USE to allow \z\1 et al. */
-EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL); /* Used by vim_regexec():
- * strings for \z\1...\z\9 */
-EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL); /* Set by vim_regexec()
- * to store \z\(...\) matches */
+EXTERN int bangredo INIT(= false); // set to true with ! command
+EXTERN int searchcmdlen; // length of previous search cmd
+EXTERN int reg_do_extmatch INIT(= 0); // Used when compiling regexp:
+ // REX_SET to allow \z\(...\),
+ // REX_USE to allow \z\1 et al.
+// Used by vim_regexec(): strings for \z\1...\z\9
+EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL);
+// Set by vim_regexec() to store \z\(...\) matches
+EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL);
EXTERN int did_outofmem_msg INIT(= false);
// set after out of memory msg
@@ -781,11 +736,11 @@ EXTERN int autocmd_bufnr INIT(= 0); // fnum for <abuf> on cmdline
EXTERN char_u *autocmd_match INIT(= NULL); // name for <amatch> on cmdline
EXTERN int did_cursorhold INIT(= false); // set when CursorHold t'gerd
-EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */
-EXTERN int postponed_split_flags INIT(= 0); /* args for win_split() */
-EXTERN int postponed_split_tab INIT(= 0); /* cmdmod.tab */
-EXTERN int g_do_tagpreview INIT(= 0); /* for tag preview commands:
- height of preview window */
+EXTERN int postponed_split INIT(= 0); // for CTRL-W CTRL-] command
+EXTERN int postponed_split_flags INIT(= 0); // args for win_split()
+EXTERN int postponed_split_tab INIT(= 0); // cmdmod.tab
+EXTERN int g_do_tagpreview INIT(= 0); // for tag preview commands:
+ // height of preview window
EXTERN int g_tag_at_cursor INIT(= false); // whether the tag command comes
// from the command line (0) or was
// invoked as a normal command (1)
@@ -793,15 +748,13 @@ EXTERN int g_tag_at_cursor INIT(= false); // whether the tag command comes
EXTERN int replace_offset INIT(= 0); // offset for replace_push()
EXTERN char_u *escape_chars INIT(= (char_u *)" \t\\\"|");
-/* need backslash in cmd line */
+// need backslash in cmd line
-EXTERN int keep_help_flag INIT(= FALSE); /* doing :ta from help file */
+EXTERN int keep_help_flag INIT(= false); // doing :ta from help file
-/*
- * When a string option is NULL (which only happens in out-of-memory
- * situations), it is set to empty_option, to avoid having to check for NULL
- * everywhere.
- */
+// When a string option is NULL (which only happens in out-of-memory
+// situations), it is set to empty_option, to avoid having to check for NULL
+// everywhere.
EXTERN char_u *empty_option INIT(= (char_u *)"");
EXTERN int redir_off INIT(= false); // no redirection for a moment
@@ -810,10 +763,10 @@ EXTERN int redir_reg INIT(= 0); // message redirection register
EXTERN int redir_vname INIT(= 0); // message redirection variable
EXTERN garray_T *capture_ga INIT(= NULL); // captured output for execute()
-EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */
+EXTERN char_u langmap_mapchar[256]; // mapping for language keys
-EXTERN int save_p_ls INIT(= -1); /* Save 'laststatus' setting */
-EXTERN int save_p_wmh INIT(= -1); /* Save 'winminheight' setting */
+EXTERN int save_p_ls INIT(= -1); // Save 'laststatus' setting
+EXTERN int save_p_wmh INIT(= -1); // Save 'winminheight' setting
EXTERN int wild_menu_showing INIT(= 0);
enum {
WM_SHOWN = 1, ///< wildmenu showing
@@ -822,10 +775,8 @@ enum {
};
-/*
- * Some file names are stored in pathdef.c, which is generated from the
- * Makefile to make their value depend on the Makefile.
- */
+// Some file names are stored in pathdef.c, which is generated from the
+// Makefile to make their value depend on the Makefile.
#ifdef HAVE_PATHDEF
extern char *default_vim_dir;
extern char *default_vimruntime_dir;
@@ -834,14 +785,14 @@ extern char_u *compiled_user;
extern char_u *compiled_sys;
#endif
-/* When a window has a local directory, the absolute path of the global
- * current directory is stored here (in allocated memory). If the current
- * directory is not a local directory, globaldir is NULL. */
+// When a window has a local directory, the absolute path of the global
+// current directory is stored here (in allocated memory). If the current
+// directory is not a local directory, globaldir is NULL.
EXTERN char_u *globaldir INIT(= NULL);
-/* Whether 'keymodel' contains "stopsel" and "startsel". */
-EXTERN int km_stopsel INIT(= FALSE);
-EXTERN int km_startsel INIT(= FALSE);
+// Whether 'keymodel' contains "stopsel" and "startsel".
+EXTERN int km_stopsel INIT(= false);
+EXTERN int km_startsel INIT(= false);
EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option
EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0
@@ -850,18 +801,16 @@ EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level
EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--"));
-/*
- * When ":global" is used to number of substitutions and changed lines is
- * accumulated until it's finished.
- * Also used for ":spellrepall".
- */
-EXTERN long sub_nsubs; /* total number of substitutions */
-EXTERN linenr_T sub_nlines; /* total number of lines changed */
+// When ":global" is used to number of substitutions and changed lines is
+// accumulated until it's finished.
+// Also used for ":spellrepall".
+EXTERN long sub_nsubs; // total number of substitutions
+EXTERN linenr_T sub_nlines; // total number of lines changed
-/* table to store parsed 'wildmode' */
+// table to store parsed 'wildmode'
EXTERN char_u wim_flags[4];
-/* whether titlestring and iconstring contains statusline syntax */
+// whether titlestring and iconstring contains statusline syntax
# define STL_IN_ICON 1
# define STL_IN_TITLE 2
EXTERN int stl_syntax INIT(= 0);
@@ -869,7 +818,7 @@ EXTERN int stl_syntax INIT(= 0);
// don't use 'hlsearch' temporarily
EXTERN bool no_hlsearch INIT(= false);
-/* Page number used for %N in 'pageheader' and 'guitablabel'. */
+// Page number used for %N in 'pageheader' and 'guitablabel'.
EXTERN linenr_T printer_page_num;
@@ -887,18 +836,16 @@ EXTERN char pseps[2] INIT(= { '\\', 0 }); // normal path separator string
// kNone when no operator is being executed, kFalse otherwise.
EXTERN TriState virtual_op INIT(= kNone);
-/* Display tick, incremented for each call to update_screen() */
+// Display tick, incremented for each call to update_screen()
EXTERN disptick_T display_tick INIT(= 0);
-/* Line in which spell checking wasn't highlighted because it touched the
- * cursor position in Insert mode. */
+// Line in which spell checking wasn't highlighted because it touched the
+// cursor position in Insert mode.
EXTERN linenr_T spell_redraw_lnum INIT(= 0);
-/*
- * The error messages that can be shared are included here.
- * Excluded are errors that are only used once and debugging messages.
- */
+// The error messages that can be shared are included here.
+// Excluded are errors that are only used once and debugging messages.
EXTERN char_u e_abort[] INIT(= N_("E470: Command aborted"));
EXTERN char_u e_afterinit[] INIT(= N_(
"E905: Cannot set this option after startup"));
@@ -1070,7 +1017,7 @@ EXTERN char line_msg[] INIT(= N_(" line "));
// For undo we need to know the lowest time possible.
EXTERN time_t starttime;
-EXTERN FILE *time_fd INIT(= NULL); /* where to write startup timing */
+EXTERN FILE *time_fd INIT(= NULL); // where to write startup timing
// Some compilers warn for not using a return value, but in some situations we
// can't do anything useful with the value. Assign to this variable to avoid
@@ -1106,4 +1053,4 @@ typedef enum {
#define MIN_CD_SCOPE kCdScopeWindow
#define MAX_CD_SCOPE kCdScopeGlobal
-#endif /* NVIM_GLOBALS_H */
+#endif // NVIM_GLOBALS_H
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index 67a7e58ed7..bb443161ef 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -3372,11 +3372,9 @@ term_again:
continue;
}
- /*
- * Are we at the start of a cpp base class declaration or
- * constructor initialization?
- */ /* XXX */
- n = false;
+ // Are we at the start of a cpp base class declaration or
+ // constructor initialization? XXX
+ n = 0;
if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{') {
n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
l = get_cursor_line_ptr();
@@ -3409,7 +3407,6 @@ term_again:
* } foo,
* bar;
*/
- n = 0;
if (cin_ends_in(l, (char_u *)",", NULL)
|| (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\')) {
/* take us back to opening paren */
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 9e0063ebaa..9167ec5e54 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -11,6 +11,7 @@
#include "nvim/func_attr.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/private/handle.h"
#include "nvim/api/vim.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/vim.h"
@@ -19,6 +20,7 @@
#include "nvim/message.h"
#include "nvim/memline.h"
#include "nvim/buffer_defs.h"
+#include "nvim/regexp.h"
#include "nvim/macros.h"
#include "nvim/screen.h"
#include "nvim/cursor.h"
@@ -244,6 +246,14 @@ static int nlua_schedule(lua_State *const lstate)
return 0;
}
+static struct luaL_Reg regex_meta[] = {
+ { "__gc", regex_gc },
+ { "__tostring", regex_tostring },
+ { "match_str", regex_match_str },
+ { "match_line", regex_match_line },
+ { NULL, NULL }
+};
+
/// Initialize lua interpreter state
///
/// Called by lua interpreter itself to initialize state.
@@ -291,6 +301,15 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// call
lua_pushcfunction(lstate, &nlua_call);
lua_setfield(lstate, -2, "call");
+ // regex
+ lua_pushcfunction(lstate, &nlua_regex);
+ lua_setfield(lstate, -2, "regex");
+
+ luaL_newmetatable(lstate, "nvim_regex");
+ luaL_register(lstate, NULL, regex_meta);
+ lua_pushvalue(lstate, -1); // [meta, meta]
+ lua_setfield(lstate, -2, "__index"); // [meta]
+ lua_pop(lstate, 1); // don't use metatable now
// rpcrequest
lua_pushcfunction(lstate, &nlua_rpcrequest);
@@ -1037,3 +1056,136 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
lua_pushcfunction(lstate, ts_lua_parse_query);
lua_setfield(lstate, -2, "_ts_parse_query");
}
+
+static int nlua_regex(lua_State *lstate)
+{
+ Error err = ERROR_INIT;
+ const char *text = luaL_checkstring(lstate, 1);
+ regprog_T *prog = NULL;
+
+ TRY_WRAP({
+ try_start();
+ prog = vim_regcomp((char_u *)text, RE_AUTO | RE_MAGIC | RE_STRICT);
+ try_end(&err);
+ });
+
+ if (ERROR_SET(&err)) {
+ return luaL_error(lstate, "couldn't parse regex: %s", err.msg);
+ }
+ assert(prog);
+
+ regprog_T **p = lua_newuserdata(lstate, sizeof(regprog_T *));
+ *p = prog;
+
+ lua_getfield(lstate, LUA_REGISTRYINDEX, "nvim_regex"); // [udata, meta]
+ lua_setmetatable(lstate, -2); // [udata]
+ return 1;
+}
+
+static regprog_T **regex_check(lua_State *L)
+{
+ return luaL_checkudata(L, 1, "nvim_regex");
+}
+
+
+static int regex_gc(lua_State *lstate)
+{
+ regprog_T **prog = regex_check(lstate);
+ vim_regfree(*prog);
+ return 0;
+}
+
+static int regex_tostring(lua_State *lstate)
+{
+ lua_pushstring(lstate, "<regex>");
+ return 1;
+}
+
+static int regex_match(lua_State *lstate, regprog_T **prog, char_u *str)
+{
+ regmatch_T rm;
+ rm.regprog = *prog;
+ rm.rm_ic = false;
+ bool match = vim_regexec(&rm, str, 0);
+ *prog = rm.regprog;
+
+ if (match) {
+ lua_pushinteger(lstate, (lua_Integer)(rm.startp[0]-str));
+ lua_pushinteger(lstate, (lua_Integer)(rm.endp[0]-str));
+ return 2;
+ }
+ return 0;
+}
+
+static int regex_match_str(lua_State *lstate)
+{
+ regprog_T **prog = regex_check(lstate);
+ const char *str = luaL_checkstring(lstate, 2);
+ int nret = regex_match(lstate, prog, (char_u *)str);
+
+ if (!*prog) {
+ return luaL_error(lstate, "regex: internal error");
+ }
+
+ return nret;
+}
+
+static int regex_match_line(lua_State *lstate)
+{
+ regprog_T **prog = regex_check(lstate);
+
+ int narg = lua_gettop(lstate);
+ if (narg < 3) {
+ return luaL_error(lstate, "not enough args");
+ }
+
+ long bufnr = luaL_checkinteger(lstate, 2);
+ long rownr = luaL_checkinteger(lstate, 3);
+ long start = 0, end = -1;
+ if (narg >= 4) {
+ start = luaL_checkinteger(lstate, 4);
+ }
+ if (narg >= 5) {
+ end = luaL_checkinteger(lstate, 5);
+ if (end < 0) {
+ return luaL_error(lstate, "invalid end");
+ }
+ }
+
+ buf_T *buf = bufnr ? handle_get_buffer((int)bufnr) : curbuf;
+ if (!buf || buf->b_ml.ml_mfp == NULL) {
+ return luaL_error(lstate, "invalid buffer");
+ }
+
+ if (rownr >= buf->b_ml.ml_line_count) {
+ return luaL_error(lstate, "invalid row");
+ }
+
+ char_u *line = ml_get_buf(buf, rownr+1, false);
+ size_t len = STRLEN(line);
+
+ if (start < 0 || (size_t)start > len) {
+ return luaL_error(lstate, "invalid start");
+ }
+
+ char_u save = NUL;
+ if (end >= 0) {
+ if ((size_t)end > len || end < start) {
+ return luaL_error(lstate, "invalid end");
+ }
+ save = line[end];
+ line[end] = NUL;
+ }
+
+ int nret = regex_match(lstate, prog, line+start);
+
+ if (end >= 0) {
+ line[end] = save;
+ }
+
+ if (!*prog) {
+ return luaL_error(lstate, "regex: internal error");
+ }
+
+ return nret;
+}
diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c
index a420f79ffd..4753df7b87 100644
--- a/src/nvim/lua/treesitter.c
+++ b/src/nvim/lua/treesitter.c
@@ -93,10 +93,7 @@ static PMap(cstr_t) *langs;
static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
{
if (luaL_newmetatable(L, tname)) { // [meta]
- for (size_t i = 0; meta[i].name != NULL; i++) {
- lua_pushcfunction(L, meta[i].func); // [meta, func]
- lua_setfield(L, -2, meta[i].name); // [meta]
- }
+ luaL_register(L, NULL, meta);
lua_pushvalue(L, -1); // [meta, meta]
lua_setfield(L, -2, "__index"); // [meta]
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 56d9030a7f..4a9f2371a2 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -10,6 +10,7 @@
#include <msgpack.h>
#include "nvim/ascii.h"
+#include "nvim/channel.h"
#include "nvim/vim.h"
#include "nvim/main.h"
#include "nvim/aucmd.h"
diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c
index 25b07366d7..6dd452b5af 100644
--- a/src/nvim/marktree.c
+++ b/src/nvim/marktree.c
@@ -849,7 +849,8 @@ bool marktree_splice(MarkTree *b,
bool same_line = old_extent.row == 0 && new_extent.row == 0;
unrelative(start, &old_extent);
unrelative(start, &new_extent);
- MarkTreeIter itr[1], enditr[1];
+ MarkTreeIter itr[1] = { 0 };
+ MarkTreeIter enditr[1] = { 0 };
mtpos_t oldbase[MT_MAX_DEPTH];
@@ -905,6 +906,7 @@ continue_same_node:
refkey(b, itr->node, itr->i);
refkey(b, enditr->node, enditr->i);
} else {
+ past_right = true; // NOLINT
break;
}
}
@@ -1002,7 +1004,7 @@ void marktree_move_region(MarkTree *b,
mtpos_t start = { start_row, start_col }, size = { extent_row, extent_col };
mtpos_t end = size;
unrelative(start, &end);
- MarkTreeIter itr[1];
+ MarkTreeIter itr[1] = { 0 };
marktree_itr_get_ext(b, start, itr, false, true, NULL);
kvec_t(mtkey_t) saved = KV_INITIAL_VALUE;
while (itr->node) {
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 85e6697bfb..e67be60aa6 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -265,68 +265,70 @@ static struct
{ const char *name; int canon; }
enc_alias_table[] =
{
- {"ansi", IDX_LATIN_1},
- {"iso-8859-1", IDX_LATIN_1},
- {"latin2", IDX_ISO_2},
- {"latin3", IDX_ISO_3},
- {"latin4", IDX_ISO_4},
- {"cyrillic", IDX_ISO_5},
- {"arabic", IDX_ISO_6},
- {"greek", IDX_ISO_7},
- {"hebrew", IDX_ISO_8},
- {"latin5", IDX_ISO_9},
- {"turkish", IDX_ISO_9}, /* ? */
- {"latin6", IDX_ISO_10},
- {"nordic", IDX_ISO_10}, /* ? */
- {"thai", IDX_ISO_11}, /* ? */
- {"latin7", IDX_ISO_13},
- {"latin8", IDX_ISO_14},
- {"latin9", IDX_ISO_15},
- {"utf8", IDX_UTF8},
- {"unicode", IDX_UCS2},
- {"ucs2", IDX_UCS2},
- {"ucs2be", IDX_UCS2},
- {"ucs-2be", IDX_UCS2},
- {"ucs2le", IDX_UCS2LE},
- {"utf16", IDX_UTF16},
- {"utf16be", IDX_UTF16},
- {"utf-16be", IDX_UTF16},
- {"utf16le", IDX_UTF16LE},
- {"ucs4", IDX_UCS4},
- {"ucs4be", IDX_UCS4},
- {"ucs-4be", IDX_UCS4},
- {"ucs4le", IDX_UCS4LE},
- {"utf32", IDX_UCS4},
- {"utf-32", IDX_UCS4},
- {"utf32be", IDX_UCS4},
- {"utf-32be", IDX_UCS4},
- {"utf32le", IDX_UCS4LE},
- {"utf-32le", IDX_UCS4LE},
- {"932", IDX_CP932},
- {"949", IDX_CP949},
- {"936", IDX_CP936},
- {"gbk", IDX_CP936},
- {"950", IDX_CP950},
- {"eucjp", IDX_EUC_JP},
- {"unix-jis", IDX_EUC_JP},
- {"ujis", IDX_EUC_JP},
- {"shift-jis", IDX_SJIS},
- {"pck", IDX_SJIS}, /* Sun: PCK */
- {"euckr", IDX_EUC_KR},
- {"5601", IDX_EUC_KR}, /* Sun: KS C 5601 */
- {"euccn", IDX_EUC_CN},
- {"gb2312", IDX_EUC_CN},
- {"euctw", IDX_EUC_TW},
- {"japan", IDX_EUC_JP},
- {"korea", IDX_EUC_KR},
- {"prc", IDX_EUC_CN},
- {"chinese", IDX_EUC_CN},
- {"taiwan", IDX_EUC_TW},
- {"cp950", IDX_BIG5},
- {"950", IDX_BIG5},
- {"mac", IDX_MACROMAN},
- {"mac-roman", IDX_MACROMAN},
- {NULL, 0}
+ { "ansi", IDX_LATIN_1 },
+ { "iso-8859-1", IDX_LATIN_1 },
+ { "latin2", IDX_ISO_2 },
+ { "latin3", IDX_ISO_3 },
+ { "latin4", IDX_ISO_4 },
+ { "cyrillic", IDX_ISO_5 },
+ { "arabic", IDX_ISO_6 },
+ { "greek", IDX_ISO_7 },
+ { "hebrew", IDX_ISO_8 },
+ { "latin5", IDX_ISO_9 },
+ { "turkish", IDX_ISO_9 }, // ?
+ { "latin6", IDX_ISO_10 },
+ { "nordic", IDX_ISO_10 }, // ?
+ { "thai", IDX_ISO_11 }, // ?
+ { "latin7", IDX_ISO_13 },
+ { "latin8", IDX_ISO_14 },
+ { "latin9", IDX_ISO_15 },
+ { "utf8", IDX_UTF8 },
+ { "unicode", IDX_UCS2 },
+ { "ucs2", IDX_UCS2 },
+ { "ucs2be", IDX_UCS2 },
+ { "ucs-2be", IDX_UCS2 },
+ { "ucs2le", IDX_UCS2LE },
+ { "utf16", IDX_UTF16 },
+ { "utf16be", IDX_UTF16 },
+ { "utf-16be", IDX_UTF16 },
+ { "utf16le", IDX_UTF16LE },
+ { "ucs4", IDX_UCS4 },
+ { "ucs4be", IDX_UCS4 },
+ { "ucs-4be", IDX_UCS4 },
+ { "ucs4le", IDX_UCS4LE },
+ { "utf32", IDX_UCS4 },
+ { "utf-32", IDX_UCS4 },
+ { "utf32be", IDX_UCS4 },
+ { "utf-32be", IDX_UCS4 },
+ { "utf32le", IDX_UCS4LE },
+ { "utf-32le", IDX_UCS4LE },
+ { "932", IDX_CP932 },
+ { "949", IDX_CP949 },
+ { "936", IDX_CP936 },
+ { "gbk", IDX_CP936 },
+ { "950", IDX_CP950 },
+ { "eucjp", IDX_EUC_JP },
+ { "unix-jis", IDX_EUC_JP },
+ { "ujis", IDX_EUC_JP },
+ { "shift-jis", IDX_SJIS },
+ { "pck", IDX_SJIS }, // Sun: PCK
+ { "euckr", IDX_EUC_KR },
+ { "5601", IDX_EUC_KR }, // Sun: KS C 5601
+ { "euccn", IDX_EUC_CN },
+ { "gb2312", IDX_EUC_CN },
+ { "euctw", IDX_EUC_TW },
+ { "japan", IDX_EUC_JP },
+ { "korea", IDX_EUC_KR },
+ { "prc", IDX_EUC_CN },
+ { "zh-cn", IDX_EUC_CN },
+ { "chinese", IDX_EUC_CN },
+ { "zh-tw", IDX_EUC_TW },
+ { "taiwan", IDX_EUC_TW },
+ { "cp950", IDX_BIG5 },
+ { "950", IDX_BIG5 },
+ { "mac", IDX_MACROMAN },
+ { "mac-roman", IDX_MACROMAN },
+ { NULL, 0 }
};
/*
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index e395654e04..32d8352d9b 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -73,6 +73,7 @@ int jump_to_mouse(int flags,
int col = mouse_col;
int grid = mouse_grid;
int mouse_char;
+ int fdc = 0;
mouse_past_bottom = false;
mouse_past_eol = false;
@@ -131,6 +132,7 @@ retnomove:
if (wp == NULL) {
return IN_UNKNOWN;
}
+ fdc = win_fdccol_count(wp);
dragwin = NULL;
// winpos and height may change in win_enter()!
if (grid == DEFAULT_GRID_HANDLE && row >= wp->w_height) {
@@ -165,9 +167,8 @@ retnomove:
|| (!on_status_line
&& !on_sep_line
&& (wp->w_p_rl
- ? col < wp->w_width_inner - wp->w_p_fdc
- : col >= wp->w_p_fdc + (cmdwin_type == 0 && wp == curwin
- ? 0 : 1))
+ ? col < wp->w_width_inner - fdc
+ : col >= fdc + (cmdwin_type == 0 && wp == curwin ? 0 : 1))
&& (flags & MOUSE_MAY_STOP_VIS)))) {
end_visual_mode();
redraw_curbuf_later(INVERTED); // delete the inversion
@@ -305,8 +306,8 @@ retnomove:
}
// Check for position outside of the fold column.
- if (curwin->w_p_rl ? col < curwin->w_width_inner - curwin->w_p_fdc :
- col >= curwin->w_p_fdc + (cmdwin_type == 0 ? 0 : 1)) {
+ if (curwin->w_p_rl ? col < curwin->w_width_inner - fdc :
+ col >= fdc + (cmdwin_type == 0 ? 0 : 1)) {
mouse_char = ' ';
}
diff --git a/src/nvim/move.c b/src/nvim/move.c
index 3ae4f32a83..f47853e9cb 100644
--- a/src/nvim/move.c
+++ b/src/nvim/move.c
@@ -674,7 +674,7 @@ int win_col_off(win_T *wp)
{
return ((wp->w_p_nu || wp->w_p_rnu) ? number_width(wp) + 1 : 0)
+ (cmdwin_type == 0 || wp != curwin ? 0 : 1)
- + (int)wp->w_p_fdc
+ + win_fdccol_count(wp)
+ (win_signcol_count(wp) * win_signcol_width(wp));
}
diff --git a/src/nvim/msgpack_rpc/channel.h b/src/nvim/msgpack_rpc/channel.h
index 9ff5abdc5f..90e1c7d48b 100644
--- a/src/nvim/msgpack_rpc/channel.h
+++ b/src/nvim/msgpack_rpc/channel.h
@@ -15,7 +15,7 @@
/// HACK: os/input.c drains this queue immediately before blocking for input.
/// Events on this queue are async-safe, but they need the resolved state
/// of os_inchar(), so they are processed "just-in-time".
-MultiQueue *ch_before_blocking_events;
+EXTERN MultiQueue *ch_before_blocking_events INIT(= NULL);
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index c69b10f99a..6434bd00d8 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -4458,16 +4458,16 @@ dozet:
case 'r':
curwin->w_p_fdl += cap->count1;
{
- int d = getDeepestNesting();
+ int d = getDeepestNesting(curwin);
if (curwin->w_p_fdl >= d) {
curwin->w_p_fdl = d;
}
}
break;
- /* "zR": open all folds */
- case 'R': curwin->w_p_fdl = getDeepestNesting();
- old_fdl = -1; /* force an update */
+ case 'R': // "zR": open all folds
+ curwin->w_p_fdl = getDeepestNesting(curwin);
+ old_fdl = -1; // force an update
break;
case 'j': /* "zj" move to next fold downwards */
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 735a33ca97..5457400b76 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -842,6 +842,15 @@ static bool is_append_register(int regname)
return ASCII_ISUPPER(regname);
}
+/// @see get_yank_register
+/// @returns true when register should be inserted literally
+/// (selection or clipboard)
+static inline bool is_literal_register(int regname)
+ FUNC_ATTR_CONST
+{
+ return regname == '*' || regname == '+';
+}
+
/// Returns a copy of contents in register `name`
/// for use in do_put. Should be freed by caller.
yankreg_T *copy_register(int name)
@@ -1152,11 +1161,12 @@ static int put_in_typebuf(
*/
int insert_reg(
int regname,
- int literally /* insert literally, not as if typed */
+ bool literally_arg // insert literally, not as if typed
)
{
int retval = OK;
bool allocated;
+ const bool literally = literally_arg || is_literal_register(regname);
/*
* It is possible to get into an endless loop by having CTRL-R a in
@@ -1326,12 +1336,14 @@ bool get_spec_reg(
/// register contents will be interpreted as commands.
///
/// @param regname Register name.
-/// @param literally Insert text literally instead of "as typed".
+/// @param literally_arg Insert text literally instead of "as typed".
/// @param remcr When true, don't add CR characters.
///
/// @returns FAIL for failure, OK otherwise
-bool cmdline_paste_reg(int regname, bool literally, bool remcr)
+bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr)
{
+ const bool literally = literally_arg || is_literal_register(regname);
+
yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
if (reg->y_array == NULL)
return FAIL;
@@ -2534,7 +2546,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
case kMTCharWise:
{
colnr_T startcol = 0, endcol = MAXCOL;
- int is_oneChar = FALSE;
+ int is_oneChar = false;
colnr_T cs, ce;
p = ml_get(lnum);
bd.startspaces = 0;
@@ -2565,8 +2577,8 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
&& utf_head_off(p, p + endcol) == 0)) {
if (oap->start.lnum == oap->end.lnum
&& oap->start.col == oap->end.col) {
- /* Special case: inside a single char */
- is_oneChar = TRUE;
+ // Special case: inside a single char
+ is_oneChar = true;
bd.startspaces = oap->end.coladd
- oap->start.coladd + oap->inclusive;
endcol = startcol;
@@ -4425,8 +4437,8 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
bdp->textlen = 0;
bdp->start_vcol = 0;
bdp->end_vcol = 0;
- bdp->is_short = FALSE;
- bdp->is_oneChar = FALSE;
+ bdp->is_short = false;
+ bdp->is_oneChar = false;
bdp->pre_whitesp = 0;
bdp->pre_whitesp_c = 0;
bdp->end_char_vcols = 0;
@@ -4452,9 +4464,10 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
bdp->start_char_vcols = incr;
if (bdp->start_vcol < oap->start_vcol) { /* line too short */
bdp->end_vcol = bdp->start_vcol;
- bdp->is_short = TRUE;
- if (!is_del || oap->op_type == OP_APPEND)
+ bdp->is_short = true;
+ if (!is_del || oap->op_type == OP_APPEND) {
bdp->endspaces = oap->end_vcol - oap->start_vcol + 1;
+ }
} else {
/* notice: this converts partly selected Multibyte characters to
* spaces, too. */
@@ -4463,11 +4476,11 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
bdp->startspaces = bdp->start_char_vcols - bdp->startspaces;
pend = pstart;
bdp->end_vcol = bdp->start_vcol;
- if (bdp->end_vcol > oap->end_vcol) { /* it's all in one character */
- bdp->is_oneChar = TRUE;
- if (oap->op_type == OP_INSERT)
+ if (bdp->end_vcol > oap->end_vcol) { // it's all in one character
+ bdp->is_oneChar = true;
+ if (oap->op_type == OP_INSERT) {
bdp->endspaces = bdp->start_char_vcols - bdp->startspaces;
- else if (oap->op_type == OP_APPEND) {
+ } else if (oap->op_type == OP_APPEND) {
bdp->startspaces += oap->end_vcol - oap->start_vcol + 1;
bdp->endspaces = bdp->start_char_vcols - bdp->startspaces;
} else {
@@ -4492,17 +4505,16 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum,
if (bdp->end_vcol <= oap->end_vcol
&& (!is_del
|| oap->op_type == OP_APPEND
- || oap->op_type == OP_REPLACE)) { /* line too short */
- bdp->is_short = TRUE;
- /* Alternative: include spaces to fill up the block.
- * Disadvantage: can lead to trailing spaces when the line is
- * short where the text is put */
- /* if (!is_del || oap->op_type == OP_APPEND) */
- if (oap->op_type == OP_APPEND || virtual_op)
+ || oap->op_type == OP_REPLACE)) { // line too short
+ bdp->is_short = true;
+ // Alternative: include spaces to fill up the block.
+ // Disadvantage: can lead to trailing spaces when the line is
+ // short where the text is put
+ // if (!is_del || oap->op_type == OP_APPEND)
+ if (oap->op_type == OP_APPEND || virtual_op) {
bdp->endspaces = oap->end_vcol - bdp->end_vcol
+ oap->inclusive;
- else
- bdp->endspaces = 0; /* replace doesn't add characters */
+ }
} else if (bdp->end_vcol > oap->end_vcol) {
bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1;
if (!is_del && bdp->endspaces) {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 478c9a0ff8..5a27ff21cc 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -315,6 +315,9 @@ static char *(p_scl_values[]) = { "yes", "no", "auto", "auto:1", "auto:2",
"auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
"yes:1", "yes:2", "yes:3", "yes:4", "yes:5", "yes:6", "yes:7", "yes:8",
"yes:9", NULL };
+static char *(p_fdc_values[]) = { "auto:1", "auto:2",
+ "auto:3", "auto:4", "auto:5", "auto:6", "auto:7", "auto:8", "auto:9",
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", NULL };
/// All possible flags for 'shm'.
static char_u SHM_ALL[] = {
@@ -2565,7 +2568,7 @@ static bool valid_filetype(const char_u *val)
bool valid_spellang(const char_u *val)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- return valid_name(val, ".-_,");
+ return valid_name(val, ".-_,@");
}
/// Return true if "val" is a valid 'spellfile' value.
@@ -3199,6 +3202,11 @@ ambw_end:
if (check_opt_strings(*varp, p_scl_values, false) != OK) {
errmsg = e_invarg;
}
+ } else if (varp == &curwin->w_p_fdc || varp == &curwin->w_allbuf_opt.wo_fdc) {
+ // 'foldcolumn'
+ if (check_opt_strings(*varp, p_fdc_values, false) != OK) {
+ errmsg = e_invarg;
+ }
} else if (varp == &p_pt) {
// 'pastetoggle': translate key codes like in a mapping
if (*p_pt) {
@@ -4363,12 +4371,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
if (value < 0) {
errmsg = e_positive;
}
- } else if (pp == &curwin->w_p_fdc || pp == &curwin->w_allbuf_opt.wo_fdc) {
- if (value < 0) {
- errmsg = e_positive;
- } else if (value > 12) {
- errmsg = e_invarg;
- }
} else if (pp == &curwin->w_p_cole || pp == &curwin->w_allbuf_opt.wo_cole) {
if (value < 0) {
errmsg = e_positive;
@@ -5936,8 +5938,9 @@ void copy_winopt(winopt_T *from, winopt_T *to)
to->wo_diff_saved = from->wo_diff_saved;
to->wo_cocu = vim_strsave(from->wo_cocu);
to->wo_cole = from->wo_cole;
- to->wo_fdc = from->wo_fdc;
- to->wo_fdc_save = from->wo_fdc_save;
+ to->wo_fdc = vim_strsave(from->wo_fdc);
+ to->wo_fdc_save = from->wo_diff_saved
+ ? vim_strsave(from->wo_fdc_save) : empty_option;
to->wo_fen = from->wo_fen;
to->wo_fen_save = from->wo_fen_save;
to->wo_fdi = vim_strsave(from->wo_fdi);
@@ -5973,6 +5976,8 @@ void check_win_options(win_T *win)
*/
static void check_winopt(winopt_T *wop)
{
+ check_string_option(&wop->wo_fdc);
+ check_string_option(&wop->wo_fdc_save);
check_string_option(&wop->wo_fdi);
check_string_option(&wop->wo_fdm);
check_string_option(&wop->wo_fdm_save);
@@ -5995,6 +6000,8 @@ static void check_winopt(winopt_T *wop)
*/
void clear_winopt(winopt_T *wop)
{
+ clear_string_option(&wop->wo_fdc);
+ clear_string_option(&wop->wo_fdc_save);
clear_string_option(&wop->wo_fdi);
clear_string_option(&wop->wo_fdm);
clear_string_option(&wop->wo_fdm_save);
@@ -6073,10 +6080,8 @@ void buf_copy_options(buf_T *buf, int flags)
save_p_isk = buf->b_p_isk;
buf->b_p_isk = NULL;
}
- /*
- * Always free the allocated strings.
- * If not already initialized, set 'readonly' and copy 'fileformat'.
- */
+ // Always free the allocated strings. If not already initialized,
+ // reset 'readonly' and copy 'fileformat'.
if (!buf->b_p_initialized) {
free_buf_options(buf, true);
buf->b_p_ro = false; // don't copy readonly
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 7d080b8d56..c18b9e0697 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -831,10 +831,11 @@ return {
},
{
full_name='foldcolumn', abbreviation='fdc',
- type='number', scope={'window'},
+ type='string', scope={'window'},
vi_def=true,
+ alloced=true,
redraw={'current_window'},
- defaults={if_true={vi=false}}
+ defaults={if_true={vi="0"}}
},
{
full_name='foldenable', abbreviation='fen',
diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c
index 3b8470182a..6294d5e4e2 100644
--- a/src/nvim/os/shell.c
+++ b/src/nvim/os/shell.c
@@ -448,7 +448,6 @@ int os_expand_wildcards(int num_pat, char_u **pat, int *num_file,
} else {
buffer[len] = NUL;
}
- i = 0;
for (p = buffer; p < buffer + len; p++) {
if (*p == NUL || (*p == ' ' && check_spaces)) { // count entry
i++;
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index b6da02d9c3..2e2c6ca737 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -334,10 +334,10 @@ int update_screen(int type)
}
return FAIL;
}
+ updating_screen = 1;
- updating_screen = TRUE;
- ++display_tick; /* let syntax code know we're in a next round of
- * display updating */
+ display_tick++; // let syntax code know we're in a next round of
+ // display updating
// Tricky: vim code can reset msg_scrolled behind our back, so need
// separate bookkeeping for now.
@@ -565,7 +565,7 @@ int update_screen(int type)
wp->w_buffer->b_mod_set = false;
}
- updating_screen = FALSE;
+ updating_screen = 0;
/* Clear or redraw the command line. Done last, because scrolling may
* mess up the command line. */
@@ -1744,7 +1744,7 @@ static int advance_color_col(int vcol, int **color_cols)
// space is available for window "wp", minus "col".
static int compute_foldcolumn(win_T *wp, int col)
{
- int fdc = wp->w_p_fdc;
+ int fdc = win_fdccol_count(wp);
int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
int wwidth = wp->w_grid.Columns;
@@ -2215,9 +2215,10 @@ win_line (
int n_skip = 0; /* nr of chars to skip for 'nowrap' */
- int fromcol = 0, tocol = 0; // start/end of inverting
+ int fromcol = -10; // start of inverting
+ int tocol = MAXCOL; // end of inverting
int fromcol_prev = -2; // start of inverting after cursor
- int noinvcur = false; // don't invert the cursor
+ bool noinvcur = false; // don't invert the cursor
pos_T *top, *bot;
int lnum_in_visual_area = false;
pos_T pos;
@@ -2416,27 +2417,26 @@ win_line (
capcol_lnum = 0;
}
- //
- // handle visual active in this window
- //
- fromcol = -10;
- tocol = MAXCOL;
+ // handle Visual active in this window
if (VIsual_active && wp->w_buffer == curwin->w_buffer) {
- // Visual is after curwin->w_cursor
if (ltoreq(curwin->w_cursor, VIsual)) {
+ // Visual is after curwin->w_cursor
top = &curwin->w_cursor;
bot = &VIsual;
- } else { // Visual is before curwin->w_cursor
+ } else {
+ // Visual is before curwin->w_cursor
top = &VIsual;
bot = &curwin->w_cursor;
}
lnum_in_visual_area = (lnum >= top->lnum && lnum <= bot->lnum);
- if (VIsual_mode == Ctrl_V) { // block mode
+ if (VIsual_mode == Ctrl_V) {
+ // block mode
if (lnum_in_visual_area) {
fromcol = wp->w_old_cursor_fcol;
tocol = wp->w_old_cursor_lcol;
}
- } else { // non-block mode
+ } else {
+ // non-block mode
if (lnum > top->lnum && lnum <= bot->lnum) {
fromcol = 0;
} else if (lnum == top->lnum) {
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 23dd447744..ab5d04d39b 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -198,7 +198,7 @@ static void insert_sign(
// column for signs.
if (buf->b_signlist == NULL) {
redraw_buf_later(buf, NOT_VALID);
- changed_cline_bef_curs();
+ changed_line_abv_curs();
}
// first sign in signlist
@@ -265,6 +265,81 @@ dict_T * sign_get_info(signlist_T *sign)
return d;
}
+// Sort the signs placed on the same line as "sign" by priority. Invoked after
+// changing the priority of an already placed sign. Assumes the signs in the
+// buffer are sorted by line number and priority.
+static void sign_sort_by_prio_on_line(buf_T *buf, signlist_T *sign)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // If there is only one sign in the buffer or only one sign on the line or
+ // the sign is already sorted by priority, then return.
+ if ((sign->prev == NULL
+ || sign->prev->lnum != sign->lnum
+ || sign->prev->priority > sign->priority)
+ && (sign->next == NULL
+ || sign->next->lnum != sign->lnum
+ || sign->next->priority < sign->priority)) {
+ return;
+ }
+
+ // One or more signs on the same line as 'sign'
+ // Find a sign after which 'sign' should be inserted
+
+ // First search backward for a sign with higher priority on the same line
+ signlist_T *p = sign;
+ while (p->prev != NULL
+ && p->prev->lnum == sign->lnum
+ && p->prev->priority <= sign->priority) {
+ p = p->prev;
+ }
+ if (p == sign) {
+ // Sign not found. Search forward for a sign with priority just before
+ // 'sign'.
+ p = sign->next;
+ while (p->next != NULL
+ && p->next->lnum == sign->lnum
+ && p->next->priority > sign->priority) {
+ p = p->next;
+ }
+ }
+
+ // Remove 'sign' from the list
+ if (buf->b_signlist == sign) {
+ buf->b_signlist = sign->next;
+ }
+ if (sign->prev != NULL) {
+ sign->prev->next = sign->next;
+ }
+ if (sign->next != NULL) {
+ sign->next->prev = sign->prev;
+ }
+ sign->prev = NULL;
+ sign->next = NULL;
+
+ // Re-insert 'sign' at the right place
+ if (p->priority <= sign->priority) {
+ // 'sign' has a higher priority and should be inserted before 'p'
+ sign->prev = p->prev;
+ sign->next = p;
+ p->prev = sign;
+ if (sign->prev != NULL) {
+ sign->prev->next = sign;
+ }
+ if (buf->b_signlist == p) {
+ buf->b_signlist = sign;
+ }
+ } else {
+ // 'sign' has a lower priority and should be inserted after 'p'
+ sign->prev = p;
+ sign->next = p->next;
+ p->next = sign;
+ if (sign->next != NULL) {
+ sign->next->prev = sign;
+ }
+ }
+}
+
+
/// Add the sign into the signlist. Find the right spot to do it though.
void buf_addsign(
buf_T *buf, // buffer to store sign in
@@ -284,6 +359,8 @@ void buf_addsign(
&& sign_in_group(sign, groupname)) {
// Update an existing sign
sign->typenr = typenr;
+ sign->priority = prio;
+ sign_sort_by_prio_on_line(buf, sign);
return;
} else if (lnum < sign->lnum) {
insert_sign_by_lnum_prio(buf, prev, id, groupname, prio, lnum, typenr);
@@ -418,11 +495,11 @@ linenr_T buf_delsign(
}
}
- // When deleted the last sign needs to redraw the windows to remove the
- // sign column.
+ // When deleting the last sign the cursor position may change, because the
+ // sign columns no longer shows. And the 'signcolumn' may be hidden.
if (buf->b_signlist == NULL) {
redraw_buf_later(buf, NOT_VALID);
- changed_cline_bef_curs();
+ changed_line_abv_curs();
}
return lnum;
@@ -495,7 +572,7 @@ void buf_delete_signs(buf_T *buf, char_u *group)
// When deleting the last sign need to redraw the windows to remove the
// sign column. Not when curwin is NULL (this means we're exiting).
if (buf->b_signlist != NULL && curwin != NULL) {
- changed_cline_bef_curs();
+ changed_line_abv_curs();
}
lastp = &buf->b_signlist;
@@ -754,6 +831,14 @@ int sign_define_by_name(
} else {
sp_prev->sn_next = sp;
}
+ } else {
+ // Signs may already exist, a redraw is needed in windows with a
+ // non-empty sign list.
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_buffer->b_signlist != NULL) {
+ redraw_buf_later(wp->w_buffer, NOT_VALID);
+ }
+ }
}
// set values for a defined sign.
@@ -1531,10 +1616,44 @@ static enum
EXP_SUBCMD, // expand :sign sub-commands
EXP_DEFINE, // expand :sign define {name} args
EXP_PLACE, // expand :sign place {id} args
+ EXP_LIST, // expand :sign place args
EXP_UNPLACE, // expand :sign unplace"
- EXP_SIGN_NAMES // expand with name of placed signs
+ EXP_SIGN_NAMES, // expand with name of placed signs
+ EXP_SIGN_GROUPS, // expand with name of placed sign groups
} expand_what;
+// Return the n'th sign name (used for command line completion)
+static char_u *get_nth_sign_name(int idx)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ // Complete with name of signs already defined
+ int current_idx = 0;
+ for (sign_T *sp = first_sign; sp != NULL; sp = sp->sn_next) {
+ if (current_idx++ == idx) {
+ return sp->sn_name;
+ }
+ }
+ return NULL;
+}
+
+// Return the n'th sign group name (used for command line completion)
+static char_u *get_nth_sign_group_name(int idx)
+{
+ // Complete with name of sign groups already defined
+ int current_idx = 0;
+ int todo = (int)sg_table.ht_used;
+ for (hashitem_T *hi = sg_table.ht_array; todo > 0; hi++) {
+ if (!HASHITEM_EMPTY(hi)) {
+ todo--;
+ if (current_idx++ == idx) {
+ signgroup_T *const group = HI2SG(hi);
+ return group->sg_name;
+ }
+ }
+ }
+ return NULL;
+}
+
/// Function given to ExpandGeneric() to obtain the sign command
/// expansion.
char_u * get_sign_name(expand_T *xp, int idx)
@@ -1552,20 +1671,18 @@ char_u * get_sign_name(expand_T *xp, int idx)
"buffer=", NULL };
return (char_u *)place_arg[idx];
}
+ case EXP_LIST: {
+ char *list_arg[] = { "group=", "file=", "buffer=", NULL };
+ return (char_u *)list_arg[idx];
+ }
case EXP_UNPLACE: {
char *unplace_arg[] = { "group=", "file=", "buffer=", NULL };
return (char_u *)unplace_arg[idx];
}
- case EXP_SIGN_NAMES: {
- // Complete with name of signs already defined
- int current_idx = 0;
- for (sign_T *sp = first_sign; sp != NULL; sp = sp->sn_next) {
- if (current_idx++ == idx) {
- return sp->sn_name;
- }
- }
- }
- return NULL;
+ case EXP_SIGN_NAMES:
+ return get_nth_sign_name(idx);
+ case EXP_SIGN_GROUPS:
+ return get_nth_sign_group_name(idx);
default:
return NULL;
}
@@ -1574,7 +1691,6 @@ char_u * get_sign_name(expand_T *xp, int idx)
/// Handle command line completion for :sign command.
void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
{
- char_u *p;
char_u *end_subcmd;
char_u *last;
int cmd_idx;
@@ -1598,26 +1714,6 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
// |
// begin_subcmd_args
begin_subcmd_args = skipwhite(end_subcmd);
- p = skiptowhite(begin_subcmd_args);
- if (*p == NUL) {
- //
- // Expand first argument of subcmd when possible.
- // For ":jump {id}" and ":unplace {id}", we could
- // possibly expand the ids of all signs already placed.
- //
- xp->xp_pattern = begin_subcmd_args;
- switch (cmd_idx) {
- case SIGNCMD_LIST:
- case SIGNCMD_UNDEFINE:
- // :sign list <CTRL-D>
- // :sign undefine <CTRL-D>
- expand_what = EXP_SIGN_NAMES;
- break;
- default:
- xp->xp_context = EXPAND_NOTHING;
- }
- return;
- }
// Expand last argument of subcmd.
//
@@ -1626,6 +1722,7 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
// p
// Loop until reaching last argument.
+ char_u *p = begin_subcmd_args;
do {
p = skipwhite(p);
last = p;
@@ -1645,7 +1742,20 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
expand_what = EXP_DEFINE;
break;
case SIGNCMD_PLACE:
- expand_what = EXP_PLACE;
+ // List placed signs
+ if (ascii_isdigit(*begin_subcmd_args)) {
+ // :sign place {id} {args}...
+ expand_what = EXP_PLACE;
+ } else {
+ // :sign place {args}...
+ expand_what = EXP_LIST;
+ }
+ break;
+ case SIGNCMD_LIST:
+ case SIGNCMD_UNDEFINE:
+ // :sign list <CTRL-D>
+ // :sign undefine <CTRL-D>
+ expand_what = EXP_SIGN_NAMES;
break;
case SIGNCMD_JUMP:
case SIGNCMD_UNPLACE:
@@ -1659,19 +1769,33 @@ void set_context_in_sign_cmd(expand_T *xp, char_u *arg)
xp->xp_pattern = p + 1;
switch (cmd_idx) {
case SIGNCMD_DEFINE:
- if (STRNCMP(last, "texthl", p - last) == 0
- || STRNCMP(last, "linehl", p - last) == 0
- || STRNCMP(last, "numhl", p - last) == 0) {
+ if (STRNCMP(last, "texthl", 6) == 0
+ || STRNCMP(last, "linehl", 6) == 0
+ || STRNCMP(last, "numhl", 5) == 0) {
xp->xp_context = EXPAND_HIGHLIGHT;
- } else if (STRNCMP(last, "icon", p - last) == 0) {
+ } else if (STRNCMP(last, "icon", 4) == 0) {
xp->xp_context = EXPAND_FILES;
} else {
xp->xp_context = EXPAND_NOTHING;
}
break;
case SIGNCMD_PLACE:
- if (STRNCMP(last, "name", p - last) == 0) {
+ if (STRNCMP(last, "name", 4) == 0) {
expand_what = EXP_SIGN_NAMES;
+ } else if (STRNCMP(last, "group", 5) == 0) {
+ expand_what = EXP_SIGN_GROUPS;
+ } else if (STRNCMP(last, "file", 4) == 0) {
+ xp->xp_context = EXPAND_BUFFERS;
+ } else {
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ break;
+ case SIGNCMD_UNPLACE:
+ case SIGNCMD_JUMP:
+ if (STRNCMP(last, "group", 5) == 0) {
+ expand_what = EXP_SIGN_GROUPS;
+ } else if (STRNCMP(last, "file", 4) == 0) {
+ xp->xp_context = EXPAND_BUFFERS;
} else {
xp->xp_context = EXPAND_NOTHING;
}
diff --git a/src/nvim/testdir/test_diffmode.vim b/src/nvim/testdir/test_diffmode.vim
index 21e0271bda..fed642e34b 100644
--- a/src/nvim/testdir/test_diffmode.vim
+++ b/src/nvim/testdir/test_diffmode.vim
@@ -67,7 +67,7 @@ func Common_vert_split()
set foldmethod=marker foldcolumn=4
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
- call assert_equal(4, &foldcolumn)
+ call assert_equal('4', &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
@@ -76,7 +76,7 @@ func Common_vert_split()
vert diffsplit Xtest2
call assert_equal(1, &diff)
call assert_equal('diff', &foldmethod)
- call assert_equal(2, &foldcolumn)
+ call assert_equal('2', &foldcolumn)
call assert_equal(1, &scrollbind)
call assert_equal(1, &cursorbind)
call assert_equal(0, &wrap)
@@ -142,7 +142,7 @@ func Common_vert_split()
1wincmd w
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
- call assert_equal(4, &foldcolumn)
+ call assert_equal('4', &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
@@ -150,7 +150,7 @@ func Common_vert_split()
wincmd w
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
- call assert_equal(4, &foldcolumn)
+ call assert_equal('4', &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
@@ -158,7 +158,7 @@ func Common_vert_split()
wincmd w
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
- call assert_equal(4, &foldcolumn)
+ call assert_equal('4', &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim
index 7290cceb0b..9605348389 100644
--- a/src/nvim/testdir/test_filetype.vim
+++ b/src/nvim/testdir/test_filetype.vim
@@ -600,6 +600,7 @@ let s:script_checks = {
\ 'haskell': [['#!/path/haskell']],
\ 'cpp': [['// Standard iostream objects -*- C++ -*-'],
\ ['// -*- C++ -*-']],
+ \ 'yaml': [['%YAML 1.2']],
\ }
func Test_script_detection()
diff --git a/src/nvim/testdir/test_messages.vim b/src/nvim/testdir/test_messages.vim
index 265dee66ce..aad21c002f 100644
--- a/src/nvim/testdir/test_messages.vim
+++ b/src/nvim/testdir/test_messages.vim
@@ -1,4 +1,4 @@
-" Tests for :messages
+" Tests for :messages, :echomsg, :echoerr
function Test_messages()
let oldmore = &more
@@ -65,6 +65,35 @@ func Test_message_completion()
call assert_equal('"message clear', @:)
endfunc
+func Test_echomsg()
+ call assert_equal("\nhello", execute(':echomsg "hello"'))
+ call assert_equal("\n", execute(':echomsg ""'))
+ call assert_equal("\n12345", execute(':echomsg 12345'))
+ call assert_equal("\n[]", execute(':echomsg []'))
+ call assert_equal("\n[1, 2, 3]", execute(':echomsg [1, 2, 3]'))
+ call assert_equal("\n{}", execute(':echomsg {}'))
+ call assert_equal("\n{'a': 1, 'b': 2}", execute(':echomsg {"a": 1, "b": 2}'))
+ if has('float')
+ call assert_equal("\n1.23", execute(':echomsg 1.23'))
+ endif
+ call assert_match("function('<lambda>\\d*')", execute(':echomsg {-> 1234}'))
+endfunc
+
+func Test_echoerr()
+ throw 'skipped: Nvim does not support test_ignore_error()'
+ call test_ignore_error('IgNoRe')
+ call assert_equal("\nIgNoRe hello", execute(':echoerr "IgNoRe hello"'))
+ call assert_equal("\n12345 IgNoRe", execute(':echoerr 12345 "IgNoRe"'))
+ call assert_equal("\n[1, 2, 'IgNoRe']", execute(':echoerr [1, 2, "IgNoRe"]'))
+ call assert_equal("\n{'IgNoRe': 2, 'a': 1}", execute(':echoerr {"a": 1, "IgNoRe": 2}'))
+ if has('float')
+ call assert_equal("\n1.23 IgNoRe", execute(':echoerr 1.23 "IgNoRe"'))
+ endif
+ call test_ignore_error('<lambda>')
+ call assert_match("function('<lambda>\\d*')", execute(':echoerr {-> 1234}'))
+ call test_ignore_error('RESET')
+endfunc
+
func Test_echospace()
set noruler noshowcmd laststatus=1
call assert_equal(&columns - 1, v:echospace)
diff --git a/src/nvim/testdir/test_number.vim b/src/nvim/testdir/test_number.vim
index 59debcea0d..3c9afc41d5 100644
--- a/src/nvim/testdir/test_number.vim
+++ b/src/nvim/testdir/test_number.vim
@@ -252,3 +252,14 @@ func Test_numberwidth_adjusted()
call s:compare_lines(expect, lines)
call s:close_windows()
endfunc
+
+" This was causing a memcheck error
+func Test_relativenumber_uninitialised()
+ new
+ set rnu
+ call setline(1, ["a", "b"])
+ redraw
+ call feedkeys("j", 'xt')
+ redraw
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_options.vim b/src/nvim/testdir/test_options.vim
index 29d391c232..c2f710358b 100644
--- a/src/nvim/testdir/test_options.vim
+++ b/src/nvim/testdir/test_options.vim
@@ -511,3 +511,11 @@ func Test_shortmess_F2()
bwipe
bwipe
endfunc
+
+func Test_visualbell()
+ set belloff=
+ set visualbell
+ call assert_beeps('normal 0h')
+ set novisualbell
+ set belloff=all
+endfunc
diff --git a/src/nvim/testdir/test_restricted.vim b/src/nvim/testdir/test_restricted.vim
new file mode 100644
index 0000000000..a29f7c33d3
--- /dev/null
+++ b/src/nvim/testdir/test_restricted.vim
@@ -0,0 +1,103 @@
+" Test for "rvim" or "vim -Z"
+
+source shared.vim
+
+"if has('win32') && has('gui')
+" " Win32 GUI shows a dialog instead of displaying the error in the last line.
+" finish
+"endif
+
+func Test_restricted()
+ call Run_restricted_test('!ls', 'E145:')
+endfunc
+
+func Run_restricted_test(ex_cmd, error)
+ let cmd = GetVimCommand('Xrestricted')
+ if cmd == ''
+ return
+ endif
+
+ " Use a VimEnter autocommand to avoid that the error message is displayed in
+ " a dialog with an OK button.
+ call writefile([
+ \ "func Init()",
+ \ " silent! " . a:ex_cmd,
+ \ " call writefile([v:errmsg], 'Xrestrout')",
+ \ " qa!",
+ \ "endfunc",
+ \ "au VimEnter * call Init()",
+ \ ], 'Xrestricted')
+ call system(cmd . ' -Z')
+ call assert_match(a:error, join(readfile('Xrestrout')))
+
+ call delete('Xrestricted')
+ call delete('Xrestrout')
+endfunc
+
+func Test_restricted_lua()
+ if !has('lua')
+ throw 'Skipped: Lua is not supported'
+ endif
+ call Run_restricted_test('lua print("Hello, Vim!")', 'E981:')
+ call Run_restricted_test('luado return "hello"', 'E981:')
+ call Run_restricted_test('luafile somefile', 'E981:')
+ call Run_restricted_test('call luaeval("expression")', 'E145:')
+endfunc
+
+func Test_restricted_mzscheme()
+ if !has('mzscheme')
+ throw 'Skipped: MzScheme is not supported'
+ endif
+ call Run_restricted_test('mzscheme statement', 'E981:')
+ call Run_restricted_test('mzfile somefile', 'E981:')
+ call Run_restricted_test('call mzeval("expression")', 'E145:')
+endfunc
+
+func Test_restricted_perl()
+ if !has('perl')
+ throw 'Skipped: Perl is not supported'
+ endif
+ " TODO: how to make Safe mode fail?
+ " call Run_restricted_test('perl system("ls")', 'E981:')
+ " call Run_restricted_test('perldo system("hello")', 'E981:')
+ " call Run_restricted_test('perlfile somefile', 'E981:')
+ " call Run_restricted_test('call perleval("system(\"ls\")")', 'E145:')
+endfunc
+
+func Test_restricted_python()
+ if !has('python')
+ throw 'Skipped: Python is not supported'
+ endif
+ call Run_restricted_test('python print "hello"', 'E981:')
+ call Run_restricted_test('pydo return "hello"', 'E981:')
+ call Run_restricted_test('pyfile somefile', 'E981:')
+ call Run_restricted_test('call pyeval("expression")', 'E145:')
+endfunc
+
+func Test_restricted_python3()
+ if !has('python3')
+ throw 'Skipped: Python3 is not supported'
+ endif
+ call Run_restricted_test('py3 print "hello"', 'E981:')
+ call Run_restricted_test('py3do return "hello"', 'E981:')
+ call Run_restricted_test('py3file somefile', 'E981:')
+ call Run_restricted_test('call py3eval("expression")', 'E145:')
+endfunc
+
+func Test_restricted_ruby()
+ if !has('ruby')
+ throw 'Skipped: Ruby is not supported'
+ endif
+ call Run_restricted_test('ruby print "Hello"', 'E981:')
+ call Run_restricted_test('rubydo print "Hello"', 'E981:')
+ call Run_restricted_test('rubyfile somefile', 'E981:')
+endfunc
+
+func Test_restricted_tcl()
+ if !has('tcl')
+ throw 'Skipped: Tcl is not supported'
+ endif
+ call Run_restricted_test('tcl puts "Hello"', 'E981:')
+ call Run_restricted_test('tcldo puts "Hello"', 'E981:')
+ call Run_restricted_test('tclfile somefile', 'E981:')
+endfunc
diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim
index 5d99027ca5..8036dea29f 100644
--- a/src/nvim/testdir/test_search.vim
+++ b/src/nvim/testdir/test_search.vim
@@ -698,3 +698,9 @@ func Test_search_display_pattern()
set norl
endif
endfunc
+
+func Test_search_special()
+ " this was causing illegal memory access and an endless loop
+ set t_PE=
+ exe "norm /\x80PS"
+endfunc
diff --git a/src/nvim/testdir/test_signs.vim b/src/nvim/testdir/test_signs.vim
index ef4b227215..8b1927e4f0 100644
--- a/src/nvim/testdir/test_signs.vim
+++ b/src/nvim/testdir/test_signs.vim
@@ -4,6 +4,8 @@ if !has('signs')
finish
endif
+source screendump.vim
+
func Test_sign()
new
call setline(1, ['a', 'b', 'c', 'd'])
@@ -210,13 +212,16 @@ func Test_sign_completion()
call assert_equal('"sign define Sign linehl=SpellBad SpellCap ' .
\ 'SpellLocal SpellRare', @:)
- call writefile(['foo'], 'XsignOne')
- call writefile(['bar'], 'XsignTwo')
+ call feedkeys(":sign define Sign texthl=Spell\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign define Sign texthl=SpellBad SpellCap ' .
+ \ 'SpellLocal SpellRare', @:)
+
+ call writefile(repeat(["Sun is shining"], 30), "XsignOne")
+ call writefile(repeat(["Sky is blue"], 30), "XsignTwo")
call feedkeys(":sign define Sign icon=Xsig\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign define Sign icon=XsignOne XsignTwo', @:)
- call delete('XsignOne')
- call delete('XsignTwo')
+ " Test for completion of arguments to ':sign undefine'
call feedkeys(":sign undefine \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign undefine Sign1 Sign2', @:)
@@ -227,17 +232,70 @@ func Test_sign_completion()
call feedkeys(":sign place 1 name=\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign place 1 name=Sign1 Sign2', @:)
+ edit XsignOne
+ sign place 1 name=Sign1 line=5
+ sign place 1 name=Sign1 group=g1 line=10
+ edit XsignTwo
+ sign place 1 name=Sign2 group=g2 line=15
+
+ " Test for completion of group= and file= arguments to ':sign place'
+ call feedkeys(":sign place 1 name=Sign1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place 1 name=Sign1 file=XsignOne XsignTwo', @:)
+ call feedkeys(":sign place 1 name=Sign1 group=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place 1 name=Sign1 group=g1 g2', @:)
+
+ " Test for completion of arguments to 'sign place' without sign identifier
+ call feedkeys(":sign place \<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place buffer= file= group=', @:)
+ call feedkeys(":sign place file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place file=XsignOne XsignTwo', @:)
+ call feedkeys(":sign place group=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place group=g1 g2', @:)
+ call feedkeys(":sign place group=g1 file=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign place group=g1 file=XsignOne XsignTwo', @:)
+
+ " Test for completion of arguments to ':sign unplace'
call feedkeys(":sign unplace 1 \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign unplace 1 buffer= file= group=', @:)
-
+ call feedkeys(":sign unplace 1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign unplace 1 file=XsignOne XsignTwo', @:)
+ call feedkeys(":sign unplace 1 group=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign unplace 1 group=g1 g2', @:)
+ call feedkeys(":sign unplace 1 group=g2 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign unplace 1 group=g2 file=XsignOne XsignTwo', @:)
+
+ " Test for completion of arguments to ':sign list'
call feedkeys(":sign list \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign list Sign1 Sign2', @:)
+ " Test for completion of arguments to ':sign jump'
call feedkeys(":sign jump 1 \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign jump 1 buffer= file= group=', @:)
+ call feedkeys(":sign jump 1 file=Xsign\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign jump 1 file=XsignOne XsignTwo', @:)
+ call feedkeys(":sign jump 1 group=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign jump 1 group=g1 g2', @:)
+
+ " Error cases
+ call feedkeys(":sign here\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"sign here', @:)
+ call feedkeys(":sign define Sign here=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"sign define Sign here=\<C-A>", @:)
+ call feedkeys(":sign place 1 here=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"sign place 1 here=\<C-A>", @:)
+ call feedkeys(":sign jump 1 here=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"sign jump 1 here=\<C-A>", @:)
+ call feedkeys(":sign here there\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"sign here there\<C-A>", @:)
+ call feedkeys(":sign here there=\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal("\"sign here there=\<C-A>", @:)
+ sign unplace * group=*
sign undefine Sign1
sign undefine Sign2
+ enew
+ call delete('XsignOne')
+ call delete('XsignTwo')
endfunc
func Test_sign_invalid_commands()
@@ -1127,6 +1185,319 @@ func Test_sign_priority()
\ 'priority' : 10}],
\ s[0].signs)
+ call sign_unplace('*')
+
+ " Three signs on different lines with changing priorities
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 11, 'priority' : 50})
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 12, 'priority' : 60})
+ call sign_place(3, '', 'sign3', 'Xsign',
+ \ {'lnum' : 13, 'priority' : 70})
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 12, 'priority' : 40})
+ call sign_place(3, '', 'sign3', 'Xsign',
+ \ {'lnum' : 13, 'priority' : 30})
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 11, 'priority' : 50})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 11, 'group' : '',
+ \ 'priority' : 50},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 12, 'group' : '',
+ \ 'priority' : 40},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 13, 'group' : '',
+ \ 'priority' : 30}],
+ \ s[0].signs)
+
+ call sign_unplace('*')
+
+ " Two signs on the same line with changing priorities
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 30})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+ " Change the priority of the last sign to highest
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 40})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 40},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30}],
+ \ s[0].signs)
+ " Change the priority of the first sign to lowest
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 25})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 25}],
+ \ s[0].signs)
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 45})
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 55})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 55},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 45}],
+ \ s[0].signs)
+
+ call sign_unplace('*')
+
+ " Three signs on the same line with changing priorities
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 40})
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 30})
+ call sign_place(3, '', 'sign3', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 40},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+
+ " Change the priority of the middle sign to the highest
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 50})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 50},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 40},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+
+ " Change the priority of the middle sign to the lowest
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 15})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 50},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 15}],
+ \ s[0].signs)
+
+ " Change the priority of the last sign to the highest
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 55})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 55},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 50},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+
+ " Change the priority of the first sign to the lowest
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 15})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 50},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 15}],
+ \ s[0].signs)
+
+ call sign_unplace('*')
+
+ " Three signs on the same line with changing priorities along with other
+ " signs
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 2, 'priority' : 10})
+ call sign_place(2, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 30})
+ call sign_place(3, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ call sign_place(4, '', 'sign3', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 25})
+ call sign_place(5, '', 'sign2', 'Xsign',
+ \ {'lnum' : 6, 'priority' : 80})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 25},
+ \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '',
+ \ 'priority' : 80}],
+ \ s[0].signs)
+
+ " Change the priority of the first sign to lowest
+ call sign_place(2, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 15})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 25},
+ \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 15},
+ \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '',
+ \ 'priority' : 80}],
+ \ s[0].signs)
+
+ " Change the priority of the last sign to highest
+ call sign_place(2, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 30})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 25},
+ \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '',
+ \ 'priority' : 80}],
+ \ s[0].signs)
+
+ " Change the priority of the middle sign to lowest
+ call sign_place(4, '', 'sign3', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 15})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 15},
+ \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '',
+ \ 'priority' : 80}],
+ \ s[0].signs)
+
+ " Change the priority of the middle sign to highest
+ call sign_place(3, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 35})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 2, 'group' : '',
+ \ 'priority' : 10},
+ \ {'id' : 3, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 35},
+ \ {'id' : 2, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 30},
+ \ {'id' : 4, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 15},
+ \ {'id' : 5, 'name' : 'sign2', 'lnum' : 6, 'group' : '',
+ \ 'priority' : 80}],
+ \ s[0].signs)
+
+ call sign_unplace('*')
+
+ " Multiple signs with the same priority on the same line
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ call sign_place(2, '', 'sign2', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ call sign_place(3, '', 'sign3', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+ " Place the last sign again with the same priority
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+ " Place the first sign again with the same priority
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+ " Place the middle sign again with the same priority
+ call sign_place(3, '', 'sign3', 'Xsign',
+ \ {'lnum' : 4, 'priority' : 20})
+ let s = sign_getplaced('Xsign', {'group' : '*'})
+ call assert_equal([
+ \ {'id' : 3, 'name' : 'sign3', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 1, 'name' : 'sign1', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20},
+ \ {'id' : 2, 'name' : 'sign2', 'lnum' : 4, 'group' : '',
+ \ 'priority' : 20}],
+ \ s[0].signs)
+
+ call sign_unplace('*')
+
+ " Place multiple signs with same id on a line with different priority
+ call sign_place(1, '', 'sign1', 'Xsign',
+ \ {'lnum' : 5, 'priority' : 20})
+ call sign_place(1, '', 'sign2', 'Xsign',
+ \ {'lnum' : 5, 'priority' : 10})
+ let s = sign_getplaced('Xsign', {'lnum' : 5})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign2', 'lnum' : 5, 'group' : '',
+ \ 'priority' : 10}],
+ \ s[0].signs)
+ call sign_place(1, '', 'sign2', 'Xsign',
+ \ {'lnum' : 5, 'priority' : 5})
+ let s = sign_getplaced('Xsign', {'lnum' : 5})
+ call assert_equal([
+ \ {'id' : 1, 'name' : 'sign2', 'lnum' : 5, 'group' : '',
+ \ 'priority' : 5}],
+ \ s[0].signs)
+
" Error case
call assert_fails("call sign_place(1, 'g1', 'sign1', 'Xsign',
\ [])", 'E715:')
@@ -1339,3 +1710,35 @@ func Test_sign_jump_func()
sign undefine sign1
enew! | only!
endfunc
+
+" Test for correct cursor position after the sign column appears or disappears.
+func Test_sign_cursor_position()
+ if !CanRunVimInTerminal()
+ throw 'Skipped: cannot make screendumps'
+ endif
+
+ let lines =<< trim END
+ call setline(1, [repeat('x', 75), 'mmmm', 'yyyy'])
+ call cursor(2,1)
+ sign define s1 texthl=Search text==>
+ redraw
+ sign place 10 line=2 name=s1
+ END
+ call writefile(lines, 'XtestSigncolumn')
+ let buf = RunVimInTerminal('-S XtestSigncolumn', {'rows': 6})
+ call VerifyScreenDump(buf, 'Test_sign_cursor_1', {})
+
+ " Change the sign text
+ call term_sendkeys(buf, ":sign define s1 text=-)\<CR>")
+ call VerifyScreenDump(buf, 'Test_sign_cursor_2', {})
+
+ " update cursor position calculation
+ call term_sendkeys(buf, "lh")
+ call term_sendkeys(buf, ":sign unplace 10\<CR>")
+ call VerifyScreenDump(buf, 'Test_sign_cursor_3', {})
+
+
+ " clean up
+ call StopVimInTerminal(buf)
+ call delete('XtestSigncolumn')
+endfunc
diff --git a/src/nvim/testdir/test_timers.vim b/src/nvim/testdir/test_timers.vim
index 3043103270..40376a877e 100644
--- a/src/nvim/testdir/test_timers.vim
+++ b/src/nvim/testdir/test_timers.vim
@@ -339,4 +339,8 @@ func Test_nocatch_garbage_collect()
delfunc FeedChar
endfunc
+func Test_timer_invalid_callback()
+ call assert_fails('call timer_start(0, "0")', 'E921')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index e9276db484..22f4501be2 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1099,6 +1099,7 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, Integer endrow,
set_scroll_region(ui, top, bot, left, right);
}
cursor_goto(ui, top, left);
+ update_attrs(ui, 0);
if (rows > 0) {
if (rows == 1) {
diff --git a/src/nvim/version.c b/src/nvim/version.c
index c67fd9175f..6412d4caae 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -129,7 +129,7 @@ static const int included_patches[] = {
1792,
1791,
1790,
- // 1789,
+ 1789,
1788,
1787,
1786,
@@ -258,7 +258,7 @@ static const int included_patches[] = {
1663,
1662,
1661,
- // 1660,
+ 1660,
1659,
1658,
1657,
diff --git a/src/nvim/viml/parser/expressions.h b/src/nvim/viml/parser/expressions.h
index 23e172da75..838a742271 100644
--- a/src/nvim/viml/parser/expressions.h
+++ b/src/nvim/viml/parser/expressions.h
@@ -326,7 +326,7 @@ struct expr_ast_node {
} data;
};
-enum {
+enum ExprParserFlags {
/// Allow multiple expressions in a row: e.g. for :echo
///
/// Parser will still parse only one of them though.
@@ -345,7 +345,7 @@ enum {
// viml_expressions_parser.c, nvim_parse_expression() flags parsing
// alongside with its documentation and flag sets in check_parsing()
// function in expressions parser functional and unit tests.
-} ExprParserFlags;
+};
/// AST error definition
typedef struct {
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 8181883426..f61a46996d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -618,7 +618,6 @@ void win_set_minimal_style(win_T *wp)
wp->w_p_cuc = false;
wp->w_p_spell = false;
wp->w_p_list = false;
- wp->w_p_fdc = 0;
// Hide EOB region: use " " fillchar and cleared highlighting
if (wp->w_p_fcs_chars.eob != ' ') {
@@ -642,6 +641,12 @@ void win_set_minimal_style(win_T *wp)
wp->w_p_scl = (char_u *)xstrdup("auto");
}
+ // foldcolumn: use 'auto'
+ if (wp->w_p_fdc[0] != '0') {
+ xfree(wp->w_p_fdc);
+ wp->w_p_fdc = (char_u *)xstrdup("0");
+ }
+
// colorcolumn: cleared
if (wp->w_p_cc != NULL && *wp->w_p_cc != NUL) {
xfree(wp->w_p_cc);
@@ -689,6 +694,21 @@ void win_check_anchored_floats(win_T *win)
}
}
+/// Return the number of fold columns to display
+int win_fdccol_count(win_T *wp)
+{
+ const char *fdc = (const char *)wp->w_p_fdc;
+
+ // auto:<NUM>
+ if (strncmp(fdc, "auto:", 5) == 0) {
+ int needed_fdccols = getDeepestNesting(wp);
+ return MIN(fdc[5] - '0', needed_fdccols);
+ } else {
+ return fdc[0] - '0';
+ }
+}
+
+
static void ui_ext_win_position(win_T *wp)
{
if (!wp->w_floating) {
diff --git a/src/tree_sitter/api.h b/src/tree_sitter/api.h
index 40187e3db0..9d832e6ec4 100644
--- a/src/tree_sitter/api.h
+++ b/src/tree_sitter/api.h
@@ -174,8 +174,19 @@ const TSLanguage *ts_parser_language(const TSParser *self);
* The second and third parameters specify the location and length of an array
* of ranges. The parser does *not* take ownership of these ranges; it copies
* the data, so it doesn't matter how these ranges are allocated.
+ *
+ * If `length` is zero, then the entire document will be parsed. Otherwise,
+ * the given ranges must be ordered from earliest to latest in the document,
+ * and they must not overlap. That is, the following must hold for all
+ * `i` < `length - 1`:
+ *
+ * ranges[i].end_byte <= ranges[i + 1].start_byte
+ *
+ * If this requirement is not satisfied, the operation will fail, the ranges
+ * will not be assigned, and this function will return `false`. On success,
+ * this function returns `true`
*/
-void ts_parser_set_included_ranges(
+bool ts_parser_set_included_ranges(
TSParser *self,
const TSRange *ranges,
uint32_t length
@@ -325,14 +336,6 @@ TSLogger ts_parser_logger(const TSParser *self);
*/
void ts_parser_print_dot_graphs(TSParser *self, int file);
-/**
- * Set whether or not the parser should halt immediately upon detecting an
- * error. This will generally result in a syntax tree with an error at the
- * root, and one or more partial syntax trees within the error. This behavior
- * may not be supported long-term.
- */
-void ts_parser_halt_on_error(TSParser *self, bool halt);
-
/******************/
/* Section - Tree */
/******************/
@@ -732,13 +735,23 @@ const char *ts_query_string_value_for_id(
);
/**
- * Disable a certain capture within a query. This prevents the capture
- * from being returned in matches, and also avoids any resource usage
- * associated with recording the capture.
+ * Disable a certain capture within a query.
+ *
+ * This prevents the capture from being returned in matches, and also avoids
+ * any resource usage associated with recording the capture. Currently, there
+ * is no way to undo this.
*/
void ts_query_disable_capture(TSQuery *, const char *, uint32_t);
/**
+ * Disable a certain pattern within a query.
+ *
+ * This prevents the pattern from matching and removes most of the overhead
+ * associated with the pattern. Currently, there is no way to undo this.
+ */
+void ts_query_disable_pattern(TSQuery *, uint32_t);
+
+/**
* Create a new cursor for executing a given query.
*
* The cursor stores the state that is needed to iteratively search
diff --git a/src/tree_sitter/array.h b/src/tree_sitter/array.h
index bc77e687bf..26cb8448f1 100644
--- a/src/tree_sitter/array.h
+++ b/src/tree_sitter/array.h
@@ -126,12 +126,28 @@ static inline void array__splice(VoidArray *self, size_t element_size,
array__reserve(self, element_size, new_size);
char *contents = (char *)self->contents;
- if (self->size > old_end)
- memmove(contents + new_end * element_size, contents + old_end * element_size,
- (self->size - old_end) * element_size);
- if (new_count > 0)
- memcpy((contents + index * element_size), elements,
- new_count * element_size);
+ if (self->size > old_end) {
+ memmove(
+ contents + new_end * element_size,
+ contents + old_end * element_size,
+ (self->size - old_end) * element_size
+ );
+ }
+ if (new_count > 0) {
+ if (elements) {
+ memcpy(
+ (contents + index * element_size),
+ elements,
+ new_count * element_size
+ );
+ } else {
+ memset(
+ (contents + index * element_size),
+ 0,
+ new_count * element_size
+ );
+ }
+ }
self->size += new_count - old_count;
}
diff --git a/src/tree_sitter/atomic.h b/src/tree_sitter/atomic.h
index 301ee36700..7bd0e850a9 100644
--- a/src/tree_sitter/atomic.h
+++ b/src/tree_sitter/atomic.h
@@ -12,11 +12,11 @@ static inline size_t atomic_load(const volatile size_t *p) {
}
static inline uint32_t atomic_inc(volatile uint32_t *p) {
- return InterlockedIncrement(p);
+ return InterlockedIncrement((long volatile *)p);
}
static inline uint32_t atomic_dec(volatile uint32_t *p) {
- return InterlockedDecrement(p);
+ return InterlockedDecrement((long volatile *)p);
}
#else
diff --git a/src/tree_sitter/bits.h b/src/tree_sitter/bits.h
index 3bec455dd1..ce7a715567 100644
--- a/src/tree_sitter/bits.h
+++ b/src/tree_sitter/bits.h
@@ -7,7 +7,7 @@ static inline uint32_t bitmask_for_index(uint16_t id) {
return (1u << (31 - id));
}
-#ifdef _WIN32
+#if defined _WIN32 && !defined __GNUC__
#include <intrin.h>
diff --git a/src/tree_sitter/language.h b/src/tree_sitter/language.h
index d7e17c3d70..f908b4593a 100644
--- a/src/tree_sitter/language.h
+++ b/src/tree_sitter/language.h
@@ -29,10 +29,12 @@ static inline bool ts_language_is_symbol_external(const TSLanguage *self, TSSymb
return 0 < symbol && symbol < self->external_token_count + 1;
}
-static inline const TSParseAction *ts_language_actions(const TSLanguage *self,
- TSStateId state,
- TSSymbol symbol,
- uint32_t *count) {
+static inline const TSParseAction *ts_language_actions(
+ const TSLanguage *self,
+ TSStateId state,
+ TSSymbol symbol,
+ uint32_t *count
+) {
TableEntry entry;
ts_language_table_entry(self, state, symbol, &entry);
*count = entry.action_count;
@@ -90,8 +92,8 @@ static inline TSStateId ts_language_next_state(const TSLanguage *self,
const TSParseAction *actions = ts_language_actions(self, state, symbol, &count);
if (count > 0) {
TSParseAction action = actions[count - 1];
- if (action.type == TSParseActionTypeShift || action.type == TSParseActionTypeRecover) {
- return action.params.state;
+ if (action.type == TSParseActionTypeShift) {
+ return action.params.extra ? state : action.params.state;
}
}
return 0;
diff --git a/src/tree_sitter/lexer.c b/src/tree_sitter/lexer.c
index e2ca851973..3f8a4c0ae8 100644
--- a/src/tree_sitter/lexer.c
+++ b/src/tree_sitter/lexer.c
@@ -355,7 +355,7 @@ void ts_lexer_mark_end(Lexer *self) {
ts_lexer__mark_end(&self->data);
}
-void ts_lexer_set_included_ranges(
+bool ts_lexer_set_included_ranges(
Lexer *self,
const TSRange *ranges,
uint32_t count
@@ -363,6 +363,16 @@ void ts_lexer_set_included_ranges(
if (count == 0 || !ranges) {
ranges = &DEFAULT_RANGE;
count = 1;
+ } else {
+ uint32_t previous_byte = 0;
+ for (unsigned i = 0; i < count; i++) {
+ const TSRange *range = &ranges[i];
+ if (
+ range->start_byte < previous_byte ||
+ range->end_byte < range->start_byte
+ ) return false;
+ previous_byte = range->end_byte;
+ }
}
size_t size = count * sizeof(TSRange);
@@ -370,6 +380,7 @@ void ts_lexer_set_included_ranges(
memcpy(self->included_ranges, ranges, size);
self->included_range_count = count;
ts_lexer_goto(self, self->current_position);
+ return true;
}
TSRange *ts_lexer_included_ranges(const Lexer *self, uint32_t *count) {
diff --git a/src/tree_sitter/lexer.h b/src/tree_sitter/lexer.h
index 8cd9c26706..5e39294529 100644
--- a/src/tree_sitter/lexer.h
+++ b/src/tree_sitter/lexer.h
@@ -38,7 +38,7 @@ void ts_lexer_start(Lexer *);
void ts_lexer_finish(Lexer *, uint32_t *);
void ts_lexer_advance_to_end(Lexer *);
void ts_lexer_mark_end(Lexer *);
-void ts_lexer_set_included_ranges(Lexer *self, const TSRange *ranges, uint32_t count);
+bool ts_lexer_set_included_ranges(Lexer *self, const TSRange *ranges, uint32_t count);
TSRange *ts_lexer_included_ranges(const Lexer *self, uint32_t *count);
#ifdef __cplusplus
diff --git a/src/tree_sitter/parser.c b/src/tree_sitter/parser.c
index f381afccab..0fa0c4195b 100644
--- a/src/tree_sitter/parser.c
+++ b/src/tree_sitter/parser.c
@@ -71,7 +71,6 @@ struct TSParser {
unsigned accept_count;
unsigned operation_count;
const volatile size_t *cancellation_flag;
- bool halt_on_error;
Subtree old_tree;
TSRangeArray included_range_differences;
unsigned included_range_difference_index;
@@ -1014,7 +1013,9 @@ static void ts_parser__handle_error(
TSStateId state_after_missing_symbol = ts_language_next_state(
self->language, state, missing_symbol
);
- if (state_after_missing_symbol == 0) continue;
+ if (state_after_missing_symbol == 0 || state_after_missing_symbol == state) {
+ continue;
+ }
if (ts_language_has_reduce_action(
self->language,
@@ -1067,46 +1068,6 @@ static void ts_parser__handle_error(
LOG_STACK();
}
-static void ts_parser__halt_parse(TSParser *self) {
- LOG("halting_parse");
- LOG_STACK();
-
- ts_lexer_advance_to_end(&self->lexer);
- Length remaining_length = length_sub(
- self->lexer.current_position,
- ts_stack_position(self->stack, 0)
- );
-
- Subtree filler_node = ts_subtree_new_error(
- &self->tree_pool,
- 0,
- length_zero(),
- remaining_length,
- remaining_length.bytes,
- 0,
- self->language
- );
- ts_subtree_to_mut_unsafe(filler_node).ptr->visible = false;
- ts_stack_push(self->stack, 0, filler_node, false, 0);
-
- SubtreeArray children = array_new();
- Subtree root_error = ts_subtree_new_error_node(&self->tree_pool, &children, false, self->language);
- ts_stack_push(self->stack, 0, root_error, false, 0);
-
- Subtree eof = ts_subtree_new_leaf(
- &self->tree_pool,
- ts_builtin_sym_end,
- length_zero(),
- length_zero(),
- 0,
- 0,
- false,
- false,
- self->language
- );
- ts_parser__accept(self, 0, eof);
-}
-
static bool ts_parser__recover_to_state(
TSParser *self,
StackVersion version,
@@ -1661,7 +1622,6 @@ TSParser *ts_parser_new(void) {
self->finished_tree = NULL_SUBTREE;
self->reusable_node = reusable_node_new();
self->dot_graph_file = NULL;
- self->halt_on_error = false;
self->cancellation_flag = NULL;
self->timeout_duration = 0;
self->end_clock = clock_null();
@@ -1741,10 +1701,6 @@ void ts_parser_print_dot_graphs(TSParser *self, int fd) {
}
}
-void ts_parser_halt_on_error(TSParser *self, bool should_halt_on_error) {
- self->halt_on_error = should_halt_on_error;
-}
-
const size_t *ts_parser_cancellation_flag(const TSParser *self) {
return (const size_t *)self->cancellation_flag;
}
@@ -1761,8 +1717,12 @@ void ts_parser_set_timeout_micros(TSParser *self, uint64_t timeout_micros) {
self->timeout_duration = duration_from_micros(timeout_micros);
}
-void ts_parser_set_included_ranges(TSParser *self, const TSRange *ranges, uint32_t count) {
- ts_lexer_set_included_ranges(&self->lexer, ranges, count);
+bool ts_parser_set_included_ranges(
+ TSParser *self,
+ const TSRange *ranges,
+ uint32_t count
+) {
+ return ts_lexer_set_included_ranges(&self->lexer, ranges, count);
}
const TSRange *ts_parser_included_ranges(const TSParser *self, uint32_t *count) {
@@ -1858,9 +1818,6 @@ TSTree *ts_parser_parse(
unsigned min_error_cost = ts_parser__condense_stack(self);
if (self->finished_tree.ptr && ts_subtree_error_cost(self->finished_tree) < min_error_cost) {
break;
- } else if (self->halt_on_error && min_error_cost > 0) {
- ts_parser__halt_parse(self);
- break;
}
while (self->included_range_difference_index < self->included_range_differences.size) {
diff --git a/src/tree_sitter/query.c b/src/tree_sitter/query.c
index 2563325248..053882cf68 100644
--- a/src/tree_sitter/query.c
+++ b/src/tree_sitter/query.c
@@ -19,6 +19,8 @@ typedef struct {
uint8_t next_size;
} Stream;
+#define MAX_STEP_CAPTURE_COUNT 4
+
/*
* QueryStep - A step in the process of matching a query. Each node within
* a query S-expression maps to one of these steps. An entire pattern is
@@ -37,9 +39,11 @@ typedef struct {
typedef struct {
TSSymbol symbol;
TSFieldId field;
- uint16_t capture_id;
- uint16_t depth: 15;
+ uint16_t capture_ids[MAX_STEP_CAPTURE_COUNT];
+ uint16_t depth: 13;
bool contains_captures: 1;
+ bool is_immediate: 1;
+ bool is_last: 1;
} QueryStep;
/*
@@ -62,10 +66,12 @@ typedef struct {
} SymbolTable;
/*
- * PatternEntry - The set of steps needed to match a particular pattern,
- * represented as a slice of a shared array. These entries are stored in a
- * 'pattern map' - a sorted array that makes it possible to efficiently lookup
- * patterns based on the symbol for their first step.
+ * PatternEntry - Information about the starting point for matching a
+ * particular pattern, consisting of the index of the pattern within the query,
+ * and the index of the patter's first step in the shared `steps` array. These
+ * entries are stored in a 'pattern map' - a sorted array that makes it
+ * possible to efficiently lookup patterns based on the symbol for their first
+ * step.
*/
typedef struct {
uint16_t step_index;
@@ -140,6 +146,7 @@ static const TSQueryError PARENT_DONE = -1;
static const uint8_t PATTERN_DONE_MARKER = UINT8_MAX;
static const uint16_t NONE = UINT16_MAX;
static const TSSymbol WILDCARD_SYMBOL = 0;
+static const TSSymbol NAMED_WILDCARD_SYMBOL = UINT16_MAX - 1;
static const uint16_t MAX_STATE_COUNT = 32;
// #define LOG(...) fprintf(stderr, __VA_ARGS__)
@@ -324,6 +331,49 @@ static uint16_t symbol_table_insert_name(
return self->slices.size - 1;
}
+/************
+ * QueryStep
+ ************/
+
+static QueryStep query_step__new(
+ TSSymbol symbol,
+ uint16_t depth,
+ bool is_immediate
+) {
+ return (QueryStep) {
+ .symbol = symbol,
+ .depth = depth,
+ .field = 0,
+ .capture_ids = {NONE, NONE, NONE, NONE},
+ .contains_captures = false,
+ .is_immediate = is_immediate,
+ };
+}
+
+static void query_step__add_capture(QueryStep *self, uint16_t capture_id) {
+ for (unsigned i = 0; i < MAX_STEP_CAPTURE_COUNT; i++) {
+ if (self->capture_ids[i] == NONE) {
+ self->capture_ids[i] = capture_id;
+ break;
+ }
+ }
+}
+
+static void query_step__remove_capture(QueryStep *self, uint16_t capture_id) {
+ for (unsigned i = 0; i < MAX_STEP_CAPTURE_COUNT; i++) {
+ if (self->capture_ids[i] == capture_id) {
+ self->capture_ids[i] = NONE;
+ while (i + 1 < MAX_STEP_CAPTURE_COUNT) {
+ if (self->capture_ids[i + 1] == NONE) break;
+ self->capture_ids[i] = self->capture_ids[i + 1];
+ self->capture_ids[i + 1] = NONE;
+ i++;
+ }
+ break;
+ }
+ }
+}
+
/*********
* Query
*********/
@@ -333,7 +383,7 @@ static uint16_t symbol_table_insert_name(
// to quickly find the starting steps of all of the patterns whose root matches
// that node. Each entry has two fields: a `pattern_index`, which identifies one
// of the patterns in the query, and a `step_index`, which indicates the start
-// offset of that pattern's steps pattern within the `steps` array.
+// offset of that pattern's steps within the `steps` array.
//
// The entries are sorted by the patterns' root symbols, and lookups use a
// binary search. This ensures that the cost of this initial lookup step
@@ -399,14 +449,14 @@ static void ts_query__finalize_steps(TSQuery *self) {
for (unsigned i = 0; i < self->steps.size; i++) {
QueryStep *step = &self->steps.contents[i];
uint32_t depth = step->depth;
- if (step->capture_id != NONE) {
+ if (step->capture_ids[0] != NONE) {
step->contains_captures = true;
} else {
step->contains_captures = false;
for (unsigned j = i + 1; j < self->steps.size; j++) {
QueryStep *s = &self->steps.contents[j];
if (s->depth == PATTERN_DONE_MARKER || s->depth <= depth) break;
- if (s->capture_id != NONE) step->contains_captures = true;
+ if (s->capture_ids[0] != NONE) step->contains_captures = true;
}
}
}
@@ -533,7 +583,8 @@ static TSQueryError ts_query__parse_pattern(
TSQuery *self,
Stream *stream,
uint32_t depth,
- uint32_t *capture_count
+ uint32_t *capture_count,
+ bool is_immediate
) {
uint16_t starting_step_index = self->steps.size;
@@ -552,7 +603,7 @@ static TSQueryError ts_query__parse_pattern(
// Parse a nested list, which represents a pattern followed by
// zero-or-more predicates.
if (stream->next == '(' && depth == 0) {
- TSQueryError e = ts_query__parse_pattern(self, stream, 0, capture_count);
+ TSQueryError e = ts_query__parse_pattern(self, stream, 0, capture_count, is_immediate);
if (e) return e;
// Parse the predicates.
@@ -573,7 +624,7 @@ static TSQueryError ts_query__parse_pattern(
// Parse the wildcard symbol
if (stream->next == '*') {
- symbol = WILDCARD_SYMBOL;
+ symbol = NAMED_WILDCARD_SYMBOL;
stream_advance(stream);
}
@@ -597,24 +648,37 @@ static TSQueryError ts_query__parse_pattern(
}
// Add a step for the node.
- array_push(&self->steps, ((QueryStep) {
- .depth = depth,
- .symbol = symbol,
- .field = 0,
- .capture_id = NONE,
- .contains_captures = false,
- }));
+ array_push(&self->steps, query_step__new(symbol, depth, is_immediate));
// Parse the child patterns
stream_skip_whitespace(stream);
+ bool child_is_immediate = false;
+ uint16_t child_start_step_index = self->steps.size;
for (;;) {
- TSQueryError e = ts_query__parse_pattern(self, stream, depth + 1, capture_count);
+ if (stream->next == '.') {
+ child_is_immediate = true;
+ stream_advance(stream);
+ stream_skip_whitespace(stream);
+ }
+
+ TSQueryError e = ts_query__parse_pattern(
+ self,
+ stream,
+ depth + 1,
+ capture_count,
+ child_is_immediate
+ );
if (e == PARENT_DONE) {
+ if (child_is_immediate) {
+ self->steps.contents[child_start_step_index].is_last = true;
+ }
stream_advance(stream);
break;
} else if (e) {
return e;
}
+
+ child_is_immediate = false;
}
}
@@ -643,13 +707,7 @@ static TSQueryError ts_query__parse_pattern(
stream_reset(stream, string_content);
return TSQueryErrorNodeType;
}
- array_push(&self->steps, ((QueryStep) {
- .depth = depth,
- .symbol = symbol,
- .field = 0,
- .capture_id = NONE,
- .contains_captures = false,
- }));
+ array_push(&self->steps, query_step__new(symbol, depth, is_immediate));
if (stream->next != '"') return TSQueryErrorSyntax;
stream_advance(stream);
@@ -672,7 +730,13 @@ static TSQueryError ts_query__parse_pattern(
// Parse the pattern
uint32_t step_index = self->steps.size;
- TSQueryError e = ts_query__parse_pattern(self, stream, depth, capture_count);
+ TSQueryError e = ts_query__parse_pattern(
+ self,
+ stream,
+ depth,
+ capture_count,
+ is_immediate
+ );
if (e == PARENT_DONE) return TSQueryErrorSyntax;
if (e) return e;
@@ -695,12 +759,7 @@ static TSQueryError ts_query__parse_pattern(
stream_skip_whitespace(stream);
// Add a step that matches any kind of node
- array_push(&self->steps, ((QueryStep) {
- .depth = depth,
- .symbol = WILDCARD_SYMBOL,
- .field = 0,
- .contains_captures = false,
- }));
+ array_push(&self->steps, query_step__new(WILDCARD_SYMBOL, depth, is_immediate));
}
else {
@@ -710,7 +769,7 @@ static TSQueryError ts_query__parse_pattern(
stream_skip_whitespace(stream);
// Parse an '@'-prefixed capture pattern
- if (stream->next == '@') {
+ while (stream->next == '@') {
stream_advance(stream);
// Parse the capture name
@@ -725,7 +784,8 @@ static TSQueryError ts_query__parse_pattern(
capture_name,
length
);
- self->steps.contents[starting_step_index].capture_id = capture_id;
+ QueryStep *step = &self->steps.contents[starting_step_index];
+ query_step__add_capture(step, capture_id);
(*capture_count)++;
stream_skip_whitespace(stream);
@@ -794,8 +854,8 @@ TSQuery *ts_query_new(
.offset = self->predicate_steps.size,
.length = 0,
}));
- *error_type = ts_query__parse_pattern(self, &stream, 0, &capture_count);
- array_push(&self->steps, ((QueryStep) { .depth = PATTERN_DONE_MARKER }));
+ *error_type = ts_query__parse_pattern(self, &stream, 0, &capture_count, false);
+ array_push(&self->steps, query_step__new(0, PATTERN_DONE_MARKER, false));
// If any pattern could not be parsed, then report the error information
// and terminate.
@@ -891,16 +951,31 @@ void ts_query_disable_capture(
const char *name,
uint32_t length
) {
+ // Remove capture information for any pattern step that previously
+ // captured with the given name.
int id = symbol_table_id_for_name(&self->captures, name, length);
if (id != -1) {
for (unsigned i = 0; i < self->steps.size; i++) {
QueryStep *step = &self->steps.contents[i];
- if (step->capture_id == id) {
- step->capture_id = NONE;
- }
+ query_step__remove_capture(step, id);
+ }
+ ts_query__finalize_steps(self);
+ }
+}
+
+void ts_query_disable_pattern(
+ TSQuery *self,
+ uint32_t pattern_index
+) {
+ // Remove the given pattern from the pattern map. Its steps will still
+ // be in the `steps` array, but they will never be read.
+ for (unsigned i = 0; i < self->pattern_map.size; i++) {
+ PatternEntry *pattern = &self->pattern_map.contents[i];
+ if (pattern->pattern_index == pattern_index) {
+ array_erase(&self->pattern_map, i);
+ i--;
}
}
- ts_query__finalize_steps(self);
}
/***************
@@ -1010,7 +1085,7 @@ static bool ts_query_cursor__first_in_progress_capture(
static bool ts_query__cursor_add_state(
TSQueryCursor *self,
- const PatternEntry *slice
+ const PatternEntry *pattern
) {
uint32_t list_id = capture_list_pool_acquire(&self->capture_list_pool);
@@ -1037,11 +1112,11 @@ static bool ts_query__cursor_add_state(
}
}
- LOG(" start state. pattern:%u\n", slice->pattern_index);
+ LOG(" start state. pattern:%u\n", pattern->pattern_index);
array_push(&self->states, ((QueryState) {
.capture_list_id = list_id,
- .step_index = slice->step_index,
- .pattern_index = slice->pattern_index,
+ .step_index = pattern->step_index,
+ .pattern_index = pattern->pattern_index,
.start_depth = self->depth,
.capture_count = 0,
.consumed_capture_count = 0,
@@ -1113,15 +1188,16 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
return self->finished_states.size > 0;
}
} else {
- bool can_have_later_siblings;
+ bool has_later_siblings;
bool can_have_later_siblings_with_this_field;
TSFieldId field_id = ts_tree_cursor_current_status(
&self->cursor,
- &can_have_later_siblings,
+ &has_later_siblings,
&can_have_later_siblings_with_this_field
);
TSNode node = ts_tree_cursor_current_node(&self->cursor);
TSSymbol symbol = ts_node_symbol(node);
+ bool is_named = ts_node_is_named(node);
if (symbol != ts_builtin_sym_error && self->query->symbol_map) {
symbol = self->query->symbol_map[symbol];
}
@@ -1145,43 +1221,46 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
) return false;
LOG(
- "enter node. type:%s, field:%s, row:%u state_count:%u, finished_state_count:%u, can_have_later_siblings:%d, can_have_later_siblings_with_this_field:%d\n",
+ "enter node. "
+ "type:%s, field:%s, row:%u state_count:%u, "
+ "finished_state_count:%u, has_later_siblings:%d, "
+ "can_have_later_siblings_with_this_field:%d\n",
ts_node_type(node),
ts_language_field_name_for_id(self->query->language, field_id),
ts_node_start_point(node).row,
self->states.size,
self->finished_states.size,
- can_have_later_siblings,
+ has_later_siblings,
can_have_later_siblings_with_this_field
);
// Add new states for any patterns whose root node is a wildcard.
for (unsigned i = 0; i < self->query->wildcard_root_pattern_count; i++) {
- PatternEntry *slice = &self->query->pattern_map.contents[i];
- QueryStep *step = &self->query->steps.contents[slice->step_index];
+ PatternEntry *pattern = &self->query->pattern_map.contents[i];
+ QueryStep *step = &self->query->steps.contents[pattern->step_index];
// If this node matches the first step of the pattern, then add a new
// state at the start of this pattern.
if (step->field && field_id != step->field) continue;
- if (!ts_query__cursor_add_state(self, slice)) break;
+ if (!ts_query__cursor_add_state(self, pattern)) break;
}
// Add new states for any patterns whose root node matches this node.
unsigned i;
if (ts_query__pattern_map_search(self->query, symbol, &i)) {
- PatternEntry *slice = &self->query->pattern_map.contents[i];
- QueryStep *step = &self->query->steps.contents[slice->step_index];
+ PatternEntry *pattern = &self->query->pattern_map.contents[i];
+ QueryStep *step = &self->query->steps.contents[pattern->step_index];
do {
// If this node matches the first step of the pattern, then add a new
// state at the start of this pattern.
if (step->field && field_id != step->field) continue;
- if (!ts_query__cursor_add_state(self, slice)) break;
+ if (!ts_query__cursor_add_state(self, pattern)) break;
// Advance to the next pattern whose root node matches this node.
i++;
if (i == self->query->pattern_map.size) break;
- slice = &self->query->pattern_map.contents[i];
- step = &self->query->steps.contents[slice->step_index];
+ pattern = &self->query->pattern_map.contents[i];
+ step = &self->query->steps.contents[pattern->step_index];
} while (step->symbol == symbol);
}
@@ -1191,14 +1270,23 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
QueryStep *step = &self->query->steps.contents[state->step_index];
// Check that the node matches all of the criteria for the next
- // step of the pattern.if (
+ // step of the pattern.
if ((uint32_t)state->start_depth + (uint32_t)step->depth != self->depth) continue;
// Determine if this node matches this step of the pattern, and also
// if this node can have later siblings that match this step of the
// pattern.
- bool node_does_match = !step->symbol || step->symbol == symbol;
- bool later_sibling_can_match = can_have_later_siblings;
+ bool node_does_match =
+ step->symbol == symbol ||
+ step->symbol == WILDCARD_SYMBOL ||
+ (step->symbol == NAMED_WILDCARD_SYMBOL && is_named);
+ bool later_sibling_can_match = has_later_siblings;
+ if (step->is_immediate && is_named) {
+ later_sibling_can_match = false;
+ }
+ if (step->is_last && has_later_siblings) {
+ node_does_match = false;
+ }
if (step->field) {
if (step->field == field_id) {
if (!can_have_later_siblings_with_this_field) {
@@ -1261,11 +1349,13 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
// If the current node is captured in this pattern, add it to the
// capture list.
- if (step->capture_id != NONE) {
+ for (unsigned j = 0; j < MAX_STEP_CAPTURE_COUNT; j++) {
+ uint16_t capture_id = step->capture_ids[j];
+ if (step->capture_ids[j] == NONE) break;
LOG(
" capture node. pattern:%u, capture_id:%u\n",
next_state->pattern_index,
- step->capture_id
+ capture_id
);
TSQueryCapture *capture_list = capture_list_pool_get(
&self->capture_list_pool,
@@ -1273,7 +1363,7 @@ static inline bool ts_query_cursor__advance(TSQueryCursor *self) {
);
capture_list[next_state->capture_count++] = (TSQueryCapture) {
node,
- step->capture_id
+ capture_id
};
}
diff --git a/src/tree_sitter/stack.c b/src/tree_sitter/stack.c
index 3e842c99c3..ade1577566 100644
--- a/src/tree_sitter/stack.c
+++ b/src/tree_sitter/stack.c
@@ -11,7 +11,7 @@
#define MAX_NODE_POOL_SIZE 50
#define MAX_ITERATOR_COUNT 64
-#ifdef _WIN32
+#if defined _WIN32 && !defined __GNUC__
#define inline __forceinline
#else
#define inline static inline __attribute__((always_inline))
diff --git a/src/tree_sitter/subtree.c b/src/tree_sitter/subtree.c
index 30144fa175..b98f172339 100644
--- a/src/tree_sitter/subtree.c
+++ b/src/tree_sitter/subtree.c
@@ -322,12 +322,9 @@ void ts_subtree_balance(Subtree self, SubtreePool *pool, const TSLanguage *langu
if (tree.ptr->repeat_depth > 0) {
Subtree child1 = tree.ptr->children[0];
Subtree child2 = tree.ptr->children[tree.ptr->child_count - 1];
- if (
- ts_subtree_child_count(child1) > 0 &&
- ts_subtree_child_count(child2) > 0 &&
- child1.ptr->repeat_depth > child2.ptr->repeat_depth
- ) {
- unsigned n = child1.ptr->repeat_depth - child2.ptr->repeat_depth;
+ long repeat_delta = (long)ts_subtree_repeat_depth(child1) - (long)ts_subtree_repeat_depth(child2);
+ if (repeat_delta > 0) {
+ unsigned n = repeat_delta;
for (unsigned i = n / 2; i > 0; i /= 2) {
ts_subtree__compress(tree, i, language, &pool->tree_stack);
n -= i;
@@ -344,10 +341,6 @@ void ts_subtree_balance(Subtree self, SubtreePool *pool, const TSLanguage *langu
}
}
-static inline uint32_t ts_subtree_repeat_depth(Subtree self) {
- return ts_subtree_child_count(self) ? self.ptr->repeat_depth : 0;
-}
-
void ts_subtree_set_children(
MutableSubtree self, Subtree *children, uint32_t child_count, const TSLanguage *language
) {
diff --git a/src/tree_sitter/subtree.h b/src/tree_sitter/subtree.h
index 79ccd92390..18c48dcbd0 100644
--- a/src/tree_sitter/subtree.h
+++ b/src/tree_sitter/subtree.h
@@ -206,6 +206,10 @@ static inline uint32_t ts_subtree_child_count(Subtree self) {
return self.data.is_inline ? 0 : self.ptr->child_count;
}
+static inline uint32_t ts_subtree_repeat_depth(Subtree self) {
+ return self.data.is_inline ? 0 : self.ptr->repeat_depth;
+}
+
static inline uint32_t ts_subtree_node_count(Subtree self) {
return (self.data.is_inline || self.ptr->child_count == 0) ? 1 : self.ptr->node_count;
}