aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/mbyte.txt3
-rw-r--r--runtime/doc/options.txt16
-rw-r--r--runtime/doc/vim_diff.txt4
-rw-r--r--src/nvim/charset.c10
-rw-r--r--src/nvim/charset.h12
-rw-r--r--src/nvim/cursor.c2
-rw-r--r--src/nvim/edit.c33
-rw-r--r--src/nvim/eval.c132
-rw-r--r--src/nvim/ex_cmds.c7
-rw-r--r--src/nvim/ex_cmds2.c2
-rw-r--r--src/nvim/ex_docmd.c36
-rw-r--r--src/nvim/ex_getln.c6
-rw-r--r--src/nvim/fileio.c4
-rw-r--r--src/nvim/fold.c12
-rw-r--r--src/nvim/getchar.c2
-rw-r--r--src/nvim/globals.h58
-rw-r--r--src/nvim/macros.h16
-rw-r--r--src/nvim/mark.c2
-rw-r--r--src/nvim/mbyte.c30
-rw-r--r--src/nvim/memline.c2
-rw-r--r--src/nvim/menu.c10
-rw-r--r--src/nvim/message.c4
-rw-r--r--src/nvim/misc1.c4
-rw-r--r--src/nvim/mouse.c11
-rw-r--r--src/nvim/ops.c17
-rw-r--r--src/nvim/option.c44
-rw-r--r--src/nvim/option_defs.h7
-rw-r--r--src/nvim/options.lua3
-rw-r--r--src/nvim/path.c65
-rw-r--r--src/nvim/popupmnu.c4
-rw-r--r--src/nvim/regexp.c87
-rw-r--r--src/nvim/regexp_nfa.c34
-rw-r--r--src/nvim/screen.c936
-rw-r--r--src/nvim/search.c36
-rw-r--r--src/nvim/spell.c131
-rw-r--r--src/nvim/spellfile.c45
-rw-r--r--src/nvim/strings.c4
-rw-r--r--src/nvim/syntax.c11
-rw-r--r--src/nvim/undo.c2
-rw-r--r--src/nvim/window.c10
-rw-r--r--test/functional/options/fillchars_spec.lua66
-rw-r--r--test/functional/options/num_options_spec.lua15
-rw-r--r--test/functional/ui/fold_spec.lua5
-rw-r--r--test/functional/ui/output_spec.lua6
44 files changed, 901 insertions, 1045 deletions
diff --git a/runtime/doc/mbyte.txt b/runtime/doc/mbyte.txt
index 2d4a20ed72..d38c4fd019 100644
--- a/runtime/doc/mbyte.txt
+++ b/runtime/doc/mbyte.txt
@@ -1059,8 +1059,7 @@ widespread as file format.
A composing or combining character is used to change the meaning of the
character before it. The combining characters are drawn on top of the
preceding character.
-Up to two combining characters can be used by default. This can be changed
-with the 'maxcombine' option.
+Up to six combining characters can be displayed.
When editing text a composing character is mostly considered part of the
preceding character. For example "x" will delete a character and its
following composing characters by default.
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 7ff1281274..f924003e1f 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2393,6 +2393,7 @@ A jump table for the options with a short description can be found at |Q_op|.
fold:c '·' or '-' filling 'foldtext'
diff:c '-' deleted lines of the 'diff' option
msgsep:c ' ' message separator 'display'
+ eob:c '~' empty lines at the end of a buffer
Any one that is omitted will fall back to the default. For "stl" and
"stlnc" the space will be used when there is highlighting, '^' or '='
@@ -2415,6 +2416,7 @@ A jump table for the options with a short description can be found at |Q_op|.
vert:c VertSplit |hl-VertSplit|
fold:c Folded |hl-Folded|
diff:c DiffDelete |hl-DiffDelete|
+ eob:c EndOfBuffer |hl-EndOfBuffer|
*'fixendofline'* *'fixeol'* *'nofixendofline'* *'nofixeol'*
'fixendofline' 'fixeol' boolean (default on)
@@ -3888,16 +3890,10 @@ A jump table for the options with a short description can be found at |Q_op|.
set a time. This is to be compatible with Nvi.
*'maxcombine'* *'mco'*
-'maxcombine' 'mco' number (default 2)
- global
- {only available when compiled with the |+multi_byte|
- feature}
- The maximum number of combining characters supported for displaying.
- The default is OK for most languages. Hebrew may require 4.
- Maximum value is 6.
- Even when this option is set to 2 you can still edit text with more
- combining characters, you just can't see them. Use |g8| or |ga|.
- See |mbyte-combining|.
+'maxcombine' 'mco' Removed. |vim-differences| {Nvim}
+ Nvim always displays up to 6 combining characters. You can still edit
+ text with more than 6 combining characters, you just can't see them.
+ Use |g8| or |ga|. See |mbyte-combining|.
*'maxfuncdepth'* *'mfd'*
'maxfuncdepth' 'mfd' number (default 100)
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 1af91f24da..5394414947 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -180,7 +180,8 @@ Options:
'cpoptions' flags: |cpo-_|
'display' flag `msgsep` to minimize scrolling when showing messages
'guicursor' works in the terminal
- 'fillchars' flag `msgsep` (see 'display' above)
+ 'fillchars' flags: `msgsep` (see 'display' above)
+ and `eob` for |EndOfBuffer| marker
'inccommand' shows interactive results for |:substitute|-like commands
'scrollback'
'statusline' supports unlimited alignment sections
@@ -409,6 +410,7 @@ Options:
*'macatsui'*
'maxmem' Nvim delegates memory-management to the OS.
'maxmemtot' Nvim delegates memory-management to the OS.
+ 'maxcombine' (6 is always used)
*'restorescreen'* *'rs'* *'norestorescreen'* *'nors'*
'shelltype'
*'shortname'* *'sn'* *'noshortname'* *'nosn'*
diff --git a/src/nvim/charset.c b/src/nvim/charset.c
index 4f70bcc41a..99ced6c8c2 100644
--- a/src/nvim/charset.c
+++ b/src/nvim/charset.c
@@ -804,7 +804,7 @@ unsigned int win_linetabsize(win_T *wp, char_u *line, colnr_T len)
for (char_u *s = line;
*s != NUL && (len == MAXCOL || s < line + len);
- mb_ptr_adv(s)) {
+ MB_PTR_ADV(s)) {
col += win_lbr_chartabsize(wp, line, s, col, NULL);
}
@@ -971,7 +971,7 @@ int lbr_chartabsize_adv(char_u *line, char_u **s, colnr_T col)
int retval;
retval = lbr_chartabsize(line, *s, col);
- mb_ptr_adv(*s);
+ MB_PTR_ADV(*s);
return retval;
}
@@ -1038,7 +1038,7 @@ int win_lbr_chartabsize(win_T *wp, char_u *line, char_u *s, colnr_T col, int *he
for (;;) {
ps = s;
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
c = *s;
if (!(c != NUL
@@ -1283,7 +1283,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
}
vcol += incr;
- mb_ptr_adv(ptr);
+ MB_PTR_ADV(ptr);
}
} else {
for (;;) {
@@ -1304,7 +1304,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor,
}
vcol += incr;
- mb_ptr_adv(ptr);
+ MB_PTR_ADV(ptr);
}
}
diff --git a/src/nvim/charset.h b/src/nvim/charset.h
index eb64b6128a..e657ce19b6 100644
--- a/src/nvim/charset.h
+++ b/src/nvim/charset.h
@@ -5,6 +5,7 @@
#include "nvim/pos.h"
#include "nvim/buffer_defs.h"
#include "nvim/eval/typval.h"
+#include "nvim/option_defs.h"
/// Return the folded-case equivalent of the given character
///
@@ -34,4 +35,15 @@ typedef enum {
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "charset.h.generated.h"
#endif
+
+static inline bool vim_isbreak(int c)
+ REAL_FATTR_CONST
+ REAL_FATTR_ALWAYS_INLINE;
+
+/// Check if `c` is one of the characters in 'breakat'.
+/// Used very often if 'linebreak' is set
+static inline bool vim_isbreak(int c)
+{
+ return breakat_flags[(char_u)c];
+}
#endif // NVIM_CHARSET_H
diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c
index 0e97e2203f..177f167d74 100644
--- a/src/nvim/cursor.c
+++ b/src/nvim/cursor.c
@@ -144,7 +144,7 @@ static int coladvance2(
while (col <= wcol && *ptr != NUL) {
/* Count a tab for what it's worth (if list mode not on) */
csize = win_lbr_chartabsize(curwin, line, ptr, col, &head);
- mb_ptr_adv(ptr);
+ MB_PTR_ADV(ptr);
col += csize;
}
idx = (int)(ptr - line);
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index ccb5d6bac8..c20758cb0b 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -659,7 +659,7 @@ static int insert_execute(VimState *state, int key)
char_u *p;
if (str != NULL) {
- for (p = str; *p != NUL; mb_ptr_adv(p)) {
+ for (p = str; *p != NUL; MB_PTR_ADV(p)) {
ins_compl_addleader(PTR2CHAR(p));
}
xfree(str);
@@ -1197,7 +1197,7 @@ normalchar:
if (str != NULL) {
if (*str != NUL && stop_arrow() != FAIL) {
// Insert the new value of v:char literally.
- for (p = str; *p != NUL; mb_ptr_adv(p)) {
+ for (p = str; *p != NUL; MB_PTR_ADV(p)) {
s->c = PTR2CHAR(p);
if (s->c == CAR || s->c == K_KENTER || s->c == NL) {
ins_eol(s->c);
@@ -2009,8 +2009,8 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
const char_u *p = str;
actual_len = 0;
while (*p != NUL) {
- mb_ptr_adv(p);
- ++actual_len;
+ MB_PTR_ADV(p);
+ actual_len++;
}
} else
actual_len = len;
@@ -2020,8 +2020,8 @@ int ins_compl_add_infercase(char_u *str, int len, int icase, char_u *fname, int
const char_u *p = compl_orig_text;
actual_compl_length = 0;
while (*p != NUL) {
- mb_ptr_adv(p);
- ++actual_compl_length;
+ MB_PTR_ADV(p);
+ actual_compl_length++;
}
} else
actual_compl_length = compl_length;
@@ -2323,8 +2323,8 @@ static void ins_compl_longest_match(compl_T *match)
break;
}
if (has_mbyte) {
- mb_ptr_adv(p);
- mb_ptr_adv(s);
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(s);
} else {
++p;
++s;
@@ -2976,7 +2976,7 @@ static int ins_compl_bs(void)
line = get_cursor_line_ptr();
p = line + curwin->w_cursor.col;
- mb_ptr_back(line, p);
+ MB_PTR_BACK(line, p);
// Stop completion when the whole word was deleted. For Omni completion
// allow the word to be deleted, we won't match everything.
@@ -3442,8 +3442,9 @@ static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
;
if (len > 0)
len -= (*mb_head_off)(p, p + len);
- for (p += len; *p != NUL; mb_ptr_adv(p))
+ for (p += len; *p != NUL; MB_PTR_ADV(p)) {
AppendCharToRedobuff(K_BS);
+ }
} else {
len = 0;
}
@@ -4609,13 +4610,15 @@ static int ins_complete(int c, bool enable_pum)
if (startcol > 0) {
char_u *p = line + startcol;
- mb_ptr_back(line, p);
- while (p > line && vim_isfilec(PTR2CHAR(p)))
- mb_ptr_back(line, p);
- if (p == line && vim_isfilec(PTR2CHAR(p)))
+ MB_PTR_BACK(line, p);
+ while (p > line && vim_isfilec(PTR2CHAR(p))) {
+ MB_PTR_BACK(line, p);
+ }
+ if (p == line && vim_isfilec(PTR2CHAR(p))) {
startcol = 0;
- else
+ } else {
startcol = (int)(p - line) + 1;
+ }
}
compl_col += startcol;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 30c17af8c9..eb437931d4 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -110,8 +110,8 @@
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
-#define AUTOLOAD_CHAR '#' /* Character used as separator in autoload
- function/variable names. */
+// Character used as separator in autoload function/variable names.
+#define AUTOLOAD_CHAR '#'
/*
* Structure returned by get_lval() and used by set_var_lval().
@@ -728,8 +728,8 @@ static char_u *redir_varname = NULL;
* Start recording command output to a variable
* Returns OK if successfully completed the setup. FAIL otherwise.
*/
-int
-var_redir_start (
+int
+var_redir_start(
char_u *name,
int append /* append to an existing variable */
)
@@ -926,8 +926,8 @@ void eval_patch(const char *const origfile, const char *const difffile,
* Sets "error" to TRUE if there was an error.
* Return TRUE or FALSE.
*/
-int
-eval_to_bool (
+int
+eval_to_bool(
char_u *arg,
bool *error,
char_u **nextcmd,
@@ -1503,8 +1503,8 @@ void ex_let(exarg_T *eap)
* or concatenate.
* Returns OK or FAIL;
*/
-static int
-ex_let_vars (
+static int
+ex_let_vars(
char_u *arg_start,
typval_T *tv,
int copy, /* copy values from "tv", don't move */
@@ -2581,9 +2581,10 @@ void set_context_for_expression(expand_T *xp, char_u *arg, cmdidx_T cmdidx)
/* ":let var1 var2 ...": find last space. */
for (p = arg + STRLEN(arg); p >= arg; ) {
xp->xp_pattern = p;
- mb_ptr_back(arg, p);
- if (ascii_iswhite(*p))
+ MB_PTR_BACK(arg, p);
+ if (ascii_iswhite(*p)) {
break;
+ }
}
return;
}
@@ -4307,8 +4308,8 @@ static int eval7(
* "*arg" points to the '[' or '.'.
* Returns FAIL or OK. "*arg" is advanced to after the ']'.
*/
-static int
-eval_index (
+static int
+eval_index(
char_u **arg,
typval_T *rettv,
int evaluate,
@@ -4653,7 +4654,7 @@ static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate)
/*
* Find the end of the string, skipping backslashed characters.
*/
- for (p = *arg + 1; *p != NUL && *p != '"'; mb_ptr_adv(p)) {
+ for (p = *arg + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) {
if (*p == '\\' && p[1] != NUL) {
++p;
/* A "\<x>" form occupies at least 4 characters, and produces up
@@ -4777,7 +4778,7 @@ static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
/*
* Find the end of the string, skipping ''.
*/
- for (p = *arg + 1; *p != NUL; mb_ptr_adv(p)) {
+ for (p = *arg + 1; *p != NUL; MB_PTR_ADV(p)) {
if (*p == '\'') {
if (p[1] != '\'')
break;
@@ -6061,15 +6062,15 @@ static char_u *deref_func_name(const char *name, int *lenp,
* Allocate a variable for the result of a function.
* Return OK or FAIL.
*/
-static int
-get_func_tv (
- char_u *name, /* name of the function */
- int len, /* length of "name" */
+static int
+get_func_tv(
+ char_u *name, // name of the function
+ int len, // length of "name"
typval_T *rettv,
- char_u **arg, /* argument, pointing to the '(' */
- linenr_T firstline, /* first line of range */
- linenr_T lastline, /* last line of range */
- int *doesrange, /* return: function handled range */
+ char_u **arg, // argument, pointing to the '('
+ linenr_T firstline, // first line of range
+ linenr_T lastline, // last line of range
+ int *doesrange, // return: function handled range
int evaluate,
partial_T *partial, // for extra arguments
dict_T *selfdict // Dictionary for "self"
@@ -9961,8 +9962,8 @@ static void f_getmatches(typval_T *argvars, typval_T *rettv, FunPtr fptr)
while (cur != NULL) {
dict_T *dict = tv_dict_alloc();
if (cur->match.regprog == NULL) {
- // match added with matchaddpos()
- for (i = 0; i < MAXPOSMATCH; ++i) {
+ // match added with matchaddpos()
+ for (i = 0; i < MAXPOSMATCH; i++) {
llpos_T *llpos;
char buf[6];
@@ -10380,8 +10381,8 @@ static void f_getwinvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/*
* getwinvar() and gettabwinvar()
*/
-static void
-getwinvar (
+static void
+getwinvar(
typval_T *argvars,
typval_T *rettv,
int off /* 1 for gettabwinvar() */
@@ -13994,10 +13995,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
c = -1;
} else {
off = LineOffset[row] + col;
- if (enc_utf8 && ScreenLinesUC[off] != 0)
- c = ScreenLinesUC[off];
- else
- c = ScreenLines[off];
+ c = utf_ptr2char(ScreenLines[off]);
}
rettv->vval.v_number = c;
}
@@ -14163,17 +14161,17 @@ static void f_searchpairpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
* Used by searchpair(), see its documentation for the details.
* Returns 0 or -1 for no match,
*/
-long
-do_searchpair (
- char_u *spat, /* start pattern */
- char_u *mpat, /* middle pattern */
- char_u *epat, /* end pattern */
- int dir, /* BACKWARD or FORWARD */
- char_u *skip, /* skip expression */
- int flags, /* SP_SETPCMARK and other SP_ values */
+long
+do_searchpair(
+ char_u *spat, // start pattern
+ char_u *mpat, // middle pattern
+ char_u *epat, // end pattern
+ int dir, // BACKWARD or FORWARD
+ char_u *skip, // skip expression
+ int flags, // SP_SETPCMARK and other SP_ values
pos_T *match_pos,
- linenr_T lnum_stop, /* stop at this line if not zero */
- long time_limit /* stop after this many msec */
+ linenr_T lnum_stop, // stop at this line if not zero
+ long time_limit // stop after this many msec
)
{
char_u *save_cpo;
@@ -16401,7 +16399,7 @@ static list_T *string_to_list(const char *str, size_t len, const bool keepempty)
return list;
}
-static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
+static void get_system_output_as_rettv(typval_T *argvars, typval_T *rettv,
bool retlist)
{
rettv->v_type = VAR_STRING;
@@ -18064,16 +18062,17 @@ static const char_u *find_name_end(const char_u *arg, const char_u **expr_start,
|| *p == '{'
|| ((flags & FNE_INCL_BR) && (*p == '[' || *p == '.'))
|| mb_nest != 0
- || br_nest != 0); mb_ptr_adv(p)) {
+ || br_nest != 0); MB_PTR_ADV(p)) {
if (*p == '\'') {
- /* skip over 'string' to avoid counting [ and ] inside it. */
- for (p = p + 1; *p != NUL && *p != '\''; mb_ptr_adv(p))
- ;
- if (*p == NUL)
+ // skip over 'string' to avoid counting [ and ] inside it.
+ for (p = p + 1; *p != NUL && *p != '\''; MB_PTR_ADV(p)) {
+ }
+ if (*p == NUL) {
break;
+ }
} else if (*p == '"') {
// skip over "str\"ing" to avoid counting [ and ] inside it.
- for (p = p + 1; *p != NUL && *p != '"'; mb_ptr_adv(p)) {
+ for (p = p + 1; *p != NUL && *p != '"'; MB_PTR_ADV(p)) {
if (*p == '\\' && p[1] != NUL) {
++p;
}
@@ -20696,8 +20695,8 @@ void func_dump_profile(FILE *fd)
xfree(sorttab);
}
-static void
-prof_sort_list (
+static void
+prof_sort_list(
FILE *fd,
ufunc_T **sorttab,
int st_len,
@@ -21554,8 +21553,8 @@ static int can_free_funccal(funccall_T *fc, int copyID)
/*
* Free "fc" and what it contains.
*/
-static void
-free_funccal (
+static void
+free_funccal(
funccall_T *fc,
int free_val /* a: vars were allocated */
)
@@ -22109,13 +22108,13 @@ void reset_v_option_vars(void)
* Returns VALID_ flags or -1 for failure.
* When there is an error, *fnamep is set to NULL.
*/
-int
-modify_fname (
- char_u *src, /* string with modifiers */
- size_t *usedlen, /* characters after src that are used */
- char_u **fnamep, /* file name so far */
- char_u **bufp, /* buffer for allocated file name or NULL */
- size_t *fnamelen /* length of fnamep */
+int
+modify_fname(
+ char_u *src, // string with modifiers
+ size_t *usedlen, // characters after src that are used
+ char_u **fnamep, // file name so far
+ char_u **bufp, // buffer for allocated file name or NULL
+ size_t *fnamelen // length of fnamep
)
{
int valid = 0;
@@ -22151,15 +22150,16 @@ repeat:
return -1;
}
- /* When "/." or "/.." is used: force expansion to get rid of it. */
- for (p = *fnamep; *p != NUL; mb_ptr_adv(p)) {
+ // When "/." or "/.." is used: force expansion to get rid of it.
+ for (p = *fnamep; *p != NUL; MB_PTR_ADV(p)) {
if (vim_ispathsep(*p)
&& p[1] == '.'
&& (p[2] == NUL
|| vim_ispathsep(p[2])
|| (p[2] == '.'
- && (p[3] == NUL || vim_ispathsep(p[3])))))
+ && (p[3] == NUL || vim_ispathsep(p[3]))))) {
break;
+ }
}
/* FullName_save() is slow, don't use it when not needed. */
@@ -22239,8 +22239,9 @@ repeat:
valid |= VALID_HEAD;
*usedlen += 2;
s = get_past_head(*fnamep);
- while (tail > s && after_pathsep((char *)s, (char *)tail))
- mb_ptr_back(*fnamep, tail);
+ while (tail > s && after_pathsep((char *)s, (char *)tail)) {
+ MB_PTR_BACK(*fnamep, tail);
+ }
*fnamelen = (size_t)(tail - *fnamep);
if (*fnamelen == 0) {
/* Result is empty. Turn it into "." to make ":cd %:h" work. */
@@ -22248,8 +22249,9 @@ repeat:
*bufp = *fnamep = tail = vim_strsave((char_u *)".");
*fnamelen = 1;
} else {
- while (tail > s && !after_pathsep((char *)s, (char *)tail))
- mb_ptr_back(*fnamep, tail);
+ while (tail > s && !after_pathsep((char *)s, (char *)tail)) {
+ MB_PTR_BACK(*fnamep, tail);
+ }
}
}
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 4e0bdb777c..98eda8dcb8 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3269,9 +3269,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
*cmd++ = NUL; /* replace it with a NUL */
break;
}
- if (cmd[0] == '\\' && cmd[1] != 0) /* skip escaped characters */
- ++cmd;
- mb_ptr_adv(cmd);
+ if (cmd[0] == '\\' && cmd[1] != 0) { // skip escaped characters
+ cmd++;
+ }
+ MB_PTR_ADV(cmd);
}
if (!eap->skip && !preview) {
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index e95890adbf..46a7c869e1 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2532,7 +2532,7 @@ static void add_pack_plugin(char_u *fname, void *cookie)
if (cookie != &APP_LOAD && strstr((char *)p_rtp, ffname) == NULL) {
// directory is not yet in 'runtimepath', add it
p4 = p3 = p2 = p1 = get_past_head((char_u *)ffname);
- for (p = p1; *p; mb_ptr_adv(p)) {
+ for (p = p1; *p; MB_PTR_ADV(p)) {
if (vim_ispathsep_nocolon(*p)) {
p4 = p3; p3 = p2; p2 = p1; p1 = p;
}
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 709dc60b13..9590a3715e 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -2872,7 +2872,7 @@ const char * set_one_cmd_context(
return NULL; /* It's a comment */
}
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
}
@@ -2890,9 +2890,10 @@ const char * set_one_cmd_context(
// Argument starts after a space.
xp->xp_pattern = (char_u *)++p;
} else {
- if (*p == '\\' && *(p + 1) != NUL)
- ++p; /* skip over escaped character */
- mb_ptr_adv(p);
+ if (*p == '\\' && *(p + 1) != NUL) {
+ p++; // skip over escaped character
+ }
+ MB_PTR_ADV(p);
}
}
@@ -2943,7 +2944,7 @@ const char * set_one_cmd_context(
} else {
len = 1;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
if (in_quote) {
bow = p;
@@ -2952,7 +2953,7 @@ const char * set_one_cmd_context(
}
p -= len;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
/*
@@ -3336,12 +3337,13 @@ const char * set_one_cmd_context(
// Find start of last argument.
p = arg;
while (*p) {
- if (*p == ' ')
- /* argument starts after a space */
+ if (*p == ' ') {
+ // argument starts after a space
arg = p + 1;
- else if (*p == '\\' && *(p + 1) != NUL)
- ++p; /* skip over escaped character */
- mb_ptr_adv(p);
+ } else if (*p == '\\' && *(p + 1) != NUL) {
+ p++; // skip over escaped character
+ }
+ MB_PTR_ADV(p);
}
xp->xp_pattern = (char_u *)arg;
}
@@ -4238,7 +4240,7 @@ void separate_nextcmd(exarg_T *eap)
p = skip_grep_pat(eap);
- for (; *p; mb_ptr_adv(p)) {
+ for (; *p; MB_PTR_ADV(p)) {
if (*p == Ctrl_V) {
if (eap->argt & (USECTRLV | XFILE))
++p; /* skip CTRL-V and next char */
@@ -4322,7 +4324,7 @@ skip_cmd_arg (
else
++p;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
return p;
}
@@ -9486,10 +9488,12 @@ static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp)
char_u *sname = home_replace_save(NULL, name);
if (*flagp & SSOP_SLASH) {
- /* change all backslashes to forward slashes */
- for (p = sname; *p != NUL; mb_ptr_adv(p))
- if (*p == '\\')
+ // change all backslashes to forward slashes
+ for (p = sname; *p != NUL; MB_PTR_ADV(p)) {
+ if (*p == '\\') {
*p = '/';
+ }
+ }
}
// Escape special characters.
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index d2db309c4f..9b1dcfcafb 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -2934,7 +2934,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line)
Array content = ARRAY_DICT_INIT;
if (cmdline_star) {
size_t len = 0;
- for (char_u *p = ccline.cmdbuff; *p; mb_ptr_adv(p)) {
+ for (char_u *p = ccline.cmdbuff; *p; MB_PTR_ADV(p)) {
len++;
}
char *buf = xmallocz(len);
@@ -4254,7 +4254,7 @@ char_u *sm_gettail(char_u *s)
t = p;
had_sep = FALSE;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
return t;
}
@@ -5179,7 +5179,7 @@ static int ExpandRTDir(char_u *pat, int flags, int *num_file, char_u ***file,
char_u *e = s + STRLEN(s);
if (e - s > 4 && STRNICMP(e - 4, ".vim", 4) == 0) {
e -= 4;
- for (s = e; s > match; mb_ptr_back(match, s)) {
+ for (s = e; s > match; MB_PTR_BACK(match, s)) {
if (vim_ispathsep(*s)) {
break;
}
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 0417c3daed..3b6a3a7995 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -4404,7 +4404,7 @@ char *modname(const char *fname, const char *ext, bool prepend_dot)
// Search backwards until we hit a '/', '\' or ':'.
// Then truncate what is after the '/', '\' or ':' to BASENAMELEN characters.
char *ptr = NULL;
- for (ptr = retval + fnamelen; ptr > retval; mb_ptr_back(retval, ptr)) {
+ for (ptr = retval + fnamelen; ptr > retval; MB_PTR_BACK(retval, ptr)) {
if (vim_ispathsep(*ptr)) {
ptr++;
break;
@@ -6653,7 +6653,7 @@ bool trigger_cursorhold(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
/// Return true if "event" autocommand is defined.
///
/// @param event the autocommand to check
-bool has_event(int event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
+bool has_event(event_T event) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return first_autopat[event] != NULL;
}
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 282b72b67a..aea7cdd302 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -1883,7 +1883,7 @@ void foldtext_cleanup(char_u *str)
++len;
STRMOVE(s, s + len);
} else {
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
}
}
}
@@ -3054,10 +3054,12 @@ static void foldlevelMarker(fline_T *flp)
if (flp->lvl_next > start_lvl)
flp->lvl_next = start_lvl;
}
- } else
- --flp->lvl_next;
- } else
- mb_ptr_adv(s);
+ } else {
+ flp->lvl_next--;
+ }
+ } else {
+ MB_PTR_ADV(s);
+ }
}
/* The level can't go negative, must be missing a start marker. */
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 690a83af50..1c0464b575 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -4249,7 +4249,7 @@ static bool typebuf_match_len(const uint8_t *str, int *mlen)
mapblock_T *get_maphash(int index, buf_T *buf)
FUNC_ATTR_PURE
{
- if (index > MAX_MAPHASH) {
+ if (index >= MAX_MAPHASH) {
return NULL;
}
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 51bc3f1289..d9103f516c 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -131,38 +131,39 @@ typedef off_t off_T;
/*
* The characters and attributes cached for the screen.
*/
-typedef char_u schar_T;
-typedef unsigned short sattr_T;
-
-/*
- * The characters that are currently on the screen are kept in ScreenLines[].
- * It is a single block of characters, the size of the screen plus one line.
- * The attributes for those characters are kept in ScreenAttrs[].
- *
- * "LineOffset[n]" is the offset from ScreenLines[] for the start of line 'n'.
- * The same value is used for ScreenLinesUC[] and ScreenAttrs[].
- *
- * Note: before the screen is initialized and when out of memory these can be
- * NULL.
- */
+typedef char_u schar_T[(MAX_MCO+1) * 4 + 1];
+typedef int16_t sattr_T;
+
+/// ScreenLines[] contains a copy of the whole screen, as it currently is
+/// displayed. It is a single block of screen cells, the size of the screen
+/// plus one line. The extra line used as a buffer while redrawing a window
+/// line, so it can be compared with the previous state of that line. This way
+/// we can avoid sending bigger updates than neccessary to the Ul layer.
+///
+/// Screen cells are stored as NUL-terminated UTF-8 strings, and a cell can
+/// contain up to MAX_MCO composing characters after the base character.
+/// The composing characters are to be drawn on top of the original character.
+/// The content after the NUL is not defined (so comparison must be done a
+/// single cell at a time). Double-width characters are stored in the left cell,
+/// and the right cell should only contain the empty string. When a part of the
+/// screen is cleared, the cells should be filled with a single whitespace char.
+///
+/// ScreenAttrs[] contains the highlighting attribute for each cell.
+/// LineOffset[n] is the offset from ScreenLines[] and ScreenAttrs[] for the
+/// start of line 'n'. These offsets are in general not linear, as full screen
+/// scrolling is implemented by rotating the offsets in the LineOffset array.
+/// LineWraps[] is an array of boolean flags indicating if the screen line wraps
+/// to the next line. It can only be true if a window occupies the entire screen
+/// width.
+///
+///
+/// Note: before the screen is initialized and when out of memory these can be
+/// NULL.
EXTERN schar_T *ScreenLines INIT(= NULL);
EXTERN sattr_T *ScreenAttrs INIT(= NULL);
EXTERN unsigned *LineOffset INIT(= NULL);
EXTERN char_u *LineWraps INIT(= NULL); /* line wraps to next line */
-/*
- * When using Unicode characters (in UTF-8 encoding) the character in
- * ScreenLinesUC[] contains the Unicode for the character at this position, or
- * NUL when the character in ScreenLines[] is to be used (ASCII char).
- * The composing characters are to be drawn on top of the original character.
- * ScreenLinesC[0][off] is only to be used when ScreenLinesUC[off] != 0.
- * Note: These three are only allocated when enc_utf8 is set!
- */
-EXTERN u8char_T *ScreenLinesUC INIT(= NULL); /* decoded UTF-8 characters */
-EXTERN u8char_T *ScreenLinesC[MAX_MCO]; /* composing characters */
-EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when
- allocating ScreenLinesC[] */
-
EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */
EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */
@@ -871,8 +872,6 @@ enum {
};
-EXTERN char breakat_flags[256]; /* which characters are in 'breakat' */
-
/*
* Some file names are stored in pathdef.c, which is generated from the
* Makefile to make their value depend on the Makefile.
@@ -907,6 +906,7 @@ EXTERN int fill_vert INIT(= 9474); // │
EXTERN int fill_fold INIT(= 183); // ·
EXTERN int fill_diff INIT(= '-');
EXTERN int fill_msgsep INIT(= ' ');
+EXTERN int fill_eob INIT(= '~');
/* Whether 'keymodel' contains "stopsel" and "startsel". */
EXTERN int km_stopsel INIT(= FALSE);
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 348df2d9b6..7eb58bea2a 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -82,12 +82,6 @@
} \
} while (0)
-/*
- * vim_isbreak() is used very often if 'linebreak' is set, use a macro to make
- * it work fast.
- */
-#define vim_isbreak(c) (breakat_flags[(char_u)(c)])
-
#define WRITEBIN "wb" /* no CR-LF translation */
#define READBIN "rb"
#define APPENDBIN "ab"
@@ -110,9 +104,9 @@
/* Whether to draw the vertical bar on the right side of the cell. */
# define CURSOR_BAR_RIGHT (curwin->w_p_rl && (!(State & CMDLINE) || cmdmsg_rl))
-// mb_ptr_adv(): advance a pointer to the next character, taking care of
+// MB_PTR_ADV(): advance a pointer to the next character, taking care of
// multi-byte characters if needed.
-// mb_ptr_back(): backup a pointer to the previous character, taking care of
+// MB_PTR_BACK(): backup a pointer to the previous character, taking care of
// multi-byte characters if needed.
// MB_COPY_CHAR(f, t): copy one char from "f" to "t" and advance the pointers.
// PTR2CHAR(): get character from pointer.
@@ -120,11 +114,11 @@
// Get the length of the character p points to
# define MB_PTR2LEN(p) mb_ptr2len(p)
// Advance multi-byte pointer, skip over composing chars.
-# define mb_ptr_adv(p) (p += mb_ptr2len((char_u *)p))
+# define MB_PTR_ADV(p) (p += mb_ptr2len((char_u *)p))
// Advance multi-byte pointer, do not skip over composing chars.
-# define mb_cptr_adv(p) (p += utf_ptr2len(p))
+# define MB_CPTR_ADV(p) (p += utf_ptr2len(p))
// Backup multi-byte pointer. Only use with "p" > "s" !
-# define mb_ptr_back(s, p) (p -= mb_head_off((char_u *)s, (char_u *)p - 1) + 1)
+# define MB_PTR_BACK(s, p) (p -= mb_head_off((char_u *)s, (char_u *)p - 1) + 1)
// get length of multi-byte char, not including composing chars
# define MB_CPTR2LEN(p) utf_ptr2len(p)
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 7cfe3f4a18..49e60b5166 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -603,7 +603,7 @@ static char_u *mark_line(pos_T *mp, int lead_len)
/* Truncate the line to fit it in the window */
len = 0;
- for (p = s; *p != NUL; mb_ptr_adv(p)) {
+ for (p = s; *p != NUL; MB_PTR_ADV(p)) {
len += ptr2cells(p);
if (len >= Columns - lead_len)
break;
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 05e326104b..a8781ffbb8 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -560,7 +560,7 @@ size_t mb_string2cells(const char_u *str)
/// We make sure that the offset used is less than "max_off".
int utf_off2cells(unsigned off, unsigned max_off)
{
- return (off + 1 < max_off && ScreenLines[off + 1] == 0) ? 2 : 1;
+ return (off + 1 < max_off && ScreenLines[off + 1][0] == 0) ? 2 : 1;
}
/// Convert a UTF-8 byte sequence to a wide character
@@ -790,27 +790,6 @@ int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen)
#undef ISCOMPOSING
}
-/*
- * Convert the character at screen position "off" to a sequence of bytes.
- * Includes the composing characters.
- * "buf" must at least have the length MB_MAXBYTES + 1.
- * Only to be used when ScreenLinesUC[off] != 0.
- * Returns the produced number of bytes.
- */
-int utfc_char2bytes(int off, char_u *buf)
-{
- int len;
- int i;
-
- len = utf_char2bytes(ScreenLinesUC[off], buf);
- for (i = 0; i < Screen_mco; ++i) {
- if (ScreenLinesC[i][off] == 0)
- break;
- len += utf_char2bytes(ScreenLinesC[i][off], buf + len);
- }
- return len;
-}
-
/// Get the length of a UTF-8 byte sequence representing a single codepoint
///
/// @param[in] p UTF-8 string.
@@ -1743,8 +1722,9 @@ char_u * mb_prevptr(
char_u *p
)
{
- if (p > line)
- mb_ptr_back(line, p);
+ if (p > line) {
+ MB_PTR_BACK(line, p);
+ }
return p;
}
@@ -1853,7 +1833,7 @@ int mb_fix_col(int col, int row)
col = check_col(col);
row = check_row(row);
if (ScreenLines != NULL && col > 0
- && ScreenLines[LineOffset[row] + col] == 0) {
+ && ScreenLines[LineOffset[row] + col][0] == 0) {
return col - 1;
}
return col;
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 0449af1e2b..b156f2c513 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -1432,7 +1432,7 @@ static char *make_percent_swname(const char *dir, char *name)
char *f = fix_fname(name != NULL ? name : "");
if (f != NULL) {
char *s = xstrdup(f);
- for (d = s; *d != NUL; mb_ptr_adv(d)) {
+ for (d = s; *d != NUL; MB_PTR_ADV(d)) {
if (vim_ispathsep(*d)) {
*d = '%';
}
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 1bbd07686b..968962c894 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -97,7 +97,7 @@ ex_menu(exarg_T *eap)
while (*arg != NUL && *arg != ' ') {
if (*arg == '\\')
STRMOVE(arg, arg + 1);
- mb_ptr_adv(arg);
+ MB_PTR_ADV(arg);
}
if (*arg != NUL) {
*arg++ = NUL;
@@ -1099,7 +1099,7 @@ char_u *menu_name_skip(char_u *const name)
{
char_u *p;
- for (p = name; *p && *p != '.'; mb_ptr_adv(p)) {
+ for (p = name; *p && *p != '.'; MB_PTR_ADV(p)) {
if (*p == '\\' || *p == Ctrl_V) {
STRMOVE(p, p + 1);
if (*p == NUL)
@@ -1549,9 +1549,11 @@ static void menu_unescape_name(char_u *name)
{
char_u *p;
- for (p = name; *p && *p != '.'; mb_ptr_adv(p))
- if (*p == '\\')
+ for (p = name; *p && *p != '.'; MB_PTR_ADV(p)) {
+ if (*p == '\\') {
STRMOVE(p, p + 1);
+ }
+ }
}
/*
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 7935bcbc2f..2643d644a9 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -2935,7 +2935,7 @@ static char_u * console_dialog_alloc(const char_u *message,
}
// Advance to the next character
- mb_ptr_adv(r);
+ MB_PTR_ADV(r);
}
len += (int)(STRLEN(message)
@@ -3053,7 +3053,7 @@ static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons,
}
// advance to the next character
- mb_ptr_adv(r);
+ MB_PTR_ADV(r);
}
*msgp++ = ':';
diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c
index a5da9d3220..5678360ef0 100644
--- a/src/nvim/misc1.c
+++ b/src/nvim/misc1.c
@@ -531,7 +531,7 @@ open_line (
int l;
while (old_size < repl_size && p > leader) {
- mb_ptr_back(leader, p);
+ MB_PTR_BACK(leader, p);
old_size += ptr2cells(p);
}
l = lead_repl_len - (int)(endp - p);
@@ -1311,7 +1311,7 @@ int plines_win_col(win_T *wp, linenr_T lnum, long column)
colnr_T col = 0;
while (*s != NUL && --column >= 0) {
col += win_lbr_chartabsize(wp, line, s, col, NULL);
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
}
// If *s is a TAB, and the TAB is not displayed as ^I, and we're not in
diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c
index 6f636f643a..8c615f52e7 100644
--- a/src/nvim/mouse.c
+++ b/src/nvim/mouse.c
@@ -108,12 +108,13 @@ retnomove:
goto retnomove; // ugly goto...
// Remember the character under the mouse, it might be a '-' or '+' in the
- // fold column.
+ // fold column. NB: only works for ASCII chars!
if (row >= 0 && row < Rows && col >= 0 && col <= Columns
- && ScreenLines != NULL)
- mouse_char = ScreenLines[LineOffset[row] + (unsigned)col];
- else
+ && ScreenLines != NULL) {
+ mouse_char = ScreenLines[LineOffset[row] + (unsigned)col][0];
+ } else {
mouse_char = ' ';
+ }
old_curwin = curwin;
old_cursor = curwin->w_cursor;
@@ -525,7 +526,7 @@ static colnr_T scroll_line_len(linenr_T lnum)
if (*line != NUL) {
for (;;) {
int numchar = chartabsize(line, col);
- mb_ptr_adv(line);
+ MB_PTR_ADV(line);
if (*line == NUL) { // don't count the last character
break;
}
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 45de76f80a..c95345f9b2 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -406,8 +406,9 @@ static void shift_block(oparg_T *oap, int amount)
/* If "bd.startspaces" is set, "bd.textstart" points to the character,
* the part of which is displayed at the block's beginning. Let's start
* searching from the next character. */
- if (bd.startspaces)
- mb_ptr_adv(non_white);
+ if (bd.startspaces) {
+ MB_PTR_ADV(non_white);
+ }
/* The character's column is in "bd.start_vcol". */
non_white_col = bd.start_vcol;
@@ -443,7 +444,7 @@ static void shift_block(oparg_T *oap, int amount)
if (verbatim_copy_width + incr > destination_col)
break;
verbatim_copy_width += incr;
- mb_ptr_adv(verbatim_copy_end);
+ MB_PTR_ADV(verbatim_copy_end);
}
/* If "destination_col" is different from the width of the initial
@@ -2820,7 +2821,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
char_u *p = get_cursor_pos_ptr();
if (dir == FORWARD && *p != NUL) {
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
ptr = vim_strsave(p);
ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, false);
@@ -2829,7 +2830,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
oldp = get_cursor_line_ptr();
p = oldp + curwin->w_cursor.col;
if (dir == FORWARD && *p != NUL) {
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
ptr = vim_strnsave(oldp, (size_t)(p - oldp));
ml_replace(curwin->w_cursor.lnum, ptr, false);
@@ -3632,10 +3633,10 @@ int do_join(size_t count,
if (insert_space && currsize > 0) {
if (has_mbyte) {
cend = curr + currsize;
- mb_ptr_back(curr, cend);
+ MB_PTR_BACK(curr, cend);
endcurr1 = (*mb_ptr2char)(cend);
if (cend > curr) {
- mb_ptr_back(curr, cend);
+ MB_PTR_BACK(curr, cend);
endcurr2 = (*mb_ptr2char)(cend);
}
} else {
@@ -4272,7 +4273,7 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i
bdp->pre_whitesp_c = 0;
}
prev_pstart = pstart;
- mb_ptr_adv(pstart);
+ MB_PTR_ADV(pstart);
}
bdp->start_char_vcols = incr;
if (bdp->start_vcol < oap->start_vcol) { /* line too short */
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 882289c8b8..0851e6cc5f 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -2830,7 +2830,7 @@ did_set_string_option (
for (s = p_sbr; *s; ) {
if (ptr2cells(s) != 1)
errmsg = (char_u *)N_("E595: contains unprintable or wide character");
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
}
}
@@ -3386,6 +3386,7 @@ static char_u *set_chars_option(char_u **varp)
{ &fill_fold, "fold" , 183 }, // ·
{ &fill_diff, "diff" , '-' },
{ &fill_msgsep, "msgsep", ' ' },
+ { &fill_eob, "eob", '~' },
};
static struct charstab lcstab[] = {
{ &lcs_eol, "eol", NUL },
@@ -3437,16 +3438,20 @@ static char_u *set_chars_option(char_u **varp)
&& p[len] == ':'
&& p[len + 1] != NUL) {
s = p + len + 1;
- c1 = mb_ptr2char_adv((const char_u **)&s);
- if (mb_char2cells(c1) > 1) {
+
+ // TODO(bfredl): use schar_T representation and utfc_ptr2len
+ int c1len = utf_ptr2len(s);
+ c1 = mb_cptr2char_adv((const char_u **)&s);
+ if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
continue;
}
if (tab[i].cp == &lcs_tab2) {
if (*s == NUL) {
continue;
}
- c2 = mb_ptr2char_adv((const char_u **)&s);
- if (mb_char2cells(c2) > 1) {
+ int c2len = utf_ptr2len(s);
+ c2 = mb_cptr2char_adv((const char_u **)&s);
+ if (mb_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
continue;
}
}
@@ -4102,11 +4107,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
errmsg = e_winwidth;
}
} else if (pp == &p_mco) {
- if (value > MAX_MCO) {
- errmsg = e_invarg;
- } else if (value < 0) {
- errmsg = e_positive;
- }
+ value = MAX_MCO;
} else if (pp == &p_titlelen) {
if (value < 0) {
errmsg = e_positive;
@@ -4268,8 +4269,6 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
if (pp == &curbuf->b_p_sw || curbuf->b_p_sw == 0) {
parse_cino(curbuf);
}
- } else if (pp == &p_mco) {
- screenclear(); // will re-allocate the screen
} else if (pp == &curbuf->b_p_iminsert) {
showmode();
// Show/unshow value of 'keymap' in status lines.
@@ -6210,13 +6209,15 @@ void ExpandOldSetting(int *num_file, char_u ***file)
#ifdef BACKSLASH_IN_FILENAME
/* For MS-Windows et al. we don't double backslashes at the start and
* before a file name character. */
- for (var = buf; *var != NUL; mb_ptr_adv(var))
+ for (var = buf; *var != NUL; MB_PTR_ADV(var)) {
if (var[0] == '\\' && var[1] == '\\'
&& expand_option_idx >= 0
&& (options[expand_option_idx].flags & P_EXPAND)
&& vim_isfilec(var[2])
- && (var[2] != '\\' || (var == buf && var[4] != '\\')))
+ && (var[2] != '\\' || (var == buf && var[4] != '\\'))) {
STRMOVE(var, var + 1);
+ }
+ }
#endif
*file[0] = buf;
@@ -6384,9 +6385,10 @@ static void langmap_set(void)
for (p = p_langmap; p[0] != NUL; ) {
for (p2 = p; p2[0] != NUL && p2[0] != ',' && p2[0] != ';';
- mb_ptr_adv(p2)) {
- if (p2[0] == '\\' && p2[1] != NUL)
- ++p2;
+ MB_PTR_ADV(p2)) {
+ if (p2[0] == '\\' && p2[1] != NUL) {
+ p2++;
+ }
}
if (p2[0] == ';')
++p2; /* abcd;ABCD form, p2 points to A */
@@ -6402,7 +6404,7 @@ static void langmap_set(void)
from = (*mb_ptr2char)(p);
to = NUL;
if (p2 == NULL) {
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
if (p[0] != ',') {
if (p[0] == '\\')
++p;
@@ -6428,10 +6430,10 @@ static void langmap_set(void)
langmap_mapchar[from & 255] = (char_u)to;
}
- /* Advance to next pair */
- mb_ptr_adv(p);
+ // Advance to next pair
+ MB_PTR_ADV(p);
if (p2 != NULL) {
- mb_ptr_adv(p2);
+ MB_PTR_ADV(p2);
if (*p == ';') {
p = p2;
if (p[0] != NUL) {
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index f7dfa65053..6a0d0e32e0 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -314,9 +314,10 @@ static char *(p_bkc_values[]) =
# define BKC_NO 0x004
# define BKC_BREAKSYMLINK 0x008
# define BKC_BREAKHARDLINK 0x010
-EXTERN char_u *p_bdir; /* 'backupdir' */
-EXTERN char_u *p_bex; /* 'backupext' */
-EXTERN char_u *p_bo; // 'belloff'
+EXTERN char_u *p_bdir; // 'backupdir'
+EXTERN char_u *p_bex; // 'backupext'
+EXTERN char_u *p_bo; // 'belloff'
+EXTERN char breakat_flags[256]; // which characters are in 'breakat'
EXTERN unsigned bo_flags;
# ifdef IN_OPTION_C
static char *(p_bo_values[]) = {"all", "backspace", "cursor", "complete",
diff --git a/src/nvim/options.lua b/src/nvim/options.lua
index 47c9f5aa78..30ddb977bb 100644
--- a/src/nvim/options.lua
+++ b/src/nvim/options.lua
@@ -1493,9 +1493,8 @@ return {
full_name='maxcombine', abbreviation='mco',
type='number', scope={'global'},
vi_def=true,
- redraw={'curswant'},
varname='p_mco',
- defaults={if_true={vi=2}}
+ defaults={if_true={vi=6}}
},
{
full_name='maxfuncdepth', abbreviation='mfd',
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 61cfaea84a..b1e1bf3b2f 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -101,7 +101,7 @@ char_u *path_tail(const char_u *fname)
if (vim_ispathsep_nocolon(*p)) {
tail = p + 1;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
return (char_u *)tail;
}
@@ -144,7 +144,7 @@ const char_u *invocation_path_tail(const char_u *invocation, size_t *len)
const char_u *p = tail;
while (*p != NUL && *p != ' ') {
bool was_sep = vim_ispathsep_nocolon(*p);
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
if (was_sep) {
tail = p; // Now tail points one past the separator.
}
@@ -166,7 +166,7 @@ const char *path_next_component(const char *fname)
{
assert(fname != NULL);
while (*fname != NUL && !vim_ispathsep(*fname)) {
- mb_ptr_adv(fname);
+ MB_PTR_ADV(fname);
}
if (*fname != NUL) {
fname++;
@@ -468,7 +468,7 @@ char_u *save_abs_path(const char_u *name)
bool path_has_wildcard(const char_u *p)
FUNC_ATTR_NONNULL_ALL
{
- for (; *p; mb_ptr_adv(p)) {
+ for (; *p; MB_PTR_ADV(p)) {
#if defined(UNIX)
if (p[0] == '\\' && p[1] != NUL) {
p++;
@@ -503,7 +503,7 @@ static int pstrcmp(const void *a, const void *b)
bool path_has_exp_wildcard(const char_u *p)
FUNC_ATTR_NONNULL_ALL
{
- for (; *p != NUL; mb_ptr_adv(p)) {
+ for (; *p != NUL; MB_PTR_ADV(p)) {
#if defined(UNIX)
if (p[0] == '\\' && p[1] != NUL) {
p++;
@@ -744,7 +744,7 @@ static int find_previous_pathsep(char_u *path, char_u **psep)
while (*psep > path) {
if (vim_ispathsep(**psep))
return OK;
- mb_ptr_back(path, *psep);
+ MB_PTR_BACK(path, *psep);
}
return FAIL;
@@ -859,10 +859,12 @@ static char_u *get_path_cutoff(char_u *fname, garray_T *gap)
}
}
- /* skip to the file or directory name */
- if (cutoff != NULL)
- while (vim_ispathsep(*cutoff))
- mb_ptr_adv(cutoff);
+ // skip to the file or directory name
+ if (cutoff != NULL) {
+ while (vim_ispathsep(*cutoff)) {
+ MB_PTR_ADV(cutoff);
+ }
+ }
return cutoff;
}
@@ -1038,7 +1040,7 @@ const char *gettail_dir(const char *const fname)
dir_end = next_dir_end;
look_for_sep = true;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
return dir_end;
}
@@ -1085,13 +1087,12 @@ expand_in_path (
*/
static bool has_env_var(char_u *p)
{
- for (; *p; mb_ptr_adv(p)) {
- if (*p == '\\' && p[1] != NUL)
- ++p;
- else if (vim_strchr((char_u *)
- "$"
- , *p) != NULL)
+ for (; *p; MB_PTR_ADV(p)) {
+ if (*p == '\\' && p[1] != NUL) {
+ p++;
+ } else if (vim_strchr((char_u *) "$" , *p) != NULL) {
return true;
+ }
}
return false;
}
@@ -1102,7 +1103,7 @@ static bool has_env_var(char_u *p)
// cannot expand, requires using a shell.
static bool has_special_wildchar(char_u *p)
{
- for (; *p; mb_ptr_adv(p)) {
+ for (; *p; MB_PTR_ADV(p)) {
// Allow for escaping
if (*p == '\\' && p[1] != NUL) {
p++;
@@ -1343,7 +1344,7 @@ void slash_adjust(char_u *p)
if (*p == (char_u)psepcN) {
*p = (char_u)psepc;
}
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
}
#endif
@@ -1444,19 +1445,22 @@ void simplify_filename(char_u *filename)
* we are after "start", or strip "." if we are at the beginning
* of an absolute path name . */
tail = p + 1;
- if (p[1] != NUL)
- while (vim_ispathsep(*tail))
- mb_ptr_adv(tail);
- else if (p > start)
- --p; /* strip preceding path separator */
+ if (p[1] != NUL) {
+ while (vim_ispathsep(*tail)) {
+ MB_PTR_ADV(tail);
+ }
+ } else if (p > start) {
+ p--; // strip preceding path separator
+ }
STRMOVE(p, tail);
}
} else if (p[0] == '.' && p[1] == '.'
&& (vim_ispathsep(p[2]) || p[2] == NUL)) {
// Skip to after ".." or "../" or "..///".
tail = p + 2;
- while (vim_ispathsep(*tail))
- mb_ptr_adv(tail);
+ while (vim_ispathsep(*tail)) {
+ MB_PTR_ADV(tail);
+ }
if (components > 0) { /* strip one preceding component */
bool do_strip = false;
@@ -1475,10 +1479,11 @@ void simplify_filename(char_u *filename)
}
p[-1] = saved_char;
- --p;
- /* Skip back to after previous '/'. */
- while (p > start && !after_pathsep((char *)start, (char *)p))
- mb_ptr_back(start, p);
+ p--;
+ // Skip back to after previous '/'.
+ while (p > start && !after_pathsep((char *)start, (char *)p)) {
+ MB_PTR_BACK(start, p);
+ }
if (!do_strip) {
/* If the component exists in the file system, check
diff --git a/src/nvim/popupmnu.c b/src/nvim/popupmnu.c
index 4c2fc6d906..1182d3d902 100644
--- a/src/nvim/popupmnu.c
+++ b/src/nvim/popupmnu.c
@@ -374,7 +374,7 @@ void pum_redraw(void)
}
if (p != NULL) {
- for (;; mb_ptr_adv(p)) {
+ for (;; MB_PTR_ADV(p)) {
if (s == NULL) {
s = p;
}
@@ -398,7 +398,7 @@ void pum_redraw(void)
if (size > pum_width) {
do {
size -= has_mbyte ? (*mb_ptr2cells)(rt) : 1;
- mb_ptr_adv(rt);
+ MB_PTR_ADV(rt);
} while (size > pum_width);
if (size < pum_width) {
diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c
index ef02b6529c..d76da62c6d 100644
--- a/src/nvim/regexp.c
+++ b/src/nvim/regexp.c
@@ -1142,24 +1142,28 @@ static char_u *skip_anyof(char_u *p)
if (*p == ']' || *p == '-')
++p;
while (*p != NUL && *p != ']') {
- if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
+ if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) {
p += l;
- else if (*p == '-') {
- ++p;
- if (*p != ']' && *p != NUL)
- mb_ptr_adv(p);
+ } else if (*p == '-') {
+ p++;
+ if (*p != ']' && *p != NUL) {
+ MB_PTR_ADV(p);
+ }
} else if (*p == '\\'
&& (vim_strchr(REGEXP_INRANGE, p[1]) != NULL
- || (!reg_cpo_lit && vim_strchr(REGEXP_ABBR, p[1]) != NULL)))
+ || (!reg_cpo_lit
+ && vim_strchr(REGEXP_ABBR, p[1]) != NULL))) {
p += 2;
- else if (*p == '[') {
+ } else if (*p == '[') {
if (get_char_class(&p) == CLASS_NONE
&& get_equi_class(&p) == 0
&& get_coll_element(&p) == 0
- && *p != NUL)
- ++p; /* It is not a class name and not NUL */
- } else
- ++p;
+ && *p != NUL) {
+ p++; // It is not a class name and not NUL
+ }
+ } else {
+ p++;
+ }
}
return p;
@@ -1185,9 +1189,10 @@ char_u *skip_regexp(char_u *startp, int dirc, int magic, char_u **newp)
mymagic = MAGIC_OFF;
get_cpo_flags();
- for (; p[0] != NUL; mb_ptr_adv(p)) {
- if (p[0] == dirc) /* found end of regexp */
+ for (; p[0] != NUL; MB_PTR_ADV(p)) {
+ if (p[0] == dirc) { // found end of regexp
break;
+ }
if ((p[0] == '[' && mymagic >= MAGIC_ON)
|| (p[0] == '\\' && p[1] == '[' && mymagic <= MAGIC_OFF)) {
p = skip_anyof(p + 1);
@@ -3476,14 +3481,14 @@ static long bt_regexec_both(char_u *line,
if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0) {
break; // Found it.
}
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
}
} else {
while ((s = cstrchr(s, c)) != NULL) {
if (cstrncmp(s, prog->regmust, &prog->regmlen) == 0) {
break; // Found it.
}
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
}
}
if (s == NULL) { // Not present.
@@ -3753,7 +3758,7 @@ static int reg_match_visual(void)
return TRUE;
}
-#define ADVANCE_REGINPUT() mb_ptr_adv(reginput)
+#define ADVANCE_REGINPUT() MB_PTR_ADV(reginput)
/*
* The arguments from BRACE_LIMITS are stored here. They are actually local
@@ -4287,7 +4292,7 @@ regmatch (
if (enc_utf8) {
// Skip composing characters.
while (utf_iscomposing(utf_ptr2char(reginput))) {
- mb_cptr_adv(reginput);
+ MB_CPTR_ADV(reginput);
}
}
break;
@@ -4951,21 +4956,24 @@ regmatch (
(colnr_T)STRLEN(regline);
}
} else {
- if (has_mbyte)
+ if (has_mbyte) {
rp->rs_un.regsave.rs_u.pos.col -=
(*mb_head_off)(regline, regline
+ rp->rs_un.regsave.rs_u.pos.col - 1) + 1;
- else
- --rp->rs_un.regsave.rs_u.pos.col;
+ } else {
+ rp->rs_un.regsave.rs_u.pos.col--;
+ }
}
} else {
- if (rp->rs_un.regsave.rs_u.ptr == regline)
+ if (rp->rs_un.regsave.rs_u.ptr == regline) {
no = FAIL;
- else {
- mb_ptr_back(regline, rp->rs_un.regsave.rs_u.ptr);
- if (limit > 0 && (long)(behind_pos.rs_u.ptr
- - rp->rs_un.regsave.rs_u.ptr) > limit)
+ } else {
+ MB_PTR_BACK(regline, rp->rs_un.regsave.rs_u.ptr);
+ if (limit > 0
+ && (long)(behind_pos.rs_u.ptr
+ - rp->rs_un.regsave.rs_u.ptr) > limit) {
no = FAIL;
+ }
}
}
if (no == OK) {
@@ -5025,17 +5033,18 @@ regmatch (
if (--rst->count < rst->minval)
break;
if (reginput == regline) {
- /* backup to last char of previous line */
- --reglnum;
+ // backup to last char of previous line
+ reglnum--;
regline = reg_getline(reglnum);
- /* Just in case regrepeat() didn't count
- * right. */
- if (regline == NULL)
+ // Just in case regrepeat() didn't count right.
+ if (regline == NULL) {
break;
+ }
reginput = regline + STRLEN(regline);
fast_breakcheck();
- } else
- mb_ptr_back(regline, reginput);
+ } else {
+ MB_PTR_BACK(regline, reginput);
+ }
} else {
/* Range is backwards, use shortest match first.
* Careful: maxval and minval are exchanged!
@@ -5165,8 +5174,8 @@ regrepeat (
/* Matching anything means we continue until end-of-line (or
* end-of-file for ANY + ADD_NL), only limited by maxcount. */
while (*scan != NUL && count < maxcount) {
- ++count;
- mb_ptr_adv(scan);
+ count++;
+ MB_PTR_ADV(scan);
}
if (!REG_MULTI || !WITH_NL(OP(p)) || reglnum > rex.reg_maxline
|| rex.reg_line_lbr || count == maxcount) {
@@ -5188,7 +5197,7 @@ regrepeat (
case SIDENT + ADD_NL:
while (count < maxcount) {
if (vim_isIDc(PTR2CHAR(scan)) && (testval || !ascii_isdigit(*scan))) {
- mb_ptr_adv(scan);
+ MB_PTR_ADV(scan);
} else if (*scan == NUL) {
if (!REG_MULTI || !WITH_NL(OP(p)) || reglnum > rex.reg_maxline
|| rex.reg_line_lbr) {
@@ -5216,7 +5225,7 @@ regrepeat (
while (count < maxcount) {
if (vim_iswordp_buf(scan, rex.reg_buf)
&& (testval || !ascii_isdigit(*scan))) {
- mb_ptr_adv(scan);
+ MB_PTR_ADV(scan);
} else if (*scan == NUL) {
if (!REG_MULTI || !WITH_NL(OP(p)) || reglnum > rex.reg_maxline
|| rex.reg_line_lbr) {
@@ -5244,7 +5253,7 @@ regrepeat (
case SFNAME + ADD_NL:
while (count < maxcount) {
if (vim_isfilec(PTR2CHAR(scan)) && (testval || !ascii_isdigit(*scan))) {
- mb_ptr_adv(scan);
+ MB_PTR_ADV(scan);
} else if (*scan == NUL) {
if (!REG_MULTI || !WITH_NL(OP(p)) || reglnum > rex.reg_maxline
|| rex.reg_line_lbr) {
@@ -5283,7 +5292,7 @@ regrepeat (
}
} else if (vim_isprintc(PTR2CHAR(scan)) == 1
&& (testval || !ascii_isdigit(*scan))) {
- mb_ptr_adv(scan);
+ MB_PTR_ADV(scan);
} else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p))) {
scan++;
} else {
@@ -6679,7 +6688,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
if (eval_result != NULL) {
int had_backslash = FALSE;
- for (s = eval_result; *s != NUL; mb_ptr_adv(s)) {
+ for (s = eval_result; *s != NUL; MB_PTR_ADV(s)) {
// Change NL to CR, so that it becomes a line break,
// unless called from vim_regexec_nl().
// Skip over a backslashed character.
diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c
index c2b1b97ce9..2eb0ca9313 100644
--- a/src/nvim/regexp_nfa.c
+++ b/src/nvim/regexp_nfa.c
@@ -1323,7 +1323,7 @@ static int nfa_regatom(void)
EMSG(_(e_nopresub));
return FAIL;
}
- for (lp = reg_prev_sub; *lp != NUL; mb_cptr_adv(lp)) {
+ for (lp = reg_prev_sub; *lp != NUL; MB_CPTR_ADV(lp)) {
EMIT(PTR2CHAR(lp));
if (lp != reg_prev_sub)
EMIT(NFA_CONCAT);
@@ -1557,7 +1557,7 @@ collection:
} else
EMIT(result);
regparse = endp;
- mb_ptr_adv(regparse);
+ MB_PTR_ADV(regparse);
return OK;
}
/*
@@ -1565,10 +1565,10 @@ collection:
* version that turns [abc] into 'a' OR 'b' OR 'c'
*/
startc = endc = oldstartc = -1;
- negated = FALSE;
- if (*regparse == '^') { /* negated range */
- negated = TRUE;
- mb_ptr_adv(regparse);
+ negated = false;
+ if (*regparse == '^') { // negated range
+ negated = true;
+ MB_PTR_ADV(regparse);
EMIT(NFA_START_NEG_COLL);
} else
EMIT(NFA_START_COLL);
@@ -1576,7 +1576,7 @@ collection:
startc = '-';
EMIT(startc);
EMIT(NFA_CONCAT);
- mb_ptr_adv(regparse);
+ MB_PTR_ADV(regparse);
}
/* Emit the OR branches for each character in the [] */
emit_range = FALSE;
@@ -1666,8 +1666,8 @@ collection:
if (*regparse == '-' && oldstartc != -1) {
emit_range = TRUE;
startc = oldstartc;
- mb_ptr_adv(regparse);
- continue; /* reading the end of the range */
+ MB_PTR_ADV(regparse);
+ continue; // reading the end of the range
}
/* Now handle simple and escaped characters.
@@ -1683,7 +1683,7 @@ collection:
!= NULL)
)
) {
- mb_ptr_adv(regparse);
+ MB_PTR_ADV(regparse);
if (*regparse == 'n')
startc = reg_string ? NL : NFA_NEWL;
@@ -1695,8 +1695,8 @@ collection:
) {
/* TODO(RE) This needs more testing */
startc = coll_get_char();
- got_coll_char = TRUE;
- mb_ptr_back(old_regparse, regparse);
+ got_coll_char = true;
+ MB_PTR_BACK(old_regparse, regparse);
} else {
/* \r,\t,\e,\b */
startc = backslash_trans(*regparse);
@@ -1768,18 +1768,18 @@ collection:
}
}
- mb_ptr_adv(regparse);
- } /* while (p < endp) */
+ MB_PTR_ADV(regparse);
+ } // while (p < endp)
- mb_ptr_back(old_regparse, regparse);
- if (*regparse == '-') { /* if last, '-' is just a char */
+ MB_PTR_BACK(old_regparse, regparse);
+ if (*regparse == '-') { // if last, '-' is just a char
EMIT('-');
EMIT(NFA_CONCAT);
}
/* skip the trailing ] */
regparse = endp;
- mb_ptr_adv(regparse);
+ MB_PTR_ADV(regparse);
/* Mark end of the collection. */
if (negated == TRUE)
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index f36d408b25..4cb6575502 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -1,83 +1,65 @@
// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
-/*
- * screen.c: code for displaying on the screen
- *
- * Output to the screen (console, terminal emulator or GUI window) is minimized
- * by remembering what is already on the screen, and only updating the parts
- * that changed.
- *
- * ScreenLines[off] Contains a copy of the whole screen, as it is currently
- * displayed (excluding text written by external commands).
- * ScreenAttrs[off] Contains the associated attributes.
- * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[]
- * for each line.
- * LineWraps[row] Flag for each line whether it wraps to the next line.
- *
- * For double-byte characters, two consecutive bytes in ScreenLines[] can form
- * one character which occupies two display cells.
- * For UTF-8 a multi-byte character is converted to Unicode and stored in
- * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII
- * character without composing chars ScreenLinesUC[] will be 0 and
- * ScreenLinesC[][] is not used. When the character occupies two display
- * cells the next byte in ScreenLines[] is 0.
- * ScreenLinesC[][] contain up to 'maxcombine' composing characters
- * (drawn on top of the first character). There is 0 after the last one used.
- *
- * The screen_*() functions write to the screen and handle updating
- * ScreenLines[].
- *
- * update_screen() is the function that updates all windows and status lines.
- * It is called form the main loop when must_redraw is non-zero. It may be
- * called from other places when an immediate screen update is needed.
- *
- * The part of the buffer that is displayed in a window is set with:
- * - w_topline (first buffer line in window)
- * - w_topfill (filler lines above the first line)
- * - w_leftcol (leftmost window cell in window),
- * - w_skipcol (skipped window cells of first line)
- *
- * Commands that only move the cursor around in a window, do not need to take
- * action to update the display. The main loop will check if w_topline is
- * valid and update it (scroll the window) when needed.
- *
- * Commands that scroll a window change w_topline and must call
- * check_cursor() to move the cursor into the visible part of the window, and
- * call redraw_later(VALID) to have the window displayed by update_screen()
- * later.
- *
- * Commands that change text in the buffer must call changed_bytes() or
- * changed_lines() to mark the area that changed and will require updating
- * later. The main loop will call update_screen(), which will update each
- * window that shows the changed buffer. This assumes text above the change
- * can remain displayed as it is. Text after the change may need updating for
- * scrolling, folding and syntax highlighting.
- *
- * Commands that change how a window is displayed (e.g., setting 'list') or
- * invalidate the contents of a window in another way (e.g., change fold
- * settings), must call redraw_later(NOT_VALID) to have the whole window
- * redisplayed by update_screen() later.
- *
- * Commands that change how a buffer is displayed (e.g., setting 'tabstop')
- * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
- * buffer redisplayed by update_screen() later.
- *
- * Commands that change highlighting and possibly cause a scroll too must call
- * redraw_later(SOME_VALID) to update the whole window but still use scrolling
- * to avoid redrawing everything. But the length of displayed lines must not
- * change, use NOT_VALID then.
- *
- * Commands that move the window position must call redraw_later(NOT_VALID).
- * TODO: should minimize redrawing by scrolling when possible.
- *
- * Commands that change everything (e.g., resizing the screen) must call
- * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
- *
- * Things that are handled indirectly:
- * - When messages scroll the screen up, msg_scrolled will be set and
- * update_screen() called to redraw.
- */
+// screen.c: code for displaying on the screen
+//
+// Output to the screen (console, terminal emulator or GUI window) is minimized
+// by remembering what is already on the screen, and only updating the parts
+// that changed.
+//
+// The screen_*() functions write to the screen and handle updating
+// ScreenLines[].
+//
+// update_screen() is the function that updates all windows and status lines.
+// It is called from the main loop when must_redraw is non-zero. It may be
+// called from other places when an immediate screen update is needed.
+//
+// The part of the buffer that is displayed in a window is set with:
+// - w_topline (first buffer line in window)
+// - w_topfill (filler lines above the first line)
+// - w_leftcol (leftmost window cell in window),
+// - w_skipcol (skipped window cells of first line)
+//
+// Commands that only move the cursor around in a window, do not need to take
+// action to update the display. The main loop will check if w_topline is
+// valid and update it (scroll the window) when needed.
+//
+// Commands that scroll a window change w_topline and must call
+// check_cursor() to move the cursor into the visible part of the window, and
+// call redraw_later(VALID) to have the window displayed by update_screen()
+// later.
+//
+// Commands that change text in the buffer must call changed_bytes() or
+// changed_lines() to mark the area that changed and will require updating
+// later. The main loop will call update_screen(), which will update each
+// window that shows the changed buffer. This assumes text above the change
+// can remain displayed as it is. Text after the change may need updating for
+// scrolling, folding and syntax highlighting.
+//
+// Commands that change how a window is displayed (e.g., setting 'list') or
+// invalidate the contents of a window in another way (e.g., change fold
+// settings), must call redraw_later(NOT_VALID) to have the whole window
+// redisplayed by update_screen() later.
+//
+// Commands that change how a buffer is displayed (e.g., setting 'tabstop')
+// must call redraw_curbuf_later(NOT_VALID) to have all the windows for the
+// buffer redisplayed by update_screen() later.
+//
+// Commands that change highlighting and possibly cause a scroll too must call
+// redraw_later(SOME_VALID) to update the whole window but still use scrolling
+// to avoid redrawing everything. But the length of displayed lines must not
+// change, use NOT_VALID then.
+//
+// Commands that move the window position must call redraw_later(NOT_VALID).
+// TODO(neovim): should minimize redrawing by scrolling when possible.
+//
+// Commands that change everything (e.g., resizing the screen) must call
+// redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR).
+//
+// Things that are handled indirectly:
+// - When messages scroll the screen up, msg_scrolled will be set and
+// update_screen() called to redraw.
+///
#include <assert.h>
#include <inttypes.h>
@@ -1550,9 +1532,9 @@ static void win_update(win_T *wp)
} else if (dollar_vcol == -1)
wp->w_botline = lnum;
- /* make sure the rest of the screen is blank */
- /* put '~'s on rows that aren't part of the file. */
- win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_EOB);
+ // make sure the rest of the screen is blank
+ // write the 'fill_eob' character to rows that aren't part of the file.
+ win_draw_end(wp, fill_eob, ' ', row, wp->w_height, HLF_EOB);
}
/* Reset the type of redrawing required, the window has been updated. */
@@ -1752,9 +1734,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
* Ignores 'rightleft', this window is never right-left.
*/
if (cmdwin_type != 0 && wp == curwin) {
- ScreenLines[off] = cmdwin_type;
+ schar_from_ascii(ScreenLines[off], cmdwin_type);
ScreenAttrs[off] = win_hl_attr(wp, HLF_AT);
- ScreenLinesUC[off] = 0;
col++;
}
@@ -1770,7 +1751,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
win_hl_attr(wp, HLF_FC));
// reverse the fold column
for (i = 0; i < fdc; i++) {
- ScreenLines[off + wp->w_width - i - 1 - col] = buf[i];
+ schar_from_ascii(ScreenLines[off + wp->w_width - i - 1 - col], buf[i]);
}
} else {
copy_text_attr(off + col, buf, fdc, win_hl_attr(wp, HLF_FC));
@@ -1854,111 +1835,76 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
* Right-left text is put in columns 0 - number-col, normal text is put
* in columns number-col - window-width.
*/
- if (has_mbyte) {
- int cells;
- int u8c, u8cc[MAX_MCO];
- int i;
- int idx;
- int c_len;
- char_u *p;
- int prev_c = 0; /* previous Arabic character */
- int prev_c1 = 0; /* first composing char for prev_c */
-
- if (wp->w_p_rl)
- idx = off;
- else
- idx = off + col;
-
- /* Store multibyte characters in ScreenLines[] et al. correctly. */
- for (p = text; *p != NUL; ) {
- cells = (*mb_ptr2cells)(p);
- c_len = (*mb_ptr2len)(p);
- if (col + cells > wp->w_width
- - (wp->w_p_rl ? col : 0)
- )
- break;
- ScreenLines[idx] = *p;
- if (enc_utf8) {
- u8c = utfc_ptr2char(p, u8cc);
- if (*p < 0x80 && u8cc[0] == 0) {
- ScreenLinesUC[idx] = 0;
- prev_c = u8c;
- } else {
- if (p_arshape && !p_tbidi && arabic_char(u8c)) {
- /* Do Arabic shaping. */
- int pc, pc1, nc;
- int pcc[MAX_MCO];
- int firstbyte = *p;
+ int cells;
+ int u8c, u8cc[MAX_MCO];
+ int idx;
+ int c_len;
+ char_u *p;
+ int prev_c = 0; // previous Arabic character
+ int prev_c1 = 0; // first composing char for prev_c
- /* The idea of what is the previous and next
- * character depends on 'rightleft'. */
- if (wp->w_p_rl) {
- pc = prev_c;
- pc1 = prev_c1;
- nc = utf_ptr2char(p + c_len);
- prev_c1 = u8cc[0];
- } else {
- pc = utfc_ptr2char(p + c_len, pcc);
- nc = prev_c;
- pc1 = pcc[0];
- }
- prev_c = u8c;
+ if (wp->w_p_rl) {
+ idx = off;
+ } else {
+ idx = off + col;
+ }
- u8c = arabic_shape(u8c, &firstbyte, &u8cc[0],
- pc, pc1, nc);
- ScreenLines[idx] = firstbyte;
- } else
- prev_c = u8c;
- /* Non-BMP character: display as ? or fullwidth ?. */
- ScreenLinesUC[idx] = u8c;
- for (i = 0; i < Screen_mco; ++i) {
- ScreenLinesC[i][idx] = u8cc[i];
- if (u8cc[i] == 0)
- break;
- }
+ // Store multibyte characters in ScreenLines[] et al. correctly.
+ for (p = text; *p != NUL; ) {
+ cells = (*mb_ptr2cells)(p);
+ c_len = (*mb_ptr2len)(p);
+ if (col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) {
+ break;
+ }
+ u8c = utfc_ptr2char(p, u8cc);
+ if (*p < 0x80 && u8cc[0] == 0) {
+ schar_from_ascii(ScreenLines[idx], *p);
+ prev_c = u8c;
+ } else {
+ if (p_arshape && !p_tbidi && arabic_char(u8c)) {
+ // Do Arabic shaping.
+ int pc, pc1, nc;
+ int pcc[MAX_MCO];
+ int firstbyte = *p;
+
+ // The idea of what is the previous and next
+ // character depends on 'rightleft'.
+ if (wp->w_p_rl) {
+ pc = prev_c;
+ pc1 = prev_c1;
+ nc = utf_ptr2char(p + c_len);
+ prev_c1 = u8cc[0];
+ } else {
+ pc = utfc_ptr2char(p + c_len, pcc);
+ nc = prev_c;
+ pc1 = pcc[0];
}
- if (cells > 1)
- ScreenLines[idx + 1] = 0;
- } else if (cells > 1) {
- // Double-width character.
- ScreenLines[idx + 1] = p[1];
+ prev_c = u8c;
+
+ u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc);
+ } else {
+ prev_c = u8c;
}
- col += cells;
- idx += cells;
- p += c_len;
+ schar_from_cc(ScreenLines[idx], u8c, u8cc);
}
- } else {
- len = (int)STRLEN(text);
- if (len > wp->w_width - col)
- len = wp->w_width - col;
- if (len > 0) {
- if (wp->w_p_rl)
- STRNCPY(current_ScreenLine, text, len);
- else
- STRNCPY(current_ScreenLine + col, text, len);
- col += len;
+ if (cells > 1) {
+ ScreenLines[idx + 1][0] = 0;
}
+ col += cells;
+ idx += cells;
+ p += c_len;
}
/* Fill the rest of the line with the fold filler */
if (wp->w_p_rl)
col -= txtcol;
+
+ schar_T sc;
+ schar_from_char(sc, fill_fold);
while (col < wp->w_width
- (wp->w_p_rl ? txtcol : 0)
) {
- if (enc_utf8) {
- if (fill_fold >= 0x80) {
- ScreenLinesUC[off + col] = fill_fold;
- ScreenLinesC[0][off + col] = 0;
- ScreenLines[off + col] = 0x80; // avoid storing zero
- } else {
- ScreenLinesUC[off + col] = 0;
- ScreenLines[off + col] = fill_fold;
- }
- col++;
- } else {
- ScreenLines[off + col++] = fill_fold;
- }
+ schar_copy(ScreenLines[off+col++], sc);
}
if (text != buf)
@@ -2059,18 +2005,18 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T
}
}
-/*
- * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
- */
+
+/// Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr".
+///
+/// Only works for ASCII text!
static void copy_text_attr(int off, char_u *buf, int len, int attr)
{
int i;
- memmove(ScreenLines + off, buf, (size_t)len);
- if (enc_utf8)
- memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len);
- for (i = 0; i < len; ++i)
+ for (i = 0; i < len; i++) {
+ schar_from_ascii(ScreenLines[off + i], buf[i]);
ScreenAttrs[off + i] = attr;
+ }
}
/*
@@ -2528,7 +2474,7 @@ win_line (
c = win_lbr_chartabsize(wp, line, ptr, (colnr_T)vcol, NULL);
vcol += c;
prev_ptr = ptr;
- mb_ptr_adv(ptr);
+ MB_PTR_ADV(ptr);
}
// When:
@@ -3129,13 +3075,6 @@ win_line (
mb_utf8 = true;
c = 0xc0;
}
- } else {
- /* if this is a DBCS character, put it in "mb_c" */
- mb_l = MB_BYTE2LEN(c);
- if (mb_l >= n_extra)
- mb_l = 1;
- else if (mb_l > 1)
- mb_c = (c << 8) + p_extra[1];
}
if (mb_l == 0) /* at the NUL at end-of-line */
mb_l = 1;
@@ -3195,8 +3134,9 @@ win_line (
if (utf_iscomposing(mb_c)) {
int i;
- for (i = Screen_mco - 1; i > 0; --i)
+ for (i = MAX_MCO - 1; i > 0; i--) {
u8cc[i] = u8cc[i - 1];
+ }
u8cc[0] = mb_c;
mb_c = ' ';
}
@@ -3880,10 +3820,8 @@ win_line (
off += n;
col += n;
} else {
- /* Add a blank character to highlight. */
- ScreenLines[off] = ' ';
- if (enc_utf8)
- ScreenLinesUC[off] = 0;
+ // Add a blank character to highlight.
+ schar_from_ascii(ScreenLines[off], ' ');
}
if (area_attr == 0) {
/* Use attributes from match with highest priority among
@@ -3978,13 +3916,11 @@ win_line (
int mc_attr = win_hl_attr(wp, HLF_MC);
while (col < wp->w_width) {
- ScreenLines[off] = ' ';
- if (enc_utf8)
- ScreenLinesUC[off] = 0;
- ++col;
- if (draw_color_col)
- draw_color_col = advance_color_col(VCOL_HLC,
- &color_cols);
+ schar_from_ascii(ScreenLines[off], ' ');
+ col++;
+ if (draw_color_col) {
+ draw_color_col = advance_color_col(VCOL_HLC, &color_cols);
+ }
if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) {
ScreenAttrs[off++] = cuc_attr;
@@ -4006,10 +3942,7 @@ win_line (
// terminal buffers may need to highlight beyond the end of the
// logical line
while (col < wp->w_width) {
- ScreenLines[off] = ' ';
- if (enc_utf8) {
- ScreenLinesUC[off] = 0;
- }
+ schar_from_ascii(ScreenLines[off], ' ');
ScreenAttrs[off++] = term_attrs[vcol++];
col++;
}
@@ -4088,20 +4021,10 @@ win_line (
--off;
--col;
}
- ScreenLines[off] = c;
if (mb_utf8) {
- ScreenLinesUC[off] = mb_c;
- if ((c & 0xff) == 0) {
- ScreenLines[off] = 0x80; // Avoid storing zero.
- }
- for (int i = 0; i < Screen_mco; i++) {
- ScreenLinesC[i][off] = u8cc[i];
- if (u8cc[i] == 0) {
- break;
- }
- }
+ schar_from_cc(ScreenLines[off], mb_c, u8cc);
} else {
- ScreenLinesUC[off] = 0;
+ schar_from_ascii(ScreenLines[off], c);
}
if (multi_attr) {
ScreenAttrs[off] = multi_attr;
@@ -4113,13 +4036,8 @@ win_line (
// 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.
- ScreenLines[off] = mb_c & 0xff;
- }
+ // UTF-8: Put a 0 in the second screen char.
+ ScreenLines[off][0] = 0;
if (draw_state > WL_NR && filler_todo <= 0) {
vcol++;
}
@@ -4297,12 +4215,11 @@ win_line (
/* When there is a multi-byte character, just output a
* space to keep it simple. */
- if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
- screen_row -
- 1] + (Columns - 1)]) > 1) {
+ if (ScreenLines[LineOffset[screen_row - 1]
+ + (Columns - 1)][1] != 0) {
ui_putc(' ');
} else {
- ui_putc(ScreenLines[LineOffset[screen_row - 1] + (Columns - 1)]);
+ ui_puts(ScreenLines[LineOffset[screen_row - 1] + (Columns - 1)]);
}
/* force a redraw of the first char on the next line */
ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1;
@@ -4347,23 +4264,6 @@ win_line (
/*
- * Return if the composing characters at "off_from" and "off_to" differ.
- * Only to be used when ScreenLinesUC[off_from] != 0.
- */
-static int comp_char_differs(int off_from, int off_to)
-{
- int i;
-
- for (i = 0; i < Screen_mco; ++i) {
- if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to])
- return TRUE;
- if (ScreenLinesC[i][off_from] == 0)
- break;
- }
- return FALSE;
-}
-
-/*
* Check whether the given character needs redrawing:
* - the (first byte of the) character is different
* - the attributes are different
@@ -4373,13 +4273,11 @@ static int comp_char_differs(int off_from, int off_to)
static int char_needs_redraw(int off_from, int off_to, int cols)
{
return (cols > 0
- && (ScreenLines[off_from] != ScreenLines[off_to]
- || ScreenAttrs[off_from] != ScreenAttrs[off_to]
- || ScreenLinesUC[off_from] != ScreenLinesUC[off_to]
- || (ScreenLinesUC[off_from] != 0
- && comp_char_differs(off_from, off_to))
- || (utf_off2cells(off_from, off_from + cols) > 1
- && ScreenLines[off_from + 1] != ScreenLines[off_to + 1])
+ && ((schar_cmp(ScreenLines[off_from], ScreenLines[off_to])
+ || ScreenAttrs[off_from] != ScreenAttrs[off_to]
+ || ((*mb_off2cells)(off_from, off_from + cols) > 1
+ && schar_cmp(ScreenLines[off_from + 1],
+ ScreenLines[off_to + 1])))
|| p_wd < 0));
}
@@ -4427,9 +4325,9 @@ static void screen_line(int row, int coloff, int endcol,
if (rlflag) {
/* Clear rest first, because it's left of the text. */
if (clear_width > 0) {
- while (col <= endcol && ScreenLines[off_to] == ' '
+ while (col <= endcol && ScreenLines[off_to][0] == ' '
+ && ScreenLines[off_to][1] == NUL
&& ScreenAttrs[off_to] == bg_attr
- && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
@@ -4466,54 +4364,24 @@ static void screen_line(int row, int coloff, int endcol,
if (redraw_this) {
- if (enc_dbcs != 0) {
- /* Check if overwriting a double-byte with a single-byte or
- * the other way around requires another character to be
- * redrawn. For UTF-8 this isn't needed, because comparing
- * ScreenLinesUC[] is sufficient. */
- if (char_cells == 1
- && col + 1 < endcol
- && (*mb_off2cells)(off_to, max_off_to) > 1) {
- /* Writing a single-cell character over a double-cell
- * character: need to redraw the next cell. */
- ScreenLines[off_to + 1] = 0;
- redraw_next = TRUE;
- } else if (char_cells == 2
- && col + 2 < endcol
- && (*mb_off2cells)(off_to, max_off_to) == 1
- && (*mb_off2cells)(off_to + 1, max_off_to) > 1) {
- /* Writing the second half of a double-cell character over
- * a double-cell character: need to redraw the second
- * cell. */
- ScreenLines[off_to + 2] = 0;
- redraw_next = TRUE;
- }
- }
- /* When writing a single-width character over a double-width
- * character and at the end of the redrawn text, need to clear out
- * the right halve of the old character.
- * Also required when writing the right halve of a double-width
- * char over the left halve of an existing one. */
+ // When writing a single-width character over a double-width
+ // character and at the end of the redrawn text, need to clear out
+ // the right halve of the old character.
+ // Also required when writing the right halve of a double-width
+ // char over the left halve of an existing one
if (has_mbyte && col + char_cells == endcol
&& ((char_cells == 1
&& (*mb_off2cells)(off_to, max_off_to) > 1)
|| (char_cells == 2
&& (*mb_off2cells)(off_to, max_off_to) == 1
- && (*mb_off2cells)(off_to + 1, max_off_to) > 1)))
- clear_next = TRUE;
-
- ScreenLines[off_to] = ScreenLines[off_from];
- if (enc_utf8) {
- ScreenLinesUC[off_to] = ScreenLinesUC[off_from];
- if (ScreenLinesUC[off_from] != 0) {
- int i;
+ && (*mb_off2cells)(off_to + 1, max_off_to) > 1))) {
+ clear_next = true;
+ }
- for (i = 0; i < Screen_mco; ++i)
- ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from];
- }
+ schar_copy(ScreenLines[off_to], ScreenLines[off_from]);
+ if (char_cells == 2) {
+ schar_copy(ScreenLines[off_to+1], ScreenLines[off_from+1]);
}
- if (char_cells == 2)
- ScreenLines[off_to + 1] = ScreenLines[off_from + 1];
ScreenAttrs[off_to] = ScreenAttrs[off_from];
/* For simplicity set the attributes of second half of a
@@ -4521,10 +4389,7 @@ static void screen_line(int row, int coloff, int endcol,
if (char_cells == 2)
ScreenAttrs[off_to + 1] = ScreenAttrs[off_from];
- if (enc_dbcs != 0 && char_cells == 2)
- screen_char_2(off_to, row, col + coloff);
- else
- screen_char(off_to, row, col + coloff);
+ screen_char(off_to, row, col + coloff);
}
off_to += CHAR_CELLS;
@@ -4535,20 +4400,15 @@ static void screen_line(int row, int coloff, int endcol,
if (clear_next) {
/* Clear the second half of a double-wide character of which the left
* half was overwritten with a single-wide character. */
- ScreenLines[off_to] = ' ';
- if (enc_utf8)
- ScreenLinesUC[off_to] = 0;
+ schar_from_ascii(ScreenLines[off_to], ' ');
screen_char(off_to, row, col + coloff);
}
- if (clear_width > 0
- && !rlflag
- ) {
-
- /* blank out the rest of the line */
- while (col < clear_width && ScreenLines[off_to] == ' '
+ if (clear_width > 0 && !rlflag) {
+ // blank out the rest of the line
+ while (col < clear_width && ScreenLines[off_to][0] == ' '
+ && ScreenLines[off_to][1] == NUL
&& ScreenAttrs[off_to] == bg_attr
- && (!enc_utf8 || ScreenLinesUC[off_to] == 0)
) {
++off_to;
++col;
@@ -4564,22 +4424,14 @@ static void screen_line(int row, int coloff, int endcol,
if (clear_width > 0) {
// For a window that's left of another, draw the separator char.
if (col + coloff < Columns && wp->w_vsep_width > 0) {
- int c;
+ int c = fillchar_vsep(wp, &hl);
+ schar_T sc;
+ schar_from_char(sc, c);
- c = fillchar_vsep(wp, &hl);
- if (ScreenLines[off_to] != (schar_T)c
- || (enc_utf8 && (int)ScreenLinesUC[off_to]
- != (c >= 0x80 ? c : 0))
+ if (schar_cmp(ScreenLines[off_to], sc)
|| ScreenAttrs[off_to] != hl) {
- ScreenLines[off_to] = c;
+ schar_copy(ScreenLines[off_to], sc);
ScreenAttrs[off_to] = hl;
- if (enc_utf8) {
- if (c >= 0x80) {
- ScreenLinesUC[off_to] = c;
- ScreenLinesC[0][off_to] = 0;
- } else
- ScreenLinesUC[off_to] = 0;
- }
screen_char(off_to, row, col + coloff);
}
} else
@@ -4697,7 +4549,7 @@ static int status_match_len(expand_T *xp, char_u *s)
while (*s != NUL) {
s += skip_status_match_char(xp, s);
len += ptr2cells(s);
- mb_ptr_adv(s);
+ MB_PTR_ADV(s);
}
return len;
@@ -5279,6 +5131,50 @@ theend:
entered = FALSE;
}
+// Low-level functions to manipulate invidual character cells on the
+// screen grid.
+
+/// Put a ASCII character in a screen cell.
+static void schar_from_ascii(char_u *p, const char c)
+{
+ p[0] = c;
+ p[1] = 0;
+}
+
+/// Put a unicode character in a screen cell.
+static int schar_from_char(char_u *p, int c)
+{
+ int len = utf_char2bytes(c, p);
+ p[len] = NUL;
+ return len;
+}
+
+/// Put a unicode char, and up to MAX_MCO composing chars, in a screen cell.
+static int schar_from_cc(char_u *p, int c, int u8cc[MAX_MCO])
+{
+ int len = utf_char2bytes(c, p);
+ for (int i = 0; i < MAX_MCO; i++) {
+ if (u8cc[i] == 0) {
+ break;
+ }
+ len += utf_char2bytes(u8cc[i], p + len);
+ }
+ p[len] = 0;
+ return len;
+}
+
+/// compare the contents of two screen cells.
+static int schar_cmp(char_u *sc1, char_u *sc2)
+{
+ return STRNCMP(sc1, sc2, sizeof(schar_T));
+}
+
+/// copy the contents of screen cell `sc2` into cell `sc1`
+static void schar_copy(char_u *sc1, char_u *sc2)
+{
+ STRLCPY(sc1, sc2, sizeof(schar_T));
+}
+
/*
* Output a single character directly to the screen and update ScreenLines.
@@ -5287,12 +5183,7 @@ void screen_putchar(int c, int row, int col, int attr)
{
char_u buf[MB_MAXBYTES + 1];
- if (has_mbyte)
- buf[(*mb_char2bytes)(c, buf)] = NUL;
- else {
- buf[0] = c;
- buf[1] = NUL;
- }
+ buf[(*mb_char2bytes)(c, buf)] = NUL;
screen_puts(buf, row, col, attr);
}
@@ -5308,35 +5199,12 @@ void screen_getbytes(int row, int col, char_u *bytes, int *attrp)
if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns) {
off = LineOffset[row] + col;
*attrp = ScreenAttrs[off];
- bytes[0] = ScreenLines[off];
- bytes[1] = NUL;
-
- if (ScreenLinesUC[off] != 0) {
- bytes[utfc_char2bytes(off, bytes)] = NUL;
- }
+ schar_copy(bytes, ScreenLines[off]);
}
}
/*
- * Return TRUE if composing characters for screen posn "off" differs from
- * composing characters in "u8cc".
- * Only to be used when ScreenLinesUC[off] != 0.
- */
-static int screen_comp_differs(int off, int *u8cc)
-{
- int i;
-
- for (i = 0; i < Screen_mco; ++i) {
- if (ScreenLinesC[i][off] != (u8char_T)u8cc[i])
- return TRUE;
- if (u8cc[i] == 0)
- break;
- }
- return FALSE;
-}
-
-/*
* Put string '*text' on the screen at position 'row' and 'col', with
* attributes 'attr', and update ScreenLines[] and ScreenAttrs[].
* Note: only outputs within one row, message is truncated at screen boundary!
@@ -5370,28 +5238,16 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr)
int force_redraw_next = FALSE;
int need_redraw;
- const bool l_has_mbyte = has_mbyte;
- const bool l_enc_utf8 = enc_utf8;
- const int l_enc_dbcs = enc_dbcs;
-
- assert((l_has_mbyte == (l_enc_utf8 || l_enc_dbcs))
- && !(l_enc_utf8 && l_enc_dbcs));
-
if (ScreenLines == NULL || row >= screen_Rows) /* safety check */
return;
off = LineOffset[row] + col;
/* When drawing over the right halve of a double-wide char clear out the
* left halve. Only needed in a terminal. */
- if (l_has_mbyte && col > 0 && col < screen_Columns
- && mb_fix_col(col, row) != col) {
- ScreenLines[off - 1] = ' ';
+ if (col > 0 && col < screen_Columns && mb_fix_col(col, row) != col) {
+ schar_from_ascii(ScreenLines[off - 1], ' ');
ScreenAttrs[off - 1] = 0;
- if (l_enc_utf8) {
- ScreenLinesUC[off - 1] = 0;
- ScreenLinesC[0][off - 1] = 0;
- }
- /* redraw the previous cell, make it empty */
+ // redraw the previous cell, make it empty
screen_char(off - 1, row, col - 1);
/* force the cell at "col" to be redrawn */
force_redraw_next = TRUE;
@@ -5402,124 +5258,86 @@ void screen_puts_len(char_u *text, int textlen, int row, int col, int attr)
&& (len < 0 || (int)(ptr - text) < len)
&& *ptr != NUL) {
c = *ptr;
- /* check if this is the first byte of a multibyte */
- if (l_has_mbyte) {
- if (len > 0) {
- mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
- } else {
- mbyte_blen = utfc_ptr2len(ptr);
- }
- if (len >= 0) {
- u8c = utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr));
- } else {
- u8c = utfc_ptr2char(ptr, u8cc);
- }
- mbyte_cells = utf_char2cells(u8c);
- if (p_arshape && !p_tbidi && arabic_char(u8c)) {
- // Do Arabic shaping.
- if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len) {
- // Past end of string to be displayed.
- nc = NUL;
- nc1 = NUL;
- } else {
- nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
- (int)((text + len) - ptr - mbyte_blen));
- nc1 = pcc[0];
- }
- pc = prev_c;
- prev_c = u8c;
- u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
+ // check if this is the first byte of a multibyte
+ if (len > 0) {
+ mbyte_blen = utfc_ptr2len_len(ptr, (int)((text + len) - ptr));
+ } else {
+ mbyte_blen = utfc_ptr2len(ptr);
+ }
+ if (len >= 0) {
+ u8c = utfc_ptr2char_len(ptr, u8cc, (int)((text + len) - ptr));
+ } else {
+ u8c = utfc_ptr2char(ptr, u8cc);
+ }
+ mbyte_cells = utf_char2cells(u8c);
+ if (p_arshape && !p_tbidi && arabic_char(u8c)) {
+ // Do Arabic shaping.
+ if (len >= 0 && (int)(ptr - text) + mbyte_blen >= len) {
+ // Past end of string to be displayed.
+ nc = NUL;
+ nc1 = NUL;
} else {
- prev_c = u8c;
- }
- if (col + mbyte_cells > screen_Columns) {
- // Only 1 cell left, but character requires 2 cells:
- // display a '>' in the last column to avoid wrapping. */
- c = '>';
- mbyte_cells = 1;
+ nc = utfc_ptr2char_len(ptr + mbyte_blen, pcc,
+ (int)((text + len) - ptr - mbyte_blen));
+ nc1 = pcc[0];
}
+ pc = prev_c;
+ prev_c = u8c;
+ u8c = arabic_shape(u8c, &c, &u8cc[0], nc, nc1, pc);
+ } else {
+ prev_c = u8c;
}
+ if (col + mbyte_cells > screen_Columns) {
+ // Only 1 cell left, but character requires 2 cells:
+ // display a '>' in the last column to avoid wrapping. */
+ c = '>';
+ mbyte_cells = 1;
+ }
+
+ schar_T buf;
+ schar_from_cc(buf, u8c, u8cc);
+
force_redraw_this = force_redraw_next;
force_redraw_next = FALSE;
- need_redraw = ScreenLines[off] != c
- || (mbyte_cells == 2 && ScreenLines[off + 1] != 0)
- || (ScreenLinesUC[off] !=
- (u8char_T)(c < 0x80 && u8cc[0] == 0 ? 0 : u8c)
- || (ScreenLinesUC[off] != 0
- && screen_comp_differs(off, u8cc)))
+ need_redraw = schar_cmp(ScreenLines[off], buf)
+ || (mbyte_cells == 2 && ScreenLines[off + 1][0] != 0)
|| ScreenAttrs[off] != attr
|| exmode_active;
- if (need_redraw
- || force_redraw_this
- ) {
- /* When at the end of the text and overwriting a two-cell
- * character with a one-cell character, need to clear the next
- * cell. Also when overwriting the left halve of a two-cell char
- * with the right halve of a two-cell char. Do this only once
- * (mb_off2cells() may return 2 on the right halve). */
- if (clear_next_cell)
- clear_next_cell = FALSE;
- else if (l_has_mbyte
- && (len < 0 ? ptr[mbyte_blen] == NUL
- : ptr + mbyte_blen >= text + len)
- && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
- || (mbyte_cells == 2
- && (*mb_off2cells)(off, max_off) == 1
- && (*mb_off2cells)(off + 1, max_off) > 1)))
- clear_next_cell = TRUE;
-
- /* Make sure we never leave a second byte of a double-byte behind,
- * it confuses mb_off2cells(). */
- if (l_enc_dbcs
- && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
- || (mbyte_cells == 2
- && (*mb_off2cells)(off, max_off) == 1
- && (*mb_off2cells)(off + 1, max_off) > 1)))
- ScreenLines[off + mbyte_blen] = 0;
- ScreenLines[off] = c;
- ScreenAttrs[off] = attr;
- if (l_enc_utf8) {
- if (c < 0x80 && u8cc[0] == 0)
- ScreenLinesUC[off] = 0;
- else {
- int i;
+ if (need_redraw || force_redraw_this) {
+ // When at the end of the text and overwriting a two-cell
+ // character with a one-cell character, need to clear the next
+ // cell. Also when overwriting the left halve of a two-cell char
+ // with the right halve of a two-cell char. Do this only once
+ // (mb_off2cells() may return 2 on the right halve).
+ if (clear_next_cell) {
+ clear_next_cell = false;
+ } else if ((len < 0 ? ptr[mbyte_blen] == NUL
+ : ptr + mbyte_blen >= text + len)
+ && ((mbyte_cells == 1 && (*mb_off2cells)(off, max_off) > 1)
+ || (mbyte_cells == 2
+ && (*mb_off2cells)(off, max_off) == 1
+ && (*mb_off2cells)(off + 1, max_off) > 1))) {
+ clear_next_cell = true;
+ }
- ScreenLinesUC[off] = u8c;
- for (i = 0; i < Screen_mco; ++i) {
- ScreenLinesC[i][off] = u8cc[i];
- if (u8cc[i] == 0)
- break;
- }
- }
- if (mbyte_cells == 2) {
- ScreenLines[off + 1] = 0;
- ScreenAttrs[off + 1] = attr;
- }
- screen_char(off, row, col);
- } else if (mbyte_cells == 2) {
- ScreenLines[off + 1] = ptr[1];
+ schar_copy(ScreenLines[off], buf);
+ ScreenAttrs[off] = attr;
+ if (mbyte_cells == 2) {
+ ScreenLines[off + 1][0] = 0;
ScreenAttrs[off + 1] = attr;
- screen_char_2(off, row, col);
- } else {
- screen_char(off, row, col);
}
+ screen_char(off, row, col);
}
- if (l_has_mbyte) {
- off += mbyte_cells;
- col += mbyte_cells;
- ptr += mbyte_blen;
- if (clear_next_cell) {
- // This only happens at the end, display one space next.
- ptr = (char_u *)" ";
- len = -1;
- }
- } else {
- ++off;
- ++col;
- ++ptr;
+ off += mbyte_cells;
+ col += mbyte_cells;
+ ptr += mbyte_blen;
+ if (clear_next_cell) {
+ // This only happens at the end, display one space next.
+ ptr = (char_u *)" ";
+ len = -1;
}
}
@@ -5878,40 +5696,7 @@ static void screen_char(unsigned off, int row, int col)
ui_cursor_goto(row, col);
ui_set_highlight(ScreenAttrs[off]);
- if (ScreenLinesUC[off] != 0) {
- char_u buf[MB_MAXBYTES + 1];
-
- // Convert UTF-8 character to bytes and write it.
- buf[utfc_char2bytes(off, buf)] = NUL;
- ui_puts(buf);
- } else {
- ui_putc(ScreenLines[off]);
- }
-}
-
-/*
- * Used for enc_dbcs only: Put one double-wide character at ScreenLines["off"]
- * on the screen at position 'row' and 'col'.
- * The attributes of the first byte is used for all. This is required to
- * output the two bytes of a double-byte character with nothing in between.
- */
-static void screen_char_2(unsigned off, int row, int col)
-{
- /* Check for illegal values (could be wrong when screen was resized). */
- if (off + 1 >= (unsigned)(screen_Rows * screen_Columns))
- return;
-
- /* Outputting the last character on the screen may scrollup the screen.
- * Don't to it! Mark the character invalid (update it when scrolled up) */
- if (row == screen_Rows - 1 && col >= screen_Columns - 2) {
- ScreenAttrs[off] = (sattr_T)-1;
- return;
- }
-
- /* Output the first byte normally (positions the cursor), then write the
- * second byte directly. */
- screen_char(off, row, col);
- ui_putc(ScreenLines[off + 1]);
+ ui_puts(ScreenLines[off]);
}
/*
@@ -5927,6 +5712,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
int end_off;
int did_delete;
int c;
+ schar_T sc;
if (end_row > screen_Rows) /* safety check */
end_row = screen_Rows;
@@ -5970,25 +5756,19 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
off = LineOffset[row] + col;
end_off = LineOffset[row] + end_col;
- /* skip blanks (used often, keep it fast!) */
- if (enc_utf8)
- while (off < end_off && ScreenLines[off] == ' '
- && ScreenAttrs[off] == 0 && ScreenLinesUC[off] == 0)
- ++off;
- else
- while (off < end_off && ScreenLines[off] == ' '
- && ScreenAttrs[off] == 0)
- ++off;
- if (off < end_off) { /* something to be cleared */
+ // skip blanks (used often, keep it fast!)
+ while (off < end_off && ScreenLines[off][0] == ' '
+ && ScreenLines[off][1] == 0 && ScreenAttrs[off] == 0) {
+ off++;
+ }
+ if (off < end_off) { // something to be cleared
col = off - LineOffset[row];
ui_clear_highlight();
ui_cursor_goto(row, col); // clear rest of this screen line
ui_call_eol_clear();
col = end_col - col;
- while (col--) { /* clear chars in ScreenLines */
- ScreenLines[off] = ' ';
- if (enc_utf8)
- ScreenLinesUC[off] = 0;
+ while (col--) { // clear chars in ScreenLines
+ schar_from_ascii(ScreenLines[off], ' ');
ScreenAttrs[off] = 0;
++off;
}
@@ -5998,20 +5778,10 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
off = LineOffset[row] + start_col;
c = c1;
- for (col = start_col; col < end_col; ++col) {
- if (ScreenLines[off] != c
- || (enc_utf8 && (int)ScreenLinesUC[off]
- != (c >= 0x80 ? c : 0))
- || ScreenAttrs[off] != attr
- ) {
- ScreenLines[off] = c;
- if (enc_utf8) {
- if (c >= 0x80) {
- ScreenLinesUC[off] = c;
- ScreenLinesC[0][off] = 0;
- } else
- ScreenLinesUC[off] = 0;
- }
+ schar_from_char(sc, c);
+ for (col = start_col; col < end_col; col++) {
+ if (schar_cmp(ScreenLines[off], sc) || ScreenAttrs[off] != attr) {
+ schar_copy(ScreenLines[off], sc);
ScreenAttrs[off] = attr;
if (!did_delete || c != ' ')
screen_char(off, row, col);
@@ -6021,6 +5791,7 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1,
if (did_delete)
break;
c = c2;
+ schar_from_char(sc, c);
}
}
if (end_col == Columns)
@@ -6089,8 +5860,7 @@ retry:
if ((ScreenLines != NULL
&& Rows == screen_Rows
&& Columns == screen_Columns
- && ScreenLinesUC != NULL
- && p_mco == Screen_mco)
+ )
|| Rows == 0
|| Columns == 0
|| (!full_screen && ScreenLines == NULL)) {
@@ -6133,18 +5903,11 @@ retry:
if (aucmd_win != NULL)
win_free_lsize(aucmd_win);
- schar_T *new_ScreenLines = xmalloc(
- (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenLines)));
- u8char_T *new_ScreenLinesC[MAX_MCO];
- memset(new_ScreenLinesC, 0, sizeof(new_ScreenLinesC));
- u8char_T *new_ScreenLinesUC = xmalloc(
- (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenLinesUC)));
- for (int i = 0; i < p_mco; i++) {
- new_ScreenLinesC[i] = xcalloc(
- (size_t)((Rows + 1) * Columns), sizeof(new_ScreenLinesC[0][0]));
- }
- sattr_T *new_ScreenAttrs = xmalloc(
- (size_t)((Rows + 1) * Columns * sizeof(*new_ScreenAttrs)));
+ // Allocate space for an extra row as scratch space, so that a redrawn
+ // line can be compared with the previous screen line state.
+ size_t ncells = (size_t)((Rows+1) * Columns);
+ schar_T *new_ScreenLines = xmalloc(ncells * sizeof(*new_ScreenLines));
+ sattr_T *new_ScreenAttrs = xmalloc(ncells * sizeof(*new_ScreenAttrs));
unsigned *new_LineOffset = xmalloc((size_t)(Rows * sizeof(*new_LineOffset)));
char_u *new_LineWraps = xmalloc((size_t)(Rows * sizeof(*new_LineWraps)));
StlClickDefinition *new_tab_page_click_defs = xcalloc(
@@ -6157,13 +5920,11 @@ retry:
win_alloc_lines(aucmd_win);
}
- int i;
- for (i = 0; i < p_mco; i++) {
- if (new_ScreenLinesC[i] == NULL) {
- break;
- }
- }
- if (i != p_mco) {
+ if (new_ScreenLines == NULL
+ || new_ScreenAttrs == NULL
+ || new_LineOffset == NULL
+ || new_LineWraps == NULL
+ || new_tab_page_click_defs == NULL) {
if (ScreenLines != NULL || !done_outofmem_msg) {
// Guess the size.
do_outofmem_msg((Rows + 1) * Columns);
@@ -6174,12 +5935,6 @@ retry:
}
xfree(new_ScreenLines);
new_ScreenLines = NULL;
- xfree(new_ScreenLinesUC);
- new_ScreenLinesUC = NULL;
- for (i = 0; i < p_mco; ++i) {
- xfree(new_ScreenLinesC[i]);
- new_ScreenLinesC[i] = NULL;
- }
xfree(new_ScreenAttrs);
new_ScreenAttrs = NULL;
xfree(new_LineOffset);
@@ -6202,39 +5957,21 @@ retry:
* executing an external command, for the GUI).
*/
if (!doclear) {
- memset(new_ScreenLines + new_row * Columns,
- ' ', (size_t)Columns * sizeof(new_ScreenLines[0]));
- memset(new_ScreenLinesUC + new_row * Columns,
- 0, (size_t)Columns * sizeof(new_ScreenLinesUC[0]));
- for (i = 0; i < p_mco; i++) {
- memset(new_ScreenLinesC[i] + new_row * Columns,
- 0, (size_t)Columns * sizeof(new_ScreenLinesC[0][0]));
+ for (int col = 0; col < Columns; col++) {
+ schar_from_ascii(new_ScreenLines[new_row * Columns + col], ' ');
}
memset(new_ScreenAttrs + new_row * Columns,
- 0, (size_t)Columns * sizeof(new_ScreenAttrs[0]));
+ 0, (size_t)Columns * sizeof(*new_ScreenAttrs));
old_row = new_row + (screen_Rows - Rows);
if (old_row >= 0 && ScreenLines != NULL) {
if (screen_Columns < Columns)
len = screen_Columns;
else
len = Columns;
- // When switching to utf-8 don't copy characters, they
- // may be invalid now. Also when p_mco changes.
- if (ScreenLinesUC != NULL && p_mco == Screen_mco) {
- memmove(new_ScreenLines + new_LineOffset[new_row],
- ScreenLines + LineOffset[old_row],
- (size_t)len * sizeof(new_ScreenLines[0]));
- }
- if (ScreenLinesUC != NULL && p_mco == Screen_mco) {
- memmove(new_ScreenLinesUC + new_LineOffset[new_row],
- ScreenLinesUC + LineOffset[old_row],
- (size_t)len * sizeof(new_ScreenLinesUC[0]));
- for (i = 0; i < p_mco; i++) {
- memmove(new_ScreenLinesC[i] + new_LineOffset[new_row],
- ScreenLinesC[i] + LineOffset[old_row],
- (size_t)len * sizeof(new_ScreenLinesC[0][0]));
- }
- }
+
+ memmove(new_ScreenLines + new_LineOffset[new_row],
+ ScreenLines + LineOffset[old_row],
+ (size_t)len * sizeof(schar_T));
memmove(new_ScreenAttrs + new_LineOffset[new_row],
ScreenAttrs + LineOffset[old_row],
(size_t)len * sizeof(new_ScreenAttrs[0]));
@@ -6248,10 +5985,6 @@ retry:
free_screenlines();
ScreenLines = new_ScreenLines;
- ScreenLinesUC = new_ScreenLinesUC;
- for (i = 0; i < p_mco; ++i)
- ScreenLinesC[i] = new_ScreenLinesC[i];
- Screen_mco = p_mco;
ScreenAttrs = new_ScreenAttrs;
LineOffset = new_LineOffset;
LineWraps = new_LineWraps;
@@ -6285,10 +6018,6 @@ retry:
void free_screenlines(void)
{
- xfree(ScreenLinesUC);
- for (int i = 0; i < Screen_mco; i++) {
- xfree(ScreenLinesC[i]);
- }
xfree(ScreenLines);
xfree(ScreenAttrs);
xfree(LineOffset);
@@ -6360,10 +6089,9 @@ static void screenclear2(void)
*/
static void lineclear(unsigned off, int width)
{
- (void)memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
- if (enc_utf8)
- (void)memset(ScreenLinesUC + off, 0,
- (size_t)width * sizeof(u8char_T));
+ for (int col = 0; col < width; col++) {
+ schar_from_ascii(ScreenLines[off + col], ' ');
+ }
(void)memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
}
@@ -6376,15 +6104,7 @@ static void linecopy(int to, int from, win_T *wp)
const unsigned off_from = LineOffset[from] + wp->w_wincol;
memmove(ScreenLines + off_to, ScreenLines + off_from,
- wp->w_width * sizeof(ScreenLines[0]));
-
- memmove(ScreenLinesUC + off_to, ScreenLinesUC + off_from,
- wp->w_width * sizeof(ScreenLinesUC[0]));
- for (int i = 0; i < p_mco; i++) {
- memmove(ScreenLinesC[i] + off_to, ScreenLinesC[i] + off_from,
- wp->w_width * sizeof(ScreenLinesC[0]));
- }
-
+ wp->w_width * sizeof(schar_T));
memmove(ScreenAttrs + off_to, ScreenAttrs + off_from,
wp->w_width * sizeof(ScreenAttrs[0]));
}
@@ -6951,7 +6671,7 @@ static void draw_tabline(void)
if (has_mbyte)
while (len > room) {
len -= ptr2cells(p);
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
else if (len > room) {
p += len - room;
diff --git a/src/nvim/search.c b/src/nvim/search.c
index cb59eb6d04..6c974850ac 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -3239,35 +3239,41 @@ static int in_html_tag(int end_tag)
/* We search forward until the cursor, because searching backwards is
* very slow for DBCS encodings. */
- for (p = line; p < line + curwin->w_cursor.col; mb_ptr_adv(p))
+ for (p = line; p < line + curwin->w_cursor.col; MB_PTR_ADV(p)) {
if (*p == '>' || *p == '<') {
lc = *p;
lp = p;
}
- if (*p != '<') { /* check for '<' under cursor */
- if (lc != '<')
- return FALSE;
+ }
+ if (*p != '<') { // check for '<' under cursor
+ if (lc != '<') {
+ return false;
+ }
p = lp;
}
} else {
for (p = line + curwin->w_cursor.col; p > line; ) {
- if (*p == '<') /* find '<' under/before cursor */
+ if (*p == '<') { // find '<' under/before cursor
break;
- mb_ptr_back(line, p);
- if (*p == '>') /* find '>' before cursor */
+ }
+ MB_PTR_BACK(line, p);
+ if (*p == '>') { // find '>' before cursor
break;
+ }
+ }
+ if (*p != '<') {
+ return false;
}
- if (*p != '<')
- return FALSE;
}
pos.lnum = curwin->w_cursor.lnum;
pos.col = (colnr_T)(p - line);
- mb_ptr_adv(p);
- if (end_tag)
- /* check that there is a '/' after the '<' */
+ MB_PTR_ADV(p);
+ if (end_tag) {
+ // check that there is a '/' after the '<'
return *p == '/';
+ }
/* check that there is no '/' after the '<' */
if (*p == '/')
@@ -3371,8 +3377,10 @@ again:
*/
inc_cursor();
p = get_cursor_pos_ptr();
- for (cp = p; *cp != NUL && *cp != '>' && !ascii_iswhite(*cp); mb_ptr_adv(cp))
- ;
+ for (cp = p;
+ *cp != NUL && *cp != '>' && !ascii_iswhite(*cp);
+ MB_PTR_ADV(cp)) {
+ }
len = (int)(cp - p);
if (len == 0) {
curwin->w_cursor = old_pos;
diff --git a/src/nvim/spell.c b/src/nvim/spell.c
index 0db1578e8d..0714eb3137 100644
--- a/src/nvim/spell.c
+++ b/src/nvim/spell.c
@@ -395,7 +395,7 @@ size_t spell_check(
mi.mi_fend = ptr;
if (spell_iswordp(mi.mi_fend, wp)) {
do {
- mb_ptr_adv(mi.mi_fend);
+ MB_PTR_ADV(mi.mi_fend);
} while (*mi.mi_fend != NUL && spell_iswordp(mi.mi_fend, wp));
if (capcol != NULL && *capcol == 0 && wp->w_s->b_cap_prog != NULL) {
@@ -422,7 +422,7 @@ size_t 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) {
- mb_ptr_adv(mi.mi_fend);
+ MB_PTR_ADV(mi.mi_fend);
}
(void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1);
@@ -499,7 +499,7 @@ size_t spell_check(
} 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);
+ 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) {
char_u *p, *fp;
@@ -512,8 +512,8 @@ size_t spell_check(
p = mi.mi_word;
fp = mi.mi_fword;
for (;;) {
- mb_ptr_adv(p);
- mb_ptr_adv(fp);
+ MB_PTR_ADV(p);
+ MB_PTR_ADV(fp);
if (p >= mi.mi_end) {
break;
}
@@ -706,8 +706,9 @@ static void find_word(matchinf_T *mip, int mode)
// case-folded word is equal to the keep-case word.
p = mip->mi_word;
if (STRNCMP(ptr, p, wlen) != 0) {
- for (char_u *s = ptr; s < ptr + wlen; mb_ptr_adv(s))
- mb_ptr_adv(p);
+ for (char_u *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) {
+ MB_PTR_ADV(p);
+ }
wlen = (int)(p - mip->mi_word);
}
}
@@ -814,10 +815,12 @@ static void find_word(matchinf_T *mip, int mode)
mip->mi_compoff) != 0) {
// case folding may have changed the length
p = mip->mi_word;
- for (char_u *s = ptr; s < ptr + mip->mi_compoff; mb_ptr_adv(s))
- mb_ptr_adv(p);
- } else
+ for (char_u *s = ptr; s < ptr + mip->mi_compoff; MB_PTR_ADV(s)) {
+ MB_PTR_ADV(p);
+ }
+ } else {
p = mip->mi_word + mip->mi_compoff;
+ }
capflags = captype(p, mip->mi_word + wlen);
if (capflags == WF_KEEPCAP || (capflags == WF_ALLCAP
&& (flags & WF_FIXCAP) != 0))
@@ -828,12 +831,13 @@ static void find_word(matchinf_T *mip, int mode)
// character we do not accept a Onecap word. We do
// accept a no-caps word, even when the dictionary
// word specifies ONECAP.
- mb_ptr_back(mip->mi_word, p);
+ MB_PTR_BACK(mip->mi_word, p);
if (spell_iswordp_nmw(p, mip->mi_win)
? capflags == WF_ONECAP
: (flags & WF_ONECAP) != 0
- && capflags != WF_ONECAP)
+ && capflags != WF_ONECAP) {
continue;
+ }
}
}
@@ -888,8 +892,9 @@ static void find_word(matchinf_T *mip, int mode)
// the case-folded word is equal to the keep-case word.
p = mip->mi_fword;
if (STRNCMP(ptr, p, wlen) != 0) {
- for (char_u *s = ptr; s < ptr + wlen; mb_ptr_adv(s))
- mb_ptr_adv(p);
+ for (char_u *s = ptr; s < ptr + wlen; MB_PTR_ADV(s)) {
+ MB_PTR_ADV(p);
+ }
mip->mi_compoff = (int)(p - mip->mi_fword);
}
}
@@ -1288,12 +1293,13 @@ static int fold_more(matchinf_T *mip)
p = mip->mi_fend;
do {
- mb_ptr_adv(mip->mi_fend);
+ MB_PTR_ADV(mip->mi_fend);
} while (*mip->mi_fend != NUL && spell_iswordp(mip->mi_fend, mip->mi_win));
// Include the non-word character so that we can check for the word end.
- if (*mip->mi_fend != NUL)
- mb_ptr_adv(mip->mi_fend);
+ if (*mip->mi_fend != NUL) {
+ MB_PTR_ADV(mip->mi_fend);
+ }
(void)spell_casefold(p, (int)(mip->mi_fend - p),
mip->mi_fword + mip->mi_fwordlen,
@@ -2312,9 +2318,11 @@ int captype(char_u *word, char_u *end)
bool past_second = false; // past second word char
// find first letter
- for (p = word; !spell_iswordp_nmw(p, curwin); mb_ptr_adv(p))
- if (end == NULL ? *p == NUL : p >= end)
+ for (p = word; !spell_iswordp_nmw(p, curwin); MB_PTR_ADV(p)) {
+ if (end == NULL ? *p == NUL : p >= end) {
return 0; // only non-word characters, illegal word
+ }
+ }
if (has_mbyte) {
c = mb_ptr2char_adv((const char_u **)&p);
} else {
@@ -2324,19 +2332,22 @@ int captype(char_u *word, char_u *end)
// Need to check all letters to find a word with mixed upper/lower.
// But a word with an upper char only at start is a ONECAP.
- for (; end == NULL ? *p != NUL : p < end; mb_ptr_adv(p))
+ for (; end == NULL ? *p != NUL : p < end; MB_PTR_ADV(p)) {
if (spell_iswordp_nmw(p, curwin)) {
c = PTR2CHAR(p);
if (!SPELL_ISUPPER(c)) {
// UUl -> KEEPCAP
- if (past_second && allcap)
+ if (past_second && allcap) {
return WF_KEEPCAP;
+ }
allcap = false;
- } else if (!allcap)
+ } else if (!allcap) {
// UlU -> KEEPCAP
return WF_KEEPCAP;
+ }
past_second = true;
}
+ }
if (allcap)
return WF_ALLCAP;
@@ -2360,7 +2371,7 @@ static int badword_captype(char_u *word, char_u *end)
// Count the number of UPPER and lower case letters.
l = u = 0;
first = false;
- for (p = word; p < end; mb_ptr_adv(p)) {
+ for (p = word; p < end; MB_PTR_ADV(p)) {
c = PTR2CHAR(p);
if (SPELL_ISUPPER(c)) {
++u;
@@ -2764,11 +2775,12 @@ void spell_suggest(int count)
return;
}
badlen = (int)curwin->w_cursor.col - (int)VIsual.col;
- if (badlen < 0)
+ if (badlen < 0) {
badlen = -badlen;
- else
+ } else {
curwin->w_cursor.col = VIsual.col;
- ++badlen;
+ }
+ badlen++;
end_visual_mode();
} else
// Find the start of the badly spelled word.
@@ -2780,11 +2792,13 @@ void spell_suggest(int count)
line = get_cursor_line_ptr();
p = line + curwin->w_cursor.col;
// Backup to before start of word.
- while (p > line && spell_iswordp_nmw(p, curwin))
- mb_ptr_back(line, p);
+ while (p > line && spell_iswordp_nmw(p, curwin)) {
+ MB_PTR_BACK(line, p);
+ }
// Forward to start of word.
- while (*p != NUL && !spell_iswordp_nmw(p, curwin))
- mb_ptr_adv(p);
+ while (*p != NUL && !spell_iswordp_nmw(p, curwin)) {
+ MB_PTR_ADV(p);
+ }
if (!spell_iswordp_nmw(p, curwin)) { // No word found.
beep_flush();
@@ -2973,8 +2987,9 @@ static bool check_need_cap(linenr_T lnum, colnr_T col)
endcol = (colnr_T)STRLEN(line);
}
}
- } else
+ } else {
endcol = col;
+ }
if (endcol > 0) {
// Check if sentence ends before the bad word.
@@ -2982,9 +2997,10 @@ static bool check_need_cap(linenr_T lnum, colnr_T col)
regmatch.rm_ic = FALSE;
p = line + endcol;
for (;; ) {
- mb_ptr_back(line, p);
- if (p == line || spell_iswordp_nmw(p, curwin))
+ MB_PTR_BACK(line, p);
+ if (p == line || spell_iswordp_nmw(p, curwin)) {
break;
+ }
if (vim_regexec(&regmatch, p, 0)
&& regmatch.endp[0] == line + endcol) {
need_cap = true;
@@ -3861,7 +3877,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Get pointer to last char of previous word.
p = preword + sp->ts_prewordlen;
- mb_ptr_back(preword, p);
+ MB_PTR_BACK(preword, p);
}
}
@@ -3947,12 +3963,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// Give a penalty when changing non-word char to word
// char, e.g., "thes," -> "these".
p = fword + sp->ts_fidx;
- mb_ptr_back(fword, p);
+ MB_PTR_BACK(fword, p);
if (!spell_iswordp(p, curwin)) {
p = preword + STRLEN(preword);
- mb_ptr_back(preword, p);
- if (spell_iswordp(p, curwin))
+ MB_PTR_BACK(preword, p);
+ if (spell_iswordp(p, curwin)) {
newscore += SCORE_NONWORD;
+ }
}
// Give a bonus to words seen before.
@@ -4301,10 +4318,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so
// to the score. Also for the soundfold
// tree (might seem illogical but does
// give better scores).
- mb_ptr_back(tword, p);
- if (c == mb_ptr2char(p))
- sp->ts_score -= SCORE_INS
- - SCORE_INSDUP;
+ MB_PTR_BACK(tword, p);
+ if (c == mb_ptr2char(p)) {
+ sp->ts_score -= SCORE_INS - SCORE_INSDUP;
+ }
}
}
@@ -4894,10 +4911,12 @@ static int nofold_len(char_u *fword, int flen, char_u *word)
char_u *p;
int i = 0;
- for (p = fword; p < fword + flen; mb_ptr_adv(p))
- ++i;
- for (p = word; i > 0; mb_ptr_adv(p))
- --i;
+ for (p = fword; p < fword + flen; MB_PTR_ADV(p)) {
+ i++;
+ }
+ for (p = word; i > 0; MB_PTR_ADV(p)) {
+ i--;
+ }
return (int)(p - word);
}
@@ -5630,8 +5649,8 @@ add_suggestion (
badlen = (int)(pbad - su->su_badptr);
if (goodlen <= 0 || badlen <= 0)
break;
- mb_ptr_back(goodword, pgood);
- mb_ptr_back(su->su_badptr, pbad);
+ MB_PTR_BACK(goodword, pgood);
+ MB_PTR_BACK(su->su_badptr, pbad);
if (has_mbyte) {
if (mb_ptr2char(pgood) != mb_ptr2char(pbad))
break;
@@ -7517,8 +7536,9 @@ char_u *spell_to_word_end(char_u *start, win_T *win)
{
char_u *p = start;
- while (*p != NUL && spell_iswordp(p, win))
- mb_ptr_adv(p);
+ while (*p != NUL && spell_iswordp(p, win)) {
+ MB_PTR_ADV(p);
+ }
return p;
}
@@ -7533,23 +7553,26 @@ int spell_word_start(int startcol)
char_u *p;
int col = 0;
- if (no_spell_checking(curwin))
+ if (no_spell_checking(curwin)) {
return startcol;
+ }
// Find a word character before "startcol".
line = get_cursor_line_ptr();
for (p = line + startcol; p > line; ) {
- mb_ptr_back(line, p);
- if (spell_iswordp_nmw(p, curwin))
+ MB_PTR_BACK(line, p);
+ if (spell_iswordp_nmw(p, curwin)) {
break;
+ }
}
// Go back to start of the word.
while (p > line) {
col = (int)(p - line);
- mb_ptr_back(line, p);
- if (!spell_iswordp(p, curwin))
+ MB_PTR_BACK(line, p);
+ if (!spell_iswordp(p, curwin)) {
break;
+ }
col = 0;
}
diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c
index b844fd9ab8..69fa95107e 100644
--- a/src/nvim/spellfile.c
+++ b/src/nvim/spellfile.c
@@ -1507,9 +1507,10 @@ static int set_sofo(slang_T *lp, char_u *from, char_u *to)
// sl_sal_first[] for this.
for (p = from, s = to; *p != NUL && *s != NUL; ) {
c = mb_cptr2char_adv((const char_u **)&p);
- mb_cptr_adv(s);
- if (c >= 256)
- ++lp->sl_sal_first[c & 0xff];
+ MB_CPTR_ADV(s);
+ if (c >= 256) {
+ lp->sl_sal_first[c & 0xff]++;
+ }
}
if (*p != NUL || *s != NUL) // lengths differ
return SP_FORMERROR;
@@ -2427,7 +2428,7 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
|| PTR2CHAR(aff_entry->ae_cond) == c)) {
p = aff_entry->ae_add
+ STRLEN(aff_entry->ae_add);
- mb_ptr_back(aff_entry->ae_add, p);
+ MB_PTR_BACK(aff_entry->ae_add, p);
if (PTR2CHAR(p) == c_up) {
upper = true;
aff_entry->ae_chop = NULL;
@@ -2528,12 +2529,16 @@ static afffile_T *spell_read_aff(spellinfo_T *spin, char_u *fname)
if (items[0][3] == 'S' ? do_repsal : do_rep) {
// Replace underscore with space (can't include a space
// directly).
- for (p = items[1]; *p != NUL; mb_ptr_adv(p))
- if (*p == '_')
+ for (p = items[1]; *p != NUL; MB_PTR_ADV(p)) {
+ if (*p == '_') {
*p = ' ';
- for (p = items[2]; *p != NUL; mb_ptr_adv(p))
- if (*p == '_')
+ }
+ }
+ for (p = items[2]; *p != NUL; MB_PTR_ADV(p)) {
+ if (*p == '_') {
*p = ' ';
+ }
+ }
add_fromto(spin, items[0][3] == 'S'
? &spin->si_repsal
: &spin->si_rep, items[1], items[2]);
@@ -3070,10 +3075,10 @@ static int spell_read_dic(spellinfo_T *spin, char_u *fname, afffile_T *affile)
// Truncate the word at the "/", set "afflist" to what follows.
// Replace "\/" by "/" and "\\" by "\".
afflist = NULL;
- for (p = w; *p != NUL; mb_ptr_adv(p)) {
- if (*p == '\\' && (p[1] == '\\' || p[1] == '/'))
+ for (p = w; *p != NUL; MB_PTR_ADV(p)) {
+ if (*p == '\\' && (p[1] == '\\' || p[1] == '/')) {
STRMOVE(p, p + 1);
- else if (*p == '/') {
+ } else if (*p == '/') {
*p = NUL;
afflist = p + 1;
break;
@@ -3343,19 +3348,22 @@ store_aff_word (
// Match. Remove the chop and add the affix.
if (xht == NULL) {
// prefix: chop/add at the start of the word
- if (ae->ae_add == NULL)
+ if (ae->ae_add == NULL) {
*newword = NUL;
- else
+ } else {
STRLCPY(newword, ae->ae_add, MAXWLEN);
+ }
p = word;
if (ae->ae_chop != NULL) {
// Skip chop string.
if (has_mbyte) {
i = mb_charlen(ae->ae_chop);
- for (; i > 0; --i)
- mb_ptr_adv(p);
- } else
+ for (; i > 0; i--) {
+ MB_PTR_ADV(p);
+ }
+ } else {
p += STRLEN(ae->ae_chop);
+ }
}
STRCAT(newword, p);
} else {
@@ -3365,8 +3373,9 @@ store_aff_word (
// Remove chop string.
p = newword + STRLEN(newword);
i = (int)MB_CHARLEN(ae->ae_chop);
- for (; i > 0; --i)
- mb_ptr_back(newword, p);
+ for (; i > 0; i--) {
+ MB_PTR_BACK(newword, p);
+ }
*p = NUL;
}
if (ae->ae_add != NULL)
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 52677738e8..3f31914c03 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -207,7 +207,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
/* First count the number of extra bytes required. */
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
- for (const char_u *p = string; *p != NUL; mb_ptr_adv(p)) {
+ for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) {
#ifdef WIN32
if (!p_ssl) {
if (*p == '"') {
@@ -469,7 +469,7 @@ char_u *vim_strrchr(const char_u *string, int c)
while (*p) {
if (*p == c)
retval = p;
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
return (char_u *) retval;
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 68f0422f7d..b8cbf3b2a8 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -2824,11 +2824,12 @@ syn_add_end_off (
base = ml_get_buf(syn_buf, result->lnum, FALSE);
p = base + col;
if (off > 0) {
- while (off-- > 0 && *p != NUL)
- mb_ptr_adv(p);
+ while (off-- > 0 && *p != NUL) {
+ MB_PTR_ADV(p);
+ }
} else {
while (off++ < 0 && base < p) {
- mb_ptr_back(base, p);
+ MB_PTR_BACK(base, p);
}
}
col = (int)(p - base);
@@ -2873,11 +2874,11 @@ syn_add_start_off (
p = base + col;
if (off > 0) {
while (off-- && *p != NUL) {
- mb_ptr_adv(p);
+ MB_PTR_ADV(p);
}
} else {
while (off++ && base < p) {
- mb_ptr_back(base, p);
+ MB_PTR_BACK(base, p);
}
}
col = (int)(p - base);
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index c5ec077d01..3025e01439 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -703,7 +703,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading)
if (has_directory) {
if (munged_name == NULL) {
munged_name = xstrdup(ffname);
- for (char *p = munged_name; *p != NUL; mb_ptr_adv(p)) {
+ for (char *p = munged_name; *p != NUL; MB_PTR_ADV(p)) {
if (vim_ispathsep(*p)) {
*p = '%';
}
diff --git a/src/nvim/window.c b/src/nvim/window.c
index ebde81bca6..274bf72f3b 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -5101,11 +5101,13 @@ file_name_in_line (
* search forward for what could be the start of a file name
*/
ptr = line + col;
- while (*ptr != NUL && !vim_isfilec(*ptr))
- mb_ptr_adv(ptr);
- if (*ptr == NUL) { /* nothing found */
- if (options & FNAME_MESS)
+ while (*ptr != NUL && !vim_isfilec(*ptr)) {
+ MB_PTR_ADV(ptr);
+ }
+ if (*ptr == NUL) { // nothing found
+ if (options & FNAME_MESS) {
EMSG(_("E446: No file name under cursor"));
+ }
return NULL;
}
diff --git a/test/functional/options/fillchars_spec.lua b/test/functional/options/fillchars_spec.lua
new file mode 100644
index 0000000000..ab61935d4c
--- /dev/null
+++ b/test/functional/options/fillchars_spec.lua
@@ -0,0 +1,66 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, command = helpers.clear, helpers.command
+local eval = helpers.eval
+local eq = helpers.eq
+local exc_exec = helpers.exc_exec
+
+describe("'fillchars'", function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(25, 5)
+ screen:attach()
+ end)
+
+ after_each(function()
+ screen:detach()
+ end)
+
+ local function shouldfail(val,errval)
+ errval = errval or val
+ eq('Vim(set):E474: Invalid argument: fillchars='..errval,
+ exc_exec('set fillchars='..val))
+ end
+
+ describe('"eob" flag', function()
+ it("uses '~' by default", function()
+ eq('', eval('&fillchars'))
+ screen:expect([[
+ ^ |
+ ~ |
+ ~ |
+ ~ |
+ |
+ ]])
+ end)
+ it('supports whitespace', function()
+ command('set fillchars=eob:\\ ')
+ screen:expect([[
+ ^ |
+ |
+ |
+ |
+ |
+ ]])
+ end)
+ it('supports multibyte char', function()
+ command('set fillchars=eob:ñ')
+ screen:expect([[
+ ^ |
+ ñ |
+ ñ |
+ ñ |
+ |
+ ]])
+ end)
+ it('handles invalid values', function()
+ shouldfail('eob:') -- empty string
+ shouldfail('eob:馬') -- doublewidth char
+ shouldfail('eob:å̲') -- composing chars
+ shouldfail('eob:xy') -- two ascii chars
+ shouldfail('eob:\255', 'eob:<ff>') -- invalid UTF-8
+ end)
+ end)
+end)
diff --git a/test/functional/options/num_options_spec.lua b/test/functional/options/num_options_spec.lua
index ed17ffdd3c..fb0559054d 100644
--- a/test/functional/options/num_options_spec.lua
+++ b/test/functional/options/num_options_spec.lua
@@ -51,7 +51,6 @@ describe(':set validation', function()
should_succeed('winminheight', 0)
should_fail('winwidth', 0, 'E487')
should_fail('helpheight', -1, 'E487')
- should_fail('maxcombine', 7, 'E474')
should_fail('iminsert', 3, 'E474')
should_fail('imsearch', 3, 'E474')
should_fail('titlelen', -1, 'E487')
@@ -94,4 +93,18 @@ describe(':set validation', function()
feed_command('set winminwidth=3')
eq('E592', eval("v:errmsg"):match("E%d*"))
end)
+
+ it('set maxcombine resets to 6', function()
+ local function setto(value)
+ feed_command('setglobal maxcombine=' .. value)
+ feed_command('setlocal maxcombine=' .. value)
+ meths.set_option('maxcombine', value)
+ eq(6, meths.get_option('maxcombine'))
+ eq('', eval("v:errmsg"))
+ end
+ setto(0)
+ setto(1)
+ setto(6)
+ setto(7)
+ end)
end)
diff --git a/test/functional/ui/fold_spec.lua b/test/functional/ui/fold_spec.lua
index 40089d217d..9c5a59b58d 100644
--- a/test/functional/ui/fold_spec.lua
+++ b/test/functional/ui/fold_spec.lua
@@ -27,9 +27,8 @@ describe("folded lines", function()
end)
it("works with multibyte text", function()
- -- Soon, we will always use the maximum value of 'maxcombine'.
- feed_command("set maxcombine=6")
-
+ -- Currently the only allowed value of 'maxcombine'
+ eq(6, meths.get_option('maxcombine'))
eq(true, meths.get_option('arabicshape'))
insert([[
å 语 x̨̣̘̫̲͚͎̎͂̀̂͛͛̾͢͟ العَرَبِيَّة
diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua
index 02ca566bd8..93d8965cb1 100644
--- a/test/functional/ui/output_spec.lua
+++ b/test/functional/ui/output_spec.lua
@@ -111,10 +111,10 @@ describe("shell command :!", function()
feed([[<CR>]])
-- Print BELL control code. #4338
screen.bell = false
- feed([[:!printf '\x07\x07\x07\x07text'<CR>]])
+ feed([[:!printf '\007\007\007\007text'<CR>]])
screen:expect([[
~ |
- :!printf '\x07\x07\x07\x07text' |
+ :!printf '\007\007\007\007text' |
text |
Press ENTER or type command to continue^ |
]], nil, nil, function()
@@ -122,7 +122,7 @@ describe("shell command :!", function()
end)
feed([[<CR>]])
-- Print BS control code.
- feed([[:echo system('printf ''\x08\n''')<CR>]])
+ feed([[:echo system('printf ''\010\n''')<CR>]])
screen:expect([[
~ |
^H |