aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/ascii.h31
-rw-r--r--src/nvim/charset.c95
-rw-r--r--src/nvim/edit.c64
-rw-r--r--src/nvim/eval.c461
-rw-r--r--src/nvim/eval_defs.h9
-rw-r--r--src/nvim/event/libuv_process.c3
-rw-r--r--src/nvim/event/process.c23
-rw-r--r--src/nvim/event/process.h5
-rw-r--r--src/nvim/ex_cmds.c150
-rw-r--r--src/nvim/ex_getln.c34
-rw-r--r--src/nvim/ex_getln.h19
-rw-r--r--src/nvim/file_search.c9
-rw-r--r--src/nvim/fileio.c467
-rw-r--r--src/nvim/globals.h106
-rw-r--r--src/nvim/keymap.c79
-rw-r--r--src/nvim/log.c4
-rw-r--r--src/nvim/message.c144
-rw-r--r--src/nvim/normal.c138
-rw-r--r--src/nvim/ops.c305
-rw-r--r--src/nvim/option.c51
-rw-r--r--src/nvim/options.lua2
-rw-r--r--src/nvim/os/unix_defs.h2
-rw-r--r--src/nvim/os/win_defs.h4
-rw-r--r--src/nvim/path.c39
-rw-r--r--src/nvim/path.h1
-rw-r--r--src/nvim/quickfix.c24
-rw-r--r--src/nvim/regexp.c103
-rw-r--r--src/nvim/regexp_nfa.c52
-rw-r--r--src/nvim/screen.c167
-rw-r--r--src/nvim/search.c50
-rw-r--r--src/nvim/shada.c3
-rw-r--r--src/nvim/spell.c54
-rw-r--r--src/nvim/strings.c8
-rw-r--r--src/nvim/testdir/Makefile13
-rw-r--r--src/nvim/testdir/runtest.vim34
-rw-r--r--src/nvim/testdir/test39.in106
-rw-r--r--src/nvim/testdir/test39.okbin585 -> 0 bytes
-rw-r--r--src/nvim/testdir/test55.in160
-rw-r--r--src/nvim/testdir/test55.ok58
-rw-r--r--src/nvim/testdir/test83-tags22
-rw-r--r--src/nvim/testdir/test83-tags3102
-rw-r--r--src/nvim/testdir/test83.in75
-rw-r--r--src/nvim/testdir/test83.ok4
-rw-r--r--src/nvim/testdir/test88.in11
-rw-r--r--src/nvim/testdir/test88.ok5
-rw-r--r--src/nvim/testdir/test_cdo.in107
-rw-r--r--src/nvim/testdir/test_cdo.ok66
-rw-r--r--src/nvim/testdir/test_eval.in234
-rw-r--r--src/nvim/testdir/test_eval.okbin10814 -> 0 bytes
-rw-r--r--src/nvim/testdir/test_eval_func.vim12
-rw-r--r--src/nvim/testdir/test_listlbr.in10
-rw-r--r--src/nvim/testdir/test_listlbr.ok5
-rw-r--r--src/nvim/tui/tui.c12
-rw-r--r--src/nvim/version.c52
-rw-r--r--src/nvim/vim.h2
-rw-r--r--src/nvim/window.c324
-rw-r--r--src/nvim/window.h1
57 files changed, 2064 insertions, 2037 deletions
diff --git a/src/nvim/ascii.h b/src/nvim/ascii.h
index 2b3e94d5a0..44ff540b40 100644
--- a/src/nvim/ascii.h
+++ b/src/nvim/ascii.h
@@ -85,10 +85,25 @@
# define PATHSEPSTR "/"
#endif
-static inline bool ascii_iswhite(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
-static inline bool ascii_isdigit(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
-static inline bool ascii_isxdigit(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
-static inline bool ascii_isspace(int) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST;
+static inline bool ascii_iswhite(int)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
+
+static inline bool ascii_isdigit(int)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
+
+static inline bool ascii_isxdigit(int)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
+
+static inline bool ascii_isbdigit(int)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
+
+static inline bool ascii_isspace(int)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
/// Checks if `c` is a space or tab character.
///
@@ -122,6 +137,14 @@ static inline bool ascii_isxdigit(int c)
|| (c >= 'A' && c <= 'F');
}
+/// Checks if `c` is a binary digit, that is, 0-1.
+///
+/// @see {ascii_isdigit}
+static inline bool ascii_isbdigit(int c)
+{
+ return (c == '0' || c == '1');
+}
+
/// Checks if `c` is a white-space character, that is,
/// one of \f, \n, \r, \t, \v.
///
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index b93eafbf60..9c63eca1f2 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -1454,6 +1454,24 @@ char_u* skipdigits(char_u *q)
return p;
}
+/// skip over binary digits
+///
+/// @param q pointer to string
+///
+/// @return Pointer to the character after the skipped digits.
+const char* skipbin(const char *q)
+ FUNC_ATTR_PURE
+ FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_RET
+{
+ const char *p = q;
+ while (ascii_isbdigit(*p)) {
+ // skip to next non-digit
+ p++;
+ }
+ return p;
+}
+
/// skip over digits and hex characters
///
/// @param q
@@ -1485,6 +1503,24 @@ char_u* skiptodigit(char_u *q)
return p;
}
+/// skip to binary character (or NUL after the string)
+///
+/// @param q pointer to string
+///
+/// @return Pointer to the binary character or (NUL after the string).
+const char* skiptobin(const char *q)
+ FUNC_ATTR_PURE
+ FUNC_ATTR_NONNULL_ALL
+ FUNC_ATTR_NONNULL_RET
+{
+ const char *p = q;
+ while (*p != NUL && !ascii_isbdigit(*p)) {
+ // skip to next digit
+ p++;
+ }
+ return p;
+}
+
/// skip to hex character (or NUL after the string)
///
/// @param q
@@ -1720,67 +1756,76 @@ int vim_isblankline(char_u *lbuf)
}
/// Convert a string into a long and/or unsigned long, taking care of
-/// hexadecimal and octal numbers. Accepts a '-' sign.
-/// If "hexp" is not NULL, returns a flag to indicate the type of the number:
+/// hexadecimal, octal and binary numbers. Accepts a '-' sign.
+/// If "prep" is not NULL, returns a flag to indicate the type of the number:
/// 0 decimal
/// '0' octal
+/// 'B' bin
+/// 'b' bin
/// 'X' hex
/// 'x' hex
/// If "len" is not NULL, the length of the number in characters is returned.
/// If "nptr" is not NULL, the signed result is returned in it.
/// If "unptr" is not NULL, the unsigned result is returned in it.
+/// If "dobin" is non-zero recognize binary numbers, when > 1 always assume
+/// binary number.
/// If "dooct" is non-zero recognize octal numbers, when > 1 always assume
/// octal number.
/// If "dohex" is non-zero recognize hex numbers, when > 1 always assume
/// hex number.
///
/// @param start
-/// @param hexp Returns type of number 0 = decimal, 'x' or 'X' is hex,
-// '0' = octal
+/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex,
+// '0' = octal, 'b' or 'B' is bin
/// @param len Returns the detected length of number.
+/// @param dobin recognize binary number
/// @param dooct recognize octal number
/// @param dohex recognize hex number
/// @param nptr Returns the signed result.
/// @param unptr Returns the unsigned result.
-void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
+void vim_str2nr(char_u *start, int *prep, int *len,
+ int dobin, int dooct, int dohex,
long *nptr, unsigned long *unptr)
{
char_u *ptr = start;
- int hex = 0; // default is decimal
- int negative = FALSE;
+ int pre = 0; // default is decimal
+ int negative = false;
unsigned long un = 0;
- int n;
if (ptr[0] == '-') {
- negative = TRUE;
- ++ptr;
+ negative = true;
+ ptr++;
}
- // Recognize hex and octal.
+ // Recognize hex, octal, and bin.
if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) {
- hex = ptr[1];
+ pre = ptr[1];
if (dohex
- && ((hex == 'X') || (hex == 'x'))
+ && ((pre == 'X') || (pre == 'x'))
&& ascii_isxdigit(ptr[2])) {
// hexadecimal
ptr += 2;
+ } else if (dobin
+ && ((pre == 'B') || (pre == 'b'))
+ && ascii_isbdigit(ptr[2])) {
+ // binary
+ ptr += 2;
} else {
// default is decimal
- hex = 0;
+ pre = 0;
if (dooct) {
// Don't interpret "0", "08" or "0129" as octal.
- for (n = 1; ascii_isdigit(ptr[n]); ++n) {
+ for (int n = 1; ascii_isdigit(ptr[n]); ++n) {
if (ptr[n] > '7') {
// can't be octal
- hex = 0;
+ pre = 0;
break;
}
-
if (ptr[n] >= '0') {
// assume octal
- hex = '0';
+ pre = '0';
}
}
}
@@ -1788,13 +1833,19 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
}
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
- if ((hex == '0') || (dooct > 1)) {
+ if ((pre == 'B') || (pre == 'b') || (dobin > 1)) {
+ // bin
+ while ('0' <= *ptr && *ptr <= '1') {
+ un = 2 * un + (unsigned long)(*ptr - '0');
+ ptr++;
+ }
+ } else if ((pre == '0') || (dooct > 1)) {
// octal
while ('0' <= *ptr && *ptr <= '7') {
un = 8 * un + (unsigned long)(*ptr - '0');
ptr++;
}
- } else if ((hex != 0) || (dohex > 1)) {
+ } else if ((pre == 'X') || (pre == 'x') || dohex > 1) {
// hex
while (ascii_isxdigit(*ptr)) {
un = 16 * un + (unsigned long)hex2nr(*ptr);
@@ -1808,8 +1859,8 @@ void vim_str2nr(char_u *start, int *hexp, int *len, int dooct, int dohex,
}
}
- if (hexp != NULL) {
- *hexp = hex;
+ if (prep != NULL) {
+ *prep = pre;
}
if (len != NULL) {
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index ccfc9b4803..dbbcf4f1b9 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -7586,27 +7586,35 @@ static int ins_bs(int c, int mode, int *inserted_space_p)
* happen when using 'sts' and 'linebreak'. */
if (vcol >= start_vcol)
ins_bs_one(&vcol);
- }
- /*
- * Delete upto starting point, start of line or previous word.
- */
- else do {
- if (!revins_on) /* put cursor on char to be deleted */
- dec_cursor();
- /* start of word? */
- if (mode == BACKSPACE_WORD && !ascii_isspace(gchar_cursor())) {
- mode = BACKSPACE_WORD_NOT_SPACE;
- temp = vim_iswordc(gchar_cursor());
+ // Delete upto starting point, start of line or previous word.
+ } else {
+ int cclass = 0, prev_cclass = 0;
+
+ if (has_mbyte) {
+ cclass = mb_get_class(get_cursor_pos_ptr());
+ }
+ do {
+ if (!revins_on) { // put cursor on char to be deleted
+ dec_cursor();
}
- /* end of word? */
- else if (mode == BACKSPACE_WORD_NOT_SPACE
- && (ascii_isspace(cc = gchar_cursor())
- || vim_iswordc(cc) != temp)) {
- if (!revins_on)
+ cc = gchar_cursor();
+ // look multi-byte character class
+ if (has_mbyte) {
+ prev_cclass = cclass;
+ cclass = mb_get_class(get_cursor_pos_ptr());
+ }
+ if (mode == BACKSPACE_WORD && !ascii_isspace(cc)) { // start of word?
+ mode = BACKSPACE_WORD_NOT_SPACE;
+ temp = vim_iswordc(cc);
+ } else if (mode == BACKSPACE_WORD_NOT_SPACE
+ && ((ascii_isspace(cc) || vim_iswordc(cc) != temp)
+ || prev_cclass != cclass)) { // end of word?
+ if (!revins_on) {
inc_cursor();
- else if (State & REPLACE_FLAG)
+ } else if (State & REPLACE_FLAG) {
dec_cursor();
+ }
break;
}
if (State & REPLACE_FLAG)
@@ -7639,18 +7647,18 @@ static int ins_bs(int c, int mode, int *inserted_space_p)
(curwin->w_cursor.col > mincol
&& (curwin->w_cursor.lnum != Insstart_orig.lnum
|| curwin->w_cursor.col != Insstart_orig.col)));
- did_backspace = TRUE;
+ }
+ did_backspace = true;
}
- did_si = FALSE;
- can_si = FALSE;
- can_si_back = FALSE;
- if (curwin->w_cursor.col <= 1)
- did_ai = FALSE;
- /*
- * It's a little strange to put backspaces into the redo
- * buffer, but it makes auto-indent a lot easier to deal
- * with.
- */
+ did_si = false;
+ can_si = false;
+ can_si_back = false;
+ if (curwin->w_cursor.col <= 1) {
+ did_ai = false;
+ }
+ // It's a little strange to put backspaces into the redo
+ // buffer, but it makes auto-indent a lot easier to deal
+ // with.
AppendCharToRedobuff(c);
/* If deleted before the insertion point, adjust it */
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 7ac51d7bd7..a1c5f958d1 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1113,19 +1113,17 @@ typval_T *eval_expr(char_u *arg, char_u **nextcmd)
}
-/*
- * Call some vimL function and return the result in "*rettv".
- * Uses argv[argc] for the function arguments. Only Number and String
- * arguments are currently supported.
- * Returns OK or FAIL.
- */
-int
-call_vim_function (
+// Call some vimL function and return the result in "*rettv".
+// Uses argv[argc] for the function arguments. Only Number and String
+// arguments are currently supported.
+//
+// Return OK or FAIL.
+int call_vim_function(
char_u *func,
int argc,
char_u **argv,
- int safe, /* use the sandbox */
- int str_arg_only, /* all arguments are strings */
+ int safe, // use the sandbox
+ int str_arg_only, // all arguments are strings
typval_T *rettv
)
{
@@ -1138,18 +1136,19 @@ call_vim_function (
typval_T *argvars = xmalloc((argc + 1) * sizeof(typval_T));
for (int i = 0; i < argc; i++) {
- /* Pass a NULL or empty argument as an empty string */
+ // Pass a NULL or empty argument as an empty string
if (argv[i] == NULL || *argv[i] == NUL) {
argvars[i].v_type = VAR_STRING;
argvars[i].vval.v_string = (char_u *)"";
continue;
}
- if (str_arg_only)
+ if (str_arg_only) {
len = 0;
- else
- /* Recognize a number argument, the others must be strings. */
- vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL);
+ } else {
+ // Recognize a number argument, the others must be strings.
+ vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL);
+ }
if (len != 0 && len == (int)STRLEN(argv[i])) {
argvars[i].v_type = VAR_NUMBER;
argvars[i].vval.v_number = n;
@@ -1166,16 +1165,17 @@ call_vim_function (
rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
- curwin->w_cursor.lnum, curwin->w_cursor.lnum,
- &doesrange, TRUE, NULL);
+ curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &doesrange, true, NULL);
if (safe) {
--sandbox;
restore_funccal(save_funccalp);
}
xfree(argvars);
- if (ret == FAIL)
+ if (ret == FAIL) {
clear_tv(rettv);
+ }
return ret;
}
@@ -2890,9 +2890,12 @@ static int do_unlet_var(lval_T *lp, char_u *name_end, int forceit)
else if (do_unlet(lp->ll_name, forceit) == FAIL)
ret = FAIL;
*name_end = cc;
- } else if (tv_check_lock(lp->ll_tv->v_lock, lp->ll_name))
+ } else if ((lp->ll_list != NULL
+ && tv_check_lock(lp->ll_list->lv_lock, lp->ll_name))
+ || (lp->ll_dict != NULL
+ && tv_check_lock(lp->ll_dict->dv_lock, lp->ll_name))) {
return FAIL;
- else if (lp->ll_range) {
+ } else if (lp->ll_range) {
listitem_T *li;
listitem_T *ll_li = lp->ll_li;
int ll_n1 = lp->ll_n1;
@@ -2953,17 +2956,30 @@ int do_unlet(char_u *name, int forceit)
hashtab_T *ht;
hashitem_T *hi;
char_u *varname;
+ dict_T *d;
dictitem_T *di;
dict_T *dict;
ht = find_var_ht_dict(name, &varname, &dict);
if (ht != NULL && *varname != NUL) {
+ if (ht == &globvarht) {
+ d = &globvardict;
+ } else if (current_funccal != NULL
+ && ht == &current_funccal->l_vars.dv_hashtab) {
+ d = &current_funccal->l_vars;
+ } else {
+ di = find_var_in_ht(ht, *name, (char_u *)"", false);
+ d = di->di_tv.vval.v_dict;
+ }
+
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi)) {
di = HI2DI(hi);
if (var_check_fixed(di->di_flags, name)
- || var_check_ro(di->di_flags, name))
+ || var_check_ro(di->di_flags, name)
+ || tv_check_lock(d->dv_lock, name)) {
return FAIL;
+ }
typval_T oldtv;
bool watched = is_watched(dict);
@@ -4025,38 +4041,35 @@ eval6 (
return OK;
}
-/*
- * Handle sixth level expression:
- * number number constant
- * "string" string constant
- * 'string' literal string constant
- * &option-name option value
- * @r register contents
- * identifier variable value
- * function() function call
- * $VAR environment variable
- * (expression) nested expression
- * [expr, expr] List
- * {key: val, key: val} Dictionary
- *
- * Also handle:
- * ! in front logical NOT
- * - in front unary minus
- * + in front unary plus (ignored)
- * trailing [] subscript in String or List
- * trailing .name entry in Dictionary
- *
- * "arg" must point to the first non-white of the expression.
- * "arg" is advanced to the next non-white after the recognized expression.
- *
- * Return OK or FAIL.
- */
-static int
-eval7 (
+// Handle sixth level expression:
+// number number constant
+// "string" string constant
+// 'string' literal string constant
+// &option-name option value
+// @r register contents
+// identifier variable value
+// function() function call
+// $VAR environment variable
+// (expression) nested expression
+// [expr, expr] List
+// {key: val, key: val} Dictionary
+//
+// Also handle:
+// ! in front logical NOT
+// - in front unary minus
+// + in front unary plus (ignored)
+// trailing [] subscript in String or List
+// trailing .name entry in Dictionary
+//
+// "arg" must point to the first non-white of the expression.
+// "arg" is advanced to the next non-white after the recognized expression.
+//
+// Return OK or FAIL.
+static int eval7(
char_u **arg,
typval_T *rettv,
int evaluate,
- int want_string /* after "." operator */
+ int want_string // after "." operator
)
{
long n;
@@ -4066,24 +4079,19 @@ eval7 (
int ret = OK;
char_u *alias;
- /*
- * Initialise variable so that clear_tv() can't mistake this for a
- * string and free a string that isn't there.
- */
+ // Initialise variable so that clear_tv() can't mistake this for a
+ // string and free a string that isn't there.
rettv->v_type = VAR_UNKNOWN;
- /*
- * Skip '!' and '-' characters. They are handled later.
- */
+ // Skip '!' and '-' characters. They are handled later.
start_leader = *arg;
- while (**arg == '!' || **arg == '-' || **arg == '+')
+ while (**arg == '!' || **arg == '-' || **arg == '+') {
*arg = skipwhite(*arg + 1);
+ }
end_leader = *arg;
switch (**arg) {
- /*
- * Number constant.
- */
+ // Number constant.
case '0':
case '1':
case '2':
@@ -4096,27 +4104,30 @@ eval7 (
case '9':
{
char_u *p = skipdigits(*arg + 1);
- int get_float = FALSE;
+ int get_float = false;
- /* We accept a float when the format matches
- * "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
- * strict to avoid backwards compatibility problems.
- * Don't look for a float after the "." operator, so that
- * ":let vers = 1.2.3" doesn't fail. */
+ // We accept a float when the format matches
+ // "[0-9]\+\.[0-9]\+\([eE][+-]\?[0-9]\+\)\?". This is very
+ // strict to avoid backwards compatibility problems.
+ // Don't look for a float after the "." operator, so that
+ // ":let vers = 1.2.3" doesn't fail.
if (!want_string && p[0] == '.' && ascii_isdigit(p[1])) {
- get_float = TRUE;
+ get_float = true;
p = skipdigits(p + 2);
if (*p == 'e' || *p == 'E') {
++p;
- if (*p == '-' || *p == '+')
+ if (*p == '-' || *p == '+') {
++p;
- if (!ascii_isdigit(*p))
- get_float = FALSE;
- else
+ }
+ if (!ascii_isdigit(*p)) {
+ get_float = false;
+ } else {
p = skipdigits(p + 1);
+ }
+ }
+ if (ASCII_ISALPHA(*p) || *p == '.') {
+ get_float = false;
}
- if (ASCII_ISALPHA(*p) || *p == '.')
- get_float = FALSE;
}
if (get_float) {
float_T f;
@@ -4127,7 +4138,7 @@ eval7 (
rettv->vval.v_float = f;
}
} else {
- vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL);
+ vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL);
*arg += len;
if (evaluate) {
rettv->v_type = VAR_NUMBER;
@@ -4137,62 +4148,47 @@ eval7 (
break;
}
- /*
- * String constant: "string".
- */
+ // String constant: "string".
case '"': ret = get_string_tv(arg, rettv, evaluate);
break;
- /*
- * Literal string constant: 'str''ing'.
- */
+ // Literal string constant: 'str''ing'.
case '\'': ret = get_lit_string_tv(arg, rettv, evaluate);
break;
- /*
- * List: [expr, expr]
- */
+ // List: [expr, expr]
case '[': ret = get_list_tv(arg, rettv, evaluate);
break;
- /*
- * Dictionary: {key: val, key: val}
- */
+ // Dictionary: {key: val, key: val}
case '{': ret = get_dict_tv(arg, rettv, evaluate);
break;
- /*
- * Option value: &name
- */
+ // Option value: &name
case '&': ret = get_option_tv(arg, rettv, evaluate);
break;
- /*
- * Environment variable: $VAR.
- */
+ // Environment variable: $VAR.
case '$': ret = get_env_tv(arg, rettv, evaluate);
break;
- /*
- * Register contents: @r.
- */
+ // Register contents: @r.
case '@': ++*arg;
if (evaluate) {
rettv->v_type = VAR_STRING;
rettv->vval.v_string = get_reg_contents(**arg, kGRegExprSrc);
}
- if (**arg != NUL)
+ if (**arg != NUL) {
++*arg;
+ }
break;
- /*
- * nested expression: (expression).
- */
+ // nested expression: (expression).
case '(': *arg = skipwhite(*arg + 1);
- ret = eval1(arg, rettv, evaluate); /* recursive! */
- if (**arg == ')')
+ ret = eval1(arg, rettv, evaluate); // recursive!
+ if (**arg == ')') {
++*arg;
- else if (ret == OK) {
+ } else if (ret == OK) {
EMSG(_("E110: Missing ')'"));
clear_tv(rettv);
ret = FAIL;
@@ -4204,71 +4200,72 @@ eval7 (
}
if (ret == NOTDONE) {
- /*
- * Must be a variable or function name.
- * Can also be a curly-braces kind of name: {expr}.
- */
+ // Must be a variable or function name.
+ // Can also be a curly-braces kind of name: {expr}.
s = *arg;
- len = get_name_len(arg, &alias, evaluate, TRUE);
- if (alias != NULL)
+ len = get_name_len(arg, &alias, evaluate, true);
+ if (alias != NULL) {
s = alias;
+ }
- if (len <= 0)
+ if (len <= 0) {
ret = FAIL;
- else {
- if (**arg == '(') { /* recursive! */
- /* If "s" is the name of a variable of type VAR_FUNC
- * use its contents. */
+ } else {
+ if (**arg == '(') { // recursive!
+ // If "s" is the name of a variable of type VAR_FUNC
+ // use its contents.
s = deref_func_name(s, &len, !evaluate);
- /* Invoke the function. */
+ // Invoke the function.
ret = get_func_tv(s, len, rettv, arg,
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
&len, evaluate, NULL);
- /* If evaluate is FALSE rettv->v_type was not set in
- * get_func_tv, but it's needed in handle_subscript() to parse
- * what follows. So set it here. */
+ // If evaluate is false rettv->v_type was not set in
+ // get_func_tv, but it's needed in handle_subscript() to parse
+ // what follows. So set it here.
if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
rettv->vval.v_string = empty_string;
rettv->v_type = VAR_FUNC;
}
- /* Stop the expression evaluation when immediately
- * aborting on error, or when an interrupt occurred or
- * an exception was thrown but not caught. */
+ // Stop the expression evaluation when immediately
+ // aborting on error, or when an interrupt occurred or
+ // an exception was thrown but not caught.
if (aborting()) {
- if (ret == OK)
+ if (ret == OK) {
clear_tv(rettv);
+ }
ret = FAIL;
}
- } else if (evaluate)
- ret = get_var_tv(s, len, rettv, TRUE, FALSE);
- else
+ } else if (evaluate) {
+ ret = get_var_tv(s, len, rettv, true, false);
+ } else {
ret = OK;
+ }
}
xfree(alias);
}
*arg = skipwhite(*arg);
- /* Handle following '[', '(' and '.' for expr[expr], expr.name,
- * expr(expr). */
- if (ret == OK)
- ret = handle_subscript(arg, rettv, evaluate, TRUE);
+ // Handle following '[', '(' and '.' for expr[expr], expr.name,
+ // expr(expr).
+ if (ret == OK) {
+ ret = handle_subscript(arg, rettv, evaluate, true);
+ }
- /*
- * Apply logical NOT and unary '-', from right to left, ignore '+'.
- */
+ // Apply logical NOT and unary '-', from right to left, ignore '+'.
if (ret == OK && evaluate && end_leader > start_leader) {
- int error = FALSE;
+ int error = false;
int val = 0;
float_T f = 0.0;
- if (rettv->v_type == VAR_FLOAT)
+ if (rettv->v_type == VAR_FLOAT) {
f = rettv->vval.v_float;
- else
+ } else {
val = get_tv_number_chk(rettv, &error);
+ }
if (error) {
clear_tv(rettv);
ret = FAIL;
@@ -4276,15 +4273,17 @@ eval7 (
while (end_leader > start_leader) {
--end_leader;
if (*end_leader == '!') {
- if (rettv->v_type == VAR_FLOAT)
+ if (rettv->v_type == VAR_FLOAT) {
f = !f;
- else
+ } else {
val = !val;
+ }
} else if (*end_leader == '-') {
- if (rettv->v_type == VAR_FLOAT)
+ if (rettv->v_type == VAR_FLOAT) {
f = -f;
- else
+ } else {
val = -val;
+ }
}
}
if (rettv->v_type == VAR_FLOAT) {
@@ -4655,10 +4654,13 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
int n, nr;
int c = toupper(*p);
- if (c == 'X')
+ if (c == 'X') {
n = 2;
- else
+ } else if (*p == 'u') {
n = 4;
+ } else {
+ n = 8;
+ }
nr = 0;
while (--n >= 0 && ascii_isxdigit(p[1])) {
++p;
@@ -6069,7 +6071,7 @@ dictitem_T *dictitem_alloc(char_u *key) FUNC_ATTR_NONNULL_RET
#ifndef __clang_analyzer__
STRCPY(di->di_key, key);
#endif
- di->di_flags = 0;
+ di->di_flags = DI_FLAGS_ALLOC;
return di;
}
@@ -6081,7 +6083,7 @@ static dictitem_T *dictitem_copy(dictitem_T *org) FUNC_ATTR_NONNULL_RET
dictitem_T *di = xmalloc(sizeof(dictitem_T) + STRLEN(org->di_key));
STRCPY(di->di_key, org->di_key);
- di->di_flags = 0;
+ di->di_flags = DI_FLAGS_ALLOC;
copy_tv(&org->di_tv, &di->di_tv);
return di;
@@ -6109,7 +6111,9 @@ static void dictitem_remove(dict_T *dict, dictitem_T *item)
void dictitem_free(dictitem_T *item)
{
clear_tv(&item->di_tv);
- xfree(item);
+ if (item->di_flags & DI_FLAGS_ALLOC) {
+ xfree(item);
+ }
}
/// Make a copy of dictionary
@@ -7205,9 +7209,9 @@ static struct fst {
{ "getwinposx", 0, 0, f_getwinposx },
{ "getwinposy", 0, 0, f_getwinposy },
{ "getwinvar", 2, 3, f_getwinvar },
- { "glob", 1, 3, f_glob },
+ { "glob", 1, 4, f_glob },
{ "glob2regpat", 1, 1, f_glob2regpat },
- { "globpath", 2, 4, f_globpath },
+ { "globpath", 2, 5, f_globpath },
{ "has", 1, 1, f_has },
{ "has_key", 2, 2, f_has_key },
{ "haslocaldir", 0, 0, f_haslocaldir },
@@ -7236,6 +7240,7 @@ static struct fst {
{ "islocked", 1, 1, f_islocked },
{ "items", 1, 1, f_items },
{ "jobclose", 1, 2, f_jobclose },
+ { "jobpid", 1, 1, f_jobpid },
{ "jobresize", 3, 3, f_jobresize },
{ "jobsend", 2, 2, f_jobsend },
{ "jobstart", 1, 2, f_jobstart },
@@ -9225,6 +9230,7 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
hashitem_T *hi2;
int todo;
bool watched = is_watched(d1);
+ char *arg_errmsg = N_("extend() argument");
todo = (int)d2->dv_hashtab.ht_used;
for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2) {
@@ -9258,6 +9264,11 @@ void dict_extend(dict_T *d1, dict_T *d2, char_u *action)
} else if (*action == 'f' && HI2DI(hi2) != di1) {
typval_T oldtv;
+ if (tv_check_lock(di1->di_tv.v_lock, (char_u *)_(arg_errmsg))
+ || var_check_ro(di1->di_flags, (char_u *)_(arg_errmsg))) {
+ break;
+ }
+
if (watched) {
copy_tv(&di1->di_tv, &oldtv);
}
@@ -9473,12 +9484,14 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
if (argvars[0].v_type == VAR_LIST) {
if ((l = argvars[0].vval.v_list) == NULL
- || tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg)))
+ || (!map && tv_check_lock(l->lv_lock, (char_u *)_(arg_errmsg)))) {
return;
+ }
} else if (argvars[0].v_type == VAR_DICT) {
if ((d = argvars[0].vval.v_dict) == NULL
- || tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg)))
+ || (!map && tv_check_lock(d->dv_lock, (char_u *)_(arg_errmsg)))) {
return;
+ }
} else {
EMSG2(_(e_listdictarg), ermsg);
return;
@@ -9507,17 +9520,26 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
for (hi = ht->ht_array; todo > 0; ++hi) {
if (!HASHITEM_EMPTY(hi)) {
--todo;
+
di = HI2DI(hi);
- if (tv_check_lock(di->di_tv.v_lock,
- (char_u *)_(arg_errmsg)))
+ if (map
+ && (tv_check_lock(di->di_tv.v_lock, (char_u *)_(arg_errmsg))
+ || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg)))) {
break;
+ }
+
vimvars[VV_KEY].vv_str = vim_strsave(di->di_key);
int r = filter_map_one(&di->di_tv, expr, map, &rem);
clear_tv(&vimvars[VV_KEY].vv_tv);
if (r == FAIL || did_emsg)
break;
- if (!map && rem)
+ if (!map && rem) {
+ if (var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg))
+ || var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) {
+ break;
+ }
dictitem_remove(d, di);
+ }
}
}
hash_unlock(ht);
@@ -9525,8 +9547,9 @@ static void filter_map(typval_T *argvars, typval_T *rettv, int map)
vimvars[VV_KEY].vv_type = VAR_NUMBER;
for (li = l->lv_first; li != NULL; li = nli) {
- if (tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg)))
+ if (map && tv_check_lock(li->li_tv.v_lock, (char_u *)_(arg_errmsg))) {
break;
+ }
nli = li->li_next;
vimvars[VV_KEY].vv_nr = idx;
if (filter_map_one(&li->li_tv, expr, map, &rem) == FAIL
@@ -10717,10 +10740,15 @@ static void f_glob(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type != VAR_UNKNOWN) {
if (get_tv_number_chk(&argvars[1], &error))
options |= WILD_KEEP_ALL;
- if (argvars[2].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[2], &error)) {
- rettv->v_type = VAR_LIST;
- rettv->vval.v_list = NULL;
+ if (argvars[2].v_type != VAR_UNKNOWN) {
+ if (get_tv_number_chk(&argvars[2], &error)) {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = NULL;
+ }
+ if (argvars[3].v_type != VAR_UNKNOWN
+ && get_tv_number_chk(&argvars[3], &error)) {
+ options |= WILD_ALLLINKS;
+ }
}
}
if (!error) {
@@ -10759,10 +10787,15 @@ static void f_globpath(typval_T *argvars, typval_T *rettv)
flags |= WILD_KEEP_ALL;
}
- if (argvars[3].v_type != VAR_UNKNOWN
- && get_tv_number_chk(&argvars[3], &error)) {
- rettv->v_type = VAR_LIST;
- rettv->vval.v_list = NULL;
+ if (argvars[3].v_type != VAR_UNKNOWN) {
+ if (get_tv_number_chk(&argvars[3], &error)) {
+ rettv->v_type = VAR_LIST;
+ rettv->vval.v_list = NULL;
+ }
+ if (argvars[4].v_type != VAR_UNKNOWN
+ && get_tv_number_chk(&argvars[4], &error)) {
+ flags |= WILD_ALLLINKS;
+ }
}
}
@@ -10789,15 +10822,15 @@ static void f_globpath(typval_T *argvars, typval_T *rettv)
}
}
-/*
- * "glob2regpat()" function
- */
+// "glob2regpat()" function
static void f_glob2regpat(typval_T *argvars, typval_T *rettv)
{
- char_u *pat = get_tv_string_chk(&argvars[0]);
+ char_u *pat = get_tv_string_chk(&argvars[0]); // NULL on type error
- rettv->v_type = VAR_STRING;
- rettv->vval.v_string = file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = (pat == NULL)
+ ? NULL
+ : file_pat_to_reg_pat(pat, NULL, NULL, false);
}
/*
@@ -11611,6 +11644,31 @@ static void f_jobclose(typval_T *argvars, typval_T *rettv)
}
}
+// "jobpid(id)" function
+static void f_jobpid(typval_T *argvars, typval_T *rettv)
+{
+ rettv->v_type = VAR_NUMBER;
+ rettv->vval.v_number = 0;
+
+ if (check_restricted() || check_secure()) {
+ return;
+ }
+
+ if (argvars[0].v_type != VAR_NUMBER) {
+ EMSG(_(e_invarg));
+ return;
+ }
+
+ TerminalJobData *data = find_job(argvars[0].vval.v_number);
+ if (!data) {
+ EMSG(_(e_invjob));
+ return;
+ }
+
+ Process *proc = (Process *)&data->proc;
+ rettv->vval.v_number = proc->pid;
+}
+
// "jobsend()" function
static void f_jobsend(typval_T *argvars, typval_T *rettv)
{
@@ -11771,8 +11829,9 @@ static void f_jobstart(typval_T *argvars, typval_T *rettv)
}
bool pty = job_opts && get_dict_number(job_opts, (uint8_t *)"pty") != 0;
+ bool detach = job_opts && get_dict_number(job_opts, (uint8_t *)"detach") != 0;
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
- job_opts, pty);
+ job_opts, pty, detach);
Process *proc = (Process *)&data->proc;
if (pty) {
@@ -13855,9 +13914,10 @@ static void f_remove(typval_T *argvars, typval_T *rettv)
key = get_tv_string_chk(&argvars[1]);
if (key != NULL) {
di = dict_find(d, key, -1);
- if (di == NULL)
+ if (di == NULL) {
EMSG2(_(e_dictkey), key);
- else {
+ } else if (!var_check_fixed(di->di_flags, (char_u *)_(arg_errmsg))
+ && !var_check_ro(di->di_flags, (char_u *)_(arg_errmsg))) {
*rettv = di->di_tv;
init_tv(&di->di_tv);
dictitem_remove(d, di);
@@ -15971,9 +16031,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv)
rettv->v_type = VAR_FLOAT;
}
-/*
- * "str2nr()" function
- */
+// "str2nr()" function
static void f_str2nr(typval_T *argvars, typval_T *rettv)
{
int base = 10;
@@ -15982,16 +16040,21 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
if (argvars[1].v_type != VAR_UNKNOWN) {
base = get_tv_number(&argvars[1]);
- if (base != 8 && base != 10 && base != 16) {
+ if (base != 2 && base != 8 && base != 10 && base != 16) {
EMSG(_(e_invarg));
return;
}
}
p = skipwhite(get_tv_string(&argvars[0]));
- if (*p == '+')
+ if (*p == '+') {
p = skipwhite(p + 1);
- vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL);
+ }
+ vim_str2nr(p, NULL, NULL,
+ base == 2 ? 2 : 0,
+ base == 8 ? 2 : 0,
+ base == 16 ? 2 : 0,
+ &n, NULL);
rettv->vval.v_number = n;
}
@@ -16776,7 +16839,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv)
}
TerminalJobData *data = common_job_init(argv, on_stdout, on_stderr, on_exit,
- job_opts, true);
+ job_opts, true, false);
data->proc.pty.width = curwin->w_width;
data->proc.pty.height = curwin->w_height;
data->proc.pty.term_name = xstrdup("xterm-256color");
@@ -18271,9 +18334,10 @@ long get_tv_number_chk(typval_T *varp, int *denote)
EMSG(_("E703: Using a Funcref as a Number"));
break;
case VAR_STRING:
- if (varp->vval.v_string != NULL)
+ if (varp->vval.v_string != NULL) {
vim_str2nr(varp->vval.v_string, NULL, NULL,
- TRUE, TRUE, &n, NULL);
+ true, true, true, &n, NULL);
+ }
return n;
case VAR_LIST:
EMSG(_("E745: Using a List as a Number"));
@@ -18285,10 +18349,12 @@ long get_tv_number_chk(typval_T *varp, int *denote)
EMSG2(_(e_intern2), "get_tv_number()");
break;
}
- if (denote == NULL) /* useful for values that must be unsigned */
+ if (denote == NULL) {
+ // useful for values that must be unsigned
n = -1;
- else
- *denote = TRUE;
+ } else {
+ *denote = true;
+ }
return n;
}
@@ -18619,14 +18685,16 @@ static void vars_clear_ext(hashtab_T *ht, int free_val)
if (!HASHITEM_EMPTY(hi)) {
--todo;
- /* Free the variable. Don't remove it from the hashtab,
- * ht_array might change then. hash_clear() takes care of it
- * later. */
+ // Free the variable. Don't remove it from the hashtab,
+ // ht_array might change then. hash_clear() takes care of it
+ // later.
v = HI2DI(hi);
- if (free_val)
+ if (free_val) {
clear_tv(&v->di_tv);
- if ((v->di_flags & DI_FLAGS_FIX) == 0)
+ }
+ if (v->di_flags & DI_FLAGS_ALLOC) {
xfree(v);
+ }
}
}
hash_clear(ht);
@@ -18800,7 +18868,7 @@ set_var (
xfree(v);
return;
}
- v->di_flags = 0;
+ v->di_flags = DI_FLAGS_ALLOC;
}
if (copy || tv->v_type == VAR_NUMBER || tv->v_type == VAR_FLOAT) {
@@ -20691,7 +20759,7 @@ call_user_func (
v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX;
} else {
v = xmalloc(sizeof(dictitem_T) + STRLEN(name));
- v->di_flags = DI_FLAGS_RO;
+ v->di_flags = DI_FLAGS_RO | DI_FLAGS_FIX | DI_FLAGS_ALLOC;
}
STRCPY(v->di_key, name);
hash_add(&fc->l_avars.dv_hashtab, DI2HIKEY(v));
@@ -21782,8 +21850,13 @@ char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, char_u *flags)
return ret;
}
-static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
- ufunc_T *on_stderr, ufunc_T *on_exit, dict_T *self, bool pty)
+static inline TerminalJobData *common_job_init(char **argv,
+ ufunc_T *on_stdout,
+ ufunc_T *on_stderr,
+ ufunc_T *on_exit,
+ dict_T *self,
+ bool pty,
+ bool detach)
{
TerminalJobData *data = xcalloc(1, sizeof(TerminalJobData));
data->stopped = false;
@@ -21806,6 +21879,7 @@ static inline TerminalJobData *common_job_init(char **argv, ufunc_T *on_stdout,
}
proc->cb = on_process_exit;
proc->events = data->events;
+ proc->detach = detach;
return data;
}
@@ -21833,8 +21907,13 @@ static inline bool common_job_callbacks(dict_T *vopts, ufunc_T **on_stdout,
static inline bool common_job_start(TerminalJobData *data, typval_T *rettv)
{
- data->refcount++;
Process *proc = (Process *)&data->proc;
+ if (proc->type == kProcessTypePty && proc->detach) {
+ EMSG2(_(e_invarg2), "terminal/pty job cannot be detached");
+ return false;
+ }
+
+ data->refcount++;
char *cmd = xstrdup(proc->argv[0]);
if (!process_spawn(proc)) {
EMSG2(_(e_jobspawn), cmd);
diff --git a/src/nvim/eval_defs.h b/src/nvim/eval_defs.h
index ed419268d2..cdad1f3197 100644
--- a/src/nvim/eval_defs.h
+++ b/src/nvim/eval_defs.h
@@ -101,10 +101,11 @@ struct dictitem_S {
typedef struct dictitem_S dictitem_T;
-#define DI_FLAGS_RO 1 /* "di_flags" value: read-only variable */
-#define DI_FLAGS_RO_SBX 2 /* "di_flags" value: read-only in the sandbox */
-#define DI_FLAGS_FIX 4 /* "di_flags" value: fixed variable, not allocated */
-#define DI_FLAGS_LOCK 8 /* "di_flags" value: locked variable */
+#define DI_FLAGS_RO 1 // "di_flags" value: read-only variable
+#define DI_FLAGS_RO_SBX 2 // "di_flags" value: read-only in the sandbox
+#define DI_FLAGS_FIX 4 // "di_flags" value: fixed: no :unlet or remove()
+#define DI_FLAGS_LOCK 8 // "di_flags" value: locked variable
+#define DI_FLAGS_ALLOC 16 // "di_flags" value: separately allocated
/*
* Structure to hold info about a Dictionary.
diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c
index 44305c69bc..9ef3468284 100644
--- a/src/nvim/event/libuv_process.c
+++ b/src/nvim/event/libuv_process.c
@@ -21,6 +21,9 @@ bool libuv_process_spawn(LibuvProcess *uvproc)
uvproc->uvopts.args = proc->argv;
uvproc->uvopts.flags = UV_PROCESS_WINDOWS_HIDE
| UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
+ if (proc->detach) {
+ uvproc->uvopts.flags |= UV_PROCESS_DETACHED;
+ }
uvproc->uvopts.exit_cb = exit_cb;
uvproc->uvopts.cwd = NULL;
uvproc->uvopts.env = NULL;
diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c
index 0336eb880a..e6012595fd 100644
--- a/src/nvim/event/process.c
+++ b/src/nvim/event/process.c
@@ -29,6 +29,7 @@
} \
} while (0)
+static bool process_is_tearing_down = false;
bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
{
@@ -112,11 +113,22 @@ bool process_spawn(Process *proc) FUNC_ATTR_NONNULL_ALL
void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL
{
+ process_is_tearing_down = true;
kl_iter(WatcherPtr, loop->children, current) {
Process *proc = (*current)->data;
- uv_kill(proc->pid, SIGTERM);
- proc->term_sent = true;
- process_stop(proc);
+ if (proc->detach) {
+ // Close handles to process without killing it.
+ CREATE_EVENT(loop->events, process_close_handles, 1, proc);
+ } else {
+ if (proc->type == kProcessTypeUv) {
+ uv_kill(proc->pid, SIGTERM);
+ proc->term_sent = true;
+ process_stop(proc);
+ } else { // kProcessTypePty
+ process_close_streams(proc);
+ pty_process_close_master((PtyProcess *)proc);
+ }
+ }
}
// Wait until all children exit
@@ -303,6 +315,10 @@ static void decref(Process *proc)
static void process_close(Process *proc)
FUNC_ATTR_NONNULL_ARG(1)
{
+ if (process_is_tearing_down && proc->detach && proc->closed) {
+ // If a detached process dies while tearing down it might get closed twice.
+ return;
+ }
assert(!proc->closed);
proc->closed = true;
switch (proc->type) {
@@ -333,6 +349,7 @@ static void on_process_exit(Process *proc)
DLOG("Stopping process kill timer");
uv_timer_stop(&loop->children_kill_timer);
}
+
// Process handles are closed in the next event loop tick. This is done to
// give libuv more time to read data from the OS after the process exits(If
// process_close_streams is called with data still in the OS buffer, we lose
diff --git a/src/nvim/event/process.h b/src/nvim/event/process.h
index 45edc46b95..e23c8ea60f 100644
--- a/src/nvim/event/process.h
+++ b/src/nvim/event/process.h
@@ -25,7 +25,7 @@ struct process {
Stream *in, *out, *err;
process_exit_cb cb;
internal_process_cb internal_exit_cb, internal_close_cb;
- bool closed, term_sent;
+ bool closed, term_sent, detach;
Queue *events;
};
@@ -48,7 +48,8 @@ static inline Process process_init(Loop *loop, ProcessType type, void *data)
.closed = false,
.term_sent = false,
.internal_close_cb = NULL,
- .internal_exit_cb = NULL
+ .internal_exit_cb = NULL,
+ .detach = false
};
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 29d87d0fc1..407dded6af 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -329,9 +329,7 @@ static int sort_compare(const void *s1, const void *s2)
return result;
}
-/*
- * ":sort".
- */
+// ":sort".
void ex_sort(exarg_T *eap)
{
regmatch_T regmatch;
@@ -343,17 +341,19 @@ void ex_sort(exarg_T *eap)
char_u *p;
char_u *s;
char_u *s2;
- char_u c; /* temporary character storage */
- int unique = FALSE;
+ char_u c; // temporary character storage
+ int unique = false;
long deleted;
colnr_T start_col;
colnr_T end_col;
- int sort_oct; /* sort on octal number */
- int sort_hex; /* sort on hex number */
+ int sort_bin; // sort on bin number
+ int sort_oct; // sort on octal number
+ int sort_hex; // sort on hex number
- /* Sorting one line is really quick! */
- if (count <= 1)
+ // Sorting one line is really quick!
+ if (count <= 1) {
return;
+ }
if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL)
return;
@@ -362,47 +362,51 @@ void ex_sort(exarg_T *eap)
regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
- sort_abort = sort_ic = sort_rx = sort_nr = sort_oct = sort_hex = 0;
+ sort_abort = sort_ic = sort_rx = sort_nr = sort_bin = sort_oct = sort_hex = 0;
for (p = eap->arg; *p != NUL; ++p) {
- if (ascii_iswhite(*p))
- ;
- else if (*p == 'i')
- sort_ic = TRUE;
- else if (*p == 'r')
- sort_rx = TRUE;
- else if (*p == 'n')
+ if (ascii_iswhite(*p)) {
+ } else if (*p == 'i') {
+ sort_ic = true;
+ } else if (*p == 'r') {
+ sort_rx = true;
+ } else if (*p == 'n') {
sort_nr = 2;
- else if (*p == 'o')
+ } else if (*p == 'b') {
+ sort_bin = 2;
+ } else if (*p == 'o') {
sort_oct = 2;
- else if (*p == 'x')
+ } else if (*p == 'x') {
sort_hex = 2;
- else if (*p == 'u')
- unique = TRUE;
- else if (*p == '"') /* comment start */
+ } else if (*p == 'u') {
+ unique = true;
+ } else if (*p == '"') {
+ // comment start
break;
- else if (check_nextcmd(p) != NULL) {
+ } else if (check_nextcmd(p) != NULL) {
eap->nextcmd = check_nextcmd(p);
break;
} else if (!ASCII_ISALPHA(*p) && regmatch.regprog == NULL) {
- s = skip_regexp(p + 1, *p, TRUE, NULL);
+ s = skip_regexp(p + 1, *p, true, NULL);
if (*s != *p) {
EMSG(_(e_invalpat));
goto sortend;
}
*s = NUL;
- /* Use last search pattern if sort pattern is empty. */
+ // Use last search pattern if sort pattern is empty.
if (s == p + 1) {
if (last_search_pat() == NULL) {
EMSG(_(e_noprevre));
goto sortend;
}
regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
- } else
+ } else {
regmatch.regprog = vim_regcomp(p + 1, RE_MAGIC);
- if (regmatch.regprog == NULL)
+ }
+ if (regmatch.regprog == NULL) {
goto sortend;
- p = s; /* continue after the regexp */
+ }
+ p = s; // continue after the regexp
regmatch.rm_ic = p_ic;
} else {
EMSG2(_(e_invarg2), p);
@@ -410,28 +414,27 @@ void ex_sort(exarg_T *eap)
}
}
- /* Can only have one of 'n', 'o' and 'x'. */
- if (sort_nr + sort_oct + sort_hex > 2) {
+ // Can only have one of 'n', 'b', 'o' and 'x'.
+ if (sort_nr + sort_bin + sort_oct + sort_hex > 2) {
EMSG(_(e_invarg));
goto sortend;
}
- /* From here on "sort_nr" is used as a flag for any number sorting. */
- sort_nr += sort_oct + sort_hex;
+ // From here on "sort_nr" is used as a flag for any number sorting.
+ sort_nr += sort_bin + sort_oct + sort_hex;
- /*
- * Make an array with all line numbers. This avoids having to copy all
- * the lines into allocated memory.
- * When sorting on strings "start_col_nr" is the offset in the line, for
- * numbers sorting it's the number to sort on. This means the pattern
- * matching and number conversion only has to be done once per line.
- * Also get the longest line length for allocating "sortbuf".
- */
+ // Make an array with all line numbers. This avoids having to copy all
+ // the lines into allocated memory.
+ // When sorting on strings "start_col_nr" is the offset in the line, for
+ // numbers sorting it's the number to sort on. This means the pattern
+ // matching and number conversion only has to be done once per line.
+ // Also get the longest line length for allocating "sortbuf".
for (lnum = eap->line1; lnum <= eap->line2; ++lnum) {
s = ml_get(lnum);
len = (int)STRLEN(s);
- if (maxlen < len)
+ if (maxlen < len) {
maxlen = len;
+ }
start_col = 0;
end_col = len;
@@ -439,34 +442,41 @@ void ex_sort(exarg_T *eap)
if (sort_rx) {
start_col = (colnr_T)(regmatch.startp[0] - s);
end_col = (colnr_T)(regmatch.endp[0] - s);
- } else
+ } else {
start_col = (colnr_T)(regmatch.endp[0] - s);
- } else if (regmatch.regprog != NULL)
+ }
+ } else if (regmatch.regprog != NULL) {
end_col = 0;
+ }
if (sort_nr) {
- /* Make sure vim_str2nr doesn't read any digits past the end
- * of the match, by temporarily terminating the string there */
+ // Make sure vim_str2nr doesn't read any digits past the end
+ // of the match, by temporarily terminating the string there
s2 = s + end_col;
c = *s2;
*s2 = NUL;
- /* Sorting on number: Store the number itself. */
+ // Sorting on number: Store the number itself.
p = s + start_col;
- if (sort_hex)
+ if (sort_hex) {
s = skiptohex(p);
- else
+ } else if (sort_bin) {
+ s = (char_u*) skiptobin((char*) p);
+ } else {
s = skiptodigit(p);
- if (s > p && s[-1] == '-')
- --s; /* include preceding negative sign */
- if (*s == NUL)
- /* empty line should sort before any number */
+ }
+ if (s > p && s[-1] == '-') {
+ --s; // include preceding negative sign
+ }
+ if (*s == NUL) {
+ // empty line should sort before any number
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
- else
- vim_str2nr(s, NULL, NULL, sort_oct, sort_hex,
- &nrs[lnum - eap->line1].start_col_nr, NULL);
+ } else {
+ vim_str2nr(s, NULL, NULL, sort_bin, sort_oct, sort_hex,
+ &nrs[lnum - eap->line1].start_col_nr, NULL);
+ }
*s2 = c;
} else {
- /* Store the column to sort at. */
+ // Store the column to sort at.
nrs[lnum - eap->line1].start_col_nr = start_col;
nrs[lnum - eap->line1].end_col_nr = end_col;
}
@@ -479,17 +489,17 @@ void ex_sort(exarg_T *eap)
goto sortend;
}
- /* Allocate a buffer that can hold the longest line. */
+ // Allocate a buffer that can hold the longest line.
sortbuf1 = xmalloc(maxlen + 1);
sortbuf2 = xmalloc(maxlen + 1);
- /* Sort the array of line numbers. Note: can't be interrupted! */
+ // Sort the array of line numbers. Note: can't be interrupted!
qsort((void *)nrs, count, sizeof(sorti_T), sort_compare);
if (sort_abort)
goto sortend;
- /* Insert the lines in the sorted order below the last one. */
+ // Insert the lines in the sorted order below the last one.
lnum = eap->line2;
for (i = 0; i < count; ++i) {
s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum);
@@ -507,19 +517,22 @@ void ex_sort(exarg_T *eap)
goto sortend;
}
- /* delete the original lines if appending worked */
- if (i == count)
- for (i = 0; i < count; ++i)
- ml_delete(eap->line1, FALSE);
- else
+ // delete the original lines if appending worked
+ if (i == count) {
+ for (i = 0; i < count; ++i) {
+ ml_delete(eap->line1, false);
+ }
+ } else {
count = 0;
+ }
- /* Adjust marks for deleted (or added) lines and prepare for displaying. */
+ // Adjust marks for deleted (or added) lines and prepare for displaying.
deleted = (long)(count - (lnum - eap->line2));
- if (deleted > 0)
+ if (deleted > 0) {
mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted);
- else if (deleted < 0)
+ } else if (deleted < 0) {
mark_adjust(eap->line2, MAXLNUM, -deleted, 0L);
+ }
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted);
curwin->w_cursor.lnum = eap->line1;
@@ -530,8 +543,9 @@ sortend:
xfree(sortbuf1);
xfree(sortbuf2);
vim_regfree(regmatch.regprog);
- if (got_int)
+ if (got_int) {
EMSG(_(e_interr));
+ }
}
/*
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index eca62da949..b19331ad06 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -3701,6 +3701,9 @@ ExpandFromContext (
flags |= EW_KEEPALL;
if (options & WILD_SILENT)
flags |= EW_SILENT;
+ if (options & WILD_ALLLINKS) {
+ flags |= EW_ALLLINKS;
+ }
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
@@ -4767,35 +4770,40 @@ int del_history_idx(int histype, int idx)
return TRUE;
}
-/*
- * Get indices "num1,num2" that specify a range within a list (not a range of
- * text lines in a buffer!) from a string. Used for ":history" and ":clist".
- * Returns OK if parsed successfully, otherwise FAIL.
- */
+/// Get indices that specify a range within a list (not a range of text lines
+/// in a buffer!) from a string. Used for ":history" and ":clist".
+///
+/// @param str string to parse range from
+/// @param num1 from
+/// @param num2 to
+///
+/// @return OK if parsed successfully, otherwise FAIL.
int get_list_range(char_u **str, int *num1, int *num2)
{
int len;
- int first = FALSE;
+ int first = false;
long num;
*str = skipwhite(*str);
- if (**str == '-' || ascii_isdigit(**str)) { /* parse "from" part of range */
- vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
+ if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range
+ vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
*str += len;
*num1 = (int)num;
- first = TRUE;
+ first = true;
}
*str = skipwhite(*str);
- if (**str == ',') { /* parse "to" part of range */
+ if (**str == ',') { // parse "to" part of range
*str = skipwhite(*str + 1);
- vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL);
+ vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL);
if (len > 0) {
*num2 = (int)num;
*str = skipwhite(*str + len);
- } else if (!first) /* no number given at all */
+ } else if (!first) { // no number given at all
return FAIL;
- } else if (first) /* only one number given */
+ }
+ } else if (first) { // only one number given
*num2 = *num1;
+ }
return OK;
}
diff --git a/src/nvim/ex_getln.h b/src/nvim/ex_getln.h
index c537d681c6..21da8b9d42 100644
--- a/src/nvim/ex_getln.h
+++ b/src/nvim/ex_getln.h
@@ -14,15 +14,16 @@
#define WILD_LONGEST 7
#define WILD_ALL_KEEP 8
-#define WILD_LIST_NOTFOUND 1
-#define WILD_HOME_REPLACE 2
-#define WILD_USE_NL 4
-#define WILD_NO_BEEP 8
-#define WILD_ADD_SLASH 16
-#define WILD_KEEP_ALL 32
-#define WILD_SILENT 64
-#define WILD_ESCAPE 128
-#define WILD_ICASE 256
+#define WILD_LIST_NOTFOUND 0x01
+#define WILD_HOME_REPLACE 0x02
+#define WILD_USE_NL 0x04
+#define WILD_NO_BEEP 0x08
+#define WILD_ADD_SLASH 0x10
+#define WILD_KEEP_ALL 0x20
+#define WILD_SILENT 0x40
+#define WILD_ESCAPE 0x80
+#define WILD_ICASE 0x100
+#define WILD_ALLLINKS 0x200
/// Present history tables
typedef enum {
diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c
index 4f345158cf..b213a42c52 100644
--- a/src/nvim/file_search.c
+++ b/src/nvim/file_search.c
@@ -1340,6 +1340,7 @@ void free_findfile(void)
*
* options:
* FNAME_MESS give error message when not found
+ * FNAME_UNESC unescape backslashes
*
* Uses NameBuff[]!
*
@@ -1385,6 +1386,14 @@ find_file_in_path_option (
xfree(ff_file_to_find);
ff_file_to_find = vim_strsave(NameBuff);
+ if (options & FNAME_UNESC) {
+ // Change all "\ " to " ".
+ for (ptr = ff_file_to_find; *ptr != NUL; ++ptr) {
+ if (ptr[0] == '\\' && ptr[1] == ' ') {
+ memmove(ptr, ptr + 1, STRLEN(ptr));
+ }
+ }
+ }
}
rel_to_curdir = (ff_file_to_find[0] == '.'
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 97360d1881..badb5b85b0 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -1992,13 +1992,14 @@ failed:
}
#ifdef OPEN_CHR_FILES
-/*
- * Returns TRUE if the file name argument is of the form "/dev/fd/\d\+",
- * which is the name of files used for process substitution output by
- * some shells on some operating systems, e.g., bash on SunOS.
- * Do not accept "/dev/fd/[012]", opening these may hang Vim.
- */
-static int is_dev_fd_file(char_u *fname)
+/// Returns true if the file name argument is of the form "/dev/fd/\d\+",
+/// which is the name of files used for process substitution output by
+/// some shells on some operating systems, e.g., bash on SunOS.
+/// Do not accept "/dev/fd/[012]", opening these may hang Vim.
+///
+/// @param fname file name to check
+static bool is_dev_fd_file(char_u *fname)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
return STRNCMP(fname, "/dev/fd/", 8) == 0
&& ascii_isdigit(fname[8])
@@ -3806,29 +3807,30 @@ void msg_add_fname(buf_T *buf, char_u *fname)
STRCAT(IObuff, "\" ");
}
-/*
- * Append message for text mode to IObuff.
- * Return TRUE if something appended.
- */
-static int msg_add_fileformat(int eol_type)
+/// Append message for text mode to IObuff.
+///
+/// @param eol_type line ending type
+///
+/// @return true if something was appended.
+static bool msg_add_fileformat(int eol_type)
{
#ifndef USE_CRNL
if (eol_type == EOL_DOS) {
STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[dos]") : _("[dos format]"));
- return TRUE;
+ return true;
}
#endif
if (eol_type == EOL_MAC) {
STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[mac]") : _("[mac format]"));
- return TRUE;
+ return true;
}
#ifdef USE_CRNL
if (eol_type == EOL_UNIX) {
STRCAT(IObuff, shortmess(SHM_TEXT) ? _("[unix]") : _("[unix format]"));
- return TRUE;
+ return true;
}
#endif
- return FALSE;
+ return false;
}
/*
@@ -3892,7 +3894,11 @@ static int check_mtime(buf_T *buf, FileInfo *file_info)
return OK;
}
-static int time_differs(long t1, long t2)
+/// Return true if the times differ
+///
+/// @param t1 first time
+/// @param t2 second time
+static bool time_differs(long t1, long t2) FUNC_ATTR_CONST
{
#if defined(__linux__) || defined(MSWIN)
/* On a FAT filesystem, esp. under Linux, there are only 5 bits to store
@@ -4081,19 +4087,17 @@ static int buf_write_bytes(struct bw_info *ip)
return (wlen < len) ? FAIL : OK;
}
-/*
- * Convert a Unicode character to bytes.
- * Return TRUE for an error, FALSE when it's OK.
- */
-static int
-ucs2bytes (
- unsigned c, /* in: character */
- char_u **pp, /* in/out: pointer to result */
- int flags /* FIO_ flags */
-)
+/// Convert a Unicode character to bytes.
+///
+/// @param c character to convert
+/// @param[in,out] pp pointer to store the result at
+/// @param flags FIO_ flags that specify which encoding to use
+///
+/// @return true for an error, false when it's OK.
+static bool ucs2bytes(unsigned c, char_u **pp, int flags) FUNC_ATTR_NONNULL_ALL
{
char_u *p = *pp;
- int error = FALSE;
+ bool error = false;
int cc;
@@ -4115,8 +4119,9 @@ ucs2bytes (
/* Make two words, ten bits of the character in each. First
* word is 0xd800 - 0xdbff, second one 0xdc00 - 0xdfff */
c -= 0x10000;
- if (c >= 0x100000)
- error = TRUE;
+ if (c >= 0x100000) {
+ error = true;
+ }
cc = ((c >> 10) & 0x3ff) + 0xd800;
if (flags & FIO_ENDIAN_L) {
*p++ = cc;
@@ -4126,8 +4131,9 @@ ucs2bytes (
*p++ = cc;
}
c = (c & 0x3ff) + 0xdc00;
- } else
- error = TRUE;
+ } else {
+ error = true;
+ }
}
if (flags & FIO_ENDIAN_L) {
*p++ = c;
@@ -4138,7 +4144,7 @@ ucs2bytes (
}
} else { /* Latin1 */
if (c >= 0x100) {
- error = TRUE;
+ error = true;
*p++ = 0xBF;
} else
*p++ = c;
@@ -4148,11 +4154,14 @@ ucs2bytes (
return error;
}
-/*
- * Return TRUE if file encoding "fenc" requires conversion from or to
- * 'encoding'.
- */
-static int need_conversion(char_u *fenc)
+/// Return true if file encoding "fenc" requires conversion from or to
+/// 'encoding'.
+///
+/// @param fenc file encoding to check
+///
+/// @return true if conversion is required
+static bool need_conversion(const char_u *fenc)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
int same_encoding;
int enc_flags;
@@ -4179,19 +4188,19 @@ static int need_conversion(char_u *fenc)
return !(enc_utf8 && fenc_flags == FIO_UTF8);
}
-/*
- * Check "ptr" for a unicode encoding and return the FIO_ flags needed for the
- * internal conversion.
- * if "ptr" is an empty string, use 'encoding'.
- */
-static int get_fio_flags(char_u *ptr)
+/// Return the FIO_ flags needed for the internal conversion if 'name' was
+/// unicode or latin1, otherwise 0. If "name" is an empty string,
+/// use 'encoding'.
+///
+/// @param name string to check for encoding
+static int get_fio_flags(const char_u *name)
{
int prop;
- if (*ptr == NUL)
- ptr = p_enc;
-
- prop = enc_canon_props(ptr);
+ if (*name == NUL) {
+ name = p_enc;
+ }
+ prop = enc_canon_props(name);
if (prop & ENC_UNICODE) {
if (prop & ENC_2BYTE) {
if (prop & ENC_ENDIAN_L)
@@ -4423,11 +4432,15 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
return retval;
}
-/*
- * Like fgets(), but if the file line is too long, it is truncated and the
- * rest of the line is thrown away. Returns TRUE for end-of-file.
- */
-int vim_fgets(char_u *buf, int size, FILE *fp)
+/// Like fgets(), but if the file line is too long, it is truncated and the
+/// rest of the line is thrown away.
+///
+/// @param[out] buf buffer to fill
+/// @param size size of the buffer
+/// @param fp file to read from
+///
+/// @return true for end-of-file.
+bool vim_fgets(char_u *buf, int size, FILE *fp) FUNC_ATTR_NONNULL_ALL
{
char *eof;
#define FGETS_SIZE 200
@@ -5326,11 +5339,13 @@ static void au_del_group(char_u *name)
}
}
-/*
- * Find the ID of an autocmd group name.
- * Return it's ID. Returns AUGROUP_ERROR (< 0) for error.
- */
-static int au_find_group(char_u *name)
+/// Find the ID of an autocmd group name.
+///
+/// @param name augroup name
+///
+/// @return the ID or AUGROUP_ERROR (< 0) for error.
+static int au_find_group(const char_u *name)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
for (int i = 0; i < augroups.ga_len; ++i) {
if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0) {
@@ -5340,10 +5355,11 @@ static int au_find_group(char_u *name)
return AUGROUP_ERROR;
}
-/*
- * Return TRUE if augroup "name" exists.
- */
-int au_has_group(char_u *name)
+/// Return true if augroup "name" exists.
+///
+/// @param name augroup name
+bool au_has_group(const char_u *name)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return au_find_group(name) != AUGROUP_ERROR;
}
@@ -5460,21 +5476,24 @@ find_end_event (
return pat;
}
-/*
- * Return TRUE if "event" is included in 'eventignore'.
- */
-static int event_ignored(event_T event)
+/// Return true if "event" is included in 'eventignore'.
+///
+/// @param event event to check
+static bool event_ignored(event_T event)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- char_u *p = p_ei;
+ char_u *p = p_ei;
while (*p != NUL) {
- if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ','))
- return TRUE;
- if (event_name2nr(p, &p) == event)
- return TRUE;
+ if (STRNICMP(p, "all", 3) == 0 && (p[3] == NUL || p[3] == ',')) {
+ return true;
+ }
+ if (event_name2nr(p, &p) == event) {
+ return true;
+ }
}
- return FALSE;
+ return false;
}
/*
@@ -5991,18 +6010,19 @@ void ex_doautoall(exarg_T *eap)
check_cursor(); /* just in case lines got deleted */
}
-/*
- * Check *argp for <nomodeline>. When it is present return FALSE, otherwise
- * return TRUE and advance *argp to after it.
- * Thus return TRUE when do_modelines() should be called.
- */
-int check_nomodeline(char_u **argp)
+/// Check *argp for <nomodeline>. When it is present return false, otherwise
+/// return true and advance *argp to after it. Thus do_modelines() should be
+/// called when true is returned.
+///
+/// @param[in,out] argp argument string
+bool check_nomodeline(char_u **argp)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
if (STRNCMP(*argp, "<nomodeline>", 12) == 0) {
*argp = skipwhite(*argp + 12);
- return FALSE;
+ return false;
}
- return TRUE;
+ return true;
}
/*
@@ -6179,76 +6199,78 @@ win_found:
static int autocmd_nested = FALSE;
-/*
- * Execute autocommands for "event" and file name "fname".
- * Return TRUE if some commands were executed.
- */
-int
-apply_autocmds (
- event_T event,
- char_u *fname, /* NULL or empty means use actual file name */
- char_u *fname_io, /* fname to use for <afile> on cmdline */
- int force, /* when TRUE, ignore autocmd_busy */
- buf_T *buf /* buffer for <abuf> */
-)
+/// Execute autocommands for "event" and file name "fname".
+///
+/// @param event event that occured
+/// @param fname filename, NULL or empty means use actual file name
+/// @param fname_io filename to use for <afile> on cmdline
+/// @param force When true, ignore autocmd_busy
+/// @param buf Buffer for <abuf>
+///
+/// @return true if some commands were executed.
+bool apply_autocmds(event_T event, char_u *fname, char_u *fname_io, bool force,
+ buf_T *buf)
{
return apply_autocmds_group(event, fname, fname_io, force,
AUGROUP_ALL, buf, NULL);
}
-/*
- * Like apply_autocmds(), but with extra "eap" argument. This takes care of
- * setting v:filearg.
- */
-static int apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io, int force, buf_T *buf, exarg_T *eap)
+/// Like apply_autocmds(), but with extra "eap" argument. This takes care of
+/// setting v:filearg.
+///
+/// @param event event that occured
+/// @param fname NULL or empty means use actual file name
+/// @param fname_io fname to use for <afile> on cmdline
+/// @param force When true, ignore autocmd_busy
+/// @param buf Buffer for <abuf>
+/// @param exarg Ex command arguments
+///
+/// @return true if some commands were executed.
+static bool apply_autocmds_exarg(event_T event, char_u *fname, char_u *fname_io,
+ bool force, buf_T *buf, exarg_T *eap)
{
return apply_autocmds_group(event, fname, fname_io, force,
AUGROUP_ALL, buf, eap);
}
-/*
- * Like apply_autocmds(), but handles the caller's retval. If the script
- * processing is being aborted or if retval is FAIL when inside a try
- * conditional, no autocommands are executed. If otherwise the autocommands
- * cause the script to be aborted, retval is set to FAIL.
- */
-int
-apply_autocmds_retval (
- event_T event,
- char_u *fname, /* NULL or empty means use actual file name */
- char_u *fname_io, /* fname to use for <afile> on cmdline */
- int force, /* when TRUE, ignore autocmd_busy */
- buf_T *buf, /* buffer for <abuf> */
- int *retval /* pointer to caller's retval */
-)
+/// Like apply_autocmds(), but handles the caller's retval. If the script
+/// processing is being aborted or if retval is FAIL when inside a try
+/// conditional, no autocommands are executed. If otherwise the autocommands
+/// cause the script to be aborted, retval is set to FAIL.
+///
+/// @param event event that occured
+/// @param fname NULL or empty means use actual file name
+/// @param fname_io fname to use for <afile> on cmdline
+/// @param force When true, ignore autocmd_busy
+/// @param buf Buffer for <abuf>
+/// @param[in,out] retval caller's retval
+///
+/// @return true if some autocommands were executed
+bool apply_autocmds_retval(event_T event, char_u *fname, char_u *fname_io,
+ bool force, buf_T *buf, int *retval)
{
- int did_cmd;
-
- if (should_abort(*retval))
- return FALSE;
+ if (should_abort(*retval)) {
+ return false;
+ }
- did_cmd = apply_autocmds_group(event, fname, fname_io, force,
- AUGROUP_ALL, buf, NULL);
- if (did_cmd
- && aborting()
- )
+ bool did_cmd = apply_autocmds_group(event, fname, fname_io, force,
+ AUGROUP_ALL, buf, NULL);
+ if (did_cmd && aborting()) {
*retval = FAIL;
+ }
return did_cmd;
}
-/*
- * Return TRUE when there is a CursorHold autocommand defined.
- */
-int has_cursorhold(void)
+/// Return true when there is a CursorHold/CursorHoldI autocommand defined for
+/// the current mode.
+bool has_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return first_autopat[(int)(get_real_state() == NORMAL_BUSY
? EVENT_CURSORHOLD : EVENT_CURSORHOLDI)] != NULL;
}
-/*
- * Return TRUE if the CursorHold event can be triggered.
- */
-int trigger_cursorhold(void)
+/// Return true if the CursorHold/CursorHoldI event can be triggered.
+bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
int state;
@@ -6259,10 +6281,11 @@ int trigger_cursorhold(void)
&& !ins_compl_active()
) {
state = get_real_state();
- if (state == NORMAL_BUSY || (state & INSERT) != 0)
- return TRUE;
+ if (state == NORMAL_BUSY || (state & INSERT) != 0) {
+ return true;
+ }
}
- return FALSE;
+ return false;
}
/// Return true if "event" autocommand is defined.
@@ -6273,23 +6296,27 @@ bool has_event(int event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
return first_autopat[event] != NULL;
}
-static int
-apply_autocmds_group (
- event_T event,
- char_u *fname, /* NULL or empty means use actual file name */
- char_u *fname_io, /* fname to use for <afile> on cmdline, NULL means
- use fname */
- int force, /* when TRUE, ignore autocmd_busy */
- int group, /* group ID, or AUGROUP_ALL */
- buf_T *buf, /* buffer for <abuf> */
- exarg_T *eap /* command arguments */
-)
+/// Execute autocommands for "event" and file name "fname".
+///
+/// @param event event that occured
+/// @param fname filename, NULL or empty means use actual file name
+/// @param fname_io filename to use for <afile> on cmdline,
+/// NULL means use `fname`.
+/// @param force When true, ignore autocmd_busy
+/// @param group autocmd group ID or AUGROUP_ALL
+/// @param buf Buffer for <abuf>
+/// @param eap Ex command arguments
+///
+/// @return true if some commands were executed.
+static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
+ bool force, int group, buf_T *buf,
+ exarg_T *eap)
{
char_u *sfname = NULL; /* short file name */
char_u *tail;
bool save_changed;
buf_T *old_curbuf;
- int retval = FALSE;
+ bool retval = false;
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
char_u *save_autocmd_fname;
@@ -6443,7 +6470,7 @@ apply_autocmds_group (
}
if (fname == NULL) { /* out of memory */
xfree(sfname);
- retval = FALSE;
+ retval = false;
goto BYPASS_AU;
}
@@ -6526,17 +6553,19 @@ apply_autocmds_group (
if (eap != NULL) {
save_cmdarg = set_cmdarg(eap, NULL);
set_vim_var_nr(VV_CMDBANG, (long)eap->forceit);
- } else
- save_cmdarg = NULL; /* avoid gcc warning */
- retval = TRUE;
- /* mark the last pattern, to avoid an endless loop when more patterns
- * are added when executing autocommands */
- for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next)
- ap->last = FALSE;
- ap->last = TRUE;
- check_lnums(TRUE); /* make sure cursor and topline are valid */
+ } else {
+ save_cmdarg = NULL; // avoid gcc warning
+ }
+ retval = true;
+ // mark the last pattern, to avoid an endless loop when more patterns
+ // are added when executing autocommands
+ for (ap = patcmd.curpat; ap->next != NULL; ap = ap->next) {
+ ap->last = false;
+ }
+ ap->last = true;
+ check_lnums(true); // make sure cursor and topline are valid
do_cmdline(NULL, getnextac, (void *)&patcmd,
- DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
+ DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT);
if (eap != NULL) {
(void)set_cmdarg(NULL, save_cmdarg);
set_vim_var_nr(VV_CMDBANG, save_cmdbang);
@@ -6752,21 +6781,25 @@ char_u *getnextac(int c, void *cookie, int indent)
return retval;
}
-/*
- * Return TRUE if there is a matching autocommand for "fname".
- * To account for buffer-local autocommands, function needs to know
- * in which buffer the file will be opened.
- */
-int has_autocmd(event_T event, char_u *sfname, buf_T *buf)
+/// Return true if there is a matching autocommand for "fname".
+/// To account for buffer-local autocommands, function needs to know
+/// in which buffer the file will be opened.
+///
+/// @param event event that occured.
+/// @param sfname filename the event occured in.
+/// @param buf buffer the file is open in
+bool has_autocmd(event_T event, char_u *sfname, buf_T *buf)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
AutoPat *ap;
char_u *fname;
char_u *tail = path_tail(sfname);
- int retval = FALSE;
+ bool retval = false;
- fname = (char_u *)FullName_save((char *)sfname, FALSE);
- if (fname == NULL)
- return FALSE;
+ fname = (char_u *)FullName_save((char *)sfname, false);
+ if (fname == NULL) {
+ return false;
+ }
#ifdef BACKSLASH_IN_FILENAME
// Replace all backslashes with forward slashes. This makes the
@@ -6776,16 +6809,16 @@ int has_autocmd(event_T event, char_u *sfname, buf_T *buf)
forward_slash(fname);
#endif
- for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next)
+ for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
if (ap->pat != NULL && ap->cmds != NULL
&& (ap->buflocal_nr == 0
? match_file_pat(NULL, &ap->reg_prog, fname, sfname, tail,
ap->allow_dirs)
- : buf != NULL && ap->buflocal_nr == buf->b_fnum
- )) {
- retval = TRUE;
+ : buf != NULL && ap->buflocal_nr == buf->b_fnum)) {
+ retval = true;
break;
}
+ }
xfree(fname);
#ifdef BACKSLASH_IN_FILENAME
@@ -6873,29 +6906,27 @@ char_u *get_event_name(expand_T *xp, int idx)
}
-/*
- * Return TRUE if autocmd is supported.
- */
-int autocmd_supported(char_u *name)
+/// Return true if autocmd "event" is supported.
+bool autocmd_supported(char_u *event)
{
char_u *p;
- return event_name2nr(name, &p) != NUM_EVENTS;
+ return event_name2nr(event, &p) != NUM_EVENTS;
}
-/*
- * Return TRUE if an autocommand is defined for a group, event and
- * pattern: The group can be omitted to accept any group. "event" and "pattern"
- * can be NULL to accept any event and pattern. "pattern" can be NULL to accept
- * any pattern. Buffer-local patterns <buffer> or <buffer=N> are accepted.
- * Used for:
- * exists("#Group") or
- * exists("#Group#Event") or
- * exists("#Group#Event#pat") or
- * exists("#Event") or
- * exists("#Event#pat")
- */
-int au_exists(char_u *arg)
+/// Return true if an autocommand is defined for a group, event and
+/// pattern: The group can be omitted to accept any group.
+/// `event` and `pattern` can be omitted to accept any event and pattern.
+/// Buffer-local patterns <buffer> or <buffer=N> are accepted.
+/// Used for:
+/// exists("#Group") or
+/// exists("#Group#Event") or
+/// exists("#Group#Event#pat") or
+/// exists("#Event") or
+/// exists("#Event#pat")
+///
+/// @param arg autocommand string
+bool au_exists(const char_u *arg) FUNC_ATTR_WARN_UNUSED_RESULT
{
char_u *arg_save;
char_u *pattern = NULL;
@@ -6905,7 +6936,7 @@ int au_exists(char_u *arg)
AutoPat *ap;
buf_T *buflocal_buf = NULL;
int group;
- int retval = FALSE;
+ bool retval = false;
/* Make a copy so that we can change the '#' chars to a NUL. */
arg_save = vim_strsave(arg);
@@ -6921,8 +6952,8 @@ int au_exists(char_u *arg)
event_name = arg_save;
} else {
if (p == NULL) {
- /* "Group": group name is present and it's recognized */
- retval = TRUE;
+ // "Group": group name is present and it's recognized
+ retval = true;
goto theend;
}
@@ -6964,7 +6995,7 @@ int au_exists(char_u *arg)
|| (buflocal_buf == NULL
? fnamecmp(ap->pat, pattern) == 0
: ap->buflocal_nr == buflocal_buf->b_fnum))) {
- retval = TRUE;
+ retval = true;
break;
}
@@ -6979,12 +7010,13 @@ theend:
///
/// Used for autocommands and 'wildignore'.
///
-/// @param pattern the pattern to match with
-/// @param prog the pre-compiled regprog or NULL
-/// @param fname the full path of the file name
-/// @param sfname the short file name or NULL
-/// @param tail the tail of the path
-/// @param allow_dirs allow matching with dir
+/// @param pattern pattern to match with
+/// @param prog pre-compiled regprog or NULL
+/// @param fname full path of the file name
+/// @param sfname short file name or NULL
+/// @param tail tail of the path
+/// @param allow_dirs Allow matching with dir
+///
/// @return true if there is a match, false otherwise
static bool match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname,
char_u *sfname, char_u *tail, int allow_dirs)
@@ -7023,12 +7055,17 @@ static bool match_file_pat(char_u *pattern, regprog_T **prog, char_u *fname,
return result;
}
-/*
- * Return TRUE if a file matches with a pattern in "list".
- * "list" is a comma-separated list of patterns, like 'wildignore'.
- * "sfname" is the short file name or NULL, "ffname" the long file name.
- */
-int match_file_list(char_u *list, char_u *sfname, char_u *ffname)
+/// Check if a file matches with a pattern in "list".
+/// "list" is a comma-separated list of patterns, like 'wildignore'.
+/// "sfname" is the short file name or NULL, "ffname" the long file name.
+///
+/// @param list list of patterns to match
+/// @param sfname short file name
+/// @param ffname full file name
+///
+/// @return true if there was a match
+bool match_file_list(char_u *list, char_u *sfname, char_u *ffname)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1, 3)
{
char_u buf[100];
char_u *tail;
@@ -7039,20 +7076,21 @@ int match_file_list(char_u *list, char_u *sfname, char_u *ffname)
tail = path_tail(sfname);
- /* try all patterns in 'wildignore' */
+ // try all patterns in 'wildignore'
p = list;
while (*p) {
- copy_option_part(&p, buf, 100, ",");
- regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, FALSE);
- if (regpat == NULL)
+ copy_option_part(&p, buf, ARRAY_SIZE(buf), ",");
+ regpat = file_pat_to_reg_pat(buf, NULL, &allow_dirs, false);
+ if (regpat == NULL) {
break;
- match = match_file_pat(regpat, NULL, ffname, sfname,
- tail, (int)allow_dirs);
+ }
+ match = match_file_pat(regpat, NULL, ffname, sfname, tail, (int)allow_dirs);
xfree(regpat);
- if (match)
- return TRUE;
+ if (match) {
+ return true;
+ }
}
- return FALSE;
+ return false;
}
/// Convert the given pattern "pat" which has shell style wildcards in it, into
@@ -7068,6 +7106,7 @@ char_u * file_pat_to_reg_pat(
char *allow_dirs, // Result passed back out in here
int no_bslash // Don't use a backward slash as pathsep
)
+ FUNC_ATTR_NONNULL_ARG(1)
{
const char_u *endp;
char_u *reg_pat;
@@ -7080,6 +7119,10 @@ char_u * file_pat_to_reg_pat(
if (pat_end == NULL)
pat_end = pat + STRLEN(pat);
+ if (pat_end == pat) {
+ return (char_u *)xstrdup("^$");
+ }
+
size_t size = 2; // '^' at start, '$' at end.
for (p = pat; p < pat_end; p++) {
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 50eda6cb17..b45f13de4c 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -8,11 +8,10 @@
// actually defined and initialized.
#ifndef EXTERN
# define EXTERN extern
-# define INIT(x)
+# define INIT(...)
#else
# ifndef INIT
-# define INIT(x) x
-# define DO_INIT
+# define INIT(...) __VA_ARGS__
# endif
#endif
@@ -117,12 +116,9 @@
#define DFLT_COLS 80 /* default value for 'columns' */
#define DFLT_ROWS 24 /* default value for 'lines' */
-EXTERN long Rows /* nr of rows in the screen */
-#ifdef DO_INIT
- = DFLT_ROWS
-#endif
-;
-EXTERN long Columns INIT(= DFLT_COLS); /* nr of columns in the screen */
+EXTERN long Rows INIT(= DFLT_ROWS); // nr of rows in the screen
+
+EXTERN long Columns INIT(= DFLT_COLS); // nr of columns in the screen
/*
* The characters and attributes cached for the screen.
@@ -751,11 +747,8 @@ EXTERN int can_si INIT(= FALSE);
*/
EXTERN int can_si_back INIT(= FALSE);
-EXTERN pos_T saved_cursor /* w_cursor before formatting text. */
-#ifdef DO_INIT
- = INIT_POS_T(0, 0, 0)
-#endif
-;
+// w_cursor before formatting text.
+EXTERN pos_T saved_cursor INIT(= INIT_POS_T(0, 0, 0));
/*
* Stuff for insert mode.
@@ -917,19 +910,16 @@ 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 typebuf_T typebuf /* typeahead buffer */
-#ifdef DO_INIT
- = {NULL, NULL, 0, 0, 0, 0, 0, 0, 0}
-#endif
-;
-EXTERN int ex_normal_busy INIT(= 0); /* recursiveness of ex_normal() */
-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' */
+// typeahead buffer
+EXTERN typebuf_T typebuf INIT(= { NULL, NULL, 0, 0, 0, 0, 0, 0, 0 });
-EXTERN int KeyTyped; /* TRUE if user typed current char */
-EXTERN int KeyStuffed; /* TRUE if current char from stuffbuf */
-EXTERN int maptick INIT(= 0); /* tick for each non-mapped char */
+EXTERN int ex_normal_busy INIT(= 0); // recursiveness of ex_normal()
+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 int KeyTyped; // TRUE if user typed current char
+EXTERN int KeyStuffed; // TRUE if current char from stuffbuf
+EXTERN int maptick INIT(= 0); // tick for each non-mapped char
EXTERN char_u chartab[256]; /* table used in charset.c; See
init_chartab() for explanation */
@@ -959,30 +949,28 @@ EXTERN reg_extmatch_T *re_extmatch_in INIT(= NULL); /* Used by vim_regexec():
EXTERN reg_extmatch_T *re_extmatch_out INIT(= NULL); /* Set by vim_regexec()
* to store \z\(...\) matches */
-EXTERN int did_outofmem_msg INIT(= FALSE);
-/* set after out of memory msg */
-EXTERN int did_swapwrite_msg INIT(= FALSE);
-/* set after swap write error msg */
-EXTERN int undo_off INIT(= FALSE); /* undo switched off for now */
-EXTERN int global_busy INIT(= 0); /* set when :global is executing */
-EXTERN int listcmd_busy INIT(= FALSE); /* set when :argdo, :windo or
- :bufdo is executing */
-EXTERN int need_start_insertmode INIT(= FALSE);
-/* start insert mode soon */
-EXTERN char_u *last_cmdline INIT(= NULL); /* last command line (for ":) */
-EXTERN char_u *repeat_cmdline INIT(= NULL); /* command line for "." */
-EXTERN char_u *new_last_cmdline INIT(= NULL); /* new value for last_cmdline */
-EXTERN char_u *autocmd_fname INIT(= NULL); /* fname for <afile> on cmdline */
-EXTERN int autocmd_fname_full; /* autocmd_fname is full path */
-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 pos_T last_cursormoved /* for CursorMoved event */
-# ifdef DO_INIT
- = INIT_POS_T(0, 0, 0)
-# endif
-;
-EXTERN int last_changedtick INIT(= 0); /* for TextChanged event */
+EXTERN int did_outofmem_msg INIT(= false);
+// set after out of memory msg
+EXTERN int did_swapwrite_msg INIT(= false);
+// set after swap write error msg
+EXTERN int undo_off INIT(= false); // undo switched off for now
+EXTERN int global_busy INIT(= 0); // set when :global is executing
+EXTERN int listcmd_busy INIT(= false); // set when :argdo, :windo or
+ // :bufdo is executing
+EXTERN int need_start_insertmode INIT(= false);
+// start insert mode soon
+EXTERN char_u *last_cmdline INIT(= NULL); // last command line (for ":)
+EXTERN char_u *repeat_cmdline INIT(= NULL); // command line for "."
+EXTERN char_u *new_last_cmdline INIT(= NULL); // new value for last_cmdline
+EXTERN char_u *autocmd_fname INIT(= NULL); // fname for <afile> on cmdline
+EXTERN int autocmd_fname_full; // autocmd_fname is full path
+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
+// for CursorMoved event
+EXTERN pos_T last_cursormoved INIT(= INIT_POS_T(0, 0, 0));
+
+EXTERN int last_changedtick INIT(= 0); // for TextChanged event
EXTERN buf_T *last_changedtick_buf INIT(= NULL);
EXTERN int postponed_split INIT(= 0); /* for CTRL-W CTRL-] command */
@@ -1092,13 +1080,9 @@ EXTERN int typebuf_was_filled INIT(= FALSE); /* received text from client
#ifdef BACKSLASH_IN_FILENAME
-EXTERN char psepc INIT(= '\\'); /* normal path separator character */
-EXTERN char psepcN INIT(= '/'); /* abnormal path separator character */
-EXTERN char pseps[2] /* normal path separator string */
-# ifdef DO_INIT
- = {'\\', 0}
-# endif
-;
+EXTERN char psepc INIT(= '\\'); // normal path separator character
+EXTERN char psepcN INIT(= '/'); // abnormal path separator character
+EXTERN char pseps[2] INIT(= { '\\', 0 }); // normal path separator string
#endif
/* Set to TRUE when an operator is being executed with virtual editing, MAYBE
@@ -1117,12 +1101,8 @@ EXTERN int need_cursor_line_redraw INIT(= FALSE);
#ifdef USE_MCH_ERRMSG
-/* Grow array to collect error messages in until they can be displayed. */
-EXTERN garray_T error_ga
-# ifdef DO_INIT
- = GA_EMPTY_INIT_VALUE
-# endif
-;
+// Grow array to collect error messages in until they can be displayed.
+EXTERN garray_T error_ga INIT(= GA_EMPTY_INIT_VALUE);
#endif
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index b2fd929714..7054bb822a 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -531,17 +531,14 @@ trans_special (
return dlen;
}
-/*
- * Try translating a <> name at (*srcp)[], return the key and modifiers.
- * srcp is advanced to after the <> name.
- * returns 0 if there is no match.
- */
-int
-find_special_key (
+// Try translating a <> name at (*srcp)[], return the key and modifiers.
+// srcp is advanced to after the <> name.
+// returns 0 if there is no match.
+int find_special_key(
char_u **srcp,
int *modp,
- int keycode, /* prefer key code, e.g. K_DEL instead of DEL */
- int keep_x_key /* don't translate xHome to Home key */
+ int keycode, // prefer key code, e.g. K_DEL instead of DEL
+ int keep_x_key // don't translate xHome to Home key
)
{
char_u *last_dash;
@@ -558,24 +555,26 @@ find_special_key (
if (src[0] != '<')
return 0;
- /* Find end of modifier list */
+ // Find end of modifier list
last_dash = src;
for (bp = src + 1; *bp == '-' || vim_isIDc(*bp); bp++) {
if (*bp == '-') {
last_dash = bp;
if (bp[1] != NUL) {
- if (has_mbyte)
+ if (has_mbyte) {
l = mb_ptr2len(bp + 1);
- else
+ } else {
l = 1;
- if (bp[l + 1] == '>')
- bp += l; /* anything accepted, like <C-?> */
+ }
+ if (bp[l + 1] == '>') {
+ bp += l; // anything accepted, like <C-?>
+ }
}
}
- if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3])
- bp += 3; /* skip t_xx, xx may be '-' or '>' */
- else if (STRNICMP(bp, "char-", 5) == 0) {
- vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL);
+ if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) {
+ bp += 3; // skip t_xx, xx may be '-' or '>'
+ } else if (STRNICMP(bp, "char-", 5) == 0) {
+ vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL);
bp += l + 5;
break;
}
@@ -589,55 +588,53 @@ find_special_key (
for (bp = src + 1; bp < last_dash; bp++) {
if (*bp != '-') {
bit = name_to_mod_mask(*bp);
- if (bit == 0x0)
- break; /* Illegal modifier name */
+ if (bit == 0x0) {
+ break; // Illegal modifier name
+ }
modifiers |= bit;
}
}
- /*
- * Legal modifier name.
- */
+ // Legal modifier name.
if (bp >= last_dash) {
if (STRNICMP(last_dash + 1, "char-", 5) == 0
&& ascii_isdigit(last_dash[6])) {
- /* <Char-123> or <Char-033> or <Char-0x33> */
- vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n);
+ // <Char-123> or <Char-033> or <Char-0x33>
+ vim_str2nr(last_dash + 6, NULL, NULL, true, true, true, NULL, &n);
key = (int)n;
} else {
/*
* Modifier with single letter, or special key name.
*/
- if (has_mbyte)
+ if (has_mbyte) {
l = mb_ptr2len(last_dash + 1);
- else
+ } else {
l = 1;
- if (modifiers != 0 && last_dash[l + 1] == '>')
+ }
+ if (modifiers != 0 && last_dash[l + 1] == '>') {
key = PTR2CHAR(last_dash + 1);
- else {
+ } else {
key = get_special_key_code(last_dash + 1);
- if (!keep_x_key)
+ if (!keep_x_key) {
key = handle_x_keys(key);
+ }
}
}
- /*
- * get_special_key_code() may return NUL for invalid
- * special key name.
- */
+ // get_special_key_code() may return NUL for invalid
+ // special key name.
if (key != NUL) {
- /*
- * Only use a modifier when there is no special key code that
- * includes the modifier.
- */
+ // Only use a modifier when there is no special key code that
+ // includes the modifier.
key = simplify_key(key, &modifiers);
if (!keycode) {
- /* don't want keycode, use single byte code */
- if (key == K_BS)
+ // don't want keycode, use single byte code
+ if (key == K_BS) {
key = BS;
- else if (key == K_DEL || key == K_KDEL)
+ } else if (key == K_DEL || key == K_KDEL) {
key = DEL;
+ }
}
// Normal Key with modifier:
diff --git a/src/nvim/log.c b/src/nvim/log.c
index 5767da03af..773d497881 100644
--- a/src/nvim/log.c
+++ b/src/nvim/log.c
@@ -10,10 +10,6 @@
#include "nvim/os/os.h"
#include "nvim/os/time.h"
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
#define USR_LOG_FILE "$HOME" _PATHSEPSTR ".nvimlog"
static uv_mutex_t mutex;
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 66b8b9b5d2..1dd71baaa4 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -1396,7 +1396,8 @@ void msg_prt_line(char_u *s, int list)
c = *p_extra++;
} else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) {
col += (*mb_ptr2cells)(s);
- if (lcs_nbsp != NUL && list && mb_ptr2char(s) == 160) {
+ if (lcs_nbsp != NUL && list
+ && (mb_ptr2char(s) == 160 || mb_ptr2char(s) == 0x202f)) {
mb_char2bytes(lcs_nbsp, buf);
buf[(*mb_ptr2len)(buf)] = NUL;
} else {
@@ -3037,7 +3038,7 @@ static double tv_float(typval_T *tvs, int *idxp)
* http://www.ijs.si/software/snprintf/
*
* This snprintf() only supports the following conversion specifiers:
- * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
+ * s, c, b, B, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
* with flags: '-', '+', ' ', '0' and '#'.
* An asterisk is supported for field width as well as precision.
*
@@ -3103,8 +3104,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
char *p = fmt;
int arg_idx = 1;
- if (!p)
+ if (!p) {
p = "";
+ }
while (*p) {
if (*p != '%') {
// copy up to the next '%' or NUL without any changes
@@ -3176,9 +3178,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (*p == '*') {
p++;
int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
- if (j >= 0)
+ if (j >= 0) {
min_field_width = j;
- else {
+ } else {
min_field_width = -j;
justify_left = 1;
}
@@ -3187,8 +3189,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// argument like common implementations do
unsigned int uj = *p++ - '0';
- while (ascii_isdigit((int)(*p)))
+ while (ascii_isdigit((int)(*p))) {
uj = 10 * uj + (unsigned int)(*p++ - '0');
+ }
min_field_width = uj;
}
@@ -3199,9 +3202,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (*p == '*') {
int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
p++;
- if (j >= 0)
+ if (j >= 0) {
precision = j;
- else {
+ } else {
precision_specified = 0;
precision = 0;
}
@@ -3210,8 +3213,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// treat argument like common implementations do
unsigned int uj = *p++ - '0';
- while (ascii_isdigit((int)(*p)))
+ while (ascii_isdigit((int)(*p))) {
uj = 10 * uj + (unsigned int)(*p++ - '0');
+ }
precision = uj;
}
}
@@ -3262,14 +3266,13 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (!str_arg) {
str_arg = "[NULL]";
str_arg_l = 6;
- }
- // make sure not to address string beyond the specified precision
- else if (!precision_specified)
+ } else if (!precision_specified) {
+ // make sure not to address string beyond the specified precision
str_arg_l = strlen(str_arg);
- // truncate string if necessary as requested by precision
- else if (precision == 0)
+ } else if (precision == 0) {
+ // truncate string if necessary as requested by precision
str_arg_l = 0;
- else {
+ } else {
// memchr on HP does not like n > 2^31
// TODO(elmart): check if this still holds / is relevant
str_arg_l = (size_t)((char *)xmemscan(str_arg,
@@ -3283,8 +3286,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
- mb_string2cells((char_u *) str_arg);
if (precision) {
char_u *p1 = (char_u *)str_arg;
- for (size_t i = 0; i < precision && *p1; i++)
+ for (size_t i = 0; i < precision && *p1; i++) {
p1 += mb_ptr2len(p1);
+ }
str_arg_l = precision = p1 - (char_u *)str_arg;
}
}
@@ -3295,9 +3299,14 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
}
break;
- case 'd': case 'u': case 'o': case 'x': case 'X': case 'p': {
- // u, o, x, X and p conversion specifiers imply the value is unsigned;
- // d implies a signed value
+ case 'd':
+ case 'u':
+ case 'b': case 'B':
+ case 'o':
+ case 'x': case 'X':
+ case 'p': {
+ // u, b, B, o, x, X and p conversion specifiers imply
+ // the value is unsigned; d implies a signed value
// 0 if numeric argument is zero (or if pointer is NULL for 'p'),
// +1 if greater than zero (or non NULL for 'p'),
@@ -3325,8 +3334,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (fmt_spec == 'p') {
length_modifier = '\0';
ptr_arg = tvs ? (void *)tv_str(tvs, &arg_idx) : va_arg(ap, void *);
- if (ptr_arg)
+ if (ptr_arg) {
arg_sign = 1;
+ }
} else if (fmt_spec == 'd') {
// signed
switch (length_modifier) {
@@ -3334,25 +3344,28 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
case 'h':
// char and short arguments are passed as int
int_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int);
- if (int_arg > 0)
+ if (int_arg > 0) {
arg_sign = 1;
- else if (int_arg < 0)
+ } else if (int_arg < 0) {
arg_sign = -1;
+ }
break;
case 'l':
long_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, long int);
- if (long_arg > 0)
+ if (long_arg > 0) {
arg_sign = 1;
- else if (long_arg < 0)
+ } else if (long_arg < 0) {
arg_sign = -1;
+ }
break;
case '2':
long_long_arg = tvs ? tv_nr(tvs, &arg_idx)
- : va_arg(ap, long long int);
- if (long_long_arg > 0)
+ : va_arg(ap, long long int); // NOLINT (runtime/int)
+ if (long_long_arg > 0) {
arg_sign = 1;
- else if (long_long_arg < 0)
+ } else if (long_long_arg < 0) {
arg_sign = -1;
+ }
break;
}
} else {
@@ -3362,24 +3375,23 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
case 'h':
uint_arg = tvs ? (unsigned)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned int);
- if (uint_arg != 0)
- arg_sign = 1;
+ if (uint_arg != 0) { arg_sign = 1; }
break;
case 'l':
ulong_arg = tvs ? (unsigned long)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned long int);
- if (ulong_arg != 0)
- arg_sign = 1;
+ if (ulong_arg != 0) { arg_sign = 1; }
break;
case '2':
- ulong_long_arg = tvs ? (unsigned long long)tv_nr(tvs, &arg_idx)
- : va_arg(ap, unsigned long long int);
- if (ulong_long_arg) arg_sign = 1;
+ ulong_long_arg = tvs
+ ? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int)
+ : va_arg(ap, unsigned long long int); // NOLINT (runtime/int)
+ if (ulong_long_arg) { arg_sign = 1; }
break;
case 'z':
size_t_arg = tvs ? (size_t)tv_nr(tvs, &arg_idx)
: va_arg(ap, size_t);
- if (size_t_arg) arg_sign = 1;
+ if (size_t_arg) { arg_sign = 1; }
break;
}
}
@@ -3390,16 +3402,19 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// For d, i, u, o, x, and X conversions, if precision is specified,
// '0' flag should be ignored. This is so with Solaris 2.6, Digital UNIX
// 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl.
- if (precision_specified)
+ if (precision_specified) {
zero_padding = 0;
+ }
if (fmt_spec == 'd') {
- if (force_sign && arg_sign >= 0)
+ if (force_sign && arg_sign >= 0) {
tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
+ }
// leave negative numbers for sprintf to handle, to
// avoid handling tricky cases like (short int)-32768
} else if (alternate_form) {
- if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X') ) {
+ if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' ||
+ fmt_spec == 'b' || fmt_spec == 'B')) {
tmp[str_arg_l++] = '0';
tmp[str_arg_l++] = fmt_spec;
}
@@ -3407,20 +3422,20 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
}
zero_padding_insertion_ind = str_arg_l;
- if (!precision_specified)
+ if (!precision_specified) {
precision = 1; // default precision is 1
+ }
if (precision == 0 && arg_sign == 0) {
// when zero value is formatted with an explicit precision 0,
- // resulting formatted string is empty (d, i, u, o, x, X, p)
+ // resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
} else {
char f[5];
int f_l = 0;
// construct a simple format string for sprintf
f[f_l++] = '%';
- if (!length_modifier)
- ;
- else if (length_modifier == '2') {
+ if (!length_modifier) {
+ } else if (length_modifier == '2') {
f[f_l++] = 'l';
f[f_l++] = 'l';
} else
@@ -3441,6 +3456,41 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
case '2': str_arg_l += sprintf(tmp + str_arg_l, f, long_long_arg);
break;
}
+ } else if (fmt_spec == 'b' || fmt_spec == 'B') {
+ // binary
+ size_t bits = 0;
+ switch (length_modifier) {
+ case '\0':
+ case 'h': for (bits = sizeof(unsigned) * 8; bits > 0; bits--) {
+ if ((uint_arg >> (bits - 1)) & 0x1) { break; } }
+
+ while (bits > 0) {
+ tmp[str_arg_l++] =
+ ((uint_arg >> --bits) & 0x1) ? '1' : '0'; }
+ break;
+ case 'l': for (bits = sizeof(unsigned long) * 8; bits > 0; bits--) {
+ if ((ulong_arg >> (bits - 1)) & 0x1) { break; } }
+
+ while (bits > 0) {
+ tmp[str_arg_l++] =
+ ((ulong_arg >> --bits) & 0x1) ? '1' : '0'; }
+ break;
+ case '2': for (bits = sizeof(unsigned long long) * 8; // NOLINT (runtime/int)
+ bits > 0; bits--) {
+ if ((ulong_long_arg >> (bits - 1)) & 0x1) { break; } }
+
+ while (bits > 0) {
+ tmp[str_arg_l++] =
+ ((ulong_long_arg >> --bits) & 0x1) ? '1' : '0'; }
+ break;
+ case 'z': for (bits = sizeof(size_t) * 8; bits > 0; bits--) {
+ if ((size_t_arg >> (bits - 1)) & 0x1) { break; } }
+
+ while (bits > 0) {
+ tmp[str_arg_l++] =
+ ((size_t_arg >> --bits) & 0x1) ? '1' : '0'; }
+ break;
+ }
} else {
// unsigned
switch (length_modifier) {
@@ -3464,7 +3514,9 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
if (zero_padding_insertion_ind + 1 < str_arg_l
&& tmp[zero_padding_insertion_ind] == '0'
&& (tmp[zero_padding_insertion_ind + 1] == 'x'
- || tmp[zero_padding_insertion_ind + 1] == 'X'))
+ || tmp[zero_padding_insertion_ind + 1] == 'X'
+ || tmp[zero_padding_insertion_ind + 1] == 'b'
+ || tmp[zero_padding_insertion_ind + 1] == 'B'))
zero_padding_insertion_ind += 2;
}
@@ -3507,7 +3559,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
// floating point
char format[40];
int l;
- int remove_trailing_zeroes = FALSE;
+ int remove_trailing_zeroes = false;
double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
double abs_f = f < 0 ? -f : f;
@@ -3518,7 +3570,7 @@ int vim_vsnprintf(char *str, size_t str_m, char *fmt, va_list ap, typval_T *tvs)
fmt_spec = 'f';
else
fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
- remove_trailing_zeroes = TRUE;
+ remove_trailing_zeroes = true;
}
if (fmt_spec == 'f' && abs_f > 1.0e307) {
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 2f57d8c610..a116b5a0bd 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -1430,6 +1430,9 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
|| VIsual_active
) && oap->op_type != OP_NOP) {
// Avoid a problem with unwanted linebreaks in block mode
+ if (curwin->w_p_lbr) {
+ curwin->w_valid &= ~VALID_VIRTCOL;
+ }
curwin->w_p_lbr = false;
oap->is_VIsual = VIsual_active;
if (oap->motion_force == 'V')
@@ -1598,55 +1601,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
virtual_op = virtual_active();
if (VIsual_active || redo_VIsual_busy) {
- if (VIsual_mode == Ctrl_V) { /* block mode */
- colnr_T start, end;
-
- oap->motion_type = MBLOCK;
-
- getvvcol(curwin, &(oap->start),
- &oap->start_vcol, NULL, &oap->end_vcol);
- if (!redo_VIsual_busy) {
- getvvcol(curwin, &(oap->end), &start, NULL, &end);
-
- if (start < oap->start_vcol)
- oap->start_vcol = start;
- if (end > oap->end_vcol) {
- if (*p_sel == 'e' && start >= 1
- && start - 1 >= oap->end_vcol)
- oap->end_vcol = start - 1;
- else
- oap->end_vcol = end;
- }
- }
-
- /* if '$' was used, get oap->end_vcol from longest line */
- if (curwin->w_curswant == MAXCOL) {
- curwin->w_cursor.col = MAXCOL;
- oap->end_vcol = 0;
- for (curwin->w_cursor.lnum = oap->start.lnum;
- curwin->w_cursor.lnum <= oap->end.lnum;
- ++curwin->w_cursor.lnum) {
- getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
- if (end > oap->end_vcol)
- oap->end_vcol = end;
- }
- } else if (redo_VIsual_busy)
- oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
- /*
- * Correct oap->end.col and oap->start.col to be the
- * upper-left and lower-right corner of the block area.
- *
- * (Actually, this does convert column positions into character
- * positions)
- */
- curwin->w_cursor.lnum = oap->end.lnum;
- coladvance(oap->end_vcol);
- oap->end = curwin->w_cursor;
-
- curwin->w_cursor = oap->start;
- coladvance(oap->start_vcol);
- oap->start = curwin->w_cursor;
- }
+ get_op_vcol(oap, redo_VIsual_vcol, true);
if (!redo_VIsual_busy && !gui_yank) {
/*
@@ -1894,9 +1849,14 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
else
restart_edit_save = 0;
restart_edit = 0;
+
// Restore linebreak, so that when the user edits it looks as before.
- curwin->w_p_lbr = lbr_saved;
- /* Reset finish_op now, don't want it set inside edit(). */
+ if (curwin->w_p_lbr != lbr_saved) {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, false);
+ }
+
+ // Reset finish_op now, don't want it set inside edit().
finish_op = false;
if (op_change(oap)) /* will call edit() */
cap->retval |= CA_COMMAND_BUSY;
@@ -1974,7 +1934,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
restart_edit = 0;
// Restore linebreak, so that when the user edits it looks as before.
- curwin->w_p_lbr = lbr_saved;
+ if (curwin->w_p_lbr != lbr_saved) {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, false);
+ }
op_insert(oap, cap->count1);
@@ -1997,7 +1960,11 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
CancelRedo();
} else {
// Restore linebreak, so that when the user edits it looks as before.
- curwin->w_p_lbr = lbr_saved;
+ if (curwin->w_p_lbr != lbr_saved) {
+ curwin->w_p_lbr = lbr_saved;
+ get_op_vcol(oap, redo_VIsual_mode, false);
+ }
+
op_replace(oap, cap->nchar);
}
break;
@@ -7698,6 +7665,71 @@ static void nv_open(cmdarg_T *cap)
n_opencmd(cap);
}
+// calculate start/end virtual columns for operating in block mode
+static void get_op_vcol(
+ oparg_T *oap,
+ colnr_T redo_VIsual_vcol,
+ bool initial // when true: adjust position for 'selectmode'
+)
+{
+ colnr_T start;
+ colnr_T end;
+
+ if (VIsual_mode != Ctrl_V) {
+ return;
+ }
+
+ oap->motion_type = MBLOCK;
+
+ // prevent from moving onto a trail byte
+ if (has_mbyte) {
+ mb_adjustpos(curwin->w_buffer, &oap->end);
+ }
+
+ getvvcol(curwin, &(oap->start), &oap->start_vcol, NULL, &oap->end_vcol);
+ getvvcol(curwin, &(oap->end), &start, NULL, &end);
+
+ if (start < oap->start_vcol) {
+ oap->start_vcol = start;
+ }
+ if (end > oap->end_vcol) {
+ if (initial && *p_sel == 'e'
+ && start >= 1
+ && start - 1 >= oap->end_vcol) {
+ oap->end_vcol = start - 1;
+ } else {
+ oap->end_vcol = end;
+ }
+ }
+ // if '$' was used, get oap->end_vcol from longest line
+ if (curwin->w_curswant == MAXCOL) {
+ curwin->w_cursor.col = MAXCOL;
+ oap->end_vcol = 0;
+ for (curwin->w_cursor.lnum = oap->start.lnum;
+ curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum) {
+ getvvcol(curwin, &curwin->w_cursor, NULL, NULL, &end);
+ if (end > oap->end_vcol) {
+ oap->end_vcol = end;
+ }
+ }
+ } else if (redo_VIsual_busy) {
+ oap->end_vcol = oap->start_vcol + redo_VIsual_vcol - 1;
+ }
+
+ // Correct oap->end.col and oap->start.col to be the
+ // upper-left and lower-right corner of the block area.
+ //
+ // (Actually, this does convert column positions into character
+ // positions)
+ curwin->w_cursor.lnum = oap->end.lnum;
+ coladvance(oap->end_vcol);
+ oap->end = curwin->w_cursor;
+
+ curwin->w_cursor = oap->start;
+ coladvance(oap->start_vcol);
+ oap->start = curwin->w_cursor;
+}
+
// Handle an arbitrary event in normal mode
static void nv_event(cmdarg_T *cap)
{
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index c3d968ca51..19dbd0f9f6 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1991,6 +1991,7 @@ void op_insert(oparg_T *oap, long count1)
char_u *firstline, *ins_text;
struct block_def bd;
int i;
+ pos_T t1;
/* edit() changes this - record it for OP_APPEND */
bd.is_MAX = (curwin->w_curswant == MAXCOL);
@@ -2053,7 +2054,16 @@ void op_insert(oparg_T *oap, long count1)
}
}
- edit(NUL, FALSE, (linenr_T)count1);
+ t1 = oap->start;
+ edit(NUL, false, (linenr_T)count1);
+
+ // When a tab was inserted, and the characters in front of the tab
+ // have been converted to a tab as well, the column of the cursor
+ // might have actually been reduced, so need to adjust here. */
+ if (t1.lnum == curbuf->b_op_start_orig.lnum &&
+ lt(curbuf->b_op_start_orig, t1)) {
+ oap->start = curbuf->b_op_start_orig;
+ }
/* If user has moved off this line, we don't know what to do, so do
* nothing.
@@ -2069,21 +2079,23 @@ void op_insert(oparg_T *oap, long count1)
if (oap->start.lnum == curbuf->b_op_start_orig.lnum && !bd.is_MAX) {
if (oap->op_type == OP_INSERT
&& oap->start.col + oap->start.coladd
- != curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) {
+ != curbuf->b_op_start_orig.col + curbuf->b_op_start_orig.coladd) {
+ size_t t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
- pre_textlen -= getviscol2(oap->start.col, oap->start.coladd)
- - oap->start_vcol;
- oap->start_vcol = getviscol2(oap->start.col, oap->start.coladd);
+ pre_textlen -= t - oap->start_vcol;
+ oap->start_vcol = t;
} else if (oap->op_type == OP_APPEND
&& oap->end.col + oap->end.coladd
- >= curbuf->b_op_start_orig.col
- + curbuf->b_op_start_orig.coladd) {
+ >= curbuf->b_op_start_orig.col
+ + curbuf->b_op_start_orig.coladd) {
+ size_t t = getviscol2(curbuf->b_op_start_orig.col,
+ curbuf->b_op_start_orig.coladd);
oap->start.col = curbuf->b_op_start_orig.col;
/* reset pre_textlen to the value of OP_INSERT */
pre_textlen += bd.textlen;
- pre_textlen -= getviscol2(oap->start.col, oap->start.coladd)
- - oap->start_vcol;
- oap->start_vcol = getviscol2(oap->start.col, oap->start.coladd);
+ pre_textlen -= t - oap->start_vcol;
+ oap->start_vcol = t;
oap->op_type = OP_INSERT;
}
}
@@ -4186,75 +4198,102 @@ static void reverse_line(char_u *s)
# define RLADDSUBFIX(ptr) if (curwin->w_p_rl) reverse_line(ptr);
-/*
- * add or subtract 'Prenum1' from a number in a line
- * 'command' is CTRL-A for add, CTRL-X for subtract
- *
- * return FAIL for failure, OK otherwise
- */
+/// Add or subtract from a number in a line.
+///
+/// @param command CTRL-A for add, CTRL-X for subtract
+// @param Prenum1 number to add or subtract
+///
+/// @return FAIL for failure, OK otherwise
int do_addsub(int command, linenr_T Prenum1)
{
int col;
char_u *buf1;
char_u buf2[NUMBUFLEN];
- int hex; /* 'X' or 'x': hex; '0': octal */
- static int hexupper = FALSE; /* 0xABC */
+ int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
+ static int hexupper = false; // 0xABC
unsigned long n, oldn;
char_u *ptr;
int c;
- int length = 0; /* character length of the number */
+ int length = 0; // character length of the number
int todel;
int dohex;
int dooct;
+ int dobin;
int doalp;
int firstdigit;
int negative;
int subtract;
- dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); /* "heX" */
- dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); /* "Octal" */
- doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
+ dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX"
+ dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal"
+ dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
+ doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
ptr = get_cursor_line_ptr();
RLADDSUBFIX(ptr);
- /*
- * First check if we are on a hexadecimal number, after the "0x".
- */
+ // First check if we are on a hexadecimal number, after the "0x".
col = curwin->w_cursor.col;
- if (dohex)
- while (col > 0 && ascii_isxdigit(ptr[col]))
- --col;
- if ( dohex
- && col > 0
- && (ptr[col] == 'X'
- || ptr[col] == 'x')
- && ptr[col - 1] == '0'
- && ascii_isxdigit(ptr[col + 1])) {
- /*
- * Found hexadecimal number, move to its start.
- */
- --col;
+
+ if (dobin) {
+ while (col > 0 && ascii_isbdigit(ptr[col])) {
+ col--;
+ }
+ }
+
+ if (dohex) {
+ while (col > 0 && ascii_isxdigit(ptr[col])) {
+ col--;
+ }
+ }
+ if (dobin
+ && dohex
+ && !((col > 0
+ && (ptr[col] == 'X' ||
+ ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && ascii_isxdigit(ptr[col + 1])))) {
+ // In case of binary/hexadecimal pattern overlap match, rescan
+
+ col = curwin->w_cursor.col;
+
+ while (col > 0 && ascii_isdigit(ptr[col])) {
+ col--;
+ }
+ }
+
+ if ((dohex
+ && col > 0
+ && (ptr[col] == 'X'
+ || ptr[col] == 'x')
+ && ptr[col - 1] == '0'
+ && ascii_isxdigit(ptr[col + 1])) ||
+ (dobin
+ && col > 0
+ && (ptr[col] == 'B'
+ || ptr[col] == 'b')
+ && ptr[col - 1] == '0'
+ && ascii_isbdigit(ptr[col + 1]))) {
+ // Found hexadecimal or binary number, move to its start.
+ col--;
} else {
- /*
- * Search forward and then backward to find the start of number.
- */
+ // Search forward and then backward to find the start of number.
col = curwin->w_cursor.col;
while (ptr[col] != NUL
&& !ascii_isdigit(ptr[col])
- && !(doalp && ASCII_ISALPHA(ptr[col])))
- ++col;
+ && !(doalp && ASCII_ISALPHA(ptr[col]))) {
+ col++;
+ }
while (col > 0
&& ascii_isdigit(ptr[col - 1])
- && !(doalp && ASCII_ISALPHA(ptr[col])))
- --col;
+ && !(doalp && ASCII_ISALPHA(ptr[col]))) {
+ col--;
+ }
}
- /*
- * If a number was found, and saving for undo works, replace the number.
- */
+ // If a number was found, and saving for undo works, replace the number.
firstdigit = ptr[col];
RLADDSUBFIX(ptr);
if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
@@ -4263,152 +4302,170 @@ int do_addsub(int command, linenr_T Prenum1)
return FAIL;
}
- /* get ptr again, because u_save() may have changed it */
+ // get ptr again, because u_save() may have changed it
ptr = get_cursor_line_ptr();
RLADDSUBFIX(ptr);
if (doalp && ASCII_ISALPHA(firstdigit)) {
- /* decrement or increment alphabetic character */
+ // decrement or increment alphabetic character
if (command == Ctrl_X) {
if (CharOrd(firstdigit) < Prenum1) {
- if (isupper(firstdigit))
+ if (isupper(firstdigit)) {
firstdigit = 'A';
- else
+ } else {
firstdigit = 'a';
- } else
+ }
+ } else {
firstdigit -= Prenum1;
+ }
} else {
if (26 - CharOrd(firstdigit) - 1 < Prenum1) {
- if (isupper(firstdigit))
+ if (isupper(firstdigit)) {
firstdigit = 'Z';
- else
+ } else {
firstdigit = 'z';
- } else
+ }
+ } else {
firstdigit += Prenum1;
+ }
}
curwin->w_cursor.col = col;
- (void)del_char(FALSE);
+ (void)del_char(false);
ins_char(firstdigit);
} else {
- negative = FALSE;
- if (col > 0 && ptr[col - 1] == '-') { /* negative number */
+ negative = false;
+ if (col > 0 && ptr[col - 1] == '-') { // negative number
--col;
- negative = TRUE;
+ negative = true;
}
- /* get the number value (unsigned) */
- vim_str2nr(ptr + col, &hex, &length, dooct, dohex, NULL, &n);
+ // get the number value (unsigned)
+ vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n);
- /* ignore leading '-' for hex and octal numbers */
- if (hex && negative) {
+ // ignore leading '-' for hex, octal and bin numbers
+ if (pre && negative) {
++col;
--length;
- negative = FALSE;
+ negative = false;
}
- /* add or subtract */
- subtract = FALSE;
- if (command == Ctrl_X)
- subtract ^= TRUE;
- if (negative)
- subtract ^= TRUE;
+ // add or subtract
+ subtract = false;
+ if (command == Ctrl_X) {
+ subtract ^= true;
+ }
+ if (negative) {
+ subtract ^= true;
+ }
oldn = n;
- if (subtract)
- n -= (unsigned long)Prenum1;
- else
- n += (unsigned long)Prenum1;
- /* handle wraparound for decimal numbers */
- if (!hex) {
+ n = subtract ? n - (unsigned long) Prenum1
+ : n + (unsigned long) Prenum1;
+
+ // handle wraparound for decimal numbers
+ if (!pre) {
if (subtract) {
if (n > oldn) {
n = 1 + (n ^ (unsigned long)-1);
- negative ^= TRUE;
+ negative ^= true;
}
} else { /* add */
if (n < oldn) {
n = (n ^ (unsigned long)-1);
- negative ^= TRUE;
+ negative ^= true;
}
}
- if (n == 0)
- negative = FALSE;
+ if (n == 0) {
+ negative = false;
+ }
}
- /*
- * Delete the old number.
- */
+ // Delete the old number.
curwin->w_cursor.col = col;
todel = length;
c = gchar_cursor();
- /*
- * Don't include the '-' in the length, only the length of the part
- * after it is kept the same.
- */
- if (c == '-')
+
+ // Don't include the '-' in the length, only the length of the part
+ // after it is kept the same.
+ if (c == '-') {
--length;
+ }
while (todel-- > 0) {
if (c < 0x100 && isalpha(c)) {
- if (isupper(c))
- hexupper = TRUE;
- else
- hexupper = FALSE;
+ if (isupper(c)) {
+ hexupper = true;
+ } else {
+ hexupper = false;
+ }
}
- /* del_char() will mark line needing displaying */
- (void)del_char(FALSE);
+ // del_char() will mark line needing displaying
+ (void)del_char(false);
c = gchar_cursor();
}
- /*
- * Prepare the leading characters in buf1[].
- * When there are many leading zeros it could be very long. Allocate
- * a bit too much.
- */
+ // Prepare the leading characters in buf1[].
+ // When there are many leading zeros it could be very long. Allocate
+ // a bit too much.
buf1 = xmalloc(length + NUMBUFLEN);
ptr = buf1;
if (negative) {
*ptr++ = '-';
}
- if (hex) {
+ if (pre) {
*ptr++ = '0';
--length;
}
- if (hex == 'x' || hex == 'X') {
- *ptr++ = hex;
+ if (pre == 'b' || pre == 'B' ||
+ pre == 'x' || pre == 'X') {
+ *ptr++ = pre;
--length;
}
- /*
- * Put the number characters in buf2[].
- */
- if (hex == 0)
- sprintf((char *)buf2, "%" PRIu64, (uint64_t)n);
- else if (hex == '0')
- sprintf((char *)buf2, "%" PRIo64, (uint64_t)n);
- else if (hex && hexupper)
- sprintf((char *)buf2, "%" PRIX64, (uint64_t)n);
- else
- sprintf((char *)buf2, "%" PRIx64, (uint64_t)n);
+ // Put the number characters in buf2[].
+ if (pre == 'b' || pre == 'B') {
+ size_t bits = 0;
+ size_t pos = 0;
+
+ // leading zeros
+ for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) {
+ if ((n >> (bits - 1)) & 0x1) { break; }
+ }
+
+ while (bits > 0) {
+ buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0';
+ }
+
+ buf2[pos] = '\0';
+
+ } else if (pre == 0) {
+ snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n);
+ } else if (pre == '0') {
+ snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n);
+ } else if (pre && hexupper) {
+ snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n);
+ } else {
+ snprintf((char *)buf2, NUMBUFLEN, "%" PRIx64, (uint64_t)n);
+ }
length -= (int)STRLEN(buf2);
- /*
- * Adjust number of zeros to the new number of digits, so the
- * total length of the number remains the same.
- * Don't do this when
- * the result may look like an octal number.
- */
- if (firstdigit == '0' && !(dooct && hex == 0))
- while (length-- > 0)
+ // Adjust number of zeros to the new number of digits, so the
+ // total length of the number remains the same.
+ // Don't do this when
+ // the result may look like an octal number.
+ if (firstdigit == '0' && !(dooct && pre == 0)) {
+ while (length-- > 0) {
*ptr++ = '0';
+ }
+ }
*ptr = NUL;
STRCAT(buf1, buf2);
ins_str(buf1); /* insert the new number */
xfree(buf1);
}
--curwin->w_cursor.col;
- curwin->w_set_curswant = TRUE;
- ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
+ curwin->w_set_curswant = true;
+ ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
RLADDSUBFIX(ptr);
return OK;
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 2ac1abeeba..b4054dc28c 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -258,30 +258,31 @@ typedef struct vimoption {
#define PARAM_COUNT ARRAY_SIZE(options)
-static char *(p_ambw_values[]) = {"single", "double", NULL};
-static char *(p_bg_values[]) = {"light", "dark", NULL};
-static char *(p_nf_values[]) = {"octal", "hex", "alpha", NULL};
-static char *(p_ff_values[]) = {FF_UNIX, FF_DOS, FF_MAC, NULL};
-static char *(p_wop_values[]) = {"tagfile", NULL};
-static char *(p_wak_values[]) = {"yes", "menu", "no", NULL};
-static char *(p_mousem_values[]) =
-{"extend", "popup", "popup_setpos", "mac", NULL};
-static char *(p_sel_values[]) = {"inclusive", "exclusive", "old", NULL};
-static char *(p_slm_values[]) = {"mouse", "key", "cmd", NULL};
-static char *(p_km_values[]) = {"startsel", "stopsel", NULL};
-static char *(p_scbopt_values[]) = {"ver", "hor", "jump", NULL};
-static char *(p_debug_values[]) = {"msg", "throw", "beep", NULL};
-static char *(p_ead_values[]) = {"both", "ver", "hor", NULL};
-static char *(p_buftype_values[]) =
-{"nofile", "nowrite", "quickfix", "help", "acwrite", "terminal", NULL};
-static char *(p_bufhidden_values[]) = {"hide", "unload", "delete", "wipe", NULL};
-static char *(p_bs_values[]) = {"indent", "eol", "start", NULL};
-static char *(p_fdm_values[]) = {"manual", "expr", "marker", "indent", "syntax",
- "diff",
- NULL};
-static char *(p_fcl_values[]) = {"all", NULL};
-static char *(p_cot_values[]) = {"menu", "menuone", "longest", "preview",
- "noinsert", "noselect", NULL};
+static char *(p_ambw_values[]) = { "single", "double", NULL };
+static char *(p_bg_values[]) = { "light", "dark", NULL };
+static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", NULL };
+static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
+static char *(p_wop_values[]) = { "tagfile", NULL };
+static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
+static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos",
+ "mac", NULL };
+static char *(p_sel_values[]) = { "inclusive", "exclusive", "old", NULL };
+static char *(p_slm_values[]) = { "mouse", "key", "cmd", NULL };
+static char *(p_km_values[]) = { "startsel", "stopsel", NULL };
+static char *(p_scbopt_values[]) = { "ver", "hor", "jump", NULL };
+static char *(p_debug_values[]) = { "msg", "throw", "beep", NULL };
+static char *(p_ead_values[]) = { "both", "ver", "hor", NULL };
+static char *(p_buftype_values[]) = { "nofile", "nowrite", "quickfix",
+ "help", "acwrite", "terminal", NULL };
+
+static char *(p_bufhidden_values[]) = { "hide", "unload", "delete",
+ "wipe", NULL };
+static char *(p_bs_values[]) = { "indent", "eol", "start", NULL };
+static char *(p_fdm_values[]) = { "manual", "expr", "marker", "indent",
+ "syntax", "diff", NULL };
+static char *(p_fcl_values[]) = { "all", NULL };
+static char *(p_cot_values[]) = { "menu", "menuone", "longest", "preview",
+ "noinsert", "noselect", NULL };
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "option.c.generated.h"
@@ -1431,7 +1432,7 @@ do_set (
} else if (*arg == '-' || ascii_isdigit(*arg)) {
// Allow negative (for 'undolevels'), octal and
// hex numbers.
- vim_str2nr(arg, NULL, &i, true, true, &value, NULL);
+ vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL);
if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
errmsg = e_invarg;
goto skip;
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 0eccf63e15..3dd37cb5dc 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1599,7 +1599,7 @@ return {
deny_duplicates=true,
alloced=true,
varname='p_nf',
- defaults={if_true={vi="octal,hex", vim="hex"}}
+ defaults={if_true={vi="bin,octal,hex", vim="bin,hex"}}
},
{
full_name='number', abbreviation='nu',
diff --git a/src/nvim/os/unix_defs.h b/src/nvim/os/unix_defs.h
index 78fc9331d1..690a39c3cd 100644
--- a/src/nvim/os/unix_defs.h
+++ b/src/nvim/os/unix_defs.h
@@ -2,7 +2,7 @@
#define NVIM_OS_UNIX_DEFS_H
// Windows doesn't have unistd.h, so we include it here to avoid numerous
-// instances of `#ifdef HAVE_UNISTD_H'.
+// instances of `#ifdef WIN32'.
#include <unistd.h>
// POSIX.1-2008 says that NAME_MAX should be in here
diff --git a/src/nvim/os/win_defs.h b/src/nvim/os/win_defs.h
index ca3cf5d896..242d355f77 100644
--- a/src/nvim/os/win_defs.h
+++ b/src/nvim/os/win_defs.h
@@ -6,6 +6,10 @@
#include <io.h>
#include <stdio.h>
+// Windows does not have S_IFLNK but libuv defines it
+// and sets the flag for us when calling uv_fs_stat.
+#include <uv.h>
+
#define NAME_MAX _MAX_PATH
#define TEMP_DIR_NAMES {"$TMP", "$TEMP", "$USERPROFILE", ""}
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 5ac3d07f67..8b9a49dfc0 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -681,11 +681,16 @@ static size_t do_path_expand(garray_T *gap, const char_u *path,
/* remove backslashes for the remaining components only */
(void)do_path_expand(gap, buf, len + 1, flags, false);
} else {
- /* no more wildcards, check if there is a match */
- /* remove backslashes for the remaining components only */
- if (*path_end != NUL)
+ FileInfo file_info;
+
+ // no more wildcards, check if there is a match
+ // remove backslashes for the remaining components only
+ if (*path_end != NUL) {
backslash_halve(buf + len + 1);
- if (os_file_exists(buf)) { /* add existing file */
+ }
+ // add existing file or symbolic link
+ if ((flags & EW_ALLLINKS) ? os_fileinfo_link((char *)buf, &file_info)
+ : os_file_exists(buf)) {
addfile(gap, buf, flags);
}
}
@@ -1294,26 +1299,28 @@ expand_backtick (
return cnt;
}
-/*
- * Add a file to a file list. Accepted flags:
- * EW_DIR add directories
- * EW_FILE add files
- * EW_EXEC add executable files
- * EW_NOTFOUND add even when it doesn't exist
- * EW_ADDSLASH add slash after directory name
- */
-void
-addfile (
+// Add a file to a file list. Accepted flags:
+// EW_DIR add directories
+// EW_FILE add files
+// EW_EXEC add executable files
+// EW_NOTFOUND add even when it doesn't exist
+// EW_ADDSLASH add slash after directory name
+// EW_ALLLINKS add symlink also when the referred file does not exist
+void addfile(
garray_T *gap,
char_u *f, /* filename */
int flags
)
{
bool isdir;
+ FileInfo file_info;
- /* if the file/dir doesn't exist, may not add it */
- if (!(flags & EW_NOTFOUND) && !os_file_exists(f))
+ // if the file/dir/link doesn't exist, may not add it
+ if (!(flags & EW_NOTFOUND) &&
+ ((flags & EW_ALLLINKS) ?
+ !os_fileinfo_link((char *)f, &file_info) : !os_file_exists(f))) {
return;
+ }
#ifdef FNAME_ILLEGAL
/* if the file/dir contains illegal characters, don't add it */
diff --git a/src/nvim/path.h b/src/nvim/path.h
index 628ea335ed..eac367d0ac 100644
--- a/src/nvim/path.h
+++ b/src/nvim/path.h
@@ -20,6 +20,7 @@
#define EW_KEEPDOLLAR 0x800 /* do not escape $, $var is expanded */
/* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND
* is used when executing commands and EW_SILENT for interactive expanding. */
+#define EW_ALLLINKS 0x1000 // also links not pointing to existing file
/// Return value for the comparison of two files. Also @see path_full_compare.
typedef enum file_comparison {
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 3abf43cb8c..85c69af192 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2117,14 +2117,10 @@ void ex_copen(exarg_T *eap)
prevwin = win;
}
- /*
- * Fill the buffer with the quickfix list.
- */
- qf_fill_buffer(qi);
+ qf_set_title_var(qi);
- if (qi->qf_lists[qi->qf_curlist].qf_title != NULL) {
- qf_set_title_var(qi);
- }
+ // Fill the buffer with the quickfix list.
+ qf_fill_buffer(qi);
curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index;
curwin->w_cursor.col = 0;
@@ -2256,16 +2252,13 @@ static void qf_update_buffer(qf_info_T *qi)
/* set curwin/curbuf to buf and save a few things */
aucmd_prepbuf(&aco, buf);
- qf_fill_buffer(qi);
-
- if (qi->qf_lists[qi->qf_curlist].qf_title != NULL
- && (win = qf_find_win(qi)) != NULL) {
+ if ((win = qf_find_win(qi)) != NULL) {
curwin_save = curwin;
curwin = win;
qf_set_title_var(qi);
curwin = curwin_save;
-
}
+ qf_fill_buffer(qi);
/* restore curwin/curbuf and a few other things */
aucmd_restbuf(&aco);
@@ -2274,10 +2267,13 @@ static void qf_update_buffer(qf_info_T *qi)
}
}
+// Set "w:quickfix_title" if "qi" has a title.
static void qf_set_title_var(qf_info_T *qi)
{
- set_internal_string_var((char_u *)"w:quickfix_title",
- qi->qf_lists[qi->qf_curlist].qf_title);
+ if (qi->qf_lists[qi->qf_curlist].qf_title != NULL) {
+ set_internal_string_var((char_u *)"w:quickfix_title",
+ qi->qf_lists[qi->qf_curlist].qf_title);
+ }
}
/*
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index 39001939d8..608aa38466 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -796,13 +796,14 @@ static void reg_equi_class(int c)
if (enc_utf8 || STRCMP(p_enc, "latin1") == 0
|| STRCMP(p_enc, "iso-8859-15") == 0) {
switch (c) {
- case 'A': case '\300': case '\301': case '\302':
+ // Do not use '\300' style, it results in a negative number.
+ case 'A': case 0xc0: case 0xc1: case 0xc2:
+ case 0xc3: case 0xc4: case 0xc5:
CASEMBC(0x100) CASEMBC(0x102) CASEMBC(0x104) CASEMBC(0x1cd)
CASEMBC(0x1de) CASEMBC(0x1e0) CASEMBC(0x1ea2)
- case '\303': case '\304': case '\305':
- regmbc('A'); regmbc('\300'); regmbc('\301');
- regmbc('\302'); regmbc('\303'); regmbc('\304');
- regmbc('\305');
+ regmbc('A'); regmbc(0xc0); regmbc(0xc1);
+ regmbc(0xc2); regmbc(0xc3); regmbc(0xc4);
+ regmbc(0xc5);
REGMBC(0x100) REGMBC(0x102) REGMBC(0x104)
REGMBC(0x1cd) REGMBC(0x1de) REGMBC(0x1e0)
REGMBC(0x1ea2)
@@ -810,9 +811,9 @@ static void reg_equi_class(int c)
case 'B': CASEMBC(0x1e02) CASEMBC(0x1e06)
regmbc('B'); REGMBC(0x1e02) REGMBC(0x1e06)
return;
- case 'C': case '\307':
+ case 'C': case 0xc7:
CASEMBC(0x106) CASEMBC(0x108) CASEMBC(0x10a) CASEMBC(0x10c)
- regmbc('C'); regmbc('\307');
+ regmbc('C'); regmbc(0xc7);
REGMBC(0x106) REGMBC(0x108) REGMBC(0x10a)
REGMBC(0x10c)
return;
@@ -821,11 +822,11 @@ static void reg_equi_class(int c)
regmbc('D'); REGMBC(0x10e) REGMBC(0x110)
REGMBC(0x1e0a) REGMBC(0x1e0e) REGMBC(0x1e10)
return;
- case 'E': case '\310': case '\311': case '\312': case '\313':
+ case 'E': case 0xc8: case 0xc9: case 0xca: case 0xcb:
CASEMBC(0x112) CASEMBC(0x114) CASEMBC(0x116) CASEMBC(0x118)
CASEMBC(0x11a) CASEMBC(0x1eba) CASEMBC(0x1ebc)
- regmbc('E'); regmbc('\310'); regmbc('\311');
- regmbc('\312'); regmbc('\313');
+ regmbc('E'); regmbc(0xc8); regmbc(0xc9);
+ regmbc(0xca); regmbc(0xcb);
REGMBC(0x112) REGMBC(0x114) REGMBC(0x116)
REGMBC(0x118) REGMBC(0x11a) REGMBC(0x1eba)
REGMBC(0x1ebc)
@@ -845,11 +846,11 @@ static void reg_equi_class(int c)
regmbc('H'); REGMBC(0x124) REGMBC(0x126)
REGMBC(0x1e22) REGMBC(0x1e26) REGMBC(0x1e28)
return;
- case 'I': case '\314': case '\315': case '\316': case '\317':
+ case 'I': case 0xcc: case 0xcd: case 0xce: case 0xcf:
CASEMBC(0x128) CASEMBC(0x12a) CASEMBC(0x12c) CASEMBC(0x12e)
CASEMBC(0x130) CASEMBC(0x1cf) CASEMBC(0x1ec8)
- regmbc('I'); regmbc('\314'); regmbc('\315');
- regmbc('\316'); regmbc('\317');
+ regmbc('I'); regmbc(0xcc); regmbc(0xcd);
+ regmbc(0xce); regmbc(0xcf);
REGMBC(0x128) REGMBC(0x12a) REGMBC(0x12c)
REGMBC(0x12e) REGMBC(0x130) REGMBC(0x1cf)
REGMBC(0x1ec8)
@@ -871,20 +872,20 @@ static void reg_equi_class(int c)
case 'M': CASEMBC(0x1e3e) CASEMBC(0x1e40)
regmbc('M'); REGMBC(0x1e3e) REGMBC(0x1e40)
return;
- case 'N': case '\321':
+ case 'N': case 0xd1:
CASEMBC(0x143) CASEMBC(0x145) CASEMBC(0x147) CASEMBC(0x1e44)
CASEMBC(0x1e48)
- regmbc('N'); regmbc('\321');
+ regmbc('N'); regmbc(0xd1);
REGMBC(0x143) REGMBC(0x145) REGMBC(0x147)
REGMBC(0x1e44) REGMBC(0x1e48)
return;
- case 'O': case '\322': case '\323': case '\324': case '\325':
- case '\326': case '\330':
+ case 'O': case 0xd2: case 0xd3: case 0xd4: case 0xd5:
+ case 0xd6: case 0xd8:
CASEMBC(0x14c) CASEMBC(0x14e) CASEMBC(0x150) CASEMBC(0x1a0)
CASEMBC(0x1d1) CASEMBC(0x1ea) CASEMBC(0x1ec) CASEMBC(0x1ece)
- regmbc('O'); regmbc('\322'); regmbc('\323');
- regmbc('\324'); regmbc('\325'); regmbc('\326');
- regmbc('\330');
+ regmbc('O'); regmbc(0xd2); regmbc(0xd3);
+ regmbc(0xd4); regmbc(0xd5); regmbc(0xd6);
+ regmbc(0xd8);
REGMBC(0x14c) REGMBC(0x14e) REGMBC(0x150)
REGMBC(0x1a0) REGMBC(0x1d1) REGMBC(0x1ea)
REGMBC(0x1ec) REGMBC(0x1ece)
@@ -907,12 +908,12 @@ static void reg_equi_class(int c)
regmbc('T'); REGMBC(0x162) REGMBC(0x164)
REGMBC(0x166) REGMBC(0x1e6a) REGMBC(0x1e6e)
return;
- case 'U': case '\331': case '\332': case '\333': case '\334':
+ case 'U': case 0xd9: case 0xda: case 0xdb: case 0xdc:
CASEMBC(0x168) CASEMBC(0x16a) CASEMBC(0x16c) CASEMBC(0x16e)
CASEMBC(0x170) CASEMBC(0x172) CASEMBC(0x1af) CASEMBC(0x1d3)
CASEMBC(0x1ee6)
- regmbc('U'); regmbc('\331'); regmbc('\332');
- regmbc('\333'); regmbc('\334');
+ regmbc('U'); regmbc(0xd9); regmbc(0xda);
+ regmbc(0xdb); regmbc(0xdc);
REGMBC(0x168) REGMBC(0x16a) REGMBC(0x16c)
REGMBC(0x16e) REGMBC(0x170) REGMBC(0x172)
REGMBC(0x1af) REGMBC(0x1d3) REGMBC(0x1ee6)
@@ -928,10 +929,10 @@ static void reg_equi_class(int c)
case 'X': CASEMBC(0x1e8a) CASEMBC(0x1e8c)
regmbc('X'); REGMBC(0x1e8a) REGMBC(0x1e8c)
return;
- case 'Y': case '\335':
+ case 'Y': case 0xdd:
CASEMBC(0x176) CASEMBC(0x178) CASEMBC(0x1e8e) CASEMBC(0x1ef2)
CASEMBC(0x1ef6) CASEMBC(0x1ef8)
- regmbc('Y'); regmbc('\335');
+ regmbc('Y'); regmbc(0xdd);
REGMBC(0x176) REGMBC(0x178) REGMBC(0x1e8e)
REGMBC(0x1ef2) REGMBC(0x1ef6) REGMBC(0x1ef8)
return;
@@ -941,13 +942,13 @@ static void reg_equi_class(int c)
REGMBC(0x17d) REGMBC(0x1b5) REGMBC(0x1e90)
REGMBC(0x1e94)
return;
- case 'a': case '\340': case '\341': case '\342':
- case '\343': case '\344': case '\345':
+ case 'a': case 0xe0: case 0xe1: case 0xe2:
+ case 0xe3: case 0xe4: case 0xe5:
CASEMBC(0x101) CASEMBC(0x103) CASEMBC(0x105) CASEMBC(0x1ce)
CASEMBC(0x1df) CASEMBC(0x1e1) CASEMBC(0x1ea3)
- regmbc('a'); regmbc('\340'); regmbc('\341');
- regmbc('\342'); regmbc('\343'); regmbc('\344');
- regmbc('\345');
+ regmbc('a'); regmbc(0xe0); regmbc(0xe1);
+ regmbc(0xe2); regmbc(0xe3); regmbc(0xe4);
+ regmbc(0xe5);
REGMBC(0x101) REGMBC(0x103) REGMBC(0x105)
REGMBC(0x1ce) REGMBC(0x1df) REGMBC(0x1e1)
REGMBC(0x1ea3)
@@ -955,9 +956,9 @@ static void reg_equi_class(int c)
case 'b': CASEMBC(0x1e03) CASEMBC(0x1e07)
regmbc('b'); REGMBC(0x1e03) REGMBC(0x1e07)
return;
- case 'c': case '\347':
+ case 'c': case 0xe7:
CASEMBC(0x107) CASEMBC(0x109) CASEMBC(0x10b) CASEMBC(0x10d)
- regmbc('c'); regmbc('\347');
+ regmbc('c'); regmbc(0xe7);
REGMBC(0x107) REGMBC(0x109) REGMBC(0x10b)
REGMBC(0x10d)
return;
@@ -966,11 +967,11 @@ static void reg_equi_class(int c)
regmbc('d'); REGMBC(0x10f) REGMBC(0x111)
REGMBC(0x1e0b) REGMBC(0x1e0f) REGMBC(0x1e11)
return;
- case 'e': case '\350': case '\351': case '\352': case '\353':
+ case 'e': case 0xe8: case 0xe9: case 0xea: case 0xeb:
CASEMBC(0x113) CASEMBC(0x115) CASEMBC(0x117) CASEMBC(0x119)
CASEMBC(0x11b) CASEMBC(0x1ebb) CASEMBC(0x1ebd)
- regmbc('e'); regmbc('\350'); regmbc('\351');
- regmbc('\352'); regmbc('\353');
+ regmbc('e'); regmbc(0xe8); regmbc(0xe9);
+ regmbc(0xea); regmbc(0xeb);
REGMBC(0x113) REGMBC(0x115) REGMBC(0x117)
REGMBC(0x119) REGMBC(0x11b) REGMBC(0x1ebb)
REGMBC(0x1ebd)
@@ -991,11 +992,11 @@ static void reg_equi_class(int c)
REGMBC(0x1e23) REGMBC(0x1e27) REGMBC(0x1e29)
REGMBC(0x1e96)
return;
- case 'i': case '\354': case '\355': case '\356': case '\357':
+ case 'i': case 0xec: case 0xed: case 0xee: case 0xef:
CASEMBC(0x129) CASEMBC(0x12b) CASEMBC(0x12d) CASEMBC(0x12f)
CASEMBC(0x1d0) CASEMBC(0x1ec9)
- regmbc('i'); regmbc('\354'); regmbc('\355');
- regmbc('\356'); regmbc('\357');
+ regmbc('i'); regmbc(0xec); regmbc(0xed);
+ regmbc(0xee); regmbc(0xef);
REGMBC(0x129) REGMBC(0x12b) REGMBC(0x12d)
REGMBC(0x12f) REGMBC(0x1d0) REGMBC(0x1ec9)
return;
@@ -1016,20 +1017,20 @@ static void reg_equi_class(int c)
case 'm': CASEMBC(0x1e3f) CASEMBC(0x1e41)
regmbc('m'); REGMBC(0x1e3f) REGMBC(0x1e41)
return;
- case 'n': case '\361':
+ case 'n': case 0xf1:
CASEMBC(0x144) CASEMBC(0x146) CASEMBC(0x148) CASEMBC(0x149)
CASEMBC(0x1e45) CASEMBC(0x1e49)
- regmbc('n'); regmbc('\361');
+ regmbc('n'); regmbc(0xf1);
REGMBC(0x144) REGMBC(0x146) REGMBC(0x148)
REGMBC(0x149) REGMBC(0x1e45) REGMBC(0x1e49)
return;
- case 'o': case '\362': case '\363': case '\364': case '\365':
- case '\366': case '\370':
+ case 'o': case 0xf2: case 0xf3: case 0xf4: case 0xf5:
+ case 0xf6: case 0xf8:
CASEMBC(0x14d) CASEMBC(0x14f) CASEMBC(0x151) CASEMBC(0x1a1)
CASEMBC(0x1d2) CASEMBC(0x1eb) CASEMBC(0x1ed) CASEMBC(0x1ecf)
- regmbc('o'); regmbc('\362'); regmbc('\363');
- regmbc('\364'); regmbc('\365'); regmbc('\366');
- regmbc('\370');
+ regmbc('o'); regmbc(0xf2); regmbc(0xf3);
+ regmbc(0xf4); regmbc(0xf5); regmbc(0xf6);
+ regmbc(0xf8);
REGMBC(0x14d) REGMBC(0x14f) REGMBC(0x151)
REGMBC(0x1a1) REGMBC(0x1d2) REGMBC(0x1eb)
REGMBC(0x1ed) REGMBC(0x1ecf)
@@ -1052,12 +1053,12 @@ static void reg_equi_class(int c)
regmbc('t'); REGMBC(0x163) REGMBC(0x165) REGMBC(0x167)
REGMBC(0x1e6b) REGMBC(0x1e6f) REGMBC(0x1e97)
return;
- case 'u': case '\371': case '\372': case '\373': case '\374':
+ case 'u': case 0xf9: case 0xfa: case 0xfb: case 0xfc:
CASEMBC(0x169) CASEMBC(0x16b) CASEMBC(0x16d) CASEMBC(0x16f)
CASEMBC(0x171) CASEMBC(0x173) CASEMBC(0x1b0) CASEMBC(0x1d4)
CASEMBC(0x1ee7)
- regmbc('u'); regmbc('\371'); regmbc('\372');
- regmbc('\373'); regmbc('\374');
+ regmbc('u'); regmbc(0xf9); regmbc(0xfa);
+ regmbc(0xfb); regmbc(0xfc);
REGMBC(0x169) REGMBC(0x16b) REGMBC(0x16d)
REGMBC(0x16f) REGMBC(0x171) REGMBC(0x173)
REGMBC(0x1b0) REGMBC(0x1d4) REGMBC(0x1ee7)
@@ -1074,10 +1075,10 @@ static void reg_equi_class(int c)
case 'x': CASEMBC(0x1e8b) CASEMBC(0x1e8d)
regmbc('x'); REGMBC(0x1e8b) REGMBC(0x1e8d)
return;
- case 'y': case '\375': case '\377':
+ case 'y': case 0xfd: case 0xff:
CASEMBC(0x177) CASEMBC(0x1e8f) CASEMBC(0x1e99)
CASEMBC(0x1ef3) CASEMBC(0x1ef7) CASEMBC(0x1ef9)
- regmbc('y'); regmbc('\375'); regmbc('\377');
+ regmbc('y'); regmbc(0xfd); regmbc(0xff);
REGMBC(0x177) REGMBC(0x1e8f) REGMBC(0x1e99)
REGMBC(0x1ef3) REGMBC(0x1ef7) REGMBC(0x1ef9)
return;
@@ -4186,7 +4187,7 @@ regmatch (
/* When only a composing char is given match at any
* position where that composing char appears. */
status = RA_NOMATCH;
- for (i = 0; reginput[i] != NUL; i += utf_char2len(inpc)) {
+ for (i = 0; reginput[i] != NUL; i += utf_ptr2len(reginput + i)) {
inpc = mb_ptr2char(reginput + i);
if (!utf_iscomposing(inpc)) {
if (i > 0)
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index 1fd024a062..4020fa6e28 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -4762,48 +4762,54 @@ static int skip_to_start(int c, colnr_T *colp)
*/
static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
{
- colnr_T col = startcol;
- int c1, c2;
- int len1, len2;
- int match;
+#define PTR2LEN(x) enc_utf8 ? utf_ptr2len(x) : MB_PTR2LEN(x)
- for (;; ) {
- match = TRUE;
- len2 = MB_CHAR2LEN(regstart); /* skip regstart */
- for (len1 = 0; match_text[len1] != NUL; len1 += MB_CHAR2LEN(c1)) {
- c1 = PTR2CHAR(match_text + len1);
- c2 = PTR2CHAR(regline + col + len2);
- if (c1 != c2 && (!ireg_ic || vim_tolower(c1) != vim_tolower(c2))) {
- match = FALSE;
+ colnr_T col = startcol;
+ int regstart_len = PTR2LEN(regline + startcol);
+
+ for (;;) {
+ bool match = true;
+ char_u *s1 = match_text;
+ char_u *s2 = regline + col + regstart_len; // skip regstart
+ while (*s1) {
+ int c1_len = PTR2LEN(s1);
+ int c1 = PTR2CHAR(s1);
+ int c2_len = PTR2LEN(s2);
+ int c2 = PTR2CHAR(s2);
+
+ if ((c1 != c2 && (!ireg_ic || vim_tolower(c1) != vim_tolower(c2))) ||
+ c1_len != c2_len) {
+ match = false;
break;
}
- len2 += MB_CHAR2LEN(c2);
+ s1 += c1_len;
+ s2 += c2_len;
}
if (match
- /* check that no composing char follows */
- && !(enc_utf8
- && STRLEN(regline) > (size_t)(col + len2)
- && utf_iscomposing(PTR2CHAR(regline + col + len2)))
- ) {
+ // check that no composing char follows
+ && !(enc_utf8 && utf_iscomposing(PTR2CHAR(s2)))) {
cleanup_subexpr();
if (REG_MULTI) {
reg_startpos[0].lnum = reglnum;
reg_startpos[0].col = col;
reg_endpos[0].lnum = reglnum;
- reg_endpos[0].col = col + len2;
+ reg_endpos[0].col = s2 - regline;
} else {
reg_startp[0] = regline + col;
- reg_endp[0] = regline + col + len2;
+ reg_endp[0] = s2;
}
return 1L;
}
- /* Try finding regstart after the current match. */
- col += MB_CHAR2LEN(regstart); /* skip regstart */
- if (skip_to_start(regstart, &col) == FAIL)
+ // Try finding regstart after the current match.
+ col += regstart_len; // skip regstart
+ if (skip_to_start(regstart, &col) == FAIL) {
break;
+ }
}
return 0L;
+
+#undef PTR2LEN
}
/*
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index 1ae2822a93..43bc2c1f68 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -752,10 +752,11 @@ static void win_update(win_T *wp)
lnumt = wp->w_lines[i].wl_lastlnum + 1;
if (lnumb == MAXLNUM && wp->w_lines[i].wl_lnum >= mod_bot) {
lnumb = wp->w_lines[i].wl_lnum;
- /* When there is a fold column it might need updating
- * in the next line ("J" just above an open fold). */
- if (wp->w_p_fdc > 0)
- ++lnumb;
+ // When there is a fold column it might need updating
+ // in the next line ("J" just above an open fold).
+ if (compute_foldcolumn(wp, 0) > 0) {
+ lnumb++;
+ }
}
}
@@ -1567,10 +1568,11 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
{
int n = 0;
# define FDC_OFF n
+ int fdc = compute_foldcolumn(wp, 0);
if (wp->w_p_rl) {
- /* No check for cmdline window: should never be right-left. */
- n = wp->w_p_fdc;
+ // No check for cmdline window: should never be right-left.
+ n = fdc;
if (n > 0) {
/* draw the fold column at the right */
@@ -1610,8 +1612,8 @@ static void win_draw_end(win_T *wp, int c1, int c2, int row, int endrow, hlf_T h
wp->w_wincol, wp->w_wincol + n,
cmdwin_type, ' ', hl_attr(HLF_AT));
}
- if (wp->w_p_fdc > 0) {
- int nn = n + wp->w_p_fdc;
+ if (fdc > 0) {
+ int nn = n + fdc;
/* draw the fold column at the left */
if (nn > wp->w_width)
@@ -1654,6 +1656,20 @@ static int advance_color_col(int vcol, int **color_cols)
return **color_cols >= 0;
}
+// Compute the width of the foldcolumn. Based on 'foldcolumn' and how much
+// space is available for window "wp", minus "col".
+static int compute_foldcolumn(win_T *wp, int col)
+{
+ int fdc = wp->w_p_fdc;
+ int wmw = wp == curwin && p_wmw == 0 ? 1 : p_wmw;
+ int wwidth = wp->w_width;
+
+ if (fdc > wwidth - (col + wmw)) {
+ fdc = wwidth - (col + wmw);
+ }
+ return fdc;
+}
+
/*
* Display one folded line.
*/
@@ -1692,12 +1708,9 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
++col;
}
- /*
- * 2. Add the 'foldcolumn'
- */
- fdc = wp->w_p_fdc;
- if (fdc > wp->w_width - col)
- fdc = wp->w_width - col;
+ // 2. Add the 'foldcolumn'
+ // Reduce the width when there is not enough space.
+ fdc = compute_foldcolumn(wp, col);
if (fdc > 0) {
fill_foldcolumn(buf, wp, TRUE, lnum);
if (wp->w_p_rl) {
@@ -2018,37 +2031,42 @@ fill_foldcolumn (
int level;
int first_level;
int empty;
+ int fdc = compute_foldcolumn(wp, 0);
- /* Init to all spaces. */
- memset(p, ' ', (size_t)wp->w_p_fdc);
+ // Init to all spaces.
+ memset(p, ' ', (size_t)fdc);
level = win_foldinfo.fi_level;
if (level > 0) {
- /* If there is only one column put more info in it. */
- empty = (wp->w_p_fdc == 1) ? 0 : 1;
+ // If there is only one column put more info in it.
+ empty = (fdc == 1) ? 0 : 1;
- /* If the column is too narrow, we start at the lowest level that
- * fits and use numbers to indicated the depth. */
- first_level = level - wp->w_p_fdc - closed + 1 + empty;
- if (first_level < 1)
+ // If the column is too narrow, we start at the lowest level that
+ // fits and use numbers to indicated the depth.
+ first_level = level - fdc - closed + 1 + empty;
+ if (first_level < 1) {
first_level = 1;
+ }
- for (i = 0; i + empty < wp->w_p_fdc; ++i) {
+ for (i = 0; i + empty < fdc; i++) {
if (win_foldinfo.fi_lnum == lnum
- && first_level + i >= win_foldinfo.fi_low_level)
+ && first_level + i >= win_foldinfo.fi_low_level) {
p[i] = '-';
- else if (first_level == 1)
+ } else if (first_level == 1) {
p[i] = '|';
- else if (first_level + i <= 9)
+ } else if (first_level + i <= 9) {
p[i] = '0' + first_level + i;
- else
+ } else {
p[i] = '>';
- if (first_level + i == level)
+ }
+ if (first_level + i == level) {
break;
+ }
}
}
- if (closed)
- p[i >= wp->w_p_fdc ? i - 1 : i] = '+';
+ if (closed) {
+ p[i >= fdc ? i - 1 : i] = '+';
+ }
}
/*
@@ -2629,11 +2647,13 @@ win_line (
}
if (draw_state == WL_FOLD - 1 && n_extra == 0) {
+ int fdc = compute_foldcolumn(wp, 0);
+
draw_state = WL_FOLD;
- if (wp->w_p_fdc > 0) {
- /* Draw the 'foldcolumn'. */
- fill_foldcolumn(extra, wp, FALSE, lnum);
- n_extra = wp->w_p_fdc;
+ if (fdc > 0) {
+ // Draw the 'foldcolumn'.
+ fill_foldcolumn(extra, wp, false, lnum);
+ n_extra = fdc;
p_extra = extra;
p_extra[n_extra] = NUL;
c_extra = NUL;
@@ -3182,7 +3202,8 @@ win_line (
// 'list': change char 160 to lcs_nbsp and space to lcs_space.
if (wp->w_p_list
- && (((c == 160 || (mb_utf8 && mb_c == 160)) && lcs_nbsp)
+ && (((c == 160 || (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
+ && lcs_nbsp)
|| (c == ' ' && lcs_space && ptr - line <= trailcol))) {
c = (c == ' ') ? lcs_space : lcs_nbsp;
if (area_attr == 0 && search_attr == 0) {
@@ -3389,7 +3410,7 @@ win_line (
int i;
int saved_nextra = n_extra;
- if ((is_concealing || boguscols > 0) && vcol_off > 0) {
+ if (vcol_off > 0) {
// there are characters to conceal
tab_len += vcol_off;
}
@@ -3419,25 +3440,31 @@ win_line (
// n_extra will be increased by FIX_FOX_BOGUSCOLS
// macro below, so need to adjust for that here
- if ((is_concealing || boguscols > 0) && vcol_off > 0) {
+ if (vcol_off > 0) {
n_extra -= vcol_off;
}
}
- /* Tab alignment should be identical regardless of
- * 'conceallevel' value. So tab compensates of all
- * previous concealed characters, and thus resets vcol_off
- * and boguscols accumulated so far in the line. Note that
- * the tab can be longer than 'tabstop' when there
- * are concealed characters. */
- FIX_FOR_BOGUSCOLS;
- // Make sure that the highlighting for the tab char will be correctly
- // set further below (effectively reverts the FIX_FOR_BOGSUCOLS
- // macro).
- if (old_boguscols > 0 && n_extra > tab_len && wp->w_p_list
- && lcs_tab1) {
- tab_len += n_extra - tab_len;
+
+ {
+ int vc_saved = vcol_off;
+
+ // Tab alignment should be identical regardless of
+ // 'conceallevel' value. So tab compensates of all
+ // previous concealed characters, and thus resets
+ // vcol_off and boguscols accumulated so far in the
+ // line. Note that the tab can be longer than
+ // 'tabstop' when there are concealed characters.
+ FIX_FOR_BOGUSCOLS;
+
+ // Make sure, the highlighting for the tab char will be
+ // correctly set further below (effectively reverts the
+ // FIX_FOR_BOGSUCOLS macro.
+ if (n_extra == tab_len + vc_saved && wp->w_p_list && lcs_tab1) {
+ tab_len += vc_saved;
+ }
}
- mb_utf8 = FALSE; /* don't draw as UTF-8 */
+
+ mb_utf8 = (int)false; // don't draw as UTF-8
if (wp->w_p_list) {
c = lcs_tab1;
if (wp->w_p_lbr) {
@@ -3469,11 +3496,11 @@ win_line (
&& !(noinvcur
&& lnum == wp->w_cursor.lnum
&& (colnr_T)vcol == wp->w_virtcol)))
- && lcs_eol_one >= 0) {
- /* Display a '$' after the line or highlight an extra
- * character if the line break is included. */
- /* For a diff line the highlighting continues after the
- * "$". */
+ && lcs_eol_one > 0) {
+ // Display a '$' after the line or highlight an extra
+ // character if the line break is included.
+ // For a diff line the highlighting continues after the
+ // "$".
if (diff_hlf == (hlf_T)0 && line_attr == 0) {
/* In virtualedit, visual selections may extend
* beyond end of line. */
@@ -3948,20 +3975,24 @@ win_line (
ScreenAttrs[off] = char_attr;
if (has_mbyte && (*mb_char2cells)(mb_c) > 1) {
- /* Need to fill two screen columns. */
- ++off;
- ++col;
- if (enc_utf8)
- /* UTF-8: Put a 0 in the second screen char. */
+ // Need to fill two screen columns.
+ off++;
+ col++;
+ if (enc_utf8) {
+ // UTF-8: Put a 0 in the second screen char.
ScreenLines[off] = 0;
- else
- /* DBCS: Put second byte in the second screen char. */
+ } else {
+ // DBCS: Put second byte in the second screen char.
ScreenLines[off] = mb_c & 0xff;
- ++vcol;
- /* When "tocol" is halfway through a character, set it to the end of
- * the character, otherwise highlighting won't stop. */
- if (tocol == vcol)
- ++tocol;
+ }
+ if (draw_state > WL_NR && filler_todo <= 0) {
+ vcol++;
+ }
+ // When "tocol" is halfway through a character, set it to the end of
+ // the character, otherwise highlighting won't stop.
+ if (tocol == vcol) {
+ tocol++;
+ }
if (wp->w_p_rl) {
/* now it's time to backup one cell */
--off;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 18a72524cb..d393ee7d02 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -621,43 +621,39 @@ int searchit(
break;
}
matchcol = endpos.col;
- /* for empty match: advance one char */
- if (matchcol == matchpos.col
- && ptr[matchcol] != NUL) {
- if (has_mbyte)
- matchcol +=
- (*mb_ptr2len)(ptr + matchcol);
- else
- ++matchcol;
- }
+ // for empty match (matchcol == matchpos.col): advance one char
} else {
+ // Prepare to start after first matched character.
matchcol = matchpos.col;
- if (ptr[matchcol] != NUL) {
- if (has_mbyte)
- matchcol += (*mb_ptr2len)(ptr
- + matchcol);
- else
- ++matchcol;
- }
}
- if (matchcol == 0 && (options & SEARCH_START))
+
+ if (matchcol == matchpos.col && ptr[matchcol] != NUL) {
+ matchcol += MB_PTR2LEN(ptr + matchcol);
+ }
+
+ if (matchcol == 0 && (options & SEARCH_START)) {
break;
- if (STRLEN(ptr) <= (size_t)matchcol || ptr[matchcol] == NUL
- || (nmatched = vim_regexec_multi(&regmatch,
- win, buf, lnum + matchpos.lnum,
- matchcol,
- tm
- )) == 0) {
- match_ok = FALSE;
+ }
+
+ if (ptr[matchcol] == NUL ||
+ (nmatched = vim_regexec_multi(&regmatch, win, buf, lnum,
+ matchcol, tm)) == 0) {
+ match_ok = false;
break;
}
matchpos = regmatch.startpos[0];
endpos = regmatch.endpos[0];
submatch = first_submatch(&regmatch);
- /* Need to get the line pointer again, a
- * multi-line search may have made it invalid. */
- ptr = ml_get_buf(buf, lnum + matchpos.lnum, FALSE);
+ // This while-loop only works with matchpos.lnum == 0.
+ // For bigger values the next line pointer ptr might not be a
+ // buffer line.
+ if (matchpos.lnum != 0) {
+ break;
+ }
+ // Need to get the line pointer again, a multi-line search may
+ // have made it invalid.
+ ptr = ml_get_buf(buf, lnum, false);
}
if (!match_ok)
continue;
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index dcdf2195f8..def2de9b1a 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -6,9 +6,6 @@
#include <inttypes.h>
#include <errno.h>
#include <fcntl.h>
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
#include <assert.h>
#include <msgpack.h>
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 420e8e2b70..b2028109be 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -1063,8 +1063,7 @@ static char_u *repl_to = NULL;
//
// Returns the length of the word in bytes, also when it's OK, so that the
// caller can skip over the word.
-size_t
-spell_check (
+size_t spell_check(
win_T *wp, // current window
char_u *ptr,
hlf_T *attrp,
@@ -1082,12 +1081,14 @@ spell_check (
// A word never starts at a space or a control character. Return quickly
// then, skipping over the character.
- if (*ptr <= ' ')
+ if (*ptr <= ' ') {
return 1;
+ }
// Return here when loading language files failed.
- if (GA_EMPTY(&wp->w_s->b_langp))
+ if (GA_EMPTY(&wp->w_s->b_langp)) {
return 1;
+ }
memset(&mi, 0, sizeof(matchinf_T));
@@ -1095,10 +1096,13 @@ spell_check (
// 0X99FF. But always do check spelling to find "3GPP" and "11
// julifeest".
if (*ptr >= '0' && *ptr <= '9') {
- if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
+ if (*ptr == '0' && (ptr[1] == 'b' || ptr[1] == 'B')) {
+ mi.mi_end = (char_u*) skipbin((char*) ptr + 2);
+ } else if (*ptr == '0' && (ptr[1] == 'x' || ptr[1] == 'X')) {
mi.mi_end = skiphex(ptr + 2);
- else
+ } else {
mi.mi_end = skipdigits(ptr);
+ }
nrlen = (size_t)(mi.mi_end - ptr);
}
@@ -1113,12 +1117,14 @@ spell_check (
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) {
// Check word starting with capital letter.
c = PTR2CHAR(ptr);
- if (!SPELL_ISUPPER(c))
+ if (!SPELL_ISUPPER(c)) {
wrongcaplen = (size_t)(mi.mi_fend - ptr);
+ }
}
}
- if (capcol != NULL)
+ if (capcol != NULL) {
*capcol = -1;
+ }
// We always use the characters up to the next non-word character,
// also for bad words.
@@ -1131,8 +1137,9 @@ spell_check (
// case-fold the word with one non-word character, so that we can check
// for the word end.
- if (*mi.mi_fend != NUL)
+ if (*mi.mi_fend != NUL) {
mb_ptr_adv(mi.mi_fend);
+ }
(void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1);
mi.mi_fwordlen = (int)STRLEN(mi.mi_fword);
@@ -1149,8 +1156,9 @@ spell_check (
// If reloading fails the language is still in the list but everything
// has been cleared.
- if (mi.mi_lp->lp_slang->sl_fidxs == NULL)
+ if (mi.mi_lp->lp_slang->sl_fidxs == NULL) {
continue;
+ }
// Check for a matching word in case-folded words.
find_word(&mi, FIND_FOLDWORD);
@@ -1181,18 +1189,18 @@ spell_check (
// If we found a number skip over it. Allows for "42nd". Do flag
// rare and local words, e.g., "3GPP".
if (nrlen > 0) {
- if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
+ if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED) {
return nrlen;
- }
+ }
+ } else if (!spell_iswordp_nmw(ptr, wp)) {
// When we are at a non-word character there is no error, just
// skip over the character (try looking for a word after it).
- else if (!spell_iswordp_nmw(ptr, wp)) {
if (capcol != NULL && wp->w_s->b_cap_prog != NULL) {
regmatch_T regmatch;
// Check for end of sentence.
regmatch.regprog = wp->w_s->b_cap_prog;
- regmatch.rm_ic = FALSE;
+ regmatch.rm_ic = false;
int r = vim_regexec(&regmatch, ptr, 0);
wp->w_s->b_cap_prog = regmatch.regprog;
if (r) {
@@ -1204,12 +1212,12 @@ spell_check (
return (size_t)(*mb_ptr2len)(ptr);
}
return 1;
- } else if (mi.mi_end == ptr)
+ } else if (mi.mi_end == ptr) {
// Always include at least one character. Required for when there
// is a mixup in "midword".
mb_ptr_adv(mi.mi_end);
- else if (mi.mi_result == SP_BAD
- && LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
+ } else if (mi.mi_result == SP_BAD
+ && LANGP_ENTRY(wp->w_s->b_langp, 0)->lp_slang->sl_nobreak) {
char_u *p, *fp;
int save_result = mi.mi_result;
@@ -1219,11 +1227,12 @@ spell_check (
if (mi.mi_lp->lp_slang->sl_fidxs != NULL) {
p = mi.mi_word;
fp = mi.mi_fword;
- for (;; ) {
+ for (;;) {
mb_ptr_adv(p);
mb_ptr_adv(fp);
- if (p >= mi.mi_end)
+ if (p >= mi.mi_end) {
break;
+ }
mi.mi_compoff = (int)(fp - mi.mi_fword);
find_word(&mi, FIND_COMPOUND);
if (mi.mi_result != SP_BAD) {
@@ -1235,12 +1244,13 @@ spell_check (
}
}
- if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED)
+ if (mi.mi_result == SP_BAD || mi.mi_result == SP_BANNED) {
*attrp = HLF_SPB;
- else if (mi.mi_result == SP_RARE)
+ } else if (mi.mi_result == SP_RARE) {
*attrp = HLF_SPR;
- else
+ } else {
*attrp = HLF_SPL;
+ }
}
if (wrongcaplen > 0 && (mi.mi_result == SP_OK || mi.mi_result == SP_RARE)) {
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index fe91141375..37a0fb82da 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -425,9 +425,13 @@ char_u *vim_strchr(const char_u *string, int c)
const char_u *p = string;
if (enc_utf8 && c >= 0x80) {
while (*p != NUL) {
- if (utf_ptr2char(p) == c)
+ int l = (*mb_ptr2len)(p);
+
+ // Avoid matching an illegal byte here.
+ if (l > 1 && utf_ptr2char(p) == c) {
return (char_u *) p;
- p += (*mb_ptr2len)(p);
+ }
+ p += l;
}
return NULL;
}
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index b4292dbd4b..41ce2daa91 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -7,14 +7,14 @@ export SHELL := sh
VIMPROG := ../../../build/bin/nvim
SCRIPTSOURCE := ../../../runtime
-SCRIPTS := test_eval.out \
+SCRIPTS := \
test8.out test10.out \
test11.out test12.out test13.out test14.out \
test17.out \
test24.out \
test30.out \
test32.out test34.out \
- test36.out test37.out test39.out test40.out \
+ test36.out test37.out test40.out \
test42.out test45.out \
test47.out test48.out test49.out \
test52.out test53.out test55.out \
@@ -22,14 +22,12 @@ SCRIPTS := test_eval.out \
test68.out test69.out \
test73.out \
test79.out \
- test83.out \
test88.out \
test_listlbr.out \
test_breakindent.out \
test_charsearch.out \
test_close_count.out \
test_command_count.out \
- test_cdo.out \
NEW_TESTS =
@@ -97,6 +95,7 @@ clean:
*.rej \
*.orig \
test.log \
+ messages \
$(RM_ON_RUN) \
$(RM_ON_START) \
valgrind.* \
@@ -149,7 +148,7 @@ test1.out: .gdbinit test1.in
test49.out: test49.vim
nolog:
- -rm -f test.log
+ -rm -f test.log messages
# New style of tests uses Vim script with assert calls. These are easier
@@ -160,9 +159,9 @@ RUN_VIMTEST = VIMRUNTIME=$(SCRIPTSOURCE); export VIMRUNTIME; $(VALGRIND) $(VIMPR
newtests: newtestssilent
@/bin/sh -c "if test -f messages && grep -q 'FAILED' messages; then \
cat messages && cat test.log; \
- fi" \
+ fi"
newtestssilent: $(NEW_TESTS)
%.res: %.vim .gdbinit
- $(RUN_VIMTEST) -u runtest.vim $*.vim
+ $(RUN_VIMTEST) -u NONE -S runtest.vim $*.vim
diff --git a/src/nvim/testdir/runtest.vim b/src/nvim/testdir/runtest.vim
index 0dc142eb97..8314a45d0c 100644
--- a/src/nvim/testdir/runtest.vim
+++ b/src/nvim/testdir/runtest.vim
@@ -21,9 +21,7 @@
" It will be called after each Test_ function.
" Without the +eval feature we can't run these tests, bail out.
-if 0
- quit!
-endif
+so small.vim
" Check that the screen size is at least 24 x 80 characters.
if &lines < 24 || &columns < 80
@@ -38,7 +36,16 @@ endif
" Source the test script. First grab the file name, in case the script
" navigates away.
let testname = expand('%')
-source %
+let done = 0
+let fail = 0
+let errors = []
+let messages = []
+try
+ source %
+catch
+ let fail += 1
+ call add(errors, 'Caught exception: ' . v:exception . ' @ ' . v:throwpoint)
+endtry
" Locate Test_ functions and execute them.
redir @q
@@ -46,14 +53,12 @@ function /^Test_
redir END
let tests = split(substitute(@q, 'function \(\k*()\)', '\1', 'g'))
-let done = 0
-let fail = 0
-let errors = []
for test in tests
if exists("*SetUp")
call SetUp()
endif
+ call add(messages, 'Executing ' . test)
let done += 1
try
exe 'call ' . test
@@ -89,9 +94,20 @@ if len(errors) > 0
write
endif
-echo 'Executed ' . done . (done > 1 ? ' tests': ' test')
+let message = 'Executed ' . done . (done > 1 ? ' tests': ' test')
+echo message
+call add(messages, message)
if fail > 0
- echo fail . ' FAILED'
+ let message = fail . ' FAILED'
+ echo message
+ call add(messages, message)
endif
+" Append messages to "messages"
+split messages
+call append(line('$'), '')
+call append(line('$'), 'From ' . testname . ':')
+call append(line('$'), messages)
+write
+
qall!
diff --git a/src/nvim/testdir/test39.in b/src/nvim/testdir/test39.in
deleted file mode 100644
index ebbcbd6d0d..0000000000
--- a/src/nvim/testdir/test39.in
+++ /dev/null
@@ -1,106 +0,0 @@
-
-Test Visual block mode commands
-And test "U" in Visual mode, also on German sharp S.
-
-STARTTEST
-:so small.vim
-:so mbyte.vim
-/^abcde
-:" Test shift-right of a block
-jlllljj>wlljlll>
-:" Test shift-left of a block
-G$hhhhkk<
-:" Test block-insert
-GklkkkIxyz
-:" Test block-replace
-Gllllkkklllrq
-:" Test block-change
-G$khhhhhkkcmno
-:$-4,$w! test.out
-:" Test block-insert using cursor keys for movement
-/^aaaa/
-:exe ":norm! l\<C-V>jjjlllI\<Right>\<Right> \<Esc>"
-:/^aa/,/^$/w >> test.out
-/xaaa$/
-:exe ":norm! \<C-V>jjjI<>\<Left>p\<Esc>"
-:/xaaa$/,/^$/w >> test.out
-:" Test for Visual block was created with the last <C-v>$
-/^A23$/
-:exe ":norm! l\<C-V>j$Aab\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block was created with the middle <C-v>$ (1)
-/^B23$/
-:exe ":norm! l\<C-V>j$hAab\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block was created with the middle <C-v>$ (2)
-/^C23$/
-:exe ":norm! l\<C-V>j$hhAab\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block insert when virtualedit=all and utf-8 encoding
-:set ve=all
-:/\t\tline
-:exe ":norm! 07l\<C-V>jjIx\<Esc>"
-:.,/^$/w >> test.out
-:" Test for Visual block append when virtualedit=all
-:exe ":norm! 012l\<C-v>jjAx\<Esc>"
-:set ve=
-:.,/^$/w >> test.out
-:" gUe must uppercase a whole word, also when ß changes to SS
-Gothe youtußeuu endYpk0wgUe
-:" gUfx must uppercase until x, inclusive.
-O- youßtußexu -0fogUfx
-:" VU must uppercase a whole line
-YpkVU
-:" same, when it's the last line in the buffer
-YPGi111VUddP
-:" Uppercase two lines
-Oblah di
-doh dutVkUj
-:" Uppercase part of two lines
-ddppi333k0i222fyllvjfuUk
-:" visual replace using Enter or NL
-G3o1234567892k05l2jr G3o987652k02l2jr
-G3o1234567892k05l2jr
-G3o987652k02l2jr
-:"
-:" Test cursor position. When ve=block and Visual block mode and $gj
-:set ve=block
-:exe ":norm! 2k\<C-V>$gj\<Esc>"
-:let cpos=getpos("'>")
-:$put ='col:'.cpos[2].' off:'.cpos[3]
-:/^the/,$w >> test.out
-:qa!
-ENDTEST
-
- line1
- line2
- line3
-
-aaaaaa
-bbbbbb
-cccccc
-dddddd
-
-xaaa
-bbbb
-cccc
-dddd
-
-yaaa
-¿¿¿
-bbb
-
-A23
-4567
-
-B23
-4567
-
-C23
-4567
-
-abcdefghijklm
-abcdefghijklm
-abcdefghijklm
-abcdefghijklm
-abcdefghijklm
diff --git a/src/nvim/testdir/test39.ok b/src/nvim/testdir/test39.ok
deleted file mode 100644
index 198e5b14dc..0000000000
--- a/src/nvim/testdir/test39.ok
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test55.in b/src/nvim/testdir/test55.in
index c4e82d429c..7b6f684caa 100644
--- a/src/nvim/testdir/test55.in
+++ b/src/nvim/testdir/test55.in
@@ -282,6 +282,166 @@ let l = [0, 1, 2, 3]
: $put =ps
: endfor
:endfor
+:"
+:" Unletting locked variables
+:$put ='Unletting:'
+:for depth in range(5)
+: $put ='depth is ' . depth
+: for u in range(3)
+: unlet l
+: let l = [0, [1, [2, 3]], {4: 5, 6: {7: 8}}]
+: exe "lockvar " . depth . " l"
+: if u == 1
+: exe "unlockvar l"
+: elseif u == 2
+: exe "unlockvar " . depth . " l"
+: endif
+: let ps = islocked("l").islocked("l[1]").islocked("l[1][1]").islocked("l[1][1][0]").'-'.islocked("l[2]").islocked("l[2]['6']").islocked("l[2]['6'][7]")
+: $put =ps
+: let ps = ''
+: try
+: unlet l[2]['6'][7]
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: try
+: unlet l[2][6]
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: try
+: unlet l[2]
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: try
+: unlet l[1][1][0]
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: try
+: unlet l[1][1]
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: try
+: unlet l[1]
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: try
+: unlet l
+: let ps .= 'p'
+: catch
+: let ps .= 'F'
+: endtry
+: $put =ps
+: endfor
+:endfor
+:"
+:" Locked variables and :unlet or list / dict functions
+:$put ='Locks and commands or functions:'
+:"
+:$put ='No :unlet after lock on dict:'
+:unlet! d
+:let d = {'a': 99, 'b': 100}
+:lockvar 1 d
+:try
+: unlet d.a
+: $put ='did :unlet'
+:catch
+: $put =v:exception[:16]
+:endtry
+:$put =string(d)
+:"
+:$put =':unlet after lock on dict item:'
+:unlet! d
+:let d = {'a': 99, 'b': 100}
+:lockvar d.a
+:try
+: unlet d.a
+: $put ='did :unlet'
+:catch
+: $put =v:exception[:16]
+:endtry
+:$put =string(d)
+:"
+:$put ='filter() after lock on dict item:'
+:unlet! d
+:let d = {'a': 99, 'b': 100}
+:lockvar d.a
+:try
+: call filter(d, 'v:key != "a"')
+: $put ='did filter()'
+:catch
+: $put =v:exception[:16]
+:endtry
+:$put =string(d)
+:"
+:$put ='map() after lock on dict:'
+:unlet! d
+:let d = {'a': 99, 'b': 100}
+:lockvar 1 d
+:try
+: call map(d, 'v:val + 200')
+: $put ='did map()'
+:catch
+: $put =v:exception[:16]
+:endtry
+:$put =string(d)
+:"
+:$put ='No extend() after lock on dict item:'
+:unlet! d
+:let d = {'a': 99, 'b': 100}
+:lockvar d.a
+:try
+: $put =string(extend(d, {'a': 123}))
+: $put ='did extend()'
+:catch
+: $put =v:exception[:14]
+:endtry
+:$put =string(d)
+:"
+:$put ='No remove() of write-protected scope-level variable:'
+:fun! Tfunc(this_is_a_loooooooooong_parameter_name)
+: try
+: $put =string(remove(a:, 'this_is_a_loooooooooong_parameter_name'))
+: $put ='did remove()'
+: catch
+: $put =v:exception[:14]
+: endtry
+:endfun
+:call Tfunc('testval')
+:"
+:$put ='No extend() of write-protected scope-level variable:'
+:fun! Tfunc(this_is_a_loooooooooong_parameter_name)
+: try
+: $put =string(extend(a:, {'this_is_a_loooooooooong_parameter_name': 1234}))
+: $put ='did extend()'
+: catch
+: $put =v:exception[:14]
+: endtry
+:endfun
+:call Tfunc('testval')
+:"
+:$put ='No :unlet of variable in locked scope:'
+:let b:testvar = 123
+:lockvar 1 b:
+:try
+: unlet b:testvar
+: $put ='b:testvar was :unlet: '. (!exists('b:testvar'))
+:catch
+: $put =v:exception[:16]
+:endtry
+:unlockvar 1 b:
+:unlet! b:testvar
+:"
:unlet l
:let l = [1, 2, 3, 4]
:lockvar! l
diff --git a/src/nvim/testdir/test55.ok b/src/nvim/testdir/test55.ok
index ba029b2898..4e0303c26e 100644
--- a/src/nvim/testdir/test55.ok
+++ b/src/nvim/testdir/test55.ok
@@ -86,6 +86,64 @@ FFFFFFF
FFpFFpp
0000-000
ppppppp
+Unletting:
+depth is 0
+0000-000
+ppppppp
+0000-000
+ppppppp
+0000-000
+ppppppp
+depth is 1
+1000-000
+ppFppFp
+0000-000
+ppppppp
+0000-000
+ppppppp
+depth is 2
+1100-100
+pFFpFFp
+0000-000
+ppppppp
+0000-000
+ppppppp
+depth is 3
+1110-110
+FFFFFFp
+0010-010
+FppFppp
+0000-000
+ppppppp
+depth is 4
+1111-111
+FFFFFFp
+0011-011
+FppFppp
+0000-000
+ppppppp
+Locks and commands or functions:
+No :unlet after lock on dict:
+Vim(unlet):E741:
+{'a': 99, 'b': 100}
+:unlet after lock on dict item:
+did :unlet
+{'b': 100}
+filter() after lock on dict item:
+did filter()
+{'b': 100}
+map() after lock on dict:
+did map()
+{'a': 299, 'b': 300}
+No extend() after lock on dict item:
+Vim(put):E741:
+{'a': 99, 'b': 100}
+No remove() of write-protected scope-level variable:
+Vim(put):E795:
+No extend() of write-protected scope-level variable:
+Vim(put):E742:
+No :unlet of variable in locked scope:
+Vim(unlet):E741:
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
diff --git a/src/nvim/testdir/test83-tags2 b/src/nvim/testdir/test83-tags2
deleted file mode 100644
index 7f9f21b0eb..0000000000
--- a/src/nvim/testdir/test83-tags2
+++ /dev/null
@@ -1,2 +0,0 @@
-!_TAG_FILE_ENCODING cp932 //
-‚`‚a‚b Xtags2.txt /‚`‚a‚b
diff --git a/src/nvim/testdir/test83-tags3 b/src/nvim/testdir/test83-tags3
deleted file mode 100644
index 0cb6591562..0000000000
--- a/src/nvim/testdir/test83-tags3
+++ /dev/null
@@ -1,102 +0,0 @@
-!_TAG_FILE_SORTED 1 //
-!_TAG_FILE_ENCODING cp932 //
-abc1 Xtags3.txt /‚`‚a‚b
-abc2 Xtags3.txt /‚`‚a‚b
-abc3 Xtags3.txt /‚`‚a‚b
-abc4 Xtags3.txt /‚`‚a‚b
-abc5 Xtags3.txt /‚`‚a‚b
-abc6 Xtags3.txt /‚`‚a‚b
-abc7 Xtags3.txt /‚`‚a‚b
-abc8 Xtags3.txt /‚`‚a‚b
-abc9 Xtags3.txt /‚`‚a‚b
-abc10 Xtags3.txt /‚`‚a‚b
-abc11 Xtags3.txt /‚`‚a‚b
-abc12 Xtags3.txt /‚`‚a‚b
-abc13 Xtags3.txt /‚`‚a‚b
-abc14 Xtags3.txt /‚`‚a‚b
-abc15 Xtags3.txt /‚`‚a‚b
-abc16 Xtags3.txt /‚`‚a‚b
-abc17 Xtags3.txt /‚`‚a‚b
-abc18 Xtags3.txt /‚`‚a‚b
-abc19 Xtags3.txt /‚`‚a‚b
-abc20 Xtags3.txt /‚`‚a‚b
-abc21 Xtags3.txt /‚`‚a‚b
-abc22 Xtags3.txt /‚`‚a‚b
-abc23 Xtags3.txt /‚`‚a‚b
-abc24 Xtags3.txt /‚`‚a‚b
-abc25 Xtags3.txt /‚`‚a‚b
-abc26 Xtags3.txt /‚`‚a‚b
-abc27 Xtags3.txt /‚`‚a‚b
-abc28 Xtags3.txt /‚`‚a‚b
-abc29 Xtags3.txt /‚`‚a‚b
-abc30 Xtags3.txt /‚`‚a‚b
-abc31 Xtags3.txt /‚`‚a‚b
-abc32 Xtags3.txt /‚`‚a‚b
-abc33 Xtags3.txt /‚`‚a‚b
-abc34 Xtags3.txt /‚`‚a‚b
-abc35 Xtags3.txt /‚`‚a‚b
-abc36 Xtags3.txt /‚`‚a‚b
-abc37 Xtags3.txt /‚`‚a‚b
-abc38 Xtags3.txt /‚`‚a‚b
-abc39 Xtags3.txt /‚`‚a‚b
-abc40 Xtags3.txt /‚`‚a‚b
-abc41 Xtags3.txt /‚`‚a‚b
-abc42 Xtags3.txt /‚`‚a‚b
-abc43 Xtags3.txt /‚`‚a‚b
-abc44 Xtags3.txt /‚`‚a‚b
-abc45 Xtags3.txt /‚`‚a‚b
-abc46 Xtags3.txt /‚`‚a‚b
-abc47 Xtags3.txt /‚`‚a‚b
-abc48 Xtags3.txt /‚`‚a‚b
-abc49 Xtags3.txt /‚`‚a‚b
-abc50 Xtags3.txt /‚`‚a‚b
-abc51 Xtags3.txt /‚`‚a‚b
-abc52 Xtags3.txt /‚`‚a‚b
-abc53 Xtags3.txt /‚`‚a‚b
-abc54 Xtags3.txt /‚`‚a‚b
-abc55 Xtags3.txt /‚`‚a‚b
-abc56 Xtags3.txt /‚`‚a‚b
-abc57 Xtags3.txt /‚`‚a‚b
-abc58 Xtags3.txt /‚`‚a‚b
-abc59 Xtags3.txt /‚`‚a‚b
-abc60 Xtags3.txt /‚`‚a‚b
-abc61 Xtags3.txt /‚`‚a‚b
-abc62 Xtags3.txt /‚`‚a‚b
-abc63 Xtags3.txt /‚`‚a‚b
-abc64 Xtags3.txt /‚`‚a‚b
-abc65 Xtags3.txt /‚`‚a‚b
-abc66 Xtags3.txt /‚`‚a‚b
-abc67 Xtags3.txt /‚`‚a‚b
-abc68 Xtags3.txt /‚`‚a‚b
-abc69 Xtags3.txt /‚`‚a‚b
-abc70 Xtags3.txt /‚`‚a‚b
-abc71 Xtags3.txt /‚`‚a‚b
-abc72 Xtags3.txt /‚`‚a‚b
-abc73 Xtags3.txt /‚`‚a‚b
-abc74 Xtags3.txt /‚`‚a‚b
-abc75 Xtags3.txt /‚`‚a‚b
-abc76 Xtags3.txt /‚`‚a‚b
-abc77 Xtags3.txt /‚`‚a‚b
-abc78 Xtags3.txt /‚`‚a‚b
-abc79 Xtags3.txt /‚`‚a‚b
-abc80 Xtags3.txt /‚`‚a‚b
-abc81 Xtags3.txt /‚`‚a‚b
-abc82 Xtags3.txt /‚`‚a‚b
-abc83 Xtags3.txt /‚`‚a‚b
-abc84 Xtags3.txt /‚`‚a‚b
-abc85 Xtags3.txt /‚`‚a‚b
-abc86 Xtags3.txt /‚`‚a‚b
-abc87 Xtags3.txt /‚`‚a‚b
-abc88 Xtags3.txt /‚`‚a‚b
-abc89 Xtags3.txt /‚`‚a‚b
-abc90 Xtags3.txt /‚`‚a‚b
-abc91 Xtags3.txt /‚`‚a‚b
-abc92 Xtags3.txt /‚`‚a‚b
-abc93 Xtags3.txt /‚`‚a‚b
-abc94 Xtags3.txt /‚`‚a‚b
-abc95 Xtags3.txt /‚`‚a‚b
-abc96 Xtags3.txt /‚`‚a‚b
-abc97 Xtags3.txt /‚`‚a‚b
-abc98 Xtags3.txt /‚`‚a‚b
-abc99 Xtags3.txt /‚`‚a‚b
-abc100 Xtags3.txt /‚`‚a‚b
diff --git a/src/nvim/testdir/test83.in b/src/nvim/testdir/test83.in
deleted file mode 100644
index d54b1bcddd..0000000000
--- a/src/nvim/testdir/test83.in
+++ /dev/null
@@ -1,75 +0,0 @@
-Tests for tag search with !_TAG_FILE_ENCODING.
-
-STARTTEST
-:so mbyte.vim
-:if !has('iconv') || iconv("\x82\x60", "cp932", "utf-8") != "\uff21"
-: e! test.ok
-: w! test.out
-: qa!
-:endif
-
-:/^text for tags1$/,/^text for tags1$/+1w! Xtags1.txt
-:/^text for tags2$/,/^text for tags2$/+1w! Xtags2.txt
-:/^text for tags3$/,/^text for tags3$/+1w! Xtags3.txt
-:/^tags1$/+1,/^tags1-end$/-1w! Xtags1
-
-ggdG
-
-:call setline('.', 'Results of test83')
-
-:" case1:
-:new
-:set tags=Xtags1
-:let v:errmsg = ''
-:tag abcdefghijklmnopqrs
-:if v:errmsg =~ 'E426:' || getline('.') != 'abcdefghijklmnopqrs'
-: close
-: put ='case1: failed'
-:else
-: close
-: put ='case1: ok'
-:endif
-
-:" case2:
-:new
-:set tags=test83-tags2
-:let v:errmsg = ''
-:tag /.BC
-:if v:errmsg =~ 'E426:' || getline('.') != 'ABC'
-: close
-: put ='case2: failed'
-:else
-: close
-: put ='case2: ok'
-:endif
-
-:" case3:
-:new
-:set tags=test83-tags3
-:let v:errmsg = ''
-:tag abc50
-:if v:errmsg =~ 'E426:' || getline('.') != 'ABC'
-: close
-: put ='case3: failed'
-:else
-: close
-: put ='case3: ok'
-:endif
-:close
-
-:wq! test.out
-ENDTEST
-
-text for tags1
-abcdefghijklmnopqrs
-
-text for tags2
-ABC
-
-text for tags3
-ABC
-
-tags1
-!_TAG_FILE_ENCODING utf-8 //
-abcdefghijklmnopqrs Xtags1.txt /abcdefghijklmnopqrs
-tags1-end
diff --git a/src/nvim/testdir/test83.ok b/src/nvim/testdir/test83.ok
deleted file mode 100644
index 61a1a04a18..0000000000
--- a/src/nvim/testdir/test83.ok
+++ /dev/null
@@ -1,4 +0,0 @@
-Results of test83
-case1: ok
-case2: ok
-case3: ok
diff --git a/src/nvim/testdir/test88.in b/src/nvim/testdir/test88.in
index c2e6a752fa..9e43f703e9 100644
--- a/src/nvim/testdir/test88.in
+++ b/src/nvim/testdir/test88.in
@@ -71,6 +71,17 @@ GGk
:set lbr
:normal $
GGk
+:set list listchars=tab:>-
+:normal 0
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal W
+GGk
+:normal $
+GGk
:" Display result.
:call append('$', 'end:')
:call append('$', positions)
diff --git a/src/nvim/testdir/test88.ok b/src/nvim/testdir/test88.ok
index e29698b7bd..12949f274a 100644
--- a/src/nvim/testdir/test88.ok
+++ b/src/nvim/testdir/test88.ok
@@ -22,3 +22,8 @@ end:
9:25
9:26
9:26
+9:1
+9:9
+9:17
+9:25
+9:26
diff --git a/src/nvim/testdir/test_cdo.in b/src/nvim/testdir/test_cdo.in
deleted file mode 100644
index fb80ea1164..0000000000
--- a/src/nvim/testdir/test_cdo.in
+++ /dev/null
@@ -1,107 +0,0 @@
-Tests for the :cdo, :cfdo, :ldo and :lfdo commands
-
-STARTTEST
-:so small.vim
-:if !has('quickfix') | e! test.ok | wq! test.out | endif
-
-:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1')
-:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2')
-:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3')
-
-:function RunTests(cchar)
-: let nl="\n"
-
-: enew
-: " Try with an empty list
-: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-
-: " Populate the list and then try
-: exe a:cchar . "getexpr ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']"
-: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-
-: " Run command only on selected error lines
-: enew
-: exe "2,3" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: " Boundary condition tests
-: enew
-: exe "1,1" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: enew
-: exe "3" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: " Range test commands
-: enew
-: exe "%" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: enew
-: exe "1,$" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: enew
-: exe a:cchar . 'prev'
-: exe "." . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: " Invalid error lines test
-: enew
-: exe "27" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "4,5" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-
-: " Run commands from an unsaved buffer
-: let v:errmsg=''
-: enew
-: setlocal modified
-: exe "2,2" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: if v:errmsg =~# 'No write since last change'
-: let g:result .= 'Unsaved file change test passed' . nl
-: else
-: let g:result .= 'Unsaved file change test failed' . nl
-: endif
-
-: " If the executed command fails, then the operation should be aborted
-: enew!
-: let subst_count = 0
-: exe a:cchar . "do s/Line/xLine/ | let subst_count += 1"
-: if subst_count == 1 && getline('.') == 'xLine1'
-: let g:result .= 'Abort command on error test passed' . nl
-: else
-: let g:result .= 'Abort command on error test failed' . nl
-: endif
-
-: exe "2,2" . a:cchar . "do! let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-
-: " List with no valid error entries
-: edit! +2 Xtestfile1
-: exe a:cchar . "getexpr ['non-error 1', 'non-error 2', 'non-error 3']"
-: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "2" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: let v:errmsg=''
-: exe "%" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "1,$" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "." . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: let g:result .= v:errmsg
-
-: " List with only one valid entry
-: exe a:cchar . "getexpr ['Xtestfile3:3:1:Line3']"
-: exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-
-: " Tests for :cfdo and :lfdo commands
-: exe a:cchar . "getexpr ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']"
-: exe a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "3" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "2,3" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "%" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe "1,$" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-: exe a:cchar . 'pfile'
-: exe "." . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-
-: " List with only one valid entry
-: exe a:cchar . "getexpr ['Xtestfile2:2:5:Line2']"
-: exe a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
-:endfunction
-
-:let result=''
-:" Tests for the :cdo quickfix list command
-:call RunTests('c')
-:let result .= "\n"
-:" Tests for the :ldo location list command
-:call RunTests('l')
-
-:edit! test.out
-:0put =result
-:wq!
-ENDTEST
-
diff --git a/src/nvim/testdir/test_cdo.ok b/src/nvim/testdir/test_cdo.ok
deleted file mode 100644
index ddcff4bbb8..0000000000
--- a/src/nvim/testdir/test_cdo.ok
+++ /dev/null
@@ -1,66 +0,0 @@
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile2 2L 2C
-Unsaved file change test passed
-Abort command on error test passed
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile3 2L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile2 2L 2C
-Xtestfile2 2L 5C
-
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile2 2L 2C
-Unsaved file change test passed
-Abort command on error test passed
-Xtestfile2 2L 2C
-Xtestfile3 3L 1C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile3 2L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile1 1L 3C
-Xtestfile2 2L 2C
-Xtestfile3 2L 3C
-Xtestfile2 2L 2C
-Xtestfile2 2L 5C
-
diff --git a/src/nvim/testdir/test_eval.in b/src/nvim/testdir/test_eval.in
deleted file mode 100644
index 54cdb03ba2..0000000000
--- a/src/nvim/testdir/test_eval.in
+++ /dev/null
@@ -1,234 +0,0 @@
-Test for various eval features. vim: set ft=vim :
-
-Note: system clipboard is saved, changed and restored.
-
-clipboard contents
-something else
-
-STARTTEST
-:so small.vim
-:set noswapfile
-:lang C
-:fun AppendRegContents(reg)
- call AppendRegParts(a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1)))
-:endfun
-:fun AppendRegParts(reg, type, cont, strcont, cont1, strcont1)
- call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, a:type, a:cont, a:strcont, a:cont1, a:strcont1))
-endfun
-:command -nargs=? AR :call AppendRegContents(<q-args>)
-:fun SetReg(...)
- call call('setreg', a:000)
- call append('$', printf('{{{2 setreg(%s)', string(a:000)[1:-2]))
- call AppendRegContents(a:1)
- if a:1 isnot# '='
- execute "silent normal! Go==\n==\e\"".a:1."P"
- endif
-endfun
-:fun ErrExe(str)
- call append('$', 'Executing '.a:str)
- try
- execute a:str
- catch
- $put =v:exception
- endtry
-endfun
-:fun Test()
-$put ='{{{1 let tests'
-let @" = 'abc'
-AR "
-let @" = "abc\n"
-AR "
-let @" = "abc\<C-m>"
-AR "
-let @= = '"abc"'
-AR =
-
-$put ='{{{1 Basic setreg tests'
-call SetReg('a', 'abcA', 'c')
-call SetReg('b', 'abcB', 'v')
-call SetReg('c', 'abcC', 'l')
-call SetReg('d', 'abcD', 'V')
-call SetReg('e', 'abcE', 'b')
-call SetReg('f', 'abcF', "\<C-v>")
-call SetReg('g', 'abcG', 'b10')
-call SetReg('h', 'abcH', "\<C-v>10")
-call SetReg('I', 'abcI')
-
-$put ='{{{1 Appending single lines with setreg()'
-call SetReg('A', 'abcAc', 'c')
-call SetReg('A', 'abcAl', 'l')
-call SetReg('A', 'abcAc2','c')
-call SetReg('b', 'abcBc', 'ca')
-call SetReg('b', 'abcBb', 'ba')
-call SetReg('b', 'abcBc2','ca')
-call SetReg('b', 'abcBb2','b50a')
-
-call SetReg('C', 'abcCl', 'l')
-call SetReg('C', 'abcCc', 'c')
-call SetReg('D', 'abcDb', 'b')
-
-call SetReg('E', 'abcEb', 'b')
-call SetReg('E', 'abcEl', 'l')
-call SetReg('F', 'abcFc', 'c')
-
-$put ='{{{1 Appending NL with setreg()'
-call setreg('a', 'abcA2', 'c')
-call setreg('b', 'abcB2', 'v')
-call setreg('c', 'abcC2', 'l')
-call setreg('d', 'abcD2', 'V')
-call setreg('e', 'abcE2', 'b')
-call setreg('f', 'abcF2', "\<C-v>")
-call setreg('g', 'abcG2', 'b10')
-call setreg('h', 'abcH2', "\<C-v>10")
-call setreg('I', 'abcI2')
-
-call SetReg('A', "\n")
-call SetReg('B', "\n", 'c')
-call SetReg('C', "\n")
-call SetReg('D', "\n", 'l')
-call SetReg('E', "\n")
-call SetReg('F', "\n", 'b')
-
-$put ='{{{1 Setting lists with setreg()'
-call SetReg('a', ['abcA3'], 'c')
-call SetReg('b', ['abcB3'], 'l')
-call SetReg('c', ['abcC3'], 'b')
-call SetReg('d', ['abcD3'])
-call SetReg('e', [1, 2, 'abc', 3])
-call SetReg('f', [1, 2, 3])
-
-$put ='{{{1 Appending lists with setreg()'
-call SetReg('A', ['abcA3c'], 'c')
-call SetReg('b', ['abcB3l'], 'la')
-call SetReg('C', ['abcC3b'], 'lb')
-call SetReg('D', ['abcD32'])
-
-call SetReg('A', ['abcA32'])
-call SetReg('B', ['abcB3c'], 'c')
-call SetReg('C', ['abcC3l'], 'l')
-call SetReg('D', ['abcD3b'], 'b')
-
-$put ='{{{1 Appending lists with NL with setreg()'
-call SetReg('A', ["\n", 'abcA3l2'], 'l')
-call SetReg('B', ["\n", 'abcB3c2'], 'c')
-call SetReg('C', ["\n", 'abcC3b2'], 'b')
-call SetReg('D', ["\n", 'abcD3b50'],'b50')
-
-$put ='{{{1 Setting lists with NLs with setreg()'
-call SetReg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"])
-call SetReg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c')
-call SetReg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l')
-call SetReg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b')
-call SetReg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10')
-
-$put ='{{{1 Search and expressions'
-call SetReg('/', ['abc/'])
-call SetReg('/', ["abc/\n"])
-call SetReg('=', ['"abc/"'])
-call SetReg('=', ["\"abc/\n\""])
-$put ='{{{1 System clipboard'
-if has('clipboard')
-" Save and restore system clipboard.
-" If no connection to X-Server is possible, test should succeed.
-let _clipreg = ['*', getreg('*'), getregtype('*')]
-let _clipopt = &cb
-let &cb='unnamed'
-5y
-AR *
-tabdo :windo :echo "hi"
-6y
-AR *
-let &cb=_clipopt
-call call('setreg', _clipreg)
-else
- call AppendRegParts('*', 'V', "clipboard contents\n", "['clipboard contents']", "clipboard contents\n", "['clipboard contents']")
- call AppendRegParts('*', 'V', "something else\n", "['something else']", "something else\n", "['something else']")
-endif
-$put ='{{{1 Errors'
-call ErrExe('call setreg()')
-call ErrExe('call setreg(1)')
-call ErrExe('call setreg(1, 2, 3, 4)')
-call ErrExe('call setreg([], 2)')
-call ErrExe('call setreg(1, {})')
-call ErrExe('call setreg(1, 2, [])')
-call ErrExe('call setreg("/", ["1", "2"])')
-call ErrExe('call setreg("=", ["1", "2"])')
-call ErrExe('call setreg(1, ["", "", [], ""])')
-endfun
-:"
-:call Test()
-:"
-:delfunction SetReg
-:delfunction AppendRegContents
-:delfunction ErrExe
-:delfunction Test
-:delcommand AR
-:call garbagecollect(1)
-:"
-:/^start:/+1,$wq! test.out
-:" vim: et ts=4 isk-=\: fmr=???,???
-:call getchar()
-:e test.out
-:%d
-
-:" function name not starting with a capital
-:try
-: func! g:test()
-: echo "test"
-: endfunc
-:catch
-: $put =v:exception
-:endtry
-
-:" function name folowed by #
-:try
-: func! test2() "#
-: echo "test2"
-: endfunc
-:catch
-: $put =v:exception
-:endtry
-
-:" function name includes a colon
-:try
-: func! b:test()
-: echo "test"
-: endfunc
-:catch
-: $put =v:exception
-:endtry
-
-:" function name starting with/without "g:", buffer-local funcref.
-:function! g:Foo(n)
-: $put ='called Foo(' . a:n . ')'
-:endfunction
-:let b:my_func = function('Foo')
-:call b:my_func(1)
-:echo g:Foo(2)
-:echo Foo(3)
-
-:" script-local function used in Funcref must exist.
-:so test_eval_func.vim
-
-:" using $ instead of '$' must give an error
-:try
-: call append($, 'foobar')
-:catch
-: $put =v:exception
-:endtry
-
-:$put ='{{{1 getcurpos/setpos'
-/^012345678
-6l:let sp = getcurpos()
-0:call setpos('.', sp)
-jyl:$put
-
-:/^start:/+1,$wq! test.out
-:" vim: et ts=4 isk-=\: fmr=???,???
-:call getchar()
-ENDTEST
-
-012345678
-012345678
-
-start:
diff --git a/src/nvim/testdir/test_eval.ok b/src/nvim/testdir/test_eval.ok
deleted file mode 100644
index cf7a5cd418..0000000000
--- a/src/nvim/testdir/test_eval.ok
+++ /dev/null
Binary files differ
diff --git a/src/nvim/testdir/test_eval_func.vim b/src/nvim/testdir/test_eval_func.vim
deleted file mode 100644
index 48d01df27d..0000000000
--- a/src/nvim/testdir/test_eval_func.vim
+++ /dev/null
@@ -1,12 +0,0 @@
-" Vim script used in test_eval.in. Needed for script-local function.
-
-func! s:Testje()
- return "foo"
-endfunc
-
-let Bar = function('s:Testje')
-
-$put ='s:Testje exists: ' . exists('s:Testje')
-$put ='func s:Testje exists: ' . exists('*s:Testje')
-$put ='Bar exists: ' . exists('Bar')
-$put ='func Bar exists: ' . exists('*Bar')
diff --git a/src/nvim/testdir/test_listlbr.in b/src/nvim/testdir/test_listlbr.in
index 36235ea915..57202b46eb 100644
--- a/src/nvim/testdir/test_listlbr.in
+++ b/src/nvim/testdir/test_listlbr.in
@@ -60,11 +60,21 @@ STARTTEST
:set cpo&vim linebreak
:let g:test ="Test 6: set linebreak with visual block mode"
:let line="REMOVE: this not"
+:$put =g:test
:$put =line
:let line="REMOVE: aaaaaaaaaaaaa"
:$put =line
:1/^REMOVE:
0jf x:$put
+:set cpo&vim linebreak
+:let g:test ="Test 7: set linebreak with visual block mode and v_b_A"
+:$put =g:test
+Golong line: 40afoobar aTARGET at end
+:exe "norm! $3B\<C-v>eAx\<Esc>"
+:set cpo&vim linebreak sbr=
+:let g:test ="Test 8: set linebreak with visual char mode and changing block"
+:$put =g:test
+Go1111-1111-1111-11-1111-1111-11110f-lv3lc2222bgj.
:%w! test.out
:qa!
ENDTEST
diff --git a/src/nvim/testdir/test_listlbr.ok b/src/nvim/testdir/test_listlbr.ok
index ee74667661..82881234c4 100644
--- a/src/nvim/testdir/test_listlbr.ok
+++ b/src/nvim/testdir/test_listlbr.ok
@@ -32,7 +32,12 @@ Sabbbbbb bla
~
~
~
+Test 6: set linebreak with visual block mode
this not
aaaaaaaaaaaaa
REMOVE:
REMOVE:
+Test 7: set linebreak with visual block mode and v_b_A
+long line: foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar foobar TARGETx at end
+Test 8: set linebreak with visual char mode and changing block
+1111-2222-1111-11-1111-2222-1111
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 7f7d138358..00e2821075 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -845,7 +845,7 @@ static void fix_terminfo(TUIData *data)
if ((term_prog && !strcmp(term_prog, "Konsole"))
|| os_getenv("KONSOLE_DBUS_SESSION") != NULL) {
// Konsole uses a proprietary escape code to set the cursor shape
- // and does not suppport DECSCUSR.
+ // and does not support DECSCUSR.
data->unibi_ext.enter_insert_mode = (int)unibi_add_ext_str(ut, NULL,
TMUX_WRAP("\x1b]50;CursorShape=1;BlinkingCursorEnabled=1\x07"));
data->unibi_ext.enter_replace_mode = (int)unibi_add_ext_str(ut, NULL,
@@ -854,13 +854,15 @@ static void fix_terminfo(TUIData *data)
TMUX_WRAP("\x1b]50;CursorShape=0;BlinkingCursorEnabled=0\x07"));
} else if (!vte_version || atoi(vte_version) >= 3900) {
// Assume that the terminal supports DECSCUSR unless it is an
- // old VTE based terminal
+ // old VTE based terminal. This should not get wrapped for tmux,
+ // which will handle it via its Ss/Se terminfo extension - usually
+ // according to its terminal-overrides.
data->unibi_ext.enter_insert_mode = (int)unibi_add_ext_str(ut, NULL,
- TMUX_WRAP("\x1b[5 q"));
+ "\x1b[5 q");
data->unibi_ext.enter_replace_mode = (int)unibi_add_ext_str(ut, NULL,
- TMUX_WRAP("\x1b[3 q"));
+ "\x1b[3 q");
data->unibi_ext.exit_insert_mode = (int)unibi_add_ext_str(ut, NULL,
- TMUX_WRAP("\x1b[2 q"));
+ "\x1b[2 q");
}
end:
diff --git a/src/nvim/version.c b/src/nvim/version.c
index 1d98afaaa1..30f104562f 100644
--- a/src/nvim/version.c
+++ b/src/nvim/version.c
@@ -69,6 +69,16 @@ static char *features[] = {
// clang-format off
static int included_patches[] = {
+ 1137,
+
+
+
+ 1081,
+
+
+
+
+
1055,
// 1054,
// 1053,
@@ -133,7 +143,7 @@ static int included_patches[] = {
// 994 NA
// 993,
// 992 NA
- // 991,
+ 991,
// 990 NA
989,
// 988 NA
@@ -143,10 +153,10 @@ static int included_patches[] = {
// 984,
// 983,
// 982 NA
- // 981,
- // 980,
+ 981,
+ 980,
// 979 NA
- // 978,
+ 978,
// 977,
// 976 NA
975,
@@ -161,7 +171,7 @@ static int included_patches[] = {
// 966 NA
// 965 NA
// 964 NA
- // 963,
+ 963,
// 962 NA
// 961,
// 960 NA
@@ -175,7 +185,7 @@ static int included_patches[] = {
// 952,
// 951,
950,
- // 949,
+ 949,
// 948 NA
// 947,
946,
@@ -371,7 +381,7 @@ static int included_patches[] = {
// 756 NA
// 755,
// 754,
- // 753,
+ 753,
// 752,
// 751 NA
// 750 NA
@@ -385,7 +395,7 @@ static int included_patches[] = {
// 742,
// 741,
// 740,
- // 739,
+ 739,
// 738 NA
// 737,
736,
@@ -395,18 +405,18 @@ static int included_patches[] = {
// 732,
// 731 NA
// 730 NA
- // 729,
+ 729,
// 728 NA
// 727 NA
// 726 NA
// 725,
// 724 NA
723,
- // 722,
+ 722,
721,
// 720 NA
719,
- // 718,
+ 718,
// 717,
716,
715,
@@ -420,13 +430,13 @@ static int included_patches[] = {
707,
706,
// 705 NA
- // 704,
+ 704,
// 703 NA
702,
// 701 NA
// 700,
699,
- // 698,
+ 698,
// 697,
696,
695,
@@ -439,12 +449,12 @@ static int included_patches[] = {
// 688,
// 687 NA
686,
- // 685,
+ 685,
// 684,
// 683 NA
682,
// 681 NA
- // 680,
+ 680,
// 679 NA
// 678 NA
// 677 NA
@@ -468,9 +478,9 @@ static int included_patches[] = {
659,
658,
// 657 NA
- // 656,
+ 656,
655,
- // 654,
+ 654,
653,
// 652 NA
651,
@@ -482,10 +492,10 @@ static int included_patches[] = {
645,
// 644 NA
// 643,
- // 642,
+ 642,
// 641 NA
640,
- // 639,
+ 639,
// 638 NA
637,
636,
@@ -508,7 +518,7 @@ static int included_patches[] = {
// 619 NA
// 618 NA
617,
- // 616,
+ 616,
615,
614,
// 613,
@@ -521,7 +531,7 @@ static int included_patches[] = {
606,
605,
604,
- // 603,
+ 603,
602,
601,
600,
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 71d7556880..2e20d48f90 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -35,7 +35,7 @@ Error: configure did not run properly.Check auto/config.log.
#include "nvim/os/os_defs.h" /* bring lots of system header files */
-#define NUMBUFLEN 30 /* length of a buffer to store a number in ASCII */
+#define NUMBUFLEN 65 // length of a buffer to store a number in ASCII
#define MAX_TYPENR 65535
diff --git a/src/nvim/window.c b/src/nvim/window.c
index 16ff7dfb14..191cb04d75 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -1044,19 +1044,21 @@ static void win_init_some(win_T *newp, win_T *oldp)
}
-/*
- * Check if "win" is a pointer to an existing window.
- */
-int win_valid(win_T *win)
+/// Check if "win" is a pointer to an existing window in the current tabpage.
+///
+/// @param win window to check
+bool win_valid(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- if (win == NULL)
- return FALSE;
+ if (win == NULL) {
+ return false;
+ }
+
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp == win) {
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
/*
@@ -1732,21 +1734,18 @@ close_windows (
shell_new_rows();
}
-/*
- * Return TRUE if the current window is the only window that exists (ignoring
- * "aucmd_win").
- * Returns FALSE if there is a window, possibly in another tab page.
- */
-static int last_window(void)
+/// Check that current window is the last one.
+///
+/// @return true if the current window is the only window that exists, false if
+/// there is another, possibly in another tab page.
+static bool last_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return one_window() && first_tabpage->tp_next == NULL;
}
-/*
- * Return TRUE if there is only one window other than "aucmd_win" in the
- * current tab page.
- */
-bool one_window(void)
+/// Check that current tab page contains no more then one window other than
+/// "aucmd_win".
+bool one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
bool seen_one = false;
@@ -1761,14 +1760,20 @@ bool one_window(void)
return true;
}
-/*
- * Close the possibly last window in a tab page.
- * Returns TRUE when the window was closed already.
- */
-static int close_last_window_tabpage(win_T *win, int free_buf, tabpage_T *prev_curtab)
+/// Close the possibly last window in a tab page.
+///
+/// @param win window to close
+/// @param free_buf whether to free the window's current buffer
+/// @param prev_curtab previous tabpage that will be closed if "win" is the
+/// last window in the tabpage
+///
+/// @return true when the window was closed already.
+static bool close_last_window_tabpage(win_T *win, bool free_buf,
+ tabpage_T *prev_curtab)
+ FUNC_ATTR_NONNULL_ARG(1)
{
if (firstwin != lastwin) {
- return FALSE;
+ return false;
}
buf_T *old_curbuf = curbuf;
@@ -1809,14 +1814,15 @@ static int close_last_window_tabpage(win_T *win, int free_buf, tabpage_T *prev_c
terminal_resize(term, 0, 0);
}
- /* Since goto_tabpage_tp above did not trigger *Enter autocommands, do
- * that now. */
- apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, FALSE, curbuf);
- apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
- apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
- if (old_curbuf != curbuf)
- apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
- return TRUE;
+ // Since goto_tabpage_tp above did not trigger *Enter autocommands, do
+ // that now.
+ apply_autocmds(EVENT_TABCLOSED, prev_idx, prev_idx, false, curbuf);
+ apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
+ apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
+ if (old_curbuf != curbuf) {
+ apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
+ }
+ return true;
}
/*
@@ -1907,9 +1913,16 @@ int win_close(win_T *win, int free_buf)
*/
if (win->w_buffer != NULL) {
win->w_closing = true;
- close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, TRUE);
- if (win_valid(win))
+ close_buffer(win, win->w_buffer, free_buf ? DOBUF_UNLOAD : 0, true);
+ if (win_valid(win)) {
win->w_closing = false;
+ }
+
+ // Make sure curbuf is valid. It can become invalid if 'bufhidden' is
+ // "wipe".
+ if (!buf_valid(curbuf)) {
+ curbuf = firstbuf;
+ }
}
if (only_one_window() && win_valid(win) && win->w_buffer == NULL
@@ -2301,20 +2314,22 @@ static win_T *frame2win(frame_T *frp)
return frp->fr_win;
}
-/*
- * Return TRUE if frame "frp" contains window "wp".
- */
-static int frame_has_win(frame_T *frp, win_T *wp)
+/// Check that the frame "frp" contains the window "wp".
+///
+/// @param frp frame
+/// @param wp window
+static bool frame_has_win(frame_T *frp, win_T *wp)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
{
- frame_T *p;
-
- if (frp->fr_layout == FR_LEAF)
+ if (frp->fr_layout == FR_LEAF) {
return frp->fr_win == wp;
-
- for (p = frp->fr_child; p != NULL; p = p->fr_next)
- if (frame_has_win(p, wp))
- return TRUE;
- return FALSE;
+ }
+ for (frame_T *p = frp->fr_child; p != NULL; p = p->fr_next) {
+ if (frame_has_win(p, wp)) {
+ return true;
+ }
+ }
+ return false;
}
/*
@@ -2406,58 +2421,72 @@ frame_new_height (
topfrp->fr_height = height;
}
-/*
- * Return TRUE if height of frame "frp" should not be changed because of
- * the 'winfixheight' option.
- */
-static int frame_fixed_height(frame_T *frp)
+/// Return true if height of frame "frp" should not be changed because of
+/// the 'winfixheight' option.
+///
+/// @param frp frame
+///
+/// @return true if the frame has a fixed height
+static bool frame_fixed_height(frame_T *frp)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- /* frame with one window: fixed height if 'winfixheight' set. */
- if (frp->fr_win != NULL)
+ // frame with one window: fixed height if 'winfixheight' set.
+ if (frp->fr_win != NULL) {
return frp->fr_win->w_p_wfh;
-
+ }
if (frp->fr_layout == FR_ROW) {
- /* The frame is fixed height if one of the frames in the row is fixed
- * height. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
- if (frame_fixed_height(frp))
- return TRUE;
- return FALSE;
+ // The frame is fixed height if one of the frames in the row is fixed
+ // height.
+ for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ if (frame_fixed_height(frp)) {
+ return true;
+ }
+ }
+ return false;
}
- /* frp->fr_layout == FR_COL: The frame is fixed height if all of the
- * frames in the row are fixed height. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
- if (!frame_fixed_height(frp))
- return FALSE;
- return TRUE;
+ // frp->fr_layout == FR_COL: The frame is fixed height if all of the
+ // frames in the row are fixed height.
+ for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ if (!frame_fixed_height(frp)) {
+ return false;
+ }
+ }
+ return true;
}
-/*
- * Return TRUE if width of frame "frp" should not be changed because of
- * the 'winfixwidth' option.
- */
-static int frame_fixed_width(frame_T *frp)
+/// Return true if width of frame "frp" should not be changed because of
+/// the 'winfixwidth' option.
+///
+/// @param frp frame
+///
+/// @return true if the frame has a fixed width
+static bool frame_fixed_width(frame_T *frp)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- /* frame with one window: fixed width if 'winfixwidth' set. */
- if (frp->fr_win != NULL)
+ // frame with one window: fixed width if 'winfixwidth' set.
+ if (frp->fr_win != NULL) {
return frp->fr_win->w_p_wfw;
-
+ }
if (frp->fr_layout == FR_COL) {
- /* The frame is fixed width if one of the frames in the row is fixed
- * width. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
- if (frame_fixed_width(frp))
- return TRUE;
- return FALSE;
+ // The frame is fixed width if one of the frames in the row is fixed
+ // width.
+ for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ if (frame_fixed_width(frp)) {
+ return true;
+ }
+ }
+ return false;
}
- /* frp->fr_layout == FR_ROW: The frame is fixed width if all of the
- * frames in the row are fixed width. */
- for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next)
- if (!frame_fixed_width(frp))
- return FALSE;
- return TRUE;
+ // frp->fr_layout == FR_ROW: The frame is fixed width if all of the
+ // frames in the row are fixed width.
+ for (frp = frp->fr_child; frp != NULL; frp = frp->fr_next) {
+ if (!frame_fixed_width(frp)) {
+ return false;
+ }
+ }
+ return true;
}
/*
@@ -3028,10 +3057,10 @@ int make_tabpages(int maxcount)
return count - todo;
}
-/*
- * Return TRUE when "tpc" points to a valid tab page.
- */
-bool valid_tabpage(tabpage_T *tpc)
+/// Check that tpc points to a valid tab page.
+///
+/// @param[in] tpc Tabpage to check.
+bool valid_tabpage(tabpage_T *tpc) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
FOR_ALL_TABS(tp) {
if (tp == tpc) {
@@ -4837,17 +4866,15 @@ static void frame_add_height(frame_T *frp, int n)
*/
char_u *grab_file_name(long count, linenr_T *file_lnum)
{
+ int options = FNAME_MESS | FNAME_EXP | FNAME_REL | FNAME_UNESC;
if (VIsual_active) {
size_t len;
char_u *ptr;
if (get_visual_text(NULL, &ptr, &len) == FAIL)
return NULL;
- return find_file_name_in_path(ptr, len,
- FNAME_MESS|FNAME_EXP|FNAME_REL,
- count, curbuf->b_ffname);
+ return find_file_name_in_path(ptr, len, options, count, curbuf->b_ffname);
}
- return file_name_at_cursor(FNAME_MESS|FNAME_HYP|FNAME_EXP|FNAME_REL, count,
- file_lnum);
+ return file_name_at_cursor(options | FNAME_HYP, count, file_lnum);
}
/*
@@ -4918,12 +4945,18 @@ file_name_in_line (
* Also allow "://" when ':' is not in 'isfname'.
*/
len = 0;
- while (vim_isfilec(ptr[len])
- || ((options & FNAME_HYP) && path_is_url((char *)ptr + len)))
- if (has_mbyte)
+ while (vim_isfilec(ptr[len]) || (ptr[len] == '\\' && ptr[len + 1] == ' ')
+ || ((options & FNAME_HYP) && path_is_url((char *)ptr + len))) {
+ if (ptr[len] == '\\' && ptr[len + 1] == ' ') {
+ // Skip over the "\" in "\ ".
+ ++len;
+ }
+ if (has_mbyte) {
len += (size_t)(*mb_ptr2len)(ptr + len);
- else
+ } else {
++len;
+ }
+ }
/*
* If there is trailing punctuation, remove it.
@@ -5048,27 +5081,22 @@ int min_rows(void)
return total;
}
-/*
- * Return TRUE if there is only one window (in the current tab page), not
- * counting a help or preview window, unless it is the current window.
- * Does not count "aucmd_win".
- */
-int only_one_window(void)
+/// Check that there is only one window (and only one tab page), not counting a
+/// help or preview window, unless it is the current window. Does not count
+/// "aucmd_win".
+bool only_one_window(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
- int count = 0;
-
- /* If there is another tab page there always is another window. */
- if (first_tabpage->tp_next != NULL)
- return FALSE;
+ // If there is another tab page there always is another window.
+ if (first_tabpage->tp_next != NULL) {
+ return false;
+ }
+ int count = 0;
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
if (wp->w_buffer != NULL
&& (!((wp->w_buffer->b_help && !curbuf->b_help)
- || wp->w_p_pvw
- ) || wp == curwin)
- && wp != aucmd_win
- ) {
- ++count;
+ || wp->w_p_pvw) || wp == curwin) && wp != aucmd_win) {
+ count++;
}
}
return count <= 1;
@@ -5567,38 +5595,42 @@ matchitem_T *get_match(win_T *wp, int id)
}
-/*
- * Return TRUE if "topfrp" and its children are at the right height.
- */
-static int frame_check_height(frame_T *topfrp, int height)
+/// Check that "topfrp" and its children are at the right height.
+///
+/// @param topfrp top frame pointer
+/// @param height expected height
+static bool frame_check_height(frame_T *topfrp, int height)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- frame_T *frp;
-
- if (topfrp->fr_height != height)
- return FALSE;
-
- if (topfrp->fr_layout == FR_ROW)
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
- if (frp->fr_height != height)
- return FALSE;
-
- return TRUE;
+ if (topfrp->fr_height != height) {
+ return false;
+ }
+ if (topfrp->fr_layout == FR_ROW) {
+ for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ if (frp->fr_height != height) {
+ return false;
+ }
+ }
+ }
+ return true;
}
-/*
- * Return TRUE if "topfrp" and its children are at the right width.
- */
-static int frame_check_width(frame_T *topfrp, int width)
+/// Check that "topfrp" and its children are at the right width.
+///
+/// @param topfrp top frame pointer
+/// @param width expected width
+static bool frame_check_width(frame_T *topfrp, int width)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- frame_T *frp;
-
- if (topfrp->fr_width != width)
- return FALSE;
-
- if (topfrp->fr_layout == FR_COL)
- for (frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next)
- if (frp->fr_width != width)
- return FALSE;
-
- return TRUE;
+ if (topfrp->fr_width != width) {
+ return false;
+ }
+ if (topfrp->fr_layout == FR_COL) {
+ for (frame_T *frp = topfrp->fr_child; frp != NULL; frp = frp->fr_next) {
+ if (frp->fr_width != width) {
+ return false;
+ }
+ }
+ }
+ return true;
}
diff --git a/src/nvim/window.h b/src/nvim/window.h
index eccc7835a8..2ac4c00c28 100644
--- a/src/nvim/window.h
+++ b/src/nvim/window.h
@@ -10,6 +10,7 @@
#define FNAME_INCL 8 /* apply 'includeexpr' */
#define FNAME_REL 16 /* ".." and "./" are relative to the (current)
file instead of the current directory */
+#define FNAME_UNESC 32 // remove backslashes used for escaping
/*
* arguments for win_split()