diff options
35 files changed, 1367 insertions, 655 deletions
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3020c29709..71e04ec0fb 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -3220,10 +3220,11 @@ int build_stl_str_hl( // Get the byte value now, in case we need it below. This is more // efficient than making a copy of the line. int byteval; - if (wp->w_cursor.col > (colnr_T)STRLEN(line_ptr)) + if (wp->w_cursor.col > (colnr_T)STRLEN(line_ptr)) { byteval = 0; - else - byteval = (*mb_ptr2char)(line_ptr + wp->w_cursor.col); + } else { + byteval = utf_ptr2char(line_ptr + wp->w_cursor.col); + } int groupdepth = 0; diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 231bff26e8..f1b3be6b46 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1379,7 +1379,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); if (pos->col < (colnr_T)STRLEN(ptr)) { - int c = (*mb_ptr2char)(ptr + pos->col); + int c = utf_ptr2char(ptr + pos->col); if ((c != TAB) && vim_isprintc(c)) { endadd = (colnr_T)(char2cells(c) - 1); if (coladd > endadd) { diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index 177f167d74..0fda941a51 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -476,9 +476,7 @@ bool leftcol_changed(void) int gchar_cursor(void) { - if (has_mbyte) - return (*mb_ptr2char)(get_cursor_pos_ptr()); - return (int)*get_cursor_pos_ptr(); + return utf_ptr2char(get_cursor_pos_ptr()); } /* @@ -507,4 +505,3 @@ char_u *get_cursor_pos_ptr(void) return ml_get_buf(curbuf, curwin->w_cursor.lnum, false) + curwin->w_cursor.col; } - diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index 218a3f0604..c0915224e5 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1536,7 +1536,7 @@ static int getexactdigraph(int char1, int char2, int meta_char) to = string_convert(&vc, buf, &len); if (to != NULL) { - retval = (*mb_ptr2char)(to); + retval = utf_ptr2char(to); xfree(to); } (void)convert_setup(&vc, NULL, NULL); diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 95c903c90c..0d99aa8fb2 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -240,8 +240,8 @@ static int ins_need_undo; /* call u_save() before inserting a char. Set when edit() is called. after that arrow_used is used. */ -static int did_add_space = FALSE; /* auto_format() added an extra space - under the cursor */ +static bool did_add_space = false; // auto_format() added an extra space + // under the cursor static TriState dont_sync_undo = kFalse; // CTRL-G U prevents syncing undo // for the next left/right cursor @@ -1766,8 +1766,8 @@ change_indent ( /* We only put back the new line up to the cursor */ new_line[curwin->w_cursor.col] = NUL; - /* Put back original line */ - ml_replace(curwin->w_cursor.lnum, orig_line, FALSE); + // Put back original line + ml_replace(curwin->w_cursor.lnum, orig_line, false); curwin->w_cursor.col = orig_col; /* Backspace from cursor to start of line */ @@ -2311,24 +2311,14 @@ static void ins_compl_longest_match(compl_T *match) p = compl_leader; s = match->cp_str; while (*p != NUL) { - if (has_mbyte) { - c1 = mb_ptr2char(p); - c2 = mb_ptr2char(s); - } else { - c1 = *p; - c2 = *s; - } - if (match->cp_icase ? (mb_tolower(c1) != mb_tolower(c2)) - : (c1 != c2)) { + c1 = utf_ptr2char(p); + c2 = utf_ptr2char(s); + + if (match->cp_icase ? (mb_tolower(c1) != mb_tolower(c2)) : (c1 != c2)) { break; } - if (has_mbyte) { - MB_PTR_ADV(p); - MB_PTR_ADV(s); - } else { - ++p; - ++s; - } + MB_PTR_ADV(p); + MB_PTR_ADV(s); } if (*p != NUL) { @@ -5703,8 +5693,8 @@ auto_format ( pos = curwin->w_cursor; old = get_cursor_line_ptr(); - /* may remove added space */ - check_auto_format(FALSE); + // may remove added space + check_auto_format(false); /* Don't format in Insert mode when the cursor is on a trailing blank, the * user might insert normal text next. Also skip formatting when "1" is @@ -5770,12 +5760,13 @@ auto_format ( pnew = vim_strnsave(new, len + 2); pnew[len] = ' '; pnew[len + 1] = NUL; - ml_replace(curwin->w_cursor.lnum, pnew, FALSE); - /* remove the space later */ - did_add_space = TRUE; - } else - /* may remove added space */ - check_auto_format(FALSE); + ml_replace(curwin->w_cursor.lnum, pnew, false); + // remove the space later + did_add_space = true; + } else { + // may remove added space + check_auto_format(false); + } } check_cursor(); @@ -5786,9 +5777,8 @@ auto_format ( * delete it now. The space must be under the cursor, just after the insert * position. */ -static void -check_auto_format ( - int end_insert /* TRUE when ending Insert mode */ +static void check_auto_format( + bool end_insert // true when ending Insert mode ) { int c = ' '; @@ -5796,19 +5786,19 @@ check_auto_format ( if (did_add_space) { cc = gchar_cursor(); - if (!WHITECHAR(cc)) - /* Somehow the space was removed already. */ - did_add_space = FALSE; - else { + if (!WHITECHAR(cc)) { + // Somehow the space was removed already. + did_add_space = false; + } else { if (!end_insert) { inc_cursor(); c = gchar_cursor(); dec_cursor(); } if (c != NUL) { - /* The space is no longer at the end of the line, delete it. */ - del_char(FALSE); - did_add_space = FALSE; + // The space is no longer at the end of the line, delete it. + del_char(false); + did_add_space = false; } } } @@ -6033,8 +6023,8 @@ stop_insert ( } } - /* If a space was inserted for auto-formatting, remove it now. */ - check_auto_format(TRUE); + // If a space was inserted for auto-formatting, remove it now. + check_auto_format(true); /* If we just did an auto-indent, remove the white space from the end * of the line, and put the cursor back. @@ -6053,10 +6043,12 @@ stop_insert ( if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) --curwin->w_cursor.col; cc = gchar_cursor(); - if (!ascii_iswhite(cc)) + if (!ascii_iswhite(cc)) { break; - if (del_char(TRUE) == FAIL) - break; /* should not happen */ + } + if (del_char(true) == FAIL) { + break; // should not happen + } } if (curwin->w_cursor.lnum != tpos.lnum) curwin->w_cursor = tpos; @@ -6198,12 +6190,10 @@ int oneright(void) /* Adjust for multi-wide char (excluding TAB) */ ptr = get_cursor_pos_ptr(); - coladvance(getviscol() + ((*ptr != TAB && vim_isprintc( - (*mb_ptr2char)(ptr) - )) - ? ptr2cells(ptr) : 1)); - curwin->w_set_curswant = TRUE; - /* Return OK if the cursor moved, FAIL otherwise (at window edge). */ + coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) ? + ptr2cells(ptr) : 1)); + curwin->w_set_curswant = true; + // Return OK if the cursor moved, FAIL otherwise (at window edge). return (prevpos.col != curwin->w_cursor.col || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL; } @@ -6258,10 +6248,10 @@ int oneleft(void) /* Adjust for multi-wide char (not a TAB) */ ptr = get_cursor_pos_ptr(); - if (*ptr != TAB && vim_isprintc( - (*mb_ptr2char)(ptr) - ) && ptr2cells(ptr) > 1) + if (*ptr != TAB && vim_isprintc(utf_ptr2char(ptr)) + && ptr2cells(ptr) > 1) { curwin->w_cursor.coladd = 0; + } } curwin->w_set_curswant = TRUE; @@ -6710,8 +6700,8 @@ static void replace_do_bs(int limit_col) * text aligned. */ curwin->w_cursor.col += ins_len; while (vcol > orig_vcols && gchar_cursor() == ' ') { - del_char(FALSE); - ++orig_vcols; + del_char(false); + orig_vcols++; } curwin->w_cursor.col -= ins_len; } @@ -7453,13 +7443,15 @@ static void ins_shift(int c, int lastc) */ if (c == Ctrl_D && (lastc == '0' || lastc == '^') && curwin->w_cursor.col > 0) { - --curwin->w_cursor.col; - (void)del_char(FALSE); /* delete the '^' or '0' */ - /* In Replace mode, restore the characters that '^' or '0' replaced. */ - if (State & REPLACE_FLAG) + curwin->w_cursor.col--; + (void)del_char(false); // delete the '^' or '0' + // In Replace mode, restore the characters that '^' or '0' replaced. + if (State & REPLACE_FLAG) { replace_pop_ins(); - if (lastc == '^') - old_indent = get_indent(); /* remember curr. indent */ + } + if (lastc == '^') { + old_indent = get_indent(); // remember curr. indent + } change_indent(INDENT_SET, 0, TRUE, 0, TRUE); } else change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE); @@ -7475,17 +7467,23 @@ static void ins_shift(int c, int lastc) static void ins_del(void) { - int temp; - - if (stop_arrow() == FAIL) + if (stop_arrow() == FAIL) { return; - if (gchar_cursor() == NUL) { /* delete newline */ - temp = curwin->w_cursor.col; + } + if (gchar_cursor() == NUL) { // delete newline + const int temp = curwin->w_cursor.col; if (!can_bs(BS_EOL) // only if "eol" included || do_join(2, false, true, false, false) == FAIL) { vim_beep(BO_BS); } else { curwin->w_cursor.col = temp; + // Adjust orig_line_count in case more lines have been deleted than + // have been added. That makes sure, that open_line() later + // can access all buffer lines correctly + if (State & VREPLACE_FLAG + && orig_line_count > curbuf->b_ml.ml_line_count) { + orig_line_count = curbuf->b_ml.ml_line_count; + } } } else if (del_char(false) == FAIL) { // delete char under cursor vim_beep(BO_BS); @@ -7511,8 +7509,9 @@ static void ins_bs_one(colnr_T *vcolp) if (curwin->w_cursor.lnum != Insstart.lnum || curwin->w_cursor.col >= Insstart.col) replace_do_bs(-1); - } else - (void)del_char(FALSE); + } else { + (void)del_char(false); + } } /// Handle Backspace, delete-word and delete-line in Insert mode. @@ -7776,16 +7775,16 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) else { const bool l_enc_utf8 = enc_utf8; const int l_p_deco = p_deco; - if (l_enc_utf8 && l_p_deco) + if (l_enc_utf8 && l_p_deco) { (void)utfc_ptr2char(get_cursor_pos_ptr(), cpc); - (void)del_char(FALSE); - /* - * If there are combining characters and 'delcombine' is set - * move the cursor back. Don't back up before the base - * character. - */ - if (l_enc_utf8 && l_p_deco && cpc[0] != NUL) + } + (void)del_char(false); + // If there are combining characters and 'delcombine' is set + // move the cursor back. Don't back up before the base + // character. + if (l_enc_utf8 && l_p_deco && cpc[0] != NUL) { inc_cursor(); + } if (revins_chars) { revins_chars--; revins_legal++; @@ -8496,7 +8495,7 @@ int ins_copychar(linenr_T lnum) if ((colnr_T)temp > curwin->w_virtcol) ptr = prev_ptr; - c = (*mb_ptr2char)(ptr); + c = utf_ptr2char(ptr); if (c == NUL) { vim_beep(BO_COPY); } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3abc39e7bf..9765b04922 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -10210,32 +10210,34 @@ static void f_gettabinfo(typval_T *argvars, typval_T *rettv, FunPtr fptr) static void f_gettabvar(typval_T *argvars, typval_T *rettv, FunPtr fptr) { win_T *oldcurwin; - tabpage_T *tp, *oldtabpage; - dictitem_T *v; + tabpage_T *oldtabpage; bool done = false; rettv->v_type = VAR_STRING; rettv->vval.v_string = NULL; const char *const varname = tv_get_string_chk(&argvars[1]); - tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); + tabpage_T *const tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL)); if (tp != NULL && varname != NULL) { // Set tp to be our tabpage, temporarily. Also set the window to the // first window in the tabpage, otherwise the window is not valid. - win_T *window = tp->tp_firstwin == NULL ? firstwin : tp->tp_firstwin; + win_T *const window = tp == curtab || tp->tp_firstwin == NULL + ? firstwin + : tp->tp_firstwin; if (switch_win(&oldcurwin, &oldtabpage, window, tp, true) == OK) { // look up the variable // Let gettabvar({nr}, "") return the "t:" dictionary. - v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', - varname, strlen(varname), false); + const dictitem_T *const v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', + varname, strlen(varname), + false); if (v != NULL) { tv_copy(&v->di_tv, rettv); done = true; } } - /* restore previous notion of curwin */ - restore_win(oldcurwin, oldtabpage, TRUE); + // restore previous notion of curwin + restore_win(oldcurwin, oldtabpage, true); } if (!done && argvars[2].v_type != VAR_UNKNOWN) { @@ -15896,7 +15898,7 @@ static void f_strgetchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) while (charidx >= 0 && byteidx < len) { if (charidx == 0) { - rettv->vval.v_number = mb_ptr2char((const char_u *)str + byteidx); + rettv->vval.v_number = utf_ptr2char((const char_u *)str + byteidx); break; } charidx--; diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 4ef51b72b7..1420a9aae4 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -716,11 +716,13 @@ void ex_retab(exarg_T *eap) memmove(new_line + start_col + len, ptr + col, (size_t)(old_len - col + 1)); ptr = new_line + start_col; - for (col = 0; col < len; col++) + for (col = 0; col < len; col++) { ptr[col] = (col < num_tabs) ? '\t' : ' '; - ml_replace(lnum, new_line, FALSE); - if (first_line == 0) + } + ml_replace(lnum, new_line, false); + if (first_line == 0) { first_line = lnum; + } last_line = lnum; ptr = new_line; col = start_col + len; @@ -1598,6 +1600,7 @@ void ex_file(exarg_T *eap) // print full file name if :cd used fileinfo(false, false, eap->forceit); } + redraw_tabline = true; } /* @@ -3624,7 +3627,7 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, // before the cursor. len_change = (int)STRLEN(new_line) - (int)STRLEN(orig_line); curwin->w_cursor.col += len_change; - ml_replace(lnum, new_line, FALSE); + ml_replace(lnum, new_line, false); } search_match_lines = regmatch.endpos[0].lnum @@ -3666,9 +3669,10 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout, msg_col = 0; gotocmdline(TRUE); - /* restore the line */ - if (orig_line != NULL) - ml_replace(lnum, orig_line, FALSE); + // restore the line + if (orig_line != NULL) { + ml_replace(lnum, orig_line, false); + } } need_wait_return = FALSE; /* no hit-return prompt */ @@ -3925,9 +3929,10 @@ skip: prev_matchcol = (colnr_T)STRLEN(sub_firstline) - prev_matchcol; - if (u_savesub(lnum) != OK) + if (u_savesub(lnum) != OK) { break; - ml_replace(lnum, new_start, TRUE); + } + ml_replace(lnum, new_start, true); if (nmatch_tl > 0) { /* @@ -5641,7 +5646,7 @@ void ex_sign(exarg_T *eap) // Count cells and check for non-printable chars cells = 0; for (s = arg; s < p; s += (*mb_ptr2len)(s)) { - if (!vim_isprintc((*mb_ptr2char)(s))) { + if (!vim_isprintc(utf_ptr2char(s))) { break; } cells += (*mb_ptr2cells)(s); diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 0ab0178d24..3d3d02fd71 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2899,11 +2899,7 @@ const char * set_one_cmd_context( xp->xp_pattern = skipwhite((const char_u *)arg); p = (const char *)xp->xp_pattern; while (*p != NUL) { - if (has_mbyte) { - c = mb_ptr2char((const char_u *)p); - } else { - c = (uint8_t)(*p); - } + c = utf_ptr2char((const char_u *)p); if (c == '\\' && p[1] != NUL) { p++; } else if (c == '`') { @@ -2921,19 +2917,11 @@ const char * set_one_cmd_context( || ascii_iswhite(c)) { len = 0; /* avoid getting stuck when space is in 'isfname' */ while (*p != NUL) { - if (has_mbyte) { - c = mb_ptr2char((const char_u *)p); - } else { - c = *p; - } + c = utf_ptr2char((const char_u *)p); if (c == '`' || vim_isfilec_or_wc(c)) { break; } - if (has_mbyte) { - len = (size_t)(*mb_ptr2len)((const char_u *)p); - } else { - len = 1; - } + len = (size_t)utfc_ptr2len((const char_u *)p); MB_PTR_ADV(p); } if (in_quote) { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index ee616ae955..1810056a4a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -3327,16 +3327,11 @@ static bool cmdline_paste(int regname, bool literally, bool remcr) /* Locate start of last word in the cmd buffer. */ for (w = ccline.cmdbuff + ccline.cmdpos; w > ccline.cmdbuff; ) { - if (has_mbyte) { - len = (*mb_head_off)(ccline.cmdbuff, w - 1) + 1; - if (!vim_iswordc(mb_ptr2char(w - len))) - break; - w -= len; - } else { - if (!vim_iswordc(w[-1])) - break; - --w; + len = utf_head_off(ccline.cmdbuff, w - 1) + 1; + if (!vim_iswordc(utf_ptr2char(w - len))) { + break; } + w -= len; } len = (int)((ccline.cmdbuff + ccline.cmdpos) - w); if (p_ic ? STRNICMP(w, arg, len) == 0 : STRNCMP(w, arg, len) == 0) @@ -3837,24 +3832,13 @@ ExpandOne ( // Find longest common part if (mode == WILD_LONGEST && xp->xp_numfiles > 0) { - size_t len; - size_t mb_len = 1; - int c0; - int ci; + size_t len = 0; - for (len = 0; xp->xp_files[0][len]; len += mb_len) { - if (has_mbyte) { - mb_len = (* mb_ptr2len)(&xp->xp_files[0][len]); - c0 = (* mb_ptr2char)(&xp->xp_files[0][len]); - } else { - c0 = xp->xp_files[0][len]; - } - for (i = 1; i < xp->xp_numfiles; ++i) { - if (has_mbyte) { - ci =(* mb_ptr2char)(&xp->xp_files[i][len]); - } else { - ci = xp->xp_files[i][len]; - } + for (size_t mb_len; xp->xp_files[0][len]; len += mb_len) { + mb_len = utfc_ptr2len(&xp->xp_files[0][len]); + int c0 = utf_ptr2char(&xp->xp_files[0][len]); + for (i = 1; i < xp->xp_numfiles; i++) { + int ci = utf_ptr2char(&xp->xp_files[i][len]); if (p_fic && (xp->xp_context == EXPAND_DIRECTORIES || xp->xp_context == EXPAND_FILES @@ -6100,7 +6084,7 @@ static int open_cmdwin(void) /* Replace the empty last line with the current command-line and put the * cursor there. */ - ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, TRUE); + ml_replace(curbuf->b_ml.ml_line_count, ccline.cmdbuff, true); curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; curwin->w_cursor.col = ccline.cmdpos; changed_line_abv_curs(); diff --git a/src/nvim/farsi.c b/src/nvim/farsi.c index 6de84fbf4d..9862c50ab9 100644 --- a/src/nvim/farsi.c +++ b/src/nvim/farsi.c @@ -1081,7 +1081,7 @@ int fkmap(int c) if (gchar_cursor() == _LAM) { chg_l_toXor_X(); - del_char(FALSE); + del_char(false); AppendCharToRedobuff(K_BS); if (!p_ri) { diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 1ed34ef124..b00c45413a 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1687,7 +1687,7 @@ static void foldDelMarker(linenr_T lnum, char_u *marker, size_t markerlen) assert(p >= line); memcpy(newline, line, (size_t)(p - line)); STRCPY(newline + (p - line), p + len); - ml_replace(lnum, newline, FALSE); + ml_replace(lnum, newline, false); } break; } @@ -1763,12 +1763,13 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, if (text != NULL) { /* Replace unprintable characters, if there are any. But * replace a TAB with a space. */ - for (p = text; *p != NUL; ++p) { - int len; + for (p = text; *p != NUL; p++) { + int len = utfc_ptr2len(p); - if (has_mbyte && (len = (*mb_ptr2len)(p)) > 1) { - if (!vim_isprintc((*mb_ptr2char)(p))) + if (len > 1) { + if (!vim_isprintc(utf_ptr2char(p))) { break; + } p += len - 1; } else if (*p == TAB) *p = ' '; diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index e20c75cf7b..b57e1f6558 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -701,7 +701,7 @@ static int read_redo(int init, int old_redo) buf[i] = (char_u)c; if (i == n - 1) { // last byte of a character if (n != 1) { - c = (*mb_ptr2char)(buf); + c = utf_ptr2char(buf); } break; } @@ -1486,7 +1486,7 @@ int vgetc(void) } } no_mapping--; - c = (*mb_ptr2char)(buf); + c = utf_ptr2char(buf); } break; diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 7eb58bea2a..b02af723b4 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -126,7 +126,7 @@ # define MB_CHARLEN(p) mb_charlen(p) # define MB_CHAR2LEN(c) mb_char2len(c) -# define PTR2CHAR(p) mb_ptr2char(p) +# define PTR2CHAR(p) utf_ptr2char(p) # define RESET_BINDING(wp) (wp)->w_p_scb = FALSE; (wp)->w_p_crb = FALSE diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 49e60b5166..b9c91de2a8 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1470,7 +1470,7 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) // double-wide character. if (lp->coladd == 1 && p[lp->col] != TAB - && vim_isprintc((*mb_ptr2char)(p + lp->col)) + && vim_isprintc(utf_ptr2char(p + lp->col)) && ptr2cells(p + lp->col) > 1) { lp->coladd = 0; } diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 65a1a8246c..7c196831ba 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -674,7 +674,7 @@ int mb_ptr2char_adv(const char_u **const pp) { int c; - c = (*mb_ptr2char)(*pp); + c = utf_ptr2char(*pp); *pp += (*mb_ptr2len)(*pp); return c; } @@ -687,7 +687,7 @@ int mb_cptr2char_adv(const char_u **pp) { int c; - c = (*mb_ptr2char)(*pp); + c = utf_ptr2char(*pp); *pp += utf_ptr2len(*pp); return c; } @@ -1714,7 +1714,7 @@ void mb_check_adjust_col(void *win_) // Reset `coladd` when the cursor would be on the right half of a // double-wide character. if (win->w_cursor.coladd == 1 && p[win->w_cursor.col] != TAB - && vim_isprintc((*mb_ptr2char)(p + win->w_cursor.col)) + && vim_isprintc(utf_ptr2char(p + win->w_cursor.col)) && ptr2cells(p + win->w_cursor.col) > 1) { win->w_cursor.coladd = 0; } diff --git a/src/nvim/mbyte.h b/src/nvim/mbyte.h index 99aadcacad..a21c08c7fe 100644 --- a/src/nvim/mbyte.h +++ b/src/nvim/mbyte.h @@ -54,7 +54,6 @@ enum { MAX_MCO = 6 }; #define mb_ptr2cells_len utf_ptr2cells_len #define mb_char2cells utf_char2cells #define mb_off2cells utf_off2cells -#define mb_ptr2char utf_ptr2char #define mb_head_off utf_head_off /// Flags for vimconv_T diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 84ceaf0973..9a1e61d40b 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -2378,7 +2378,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, int message) ) set_keep_msg((char_u *)_(no_lines_msg), 0); - i = ml_replace((linenr_T)1, (char_u *)"", TRUE); + i = ml_replace((linenr_T)1, (char_u *)"", true); buf->b_ml.ml_flags |= ML_EMPTY; return i; diff --git a/src/nvim/message.c b/src/nvim/message.c index 46fc9115b4..947cd0735e 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -1219,7 +1219,7 @@ int msg_outtrans_len_attr(char_u *msgstr, int len, int attr) // Don't include composing chars after the end. mb_l = utfc_ptr2len_len((char_u *)str, len + 1); if (mb_l > 1) { - c = (*mb_ptr2char)((char_u *)str); + c = utf_ptr2char((char_u *)str); if (vim_isprintc(c)) { // Printable multi-byte char: count the cells. retval += (*mb_ptr2cells)((char_u *)str); @@ -1480,7 +1480,7 @@ void msg_prt_line(char_u *s, int list) col += (*mb_ptr2cells)(s); char buf[MB_MAXBYTES + 1]; if (lcs_nbsp != NUL && list - && (mb_ptr2char(s) == 160 || mb_ptr2char(s) == 0x202f)) { + && (utf_ptr2char(s) == 160 || utf_ptr2char(s) == 0x202f)) { mb_char2bytes(lcs_nbsp, (char_u *)buf); buf[(*mb_ptr2len)((char_u *)buf)] = NUL; } else { @@ -2866,14 +2866,12 @@ do_dialog ( // Make the character lowercase, as chars in "hotkeys" are. c = mb_tolower(c); retval = 1; - for (i = 0; hotkeys[i]; ++i) { - if (has_mbyte) { - if ((*mb_ptr2char)(hotkeys + i) == c) - break; - i += (*mb_ptr2len)(hotkeys + i) - 1; - } else if (hotkeys[i] == c) + for (i = 0; hotkeys[i]; i++) { + if (utf_ptr2char(hotkeys + i) == c) { break; - ++retval; + } + i += utfc_ptr2len(hotkeys + i) - 1; + retval++; } if (hotkeys[i]) break; @@ -2905,25 +2903,13 @@ copy_char ( int lowercase /* make character lower case */ ) { - int len; - int c; - - if (has_mbyte) { - if (lowercase) { - c = mb_tolower((*mb_ptr2char)(from)); - return (*mb_char2bytes)(c, to); - } else { - len = (*mb_ptr2len)(from); - memmove(to, from, (size_t)len); - return len; - } - } else { - if (lowercase) - *to = (char_u)TOLOWER_LOC(*from); - else - *to = *from; - return 1; + if (lowercase) { + int c = mb_tolower(utf_ptr2char(from)); + return utf_char2bytes(c, to); } + int len = utfc_ptr2len(from); + memmove(to, from, (size_t)len); + return len; } #define HAS_HOTKEY_LEN 30 diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index d2ecb9a74b..84d8c995a6 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -701,13 +701,12 @@ open_line ( replace_push(NUL); /* end of extra blanks */ if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES)) { while ((*p_extra == ' ' || *p_extra == '\t') - && (!enc_utf8 - || !utf_iscomposing(utf_ptr2char(p_extra + 1))) - ) { - if (REPLACE_NORMAL(State)) + && !utf_iscomposing(utf_ptr2char(p_extra + 1))) { + if (REPLACE_NORMAL(State)) { replace_push(*p_extra); - ++p_extra; - ++less_cols_off; + } + p_extra++; + less_cols_off++; } } if (*p_extra != NUL) { @@ -772,7 +771,7 @@ open_line ( (void)u_save_cursor(); /* errors are ignored! */ vr_lines_changed++; } - ml_replace(curwin->w_cursor.lnum, p_extra, TRUE); + ml_replace(curwin->w_cursor.lnum, p_extra, true); changed_bytes(curwin->w_cursor.lnum, 0); curwin->w_cursor.lnum--; did_append = FALSE; @@ -832,12 +831,13 @@ open_line ( if (dir == FORWARD) { if (trunc_line || (State & INSERT)) { - /* truncate current line at cursor */ + // truncate current line at cursor saved_line[curwin->w_cursor.col] = NUL; - /* Remove trailing white space, unless OPENLINE_KEEPTRAIL used. */ - if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) + // Remove trailing white space, unless OPENLINE_KEEPTRAIL used. + if (trunc_line && !(flags & OPENLINE_KEEPTRAIL)) { truncate_spaces(saved_line); - ml_replace(curwin->w_cursor.lnum, saved_line, FALSE); + } + ml_replace(curwin->w_cursor.lnum, saved_line, false); saved_line = NULL; if (did_append) { changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col, @@ -913,8 +913,8 @@ open_line ( /* Put new line in p_extra */ p_extra = vim_strsave(get_cursor_line_ptr()); - /* Put back original line */ - ml_replace(curwin->w_cursor.lnum, next_line, FALSE); + // Put back original line + ml_replace(curwin->w_cursor.lnum, next_line, false); /* Insert new stuff into line again */ curwin->w_cursor.col = 0; @@ -1498,8 +1498,8 @@ void ins_char_bytes(char_u *buf, size_t charlen) p[i] = ' '; } - /* Replace the line in the buffer. */ - ml_replace(lnum, newp, FALSE); + // Replace the line in the buffer. + ml_replace(lnum, newp, false); // mark the buffer as changed and prepare for displaying changed_bytes(lnum, (colnr_T)col); @@ -1512,7 +1512,7 @@ void ins_char_bytes(char_u *buf, size_t charlen) && msg_silent == 0 && !ins_compl_active() ) { - showmatch(mb_ptr2char(buf)); + showmatch(utf_ptr2char(buf)); } if (!p_ri || (State & REPLACE_FLAG)) { @@ -1549,19 +1549,17 @@ void ins_str(char_u *s) memmove(newp, oldp, (size_t)col); memmove(newp + col, s, (size_t)newlen); memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1)); - ml_replace(lnum, newp, FALSE); + ml_replace(lnum, newp, false); changed_bytes(lnum, col); curwin->w_cursor.col += newlen; } -/* - * Delete one character under the cursor. - * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line. - * Caller must have prepared for undo. - * - * return FAIL for failure, OK otherwise - */ -int del_char(int fixpos) +// Delete one character under the cursor. +// If "fixpos" is true, don't leave the cursor on the NUL after the line. +// Caller must have prepared for undo. +// +// return FAIL for failure, OK otherwise +int del_char(bool fixpos) { if (has_mbyte) { /* Make sure the cursor is at the start of a character. */ @@ -1667,8 +1665,9 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) memmove(newp, oldp, (size_t)col); } memmove(newp + col, oldp + col + count, (size_t)movelen); - if (!was_alloced) - ml_replace(lnum, newp, FALSE); + if (!was_alloced) { + ml_replace(lnum, newp, false); + } /* mark the buffer as changed and prepare for displaying */ changed_bytes(lnum, curwin->w_cursor.col); @@ -1749,11 +1748,7 @@ del_lines ( int gchar_pos(pos_T *pos) { - char_u *ptr = ml_get_pos(pos); - - if (has_mbyte) - return (*mb_ptr2char)(ptr); - return (int)*ptr; + return utf_ptr2char(ml_get_pos(pos)); } /* @@ -2389,12 +2384,12 @@ int get_keystroke(void) } break; } - if (has_mbyte) { - if (MB_BYTE2LEN(n) > len) - continue; /* more bytes to get */ - buf[len >= buflen ? buflen - 1 : len] = NUL; - n = (*mb_ptr2char)(buf); + if (MB_BYTE2LEN(n) > len) { + // more bytes to get. + continue; } + buf[len >= buflen ? buflen - 1 : len] = NUL; + n = utf_ptr2char(buf); #ifdef UNIX if (n == intr_char) n = ESC; @@ -2840,4 +2835,3 @@ int goto_im(void) { return p_im && stuff_empty() && typebuf_typed(); } - diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 4fb1a1ea9d..7defde731a 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -310,30 +310,32 @@ void shift_line( */ static void shift_block(oparg_T *oap, int amount) { - int left = (oap->op_type == OP_LSHIFT); - int oldstate = State; - int total; - char_u *newp, *oldp; - int oldcol = curwin->w_cursor.col; - int p_sw = get_sw_value(curbuf); - int p_ts = (int)curbuf->b_p_ts; + const bool left = (oap->op_type == OP_LSHIFT); + const int oldstate = State; + char_u *newp; + const int oldcol = curwin->w_cursor.col; + const int p_sw = get_sw_value(curbuf); + const int p_ts = (int)curbuf->b_p_ts; struct block_def bd; int incr; - colnr_T ws_vcol; int i = 0, j = 0; - int len; - int old_p_ri = p_ri; + const int old_p_ri = p_ri; p_ri = 0; /* don't want revins in indent */ - State = INSERT; /* don't want REPLACE for State */ - block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE); - if (bd.is_short) + State = INSERT; // don't want REPLACE for State + block_prep(oap, &bd, curwin->w_cursor.lnum, true); + if (bd.is_short) { return; + } + + // total is number of screen columns to be inserted/removed + int total = (int)((unsigned)amount * (unsigned)p_sw); + if ((total / p_sw) != amount) { + return; // multiplication overflow + } - /* total is number of screen columns to be inserted/removed */ - total = amount * p_sw; - oldp = get_cursor_line_ptr(); + char_u *const oldp = get_cursor_line_ptr(); if (!left) { /* @@ -342,8 +344,8 @@ static void shift_block(oparg_T *oap, int amount) * 3. Divvy into TABs & spp * 4. Construct new string */ - total += bd.pre_whitesp; /* all virtual WS up to & incl a split TAB */ - ws_vcol = bd.start_vcol - bd.pre_whitesp; + total += bd.pre_whitesp; // all virtual WS up to & incl a split TAB + colnr_T ws_vcol = bd.start_vcol - bd.pre_whitesp; if (bd.startspaces) { if (has_mbyte) { if ((*mb_ptr2len)(bd.textstart) == 1) { @@ -372,8 +374,8 @@ static void shift_block(oparg_T *oap, int amount) j = total; /* if we're splitting a TAB, allow for it */ bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0); - len = (int)STRLEN(bd.textstart) + 1; - newp = (char_u *) xmalloc((size_t)(bd.textcol + i + j + len)); + const int len = (int)STRLEN(bd.textstart) + 1; + newp = (char_u *)xmalloc((size_t)(bd.textcol + i + j + len)); memset(newp, NUL, (size_t)(bd.textcol + i + j + len)); memmove(newp, oldp, (size_t)bd.textcol); memset(newp + bd.textcol, TAB, (size_t)i); @@ -390,10 +392,7 @@ static void shift_block(oparg_T *oap, int amount) size_t fill; // nr of spaces that replace a TAB size_t new_line_len; // the length of the line after the // block shift - colnr_T block_space_width; - colnr_T shift_amount; char_u *non_white = bd.textstart; - colnr_T non_white_col; /* * Firstly, let's find the first non-whitespace character that is @@ -410,19 +409,20 @@ static void shift_block(oparg_T *oap, int amount) MB_PTR_ADV(non_white); } - /* The character's column is in "bd.start_vcol". */ - non_white_col = bd.start_vcol; + // The character's column is in "bd.start_vcol". + colnr_T non_white_col = bd.start_vcol; while (ascii_iswhite(*non_white)) { incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col); non_white_col += incr; } - block_space_width = non_white_col - oap->start_vcol; - /* We will shift by "total" or "block_space_width", whichever is less. - */ - shift_amount = (block_space_width < total ? block_space_width : total); + const colnr_T block_space_width = non_white_col - oap->start_vcol; + // We will shift by "total" or "block_space_width", whichever is less. + const colnr_T shift_amount = block_space_width < total + ? block_space_width + : total; // The column to which we will shift the text. destination_col = non_white_col - shift_amount; @@ -454,7 +454,7 @@ static void shift_block(oparg_T *oap, int amount) fill = (size_t)(destination_col - verbatim_copy_width); assert(verbatim_copy_end - oldp >= 0); - size_t verbatim_diff = (size_t)(verbatim_copy_end - oldp); + const size_t verbatim_diff = (size_t)(verbatim_copy_end - oldp); // The replacement line will consist of: // - the beginning of the original line up to "verbatim_copy_end", // - "fill" number of spaces, @@ -466,8 +466,8 @@ static void shift_block(oparg_T *oap, int amount) memset(newp + verbatim_diff, ' ', fill); STRMOVE(newp + verbatim_diff + fill, non_white); } - /* replace the line */ - ml_replace(curwin->w_cursor.lnum, newp, FALSE); + // replace the line + ml_replace(curwin->w_cursor.lnum, newp, false); changed_bytes(curwin->w_cursor.lnum, (colnr_T)bd.textcol); State = oldstate; curwin->w_cursor.col = oldcol; @@ -561,7 +561,7 @@ static void block_insert(oparg_T *oap, char_u *s, int b_insert, struct block_def offset += count; STRMOVE(newp + offset, oldp); - ml_replace(lnum, newp, FALSE); + ml_replace(lnum, newp, false); if (lnum == oap->end.lnum) { /* Set "']" mark to the end of the block instead of the end of @@ -1427,10 +1427,11 @@ int op_delete(oparg_T *oap) return FAIL; } - for (lnum = curwin->w_cursor.lnum; lnum <= oap->end.lnum; ++lnum) { - block_prep(oap, &bd, lnum, TRUE); - if (bd.textlen == 0) /* nothing to delete */ + for (lnum = curwin->w_cursor.lnum; lnum <= oap->end.lnum; lnum++) { + block_prep(oap, &bd, lnum, true); + if (bd.textlen == 0) { // nothing to delete continue; + } /* Adjust cursor position for tab replaced by spaces and 'lbr'. */ if (lnum == curwin->w_cursor.lnum) { @@ -1656,11 +1657,12 @@ int op_replace(oparg_T *oap, int c) */ if (oap->motion_type == kMTBlockWise) { bd.is_MAX = (curwin->w_curswant == MAXCOL); - for (; curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum) { - curwin->w_cursor.col = 0; /* make sure cursor position is valid */ - block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE); - if (bd.textlen == 0 && (!virtual_op || bd.is_MAX)) - continue; /* nothing to replace */ + for (; curwin->w_cursor.lnum <= oap->end.lnum; curwin->w_cursor.lnum++) { + curwin->w_cursor.col = 0; // make sure cursor position is valid + block_prep(oap, &bd, curwin->w_cursor.lnum, true); + if (bd.textlen == 0 && (!virtual_op || bd.is_MAX)) { + continue; // nothing to replace + } /* n == number of extra chars required * If we split a TAB, it may be replaced by several characters. @@ -1747,8 +1749,8 @@ int op_replace(oparg_T *oap, int c) after_p = (char_u *)xmalloc(after_p_len); memmove(after_p, oldp, after_p_len); } - /* replace the line */ - ml_replace(curwin->w_cursor.lnum, newp, FALSE); + // replace the line + ml_replace(curwin->w_cursor.lnum, newp, false); if (after_p != NULL) { ml_append(curwin->w_cursor.lnum++, after_p, (int)after_p_len, false); appended_lines_mark(curwin->w_cursor.lnum, 1L); @@ -1852,7 +1854,7 @@ void op_tilde(oparg_T *oap) for (; pos.lnum <= oap->end.lnum; pos.lnum++) { int one_change; - block_prep(oap, &bd, pos.lnum, FALSE); + block_prep(oap, &bd, pos.lnum, false); pos.col = bd.textcol; one_change = swapchars(oap->op_type, &pos, bd.textlen); did_change |= one_change; @@ -1956,7 +1958,7 @@ int swapchar(int op_type, pos_T *pos) /* Special handling of German sharp s: change to "SS". */ curwin->w_cursor = *pos; - del_char(FALSE); + del_char(false); ins_char('S'); ins_char('S'); curwin->w_cursor = sp; @@ -2030,8 +2032,8 @@ void op_insert(oparg_T *oap, long count1) --curwin->w_cursor.col; ve_flags = old_ve_flags; } - /* Get the info about the block before entering the text */ - block_prep(oap, &bd, oap->start.lnum, TRUE); + // Get the info about the block before entering the text + block_prep(oap, &bd, oap->start.lnum, true); firstline = ml_get(oap->start.lnum) + bd.textcol; if (oap->op_type == OP_APPEND) firstline += bd.textlen; @@ -2119,7 +2121,7 @@ void op_insert(oparg_T *oap, long count1) * tabs. Get the starting column again and correct the length. * Don't do this when "$" used, end-of-line will have changed. */ - block_prep(oap, &bd2, oap->start.lnum, TRUE); + block_prep(oap, &bd2, oap->start.lnum, true); if (!bd.is_MAX || bd2.textlen < bd.textlen) { if (oap->op_type == OP_APPEND) { pre_textlen += bd2.textlen - bd.textlen; @@ -2239,7 +2241,7 @@ int op_change(oparg_T *oap) STRLCPY(ins_text, firstline + bd.textcol, ins_len + 1); for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum; linenr++) { - block_prep(oap, &bd, linenr, TRUE); + block_prep(oap, &bd, linenr, true); if (!bd.is_short || virtual_op) { pos_T vpos; @@ -2263,7 +2265,7 @@ int op_change(oparg_T *oap) offset += ins_len; oldp += bd.textcol; STRMOVE(newp + offset, oldp); - ml_replace(linenr, newp, FALSE); + ml_replace(linenr, newp, false); } } check_cursor(); @@ -3117,10 +3119,10 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) ptr += yanklen; } STRMOVE(ptr, oldp + col); - ml_replace(lnum, newp, FALSE); - /* Place cursor on last putted char. */ + ml_replace(lnum, newp, false); + // Place cursor on last putted char. if (lnum == curwin->w_cursor.lnum) { - /* make sure curwin->w_virtcol is updated */ + // make sure curwin->w_virtcol is updated changed_cline_bef_curs(); curwin->w_cursor.col += (colnr_T)(totlen - 1); } @@ -3164,7 +3166,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags) memmove(newp, oldp, (size_t)col); /* append to first line */ memmove(newp + col, y_array[0], (size_t)(yanklen + 1)); - ml_replace(lnum, newp, FALSE); + ml_replace(lnum, newp, false); curwin->w_cursor.lnum = lnum; i = 1; @@ -3620,9 +3622,9 @@ int do_join(size_t count, curr = skipwhite(curr); if (*curr != ')' && currsize != 0 && endcurr1 != TAB && (!has_format_option(FO_MBYTE_JOIN) - || (mb_ptr2char(curr) < 0x100 && endcurr1 < 0x100)) + || (utf_ptr2char(curr) < 0x100 && endcurr1 < 0x100)) && (!has_format_option(FO_MBYTE_JOIN2) - || mb_ptr2char(curr) < 0x100 || endcurr1 < 0x100) + || utf_ptr2char(curr) < 0x100 || endcurr1 < 0x100) ) { /* don't add a space if the line is ending in a space */ if (endcurr1 == ' ') @@ -3639,18 +3641,12 @@ int do_join(size_t count, sumsize += currsize + spaces[t]; endcurr1 = endcurr2 = NUL; if (insert_space && currsize > 0) { - if (has_mbyte) { - cend = curr + currsize; + cend = curr + currsize; + MB_PTR_BACK(curr, cend); + endcurr1 = utf_ptr2char(cend); + if (cend > curr) { MB_PTR_BACK(curr, cend); - endcurr1 = (*mb_ptr2char)(cend); - if (cend > curr) { - MB_PTR_BACK(curr, cend); - endcurr2 = (*mb_ptr2char)(cend); - } - } else { - endcurr1 = *(curr + currsize - 1); - if (currsize > 1) - endcurr2 = *(curr + currsize - 2); + endcurr2 = utf_ptr2char(cend); } } line_breakcheck(); @@ -3693,7 +3689,7 @@ int do_join(size_t count, curr = skipwhite(curr); currsize = (int)STRLEN(curr); } - ml_replace(curwin->w_cursor.lnum, newp, FALSE); + ml_replace(curwin->w_cursor.lnum, newp, false); if (setmark) { // Set the '] mark. @@ -4245,7 +4241,8 @@ int paragraph_start(linenr_T lnum) * - start/endspaces is the number of columns of the first/last yanked char * that are to be yanked. */ -static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int is_del) +static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, + bool is_del) { int incr = 0; char_u *pend; @@ -5382,7 +5379,7 @@ void cursor_pos_info(dict_T *dict) switch (l_VIsual_mode) { case Ctrl_V: virtual_op = virtual_active(); - block_prep(&oparg, &bd, lnum, 0); + block_prep(&oparg, &bd, lnum, false); virtual_op = kNone; s = bd.textstart; len = (long)bd.textlen; diff --git a/src/nvim/option.c b/src/nvim/option.c index 50c172b580..8e2264c6a7 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2703,7 +2703,7 @@ did_set_string_option ( if (*p != NUL) x2 = *p++; if (*p != NUL) { - x3 = mb_ptr2char(p); + x3 = utf_ptr2char(p); p += mb_ptr2len(p); } if (x2 != ':' || x3 == -1 || (*p != NUL && *p != ',')) { @@ -6406,22 +6406,25 @@ static void langmap_set(void) ++p; break; } - if (p[0] == '\\' && p[1] != NUL) - ++p; - from = (*mb_ptr2char)(p); + if (p[0] == '\\' && p[1] != NUL) { + p++; + } + from = utf_ptr2char(p); to = NUL; if (p2 == NULL) { MB_PTR_ADV(p); if (p[0] != ',') { - if (p[0] == '\\') - ++p; - to = (*mb_ptr2char)(p); + if (p[0] == '\\') { + p++; + } + to = utf_ptr2char(p); } } else { if (p2[0] != ',') { - if (p2[0] == '\\') - ++p2; - to = (*mb_ptr2char)(p2); + if (p2[0] == '\\') { + p2++; + } + to = utf_ptr2char(p2); } } if (to == NUL) { @@ -6846,66 +6849,37 @@ int get_sts_value(void) */ void find_mps_values(int *initc, int *findc, int *backwards, int switchit) { - char_u *ptr; + char_u *ptr = curbuf->b_p_mps; - ptr = curbuf->b_p_mps; while (*ptr != NUL) { - if (has_mbyte) { - char_u *prev; - - if (mb_ptr2char(ptr) == *initc) { - if (switchit) { - *findc = *initc; - *initc = mb_ptr2char(ptr + mb_ptr2len(ptr) + 1); - *backwards = TRUE; - } else { - *findc = mb_ptr2char(ptr + mb_ptr2len(ptr) + 1); - *backwards = FALSE; - } - return; - } - prev = ptr; - ptr += mb_ptr2len(ptr) + 1; - if (mb_ptr2char(ptr) == *initc) { - if (switchit) { - *findc = *initc; - *initc = mb_ptr2char(prev); - *backwards = FALSE; - } else { - *findc = mb_ptr2char(prev); - *backwards = TRUE; - } - return; - } - ptr += mb_ptr2len(ptr); - } else { - if (*ptr == *initc) { - if (switchit) { - *backwards = TRUE; - *findc = *initc; - *initc = ptr[2]; - } else { - *backwards = FALSE; - *findc = ptr[2]; - } - return; + if (utf_ptr2char(ptr) == *initc) { + if (switchit) { + *findc = *initc; + *initc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1); + *backwards = true; + } else { + *findc = utf_ptr2char(ptr + utfc_ptr2len(ptr) + 1); + *backwards = false; } - ptr += 2; - if (*ptr == *initc) { - if (switchit) { - *backwards = FALSE; - *findc = *initc; - *initc = ptr[-2]; - } else { - *backwards = TRUE; - *findc = ptr[-2]; - } - return; + return; + } + char_u *prev = ptr; + ptr += utfc_ptr2len(ptr) + 1; + if (utf_ptr2char(ptr) == *initc) { + if (switchit) { + *findc = *initc; + *initc = utf_ptr2char(prev); + *backwards = false; + } else { + *findc = utf_ptr2char(prev); + *backwards = true; } - ++ptr; + return; + } + ptr += utfc_ptr2len(ptr); + if (*ptr == ',') { + ptr++; } - if (*ptr == ',') - ++ptr; } } diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index d76da62c6d..be6c43493b 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -772,13 +772,9 @@ static int get_equi_class(char_u **pp) char_u *p = *pp; if (p[1] == '=') { - if (has_mbyte) - l = (*mb_ptr2len)(p + 2); + l = (*mb_ptr2len)(p + 2); if (p[l + 2] == '=' && p[l + 3] == ']') { - if (has_mbyte) - c = mb_ptr2char(p + 2); - else - c = p[2]; + c = utf_ptr2char(p + 2); *pp += l + 4; return c; } @@ -1107,13 +1103,9 @@ static int get_coll_element(char_u **pp) char_u *p = *pp; if (p[0] != NUL && p[1] == '.') { - if (has_mbyte) - l = (*mb_ptr2len)(p + 2); + l = utfc_ptr2len(p + 2); if (p[l + 2] == '.' && p[l + 3] == ']') { - if (has_mbyte) - c = mb_ptr2char(p + 2); - else - c = p[2]; + c = utf_ptr2char(p + 2); *pp += l + 4; return c; } @@ -1299,10 +1291,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags) } if (OP(scan) == EXACTLY) { - if (has_mbyte) - r->regstart = (*mb_ptr2char)(OPERAND(scan)); - else - r->regstart = *OPERAND(scan); + r->regstart = utf_ptr2char(OPERAND(scan)); } else if (OP(scan) == BOW || OP(scan) == EOW || OP(scan) == NOTHING @@ -1310,10 +1299,7 @@ static regprog_T *bt_regcomp(char_u *expr, int re_flags) || OP(scan) == MCLOSE + 0 || OP(scan) == NCLOSE) { char_u *regnext_scan = regnext(scan); if (OP(regnext_scan) == EXACTLY) { - if (has_mbyte) - r->regstart = (*mb_ptr2char)(OPERAND(regnext_scan)); - else - r->regstart = *OPERAND(regnext_scan); + r->regstart = utf_ptr2char(OPERAND(regnext_scan)); } } @@ -2412,20 +2398,16 @@ collection: break; } } else { - if (has_mbyte) { - int len; - - /* produce a multibyte character, including any - * following composing characters */ - startc = mb_ptr2char(regparse); - len = (*mb_ptr2len)(regparse); - if (enc_utf8 && utf_char2len(startc) != len) - startc = -1; /* composing chars */ - while (--len >= 0) - regc(*regparse++); - } else { - startc = *regparse++; - regc(startc); + // produce a multibyte character, including any + // following composing characters. + startc = utf_ptr2char(regparse); + int len = utfc_ptr2len(regparse); + if (utf_char2len(startc) != len) { + // composing chars + startc = -1; + } + while (--len >= 0) { + regc(*regparse++); } } } @@ -2906,17 +2888,13 @@ static int peekchr(void) * Next character can never be (made) magic? * Then backslashing it won't do anything. */ - if (has_mbyte) - curchr = (*mb_ptr2char)(regparse + 1); - else - curchr = c; + curchr = utf_ptr2char(regparse + 1); } break; } default: - if (has_mbyte) - curchr = (*mb_ptr2char)(regparse); + curchr = utf_ptr2char(regparse); } return curchr; @@ -3466,12 +3444,7 @@ static long bt_regexec_both(char_u *line, /* If there is a "must appear" string, look for it. */ if (prog->regmust != NULL) { - int c; - - if (has_mbyte) - c = (*mb_ptr2char)(prog->regmust); - else - c = *prog->regmust; + int c = utf_ptr2char(prog->regmust); s = line + col; // This is used very often, esp. for ":global". Use two versions of @@ -3502,16 +3475,11 @@ static long bt_regexec_both(char_u *line, /* Simplest case: Anchored match need be tried only once. */ if (prog->reganch) { - int c; - - if (has_mbyte) - c = (*mb_ptr2char)(regline + col); - else - c = regline[col]; + int c = utf_ptr2char(regline + col); if (prog->regstart == NUL || prog->regstart == c || (rex.reg_ic - && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) + && (utf_fold(prog->regstart) == utf_fold(c) || (c < 255 && prog->regstart < 255 && mb_tolower(prog->regstart) == mb_tolower(c))))) { retval = regtry(prog, col); @@ -3858,12 +3826,10 @@ regmatch ( } else if (rex.reg_line_lbr && WITH_NL(op) && *reginput == '\n') { ADVANCE_REGINPUT(); } else { - if (WITH_NL(op)) + if (WITH_NL(op)) { op -= ADD_NL; - if (has_mbyte) - c = (*mb_ptr2char)(reginput); - else - c = *reginput; + } + c = utf_ptr2char(reginput); switch (op) { case BOL: if (reginput != regline) @@ -5473,8 +5439,8 @@ do_class: } } else if (rex.reg_line_lbr && *scan == '\n' && WITH_NL(OP(p))) { scan++; - } else if (has_mbyte && (len = (*mb_ptr2len)(scan)) > 1) { - if ((cstrchr(opnd, (*mb_ptr2char)(scan)) == NULL) == testval) { + } else if ((len = utfc_ptr2len(scan)) > 1) { + if ((cstrchr(opnd, utf_ptr2char(scan)) == NULL) == testval) { break; } scan += len; @@ -6782,18 +6748,18 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, } c = *src++; } - } else if (has_mbyte) - c = mb_ptr2char(src - 1); - - /* Write to buffer, if copy is set. */ - if (func_one != (fptr_T)NULL) - /* Turbo C complains without the typecast */ + } else { + c = utf_ptr2char(src - 1); + } + // Write to buffer, if copy is set. + if (func_one != NULL) { func_one = (fptr_T)(func_one(&cc, c)); - else if (func_all != (fptr_T)NULL) - /* Turbo C complains without the typecast */ + } else if (func_all != NULL) { func_all = (fptr_T)(func_all(&cc, c)); - else /* just copy */ + } else { + // just copy cc = c; + } if (has_mbyte) { int totlen = mb_ptr2len(src - 1); @@ -6878,10 +6844,7 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest, } dst += 2; } else { - if (has_mbyte) - c = mb_ptr2char(s); - else - c = *s; + c = utf_ptr2char(s); if (func_one != (fptr_T)NULL) /* Turbo C complains without the typecast */ diff --git a/src/nvim/regexp_nfa.c b/src/nvim/regexp_nfa.c index 2eb0ca9313..deef3042d2 100644 --- a/src/nvim/regexp_nfa.c +++ b/src/nvim/regexp_nfa.c @@ -5030,16 +5030,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, * Run for each character. */ for (;; ) { - int curc; - int clen; - - if (has_mbyte) { - curc = (*mb_ptr2char)(reginput); - clen = (*mb_ptr2len)(reginput); - } else { - curc = *reginput; - clen = 1; - } + int curc = utf_ptr2char(reginput); + int clen = utfc_ptr2len(reginput); if (curc == NUL) { clen = 0; go_to_nextline = false; @@ -5501,7 +5493,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, // We don't care about the order of composing characters. // Get them into cchars[] first. while (len < clen) { - mc = mb_ptr2char(reginput + len); + mc = utf_ptr2char(reginput + len); cchars[ccount++] = mc; len += mb_char2len(mc); if (ccount == MAX_MCO) diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 8e7a84c6b1..f7fdc6060d 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -2197,7 +2197,7 @@ win_line ( match_T *shl; // points to search_hl or a match int shl_flag; // flag to indicate whether search_hl // has been processed or not - int prevcol_hl_flag; // flag to indicate whether prevcol + bool prevcol_hl_flag; // flag to indicate whether prevcol // equals startcol of search_hl or one // of the matches int prev_c = 0; // previous Arabic character @@ -3026,6 +3026,12 @@ win_line ( if (shl != &search_hl && cur != NULL) cur = cur->next; } + // Only highlight one character after the last column. + if (*ptr == NUL + && (did_line_attr >= 1 + || (wp->w_p_list && lcs_eol_one == -1))) { + search_attr = 0; + } } if (diff_hlf != (hlf_T)0) { @@ -3674,7 +3680,9 @@ win_line ( // don't do search HL for the rest of the line if ((line_attr_lowprio || line_attr) - && char_attr == search_attr && col > 0) { + && char_attr == search_attr + && (did_line_attr > 1 + || (wp->w_p_list && lcs_eol > 0))) { char_attr = line_attr; } if (diff_hlf == HLF_TXD) { @@ -3833,9 +3841,12 @@ win_line ( || lnum == VIsual.lnum || lnum == curwin->w_cursor.lnum) && c == NUL) - /* highlight 'hlsearch' match at end of line */ - || (prevcol_hl_flag == TRUE && did_line_attr <= 1) - )) { + // highlight 'hlsearch' match at end of line + || (prevcol_hl_flag + && !(wp->w_p_cul && lnum == wp->w_cursor.lnum + && !(wp == curwin && VIsual_active)) + && diff_hlf == (hlf_T)0 + && did_line_attr <= 1))) { int n = 0; if (wp->w_p_rl) { @@ -5805,7 +5816,8 @@ void screen_fill(int start_row, int end_row, int start_col, int end_col, int c1, // TODO(bfredl): The relevant caller should do this if (row == Rows - 1) { // overwritten the command line redraw_cmdline = true; - if (c1 == ' ' && c2 == ' ') { + if (start_col == 0 && end_col == Columns + && c1 == ' ' && c2 == ' ' && attr == 0) { clear_cmdline = false; // command line has been cleared } if (start_col == 0) { diff --git a/src/nvim/search.c b/src/nvim/search.c index 472b98a501..95929f0eb4 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -1120,8 +1120,8 @@ int do_search( msgbuf = xmalloc(STRLEN(p) + 40); { msgbuf[0] = dirc; - if (enc_utf8 && utf_iscomposing(utf_ptr2char(p))) { - /* Use a space to draw the composing char on. */ + if (utf_iscomposing(utf_ptr2char(p))) { + // Use a space to draw the composing char on. msgbuf[1] = ' '; STRCPY(msgbuf + 2, p); } else diff --git a/src/nvim/spell.c b/src/nvim/spell.c index cb03257878..1cb679245b 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -1956,7 +1956,7 @@ static int count_syllables(slang_T *slang, char_u *word) skip = false; } else { // No recognized syllable item, at least a syllable char then? - c = mb_ptr2char(p); + c = utf_ptr2char(p); len = (*mb_ptr2len)(p); if (vim_strchr(slang->sl_syllable, c) == NULL) skip = false; // No, search for next syllable @@ -2271,7 +2271,7 @@ static void use_midword(slang_T *lp, win_T *wp) int c, l, n; char_u *bp; - c = mb_ptr2char(p); + c = utf_ptr2char(p); l = (*mb_ptr2len)(p); if (c < 256 && l <= 2) wp->w_s->b_spell_ismw[c] = true; @@ -2597,16 +2597,18 @@ static bool spell_iswordp(char_u *p, win_T *wp) if (wp->w_s->b_spell_ismw[*p]) s = p + 1; // skip a mid-word character } else { - c = mb_ptr2char(p); + c = utf_ptr2char(p); if (c < 256 ? wp->w_s->b_spell_ismw[c] : (wp->w_s->b_spell_ismw_mb != NULL - && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL)) + && vim_strchr(wp->w_s->b_spell_ismw_mb, c) != NULL)) { s = p + l; + } } - c = mb_ptr2char(s); - if (c > 255) + c = utf_ptr2char(s); + if (c > 255) { return spell_mb_isword_class(mb_get_class(s), wp); + } return spelltab.st_isw[c]; } @@ -2617,16 +2619,11 @@ static bool spell_iswordp(char_u *p, win_T *wp) // Unlike spell_iswordp() this doesn't check for "midword" characters. bool spell_iswordp_nmw(const char_u *p, win_T *wp) { - int c; - - if (has_mbyte) { - c = mb_ptr2char(p); - if (c > 255) { - return spell_mb_isword_class(mb_get_class(p), wp); - } - return spelltab.st_isw[c]; + int c = utf_ptr2char(p); + if (c > 255) { + return spell_mb_isword_class(mb_get_class(p), wp); } - return spelltab.st_isw[*p]; + return spelltab.st_isw[c]; } // Returns true if word class indicates a word character. @@ -2944,7 +2941,7 @@ void spell_suggest(int count) memmove(p, line, c); STRCPY(p + c, stp->st_word); STRCAT(p, sug.su_badptr + stp->st_orglen); - ml_replace(curwin->w_cursor.lnum, p, FALSE); + ml_replace(curwin->w_cursor.lnum, p, false); curwin->w_cursor.col = c; // For redo we use a change-word command. @@ -3062,7 +3059,7 @@ void ex_spellrepall(exarg_T *eap) memmove(p, line, curwin->w_cursor.col); STRCPY(p + curwin->w_cursor.col, repl_to); STRCAT(p, line + curwin->w_cursor.col + STRLEN(repl_from)); - ml_replace(curwin->w_cursor.lnum, p, FALSE); + ml_replace(curwin->w_cursor.lnum, p, false); changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); if (curwin->w_cursor.lnum != prev_lnum) { @@ -4300,14 +4297,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so && utf_iscomposing(utf_ptr2char(fword + sp->ts_fcharstart))) { sp->ts_score -= SCORE_SUBST - SCORE_SUBCOMP; - } else if (!soundfold - && slang->sl_has_map - && similar_chars(slang, - mb_ptr2char(tword - + sp->ts_twordlen - - sp->ts_tcharlen), - mb_ptr2char(fword - + sp->ts_fcharstart))) { + } else if ( + !soundfold + && slang->sl_has_map + && similar_chars( + slang, + utf_ptr2char(tword + sp->ts_twordlen - sp->ts_tcharlen), + utf_ptr2char(fword + sp->ts_fcharstart))) { // For a similar character adjust score from // SCORE_SUBST to SCORE_SIMILAR. sp->ts_score -= SCORE_SUBST - SCORE_SIMILAR; @@ -4315,8 +4311,8 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so } else if (sp->ts_isdiff == DIFF_INSERT && sp->ts_twordlen > sp->ts_tcharlen) { p = tword + sp->ts_twordlen - sp->ts_tcharlen; - c = mb_ptr2char(p); - if (enc_utf8 && utf_iscomposing(c)) { + c = utf_ptr2char(p); + if (utf_iscomposing(c)) { // Inserting a composing char doesn't // count that much. sp->ts_score -= SCORE_INS - SCORE_INSCOMP; @@ -4327,7 +4323,7 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // tree (might seem illogical but does // give better scores). MB_PTR_BACK(tword, p); - if (c == mb_ptr2char(p)) { + if (c == utf_ptr2char(p)) { sp->ts_score -= SCORE_INS - SCORE_INSDUP; } } @@ -4388,19 +4384,14 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so // score if the same character is following "nn" -> "n". It's // a bit illogical for soundfold tree but it does give better // results. - if (has_mbyte) { - c = mb_ptr2char(fword + sp->ts_fidx); - stack[depth].ts_fidx += MB_PTR2LEN(fword + sp->ts_fidx); - if (enc_utf8 && utf_iscomposing(c)) { - stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP; - } else if (c == mb_ptr2char(fword + stack[depth].ts_fidx)) { - stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP; - } - } else { - ++stack[depth].ts_fidx; - if (fword[sp->ts_fidx] == fword[sp->ts_fidx + 1]) - stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP; + c = utf_ptr2char(fword + sp->ts_fidx); + stack[depth].ts_fidx += MB_PTR2LEN(fword + sp->ts_fidx); + if (utf_iscomposing(c)) { + stack[depth].ts_score -= SCORE_DEL - SCORE_DELCOMP; + } else if (c == utf_ptr2char(fword + stack[depth].ts_fidx)) { + stack[depth].ts_score -= SCORE_DEL - SCORE_DELDUP; } + break; } // FALLTHROUGH @@ -4515,22 +4506,14 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so break; } - if (has_mbyte) { - n = MB_CPTR2LEN(p); - c = mb_ptr2char(p); - if (p[n] == NUL) - c2 = NUL; - else if (!soundfold && !spell_iswordp(p + n, curwin)) - c2 = c; // don't swap non-word char - else - c2 = mb_ptr2char(p + n); + n = MB_CPTR2LEN(p); + c = utf_ptr2char(p); + if (p[n] == NUL) { + c2 = NUL; + } else if (!soundfold && !spell_iswordp(p + n, curwin)) { + c2 = c; // don't swap non-word char } else { - if (p[1] == NUL) - c2 = NUL; - else if (!soundfold && !spell_iswordp(p + 1, curwin)) - c2 = c; // don't swap non-word char - else - c2 = p[1]; + c2 = utf_ptr2char(p + n); } // When the second character is NUL we can't swap. @@ -4550,9 +4533,10 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so if (c2 != NUL && TRY_DEEPER(su, stack, depth, SCORE_SWAP)) { go_deeper(stack, depth, SCORE_SWAP); #ifdef DEBUG_TRIEWALK - sprintf(changename[depth], "%.*s-%s: swap %c and %c", - sp->ts_twordlen, tword, fword + sp->ts_fidx, - c, c2); + snprintf(changename[depth], sizeof(changename[0]), + "%.*s-%s: swap %c and %c", + sp->ts_twordlen, tword, fword + sp->ts_fidx, + c, c2); #endif PROF_STORE(sp->ts_state) sp->ts_state = STATE_UNSWAP; @@ -4576,38 +4560,25 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNSWAP: // Undo the STATE_SWAP swap: "21" -> "12". p = fword + sp->ts_fidx; - if (has_mbyte) { - n = MB_PTR2LEN(p); - c = mb_ptr2char(p + n); - memmove(p + MB_PTR2LEN(p + n), p, n); - mb_char2bytes(c, p); - } else { - c = *p; - *p = p[1]; - p[1] = c; - } + n = MB_PTR2LEN(p); + c = utf_ptr2char(p + n); + memmove(p + MB_PTR2LEN(p + n), p, n); + mb_char2bytes(c, p); + // FALLTHROUGH case STATE_SWAP3: // Swap two bytes, skipping one: "123" -> "321". We change // "fword" here, it's changed back afterwards at STATE_UNSWAP3. p = fword + sp->ts_fidx; - if (has_mbyte) { - n = MB_CPTR2LEN(p); - c = mb_ptr2char(p); - fl = MB_CPTR2LEN(p + n); - c2 = mb_ptr2char(p + n); - if (!soundfold && !spell_iswordp(p + n + fl, curwin)) - c3 = c; // don't swap non-word char - else - c3 = mb_ptr2char(p + n + fl); + n = MB_CPTR2LEN(p); + c = utf_ptr2char(p); + fl = MB_CPTR2LEN(p + n); + c2 = utf_ptr2char(p + n); + if (!soundfold && !spell_iswordp(p + n + fl, curwin)) { + c3 = c; // don't swap non-word char } else { - c = *p; - c2 = p[1]; - if (!soundfold && !spell_iswordp(p + 2, curwin)) - c3 = c; // don't swap non-word char - else - c3 = p[2]; + c3 = utf_ptr2char(p + n + fl); } // When characters are identical: "121" then SWAP3 result is @@ -4651,22 +4622,15 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNSWAP3: // Undo STATE_SWAP3: "321" -> "123" p = fword + sp->ts_fidx; - if (has_mbyte) { - n = MB_PTR2LEN(p); - c2 = mb_ptr2char(p + n); - fl = MB_PTR2LEN(p + n); - c = mb_ptr2char(p + n + fl); - tl = MB_PTR2LEN(p + n + fl); - memmove(p + fl + tl, p, n); - mb_char2bytes(c, p); - mb_char2bytes(c2, p + tl); - p = p + tl; - } else { - c = *p; - *p = p[2]; - p[2] = c; - ++p; - } + n = MB_PTR2LEN(p); + c2 = utf_ptr2char(p + n); + fl = MB_PTR2LEN(p + n); + c = utf_ptr2char(p + n + fl); + tl = MB_PTR2LEN(p + n + fl); + memmove(p + fl + tl, p, n); + mb_char2bytes(c, p); + mb_char2bytes(c2, p + tl); + p = p + tl; if (!soundfold && !spell_iswordp(p, curwin)) { // Middle char is not a word char, skip the rotate. First and @@ -4690,21 +4654,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_state = STATE_UNROT3L; ++depth; p = fword + sp->ts_fidx; - if (has_mbyte) { - n = MB_CPTR2LEN(p); - c = mb_ptr2char(p); - fl = MB_CPTR2LEN(p + n); - fl += MB_CPTR2LEN(p + n + fl); - memmove(p, p + n, fl); - mb_char2bytes(c, p + fl); - stack[depth].ts_fidxtry = sp->ts_fidx + n + fl; - } else { - c = *p; - *p = p[1]; - p[1] = p[2]; - p[2] = c; - stack[depth].ts_fidxtry = sp->ts_fidx + 3; - } + n = MB_CPTR2LEN(p); + c = utf_ptr2char(p); + fl = MB_CPTR2LEN(p + n); + fl += MB_CPTR2LEN(p + n + fl); + memmove(p, p + n, fl); + utf_char2bytes(c, p + fl); + stack[depth].ts_fidxtry = sp->ts_fidx + n + fl; } else { PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; @@ -4714,19 +4670,12 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNROT3L: // Undo ROT3L: "231" -> "123" p = fword + sp->ts_fidx; - if (has_mbyte) { - n = MB_PTR2LEN(p); - n += MB_PTR2LEN(p + n); - c = mb_ptr2char(p + n); - tl = MB_PTR2LEN(p + n); - memmove(p + tl, p, n); - mb_char2bytes(c, p); - } else { - c = p[2]; - p[2] = p[1]; - p[1] = *p; - *p = c; - } + n = MB_PTR2LEN(p); + n += MB_PTR2LEN(p + n); + c = utf_ptr2char(p + n); + tl = MB_PTR2LEN(p + n); + memmove(p + tl, p, n); + mb_char2bytes(c, p); // Rotate three bytes right: "123" -> "312". We change "fword" // here, it's changed back afterwards at STATE_UNROT3R. @@ -4742,21 +4691,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so sp->ts_state = STATE_UNROT3R; ++depth; p = fword + sp->ts_fidx; - if (has_mbyte) { - n = MB_CPTR2LEN(p); - n += MB_CPTR2LEN(p + n); - c = mb_ptr2char(p + n); - tl = MB_CPTR2LEN(p + n); - memmove(p + tl, p, n); - mb_char2bytes(c, p); - stack[depth].ts_fidxtry = sp->ts_fidx + n + tl; - } else { - c = p[2]; - p[2] = p[1]; - p[1] = *p; - *p = c; - stack[depth].ts_fidxtry = sp->ts_fidx + 3; - } + n = MB_CPTR2LEN(p); + n += MB_CPTR2LEN(p + n); + c = utf_ptr2char(p + n); + tl = MB_CPTR2LEN(p + n); + memmove(p + tl, p, n); + mb_char2bytes(c, p); + stack[depth].ts_fidxtry = sp->ts_fidx + n + tl; } else { PROF_STORE(sp->ts_state) sp->ts_state = STATE_REP_INI; @@ -4766,19 +4707,13 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char_u *fword, bool so case STATE_UNROT3R: // Undo ROT3R: "312" -> "123" p = fword + sp->ts_fidx; - if (has_mbyte) { - c = mb_ptr2char(p); - tl = MB_PTR2LEN(p); - n = MB_PTR2LEN(p + tl); - n += MB_PTR2LEN(p + tl + n); - memmove(p, p + tl, n); - mb_char2bytes(c, p + n); - } else { - c = *p; - *p = p[1]; - p[1] = p[2]; - p[2] = c; - } + c = utf_ptr2char(p); + tl = MB_PTR2LEN(p); + n = MB_PTR2LEN(p + tl); + n += MB_PTR2LEN(p + tl + n); + memmove(p, p + tl, n); + mb_char2bytes(c, p + n); + // FALLTHROUGH case STATE_REP_INI: @@ -5604,25 +5539,29 @@ static bool similar_chars(slang_T *slang, int c1, int c2) if (c1 >= 256) { buf[mb_char2bytes(c1, buf)] = 0; hi = hash_find(&slang->sl_map_hash, buf); - if (HASHITEM_EMPTY(hi)) + if (HASHITEM_EMPTY(hi)) { m1 = 0; - else - m1 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1); - } else + } else { + m1 = utf_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1); + } + } else { m1 = slang->sl_map_array[c1]; - if (m1 == 0) + } + if (m1 == 0) { return false; - + } if (c2 >= 256) { buf[mb_char2bytes(c2, buf)] = 0; hi = hash_find(&slang->sl_map_hash, buf); - if (HASHITEM_EMPTY(hi)) + if (HASHITEM_EMPTY(hi)) { m2 = 0; - else - m2 = mb_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1); - } else + } else { + m2 = utf_ptr2char(hi->hi_key + STRLEN(hi->hi_key) + 1); + } + } else { m2 = slang->sl_map_array[c2]; + } return m1 == m2; } @@ -5659,11 +5598,9 @@ add_suggestion ( break; MB_PTR_BACK(goodword, pgood); MB_PTR_BACK(su->su_badptr, pbad); - if (has_mbyte) { - if (mb_ptr2char(pgood) != mb_ptr2char(pbad)) - break; - } else if (*pgood != *pbad) + if (utf_ptr2char(pgood) != utf_ptr2char(pbad)) { break; + } } if (badlen == 0 && goodlen == 0) @@ -7608,5 +7545,3 @@ int expand_spelling(linenr_T lnum, char_u *pat, char_u ***matchp) *matchp = ga.ga_data; return ga.ga_len; } - - diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index bd590f53c0..d7c23742ba 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -4101,13 +4101,9 @@ get_syn_options( return NULL; } } else if (flagtab[fidx].argtype == 11 && arg[5] == '=') { - /* cchar=? */ - if (has_mbyte) { - *conceal_char = mb_ptr2char(arg + 6); - arg += mb_ptr2len(arg + 6) - 1; - } else { - *conceal_char = arg[6]; - } + // cchar=? + *conceal_char = utf_ptr2char(arg + 6); + arg += mb_ptr2len(arg + 6) - 1; if (!vim_isprintc_strict(*conceal_char)) { EMSG(_("E844: invalid cchar value")); return NULL; diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 0379235ec0..361db47fc7 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -60,12 +60,14 @@ NEW_TESTS ?= \ test_fnameescape.res \ test_fold.res \ test_ga.res \ + test_getvar.res \ test_glob2regpat.res \ test_gf.res \ test_gn.res \ test_hardcopy.res \ test_help_tagjump.res \ test_hide.res \ + test_highlight.res \ test_history.res \ test_hlsearch.res \ test_increment.res \ diff --git a/src/nvim/testdir/test_getvar.vim b/src/nvim/testdir/test_getvar.vim new file mode 100644 index 0000000000..d6b6b69aa8 --- /dev/null +++ b/src/nvim/testdir/test_getvar.vim @@ -0,0 +1,104 @@ +" Tests for getwinvar(), gettabvar() and gettabwinvar(). +func Test_var() + " Use strings to test for memory leaks. First, check that in an empty + " window, gettabvar() returns the correct value + let t:testvar='abcd' + call assert_equal('abcd', gettabvar(1, 'testvar')) + call assert_equal('abcd', gettabvar(1, 'testvar')) + + " test for getwinvar() + let w:var_str = "Dance" + let def_str = "Chance" + call assert_equal('Dance', getwinvar(1, 'var_str')) + call assert_equal('Dance', getwinvar(1, 'var_str', def_str)) + call assert_equal({'var_str': 'Dance'}, getwinvar(1, '')) + call assert_equal({'var_str': 'Dance'}, getwinvar(1, '', def_str)) + unlet w:var_str + call assert_equal('Chance', getwinvar(1, 'var_str', def_str)) + call assert_equal({}, getwinvar(1, '')) + call assert_equal({}, getwinvar(1, '', def_str)) + call assert_equal('', getwinvar(9, '')) + call assert_equal('Chance', getwinvar(9, '', def_str)) + call assert_equal(0, getwinvar(1, '&nu')) + call assert_equal(0, getwinvar(1, '&nu', 1)) + unlet def_str + + " test for gettabvar() + tabnew + tabnew + let t:var_list = [1, 2, 3] + let t:other = 777 + let def_list = [4, 5, 6, 7] + tabrewind + call assert_equal([1, 2, 3], gettabvar(3, 'var_list')) + call assert_equal([1, 2, 3], gettabvar(3, 'var_list', def_list)) + call assert_equal({'var_list': [1, 2, 3], 'other': 777}, gettabvar(3, '')) + call assert_equal({'var_list': [1, 2, 3], 'other': 777}, + \ gettabvar(3, '', def_list)) + + tablast + unlet t:var_list + tabrewind + call assert_equal([4, 5, 6, 7], gettabvar(3, 'var_list', def_list)) + call assert_equal('', gettabvar(9, '')) + call assert_equal([4, 5, 6, 7], gettabvar(9, '', def_list)) + call assert_equal('', gettabvar(3, '&nu')) + call assert_equal([4, 5, 6, 7], gettabvar(3, '&nu', def_list)) + unlet def_list + tabonly + + " test for gettabwinvar() + tabnew + tabnew + tabprev + split + split + wincmd w + vert split + wincmd w + let w:var_dict = {'dict': 'tabwin'} + let def_dict = {'dict2': 'newval'} + wincmd b + tabrewind + call assert_equal({'dict': 'tabwin'}, gettabwinvar(2, 3, 'var_dict')) + call assert_equal({'dict': 'tabwin'}, + \ gettabwinvar(2, 3, 'var_dict', def_dict)) + call assert_equal({'var_dict': {'dict': 'tabwin'}}, gettabwinvar(2, 3, '')) + call assert_equal({'var_dict': {'dict': 'tabwin'}}, + \ gettabwinvar(2, 3, '', def_dict)) + + tabnext + 3wincmd w + unlet w:var_dict + tabrewind + call assert_equal({'dict2': 'newval'}, + \ gettabwinvar(2, 3, 'var_dict', def_dict)) + call assert_equal({}, gettabwinvar(2, 3, '')) + call assert_equal({}, gettabwinvar(2, 3, '', def_dict)) + call assert_equal("", gettabwinvar(2, 9, '')) + call assert_equal({'dict2': 'newval'}, gettabwinvar(2, 9, '', def_dict)) + call assert_equal('', gettabwinvar(9, 3, '')) + call assert_equal({'dict2': 'newval'}, gettabwinvar(9, 3, '', def_dict)) + + unlet def_dict + + call assert_equal('', gettabwinvar(2, 3, '&nux')) + call assert_equal(1, gettabwinvar(2, 3, '&nux', 1)) + tabonly +endfunc + +" It was discovered that "gettabvar()" would fail if called from within the +" tabline when the user closed a window. This test confirms the fix. +func Test_gettabvar_in_tabline() + let t:var_str = 'value' + + set tabline=%{assert_equal('value',gettabvar(1,'var_str'))} + set showtabline=2 + + " Simulate the user opening a split (which becomes window #1) and then + " closing the split, which triggers the redrawing of the tabline. + leftabove split + redrawstatus! + close + redrawstatus! +endfunc diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim new file mode 100644 index 0000000000..33df79581c --- /dev/null +++ b/src/nvim/testdir/test_highlight.vim @@ -0,0 +1,535 @@ +" Tests for ":highlight" and highlighting. + +source view_util.vim + +func Test_highlight() + " basic test if ":highlight" doesn't crash + highlight + hi Search + + " test setting colors. + " test clearing one color and all doesn't generate error or warning + silent! hi NewGroup term=bold cterm=italic ctermfg=DarkBlue ctermbg=Grey gui= guifg=#00ff00 guibg=Cyan + silent! hi Group2 term= cterm= + hi Group3 term=underline cterm=bold + + let res = split(execute("hi NewGroup"), "\n")[0] + " filter ctermfg and ctermbg, the numbers depend on the terminal + let res = substitute(res, 'ctermfg=\d*', 'ctermfg=2', '') + let res = substitute(res, 'ctermbg=\d*', 'ctermbg=3', '') + call assert_equal("NewGroup xxx cterm=italic ctermfg=2 ctermbg=3", + \ res) + call assert_equal("Group2 xxx cleared", + \ split(execute("hi Group2"), "\n")[0]) + call assert_equal("Group3 xxx cterm=bold", + \ split(execute("hi Group3"), "\n")[0]) + + hi clear NewGroup + call assert_equal("NewGroup xxx cleared", + \ split(execute("hi NewGroup"), "\n")[0]) + call assert_equal("Group2 xxx cleared", + \ split(execute("hi Group2"), "\n")[0]) + hi Group2 NONE + call assert_equal("Group2 xxx cleared", + \ split(execute("hi Group2"), "\n")[0]) + hi clear + call assert_equal("Group3 xxx cleared", + \ split(execute("hi Group3"), "\n")[0]) + call assert_fails("hi Crash term='asdf", "E475:") +endfunc + +function! HighlightArgs(name) + return 'hi ' . substitute(split(execute('hi ' . a:name), '\n')[0], '\<xxx\>', '', '') +endfunction + +function! IsColorable() + return has('gui_running') || str2nr(&t_Co) >= 8 +endfunction + +function! HiCursorLine() + let hiCursorLine = HighlightArgs('CursorLine') + if has('gui_running') + let guibg = matchstr(hiCursorLine, 'guibg=\w\+') + let hi_ul = 'hi CursorLine gui=underline guibg=NONE' + let hi_bg = 'hi CursorLine gui=NONE ' . guibg + else + let hi_ul = 'hi CursorLine cterm=underline ctermbg=NONE' + let hi_bg = 'hi CursorLine cterm=NONE ctermbg=Gray' + endif + return [hiCursorLine, hi_ul, hi_bg] +endfunction + +function! Check_lcs_eol_attrs(attrs, row, col) + let save_lcs = &lcs + set list + + call assert_equal(a:attrs, ScreenAttrs(a:row, a:col)[0]) + + set nolist + let &lcs = save_lcs +endfunction + +func Test_highlight_eol_with_cursorline() + let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() + + call NewWindow('topleft 5', 20) + call setline(1, 'abcd') + call matchadd('Search', '\n') + + " expected: + " 'abcd ' + " ^^^^ ^^^^^ no highlight + " ^ 'Search' highlight + let attrs0 = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3]) + call assert_equal(repeat([attrs0[0]], 5), attrs0[5:9]) + call assert_notequal(attrs0[0], attrs0[4]) + + setlocal cursorline + + " underline + exe hi_ul + + " expected: + " 'abcd ' + " ^^^^ underline + " ^ 'Search' highlight with underline + " ^^^^^ underline + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[0]], 4), attrs[0:3]) + call assert_equal([attrs[4]] + repeat([attrs[5]], 5), attrs[4:9]) + call assert_notequal(attrs[0], attrs[4]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[4], attrs[4]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + if IsColorable() + " bg-color + exe hi_bg + + " expected: + " 'abcd ' + " ^^^^ bg-color of 'CursorLine' + " ^ 'Search' highlight + " ^^^^^ bg-color of 'CursorLine' + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[0]], 4), attrs[0:3]) + call assert_equal(repeat([attrs[5]], 5), attrs[5:9]) + call assert_equal(attrs0[4], attrs[4]) + call assert_notequal(attrs[0], attrs[4]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[5], attrs[5]) + call Check_lcs_eol_attrs(attrs, 1, 10) + endif + + call CloseWindow() + exe hiCursorLine +endfunc + +func Test_highlight_eol_with_cursorline_vertsplit() + if !has('vertsplit') + return + endif + + let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() + + call NewWindow('topleft 5', 5) + call setline(1, 'abcd') + call matchadd('Search', '\n') + + let expected = "abcd |abcd " + let actual = ScreenLines(1, 15)[0] + call assert_equal(expected, actual) + + " expected: + " 'abcd |abcd ' + " ^^^^ ^^^^^^^^^ no highlight + " ^ 'Search' highlight + " ^ 'VertSplit' highlight + let attrs0 = ScreenAttrs(1, 15)[0] + call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3]) + call assert_equal(repeat([attrs0[0]], 9), attrs0[6:14]) + call assert_notequal(attrs0[0], attrs0[4]) + call assert_notequal(attrs0[0], attrs0[5]) + call assert_notequal(attrs0[4], attrs0[5]) + + setlocal cursorline + + " expected: + " 'abcd |abcd ' + " ^^^^ underline + " ^ 'Search' highlight with underline + " ^ 'VertSplit' highlight + " ^^^^^^^^^ no highlight + + " underline + exe hi_ul + + let actual = ScreenLines(1, 15)[0] + call assert_equal(expected, actual) + + let attrs = ScreenAttrs(1, 15)[0] + call assert_equal(repeat([attrs[0]], 4), attrs[0:3]) + call assert_equal(repeat([attrs[6]], 9), attrs[6:14]) + call assert_equal(attrs0[5:14], attrs[5:14]) + call assert_notequal(attrs[0], attrs[4]) + call assert_notequal(attrs[0], attrs[5]) + call assert_notequal(attrs[0], attrs[6]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs[5], attrs[6]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[4], attrs[4]) + call Check_lcs_eol_attrs(attrs, 1, 15) + + if IsColorable() + " bg-color + exe hi_bg + + let actual = ScreenLines(1, 15)[0] + call assert_equal(expected, actual) + + let attrs = ScreenAttrs(1, 15)[0] + call assert_equal(repeat([attrs[0]], 4), attrs[0:3]) + call assert_equal(repeat([attrs[6]], 9), attrs[6:14]) + call assert_equal(attrs0[5:14], attrs[5:14]) + call assert_notequal(attrs[0], attrs[4]) + call assert_notequal(attrs[0], attrs[5]) + call assert_notequal(attrs[0], attrs[6]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs[5], attrs[6]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_equal(attrs0[4], attrs[4]) + call Check_lcs_eol_attrs(attrs, 1, 15) + endif + + call CloseWindow() + exe hiCursorLine +endfunc + +func Test_highlight_eol_with_cursorline_rightleft() + if !has('rightleft') + return + endif + + let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() + + call NewWindow('topleft 5', 10) + setlocal rightleft + call setline(1, 'abcd') + call matchadd('Search', '\n') + let attrs0 = ScreenAttrs(1, 10)[0] + + setlocal cursorline + + " underline + exe hi_ul + + " expected: + " ' dcba' + " ^^^^ underline + " ^ 'Search' highlight with underline + " ^^^^^ underline + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[9]], 4), attrs[6:9]) + call assert_equal(repeat([attrs[4]], 5) + [attrs[5]], attrs[0:5]) + call assert_notequal(attrs[9], attrs[5]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs0[9], attrs[9]) + call assert_notequal(attrs0[5], attrs[5]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + if IsColorable() + " bg-color + exe hi_bg + + " expected: + " ' dcba' + " ^^^^ bg-color of 'CursorLine' + " ^ 'Search' highlight + " ^^^^^ bg-color of 'CursorLine' + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[9]], 4), attrs[6:9]) + call assert_equal(repeat([attrs[4]], 5), attrs[0:4]) + call assert_equal(attrs0[5], attrs[5]) + call assert_notequal(attrs[9], attrs[5]) + call assert_notequal(attrs[5], attrs[4]) + call assert_notequal(attrs0[9], attrs[9]) + call assert_notequal(attrs0[4], attrs[4]) + call Check_lcs_eol_attrs(attrs, 1, 10) + endif + + call CloseWindow() + exe hiCursorLine +endfunc + +func Test_highlight_eol_with_cursorline_linewrap() + let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() + + call NewWindow('topleft 5', 10) + call setline(1, [repeat('a', 51) . 'bcd', '']) + call matchadd('Search', '\n') + + setlocal wrap + normal! gg$ + let attrs0 = ScreenAttrs(5, 10)[0] + setlocal cursorline + + " underline + exe hi_ul + + " expected: + " 'abcd ' + " ^^^^ underline + " ^ 'Search' highlight with underline + " ^^^^^ underline + let attrs = ScreenAttrs(5, 10)[0] + call assert_equal(repeat([attrs[0]], 4), attrs[0:3]) + call assert_equal([attrs[4]] + repeat([attrs[5]], 5), attrs[4:9]) + call assert_notequal(attrs[0], attrs[4]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[4], attrs[4]) + call Check_lcs_eol_attrs(attrs, 5, 10) + + if IsColorable() + " bg-color + exe hi_bg + + " expected: + " 'abcd ' + " ^^^^ bg-color of 'CursorLine' + " ^ 'Search' highlight + " ^^^^^ bg-color of 'CursorLine' + let attrs = ScreenAttrs(5, 10)[0] + call assert_equal(repeat([attrs[0]], 4), attrs[0:3]) + call assert_equal(repeat([attrs[5]], 5), attrs[5:9]) + call assert_equal(attrs0[4], attrs[4]) + call assert_notequal(attrs[0], attrs[4]) + call assert_notequal(attrs[4], attrs[5]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[5], attrs[5]) + call Check_lcs_eol_attrs(attrs, 5, 10) + endif + + setlocal nocursorline nowrap + normal! gg$ + let attrs0 = ScreenAttrs(1, 10)[0] + setlocal cursorline + + " underline + exe hi_ul + + " expected: + " 'aaabcd ' + " ^^^^^^ underline + " ^ 'Search' highlight with underline + " ^^^ underline + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[0]], 6), attrs[0:5]) + call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9]) + call assert_notequal(attrs[0], attrs[6]) + call assert_notequal(attrs[6], attrs[7]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[6], attrs[6]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + if IsColorable() + " bg-color + exe hi_bg + + " expected: + " 'aaabcd ' + " ^^^^^^ bg-color of 'CursorLine' + " ^ 'Search' highlight + " ^^^ bg-color of 'CursorLine' + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[0]], 6), attrs[0:5]) + call assert_equal(repeat([attrs[7]], 3), attrs[7:9]) + call assert_equal(attrs0[6], attrs[6]) + call assert_notequal(attrs[0], attrs[6]) + call assert_notequal(attrs[6], attrs[7]) + call assert_notequal(attrs0[0], attrs[0]) + call assert_notequal(attrs0[7], attrs[7]) + call Check_lcs_eol_attrs(attrs, 1, 10) + endif + + call CloseWindow() + exe hiCursorLine +endfunc + +func Test_highlight_eol_with_cursorline_sign() + if !has('signs') + return + endif + + let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() + + call NewWindow('topleft 5', 10) + call setline(1, 'abcd') + call matchadd('Search', '\n') + + sign define Sign text=>> + exe 'sign place 1 line=1 name=Sign buffer=' . bufnr('') + let attrs0 = ScreenAttrs(1, 10)[0] + setlocal cursorline + + " underline + exe hi_ul + + " expected: + " '>>abcd ' + " ^^ sign + " ^^^^ underline + " ^ 'Search' highlight with underline + " ^^^ underline + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[2]], 4), attrs[2:5]) + call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9]) + call assert_notequal(attrs[2], attrs[6]) + call assert_notequal(attrs[6], attrs[7]) + call assert_notequal(attrs0[2], attrs[2]) + call assert_notequal(attrs0[6], attrs[6]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + if IsColorable() + " bg-color + exe hi_bg + + " expected: + " '>>abcd ' + " ^^ sign + " ^^^^ bg-color of 'CursorLine' + " ^ 'Search' highlight + " ^^^ bg-color of 'CursorLine' + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[2]], 4), attrs[2:5]) + call assert_equal(repeat([attrs[7]], 3), attrs[7:9]) + call assert_equal(attrs0[6], attrs[6]) + call assert_notequal(attrs[2], attrs[6]) + call assert_notequal(attrs[6], attrs[7]) + call assert_notequal(attrs0[2], attrs[2]) + call assert_notequal(attrs0[7], attrs[7]) + call Check_lcs_eol_attrs(attrs, 1, 10) + endif + + sign unplace 1 + call CloseWindow() + exe hiCursorLine +endfunc + +func Test_highlight_eol_with_cursorline_breakindent() + if !has('linebreak') + return + endif + + let [hiCursorLine, hi_ul, hi_bg] = HiCursorLine() + + call NewWindow('topleft 5', 10) + setlocal breakindent breakindentopt=min:0,shift:1 showbreak=> + call setline(1, ' ' . repeat('a', 9) . 'bcd') + call matchadd('Search', '\n') + let attrs0 = ScreenAttrs(2, 10)[0] + setlocal cursorline + + " underline + exe hi_ul + + " expected: + " ' >bcd ' + " ^^^ breakindent and showbreak + " ^^^ underline + " ^ 'Search' highlight with underline + " ^^^ underline + let attrs = ScreenAttrs(2, 10)[0] + call assert_equal(repeat([attrs[0]], 2), attrs[0:1]) + call assert_equal(repeat([attrs[3]], 3), attrs[3:5]) + call assert_equal([attrs[6]] + repeat([attrs[7]], 3), attrs[6:9]) + call assert_equal(attrs0[0], attrs[0]) + call assert_notequal(attrs[0], attrs[2]) + call assert_notequal(attrs[2], attrs[3]) + call assert_notequal(attrs[3], attrs[6]) + call assert_notequal(attrs[6], attrs[7]) + call assert_notequal(attrs0[2], attrs[2]) + call assert_notequal(attrs0[3], attrs[3]) + call assert_notequal(attrs0[6], attrs[6]) + call Check_lcs_eol_attrs(attrs, 2, 10) + + if IsColorable() + " bg-color + exe hi_bg + + " expected: + " ' >bcd ' + " ^^^ breakindent and showbreak + " ^^^ bg-color of 'CursorLine' + " ^ 'Search' highlight + " ^^^ bg-color of 'CursorLine' + let attrs = ScreenAttrs(2, 10)[0] + call assert_equal(repeat([attrs[0]], 2), attrs[0:1]) + call assert_equal(repeat([attrs[3]], 3), attrs[3:5]) + call assert_equal(repeat([attrs[7]], 3), attrs[7:9]) + call assert_equal(attrs0[0], attrs[0]) + call assert_equal(attrs0[6], attrs[6]) + call assert_notequal(attrs[0], attrs[2]) + call assert_notequal(attrs[2], attrs[3]) + call assert_notequal(attrs[3], attrs[6]) + call assert_notequal(attrs[6], attrs[7]) + call assert_notequal(attrs0[2], attrs[2]) + call assert_notequal(attrs0[3], attrs[3]) + call assert_notequal(attrs0[7], attrs[7]) + call Check_lcs_eol_attrs(attrs, 2, 10) + endif + + call CloseWindow() + set showbreak= + exe hiCursorLine +endfunc + +func Test_highlight_eol_on_diff() + call setline(1, ['abcd', '']) + call matchadd('Search', '\n') + let attrs0 = ScreenAttrs(1, 10)[0] + + diffthis + botright new + diffthis + + " expected: + " ' abcd ' + " ^^ sign + " ^^^^ ^^^ 'DiffAdd' highlight + " ^ 'Search' highlight + let attrs = ScreenAttrs(1, 10)[0] + call assert_equal(repeat([attrs[0]], 2), attrs[0:1]) + call assert_equal(repeat([attrs[2]], 4), attrs[2:5]) + call assert_equal(repeat([attrs[2]], 3), attrs[7:9]) + call assert_equal(attrs0[4], attrs[6]) + call assert_notequal(attrs[0], attrs[2]) + call assert_notequal(attrs[0], attrs[6]) + call assert_notequal(attrs[2], attrs[6]) + call Check_lcs_eol_attrs(attrs, 1, 10) + + bwipe! + diffoff +endfunc + +func Test_termguicolors() + if !exists('+termguicolors') + return + endif + if has('vtp') && !has('vcon') + " Win32: 'guicolors' doesn't work without virtual console. + call assert_fails('set termguicolors', 'E954:') + return + endif + + " Basic test that setting 'termguicolors' works with one color. + set termguicolors + redraw + set t_Co=1 + redraw + set t_Co=0 + redraw +endfunc diff --git a/src/nvim/testdir/test_visual.vim b/src/nvim/testdir/test_visual.vim index 0f2e7e493e..756a455ebd 100644 --- a/src/nvim/testdir/test_visual.vim +++ b/src/nvim/testdir/test_visual.vim @@ -17,6 +17,14 @@ func Test_block_shift_multibyte() q! endfunc +func Test_block_shift_overflow() + " This used to cause a multiplication overflow followed by a crash. + new + normal ii + exe "normal \<C-V>876543210>" + q! +endfunc + func Test_Visual_ctrl_o() new call setline(1, ['one', 'two', 'three']) @@ -118,9 +126,34 @@ func Test_blockwise_visual() enew! endfunc +" Test swapping corners in blockwise visual mode with o and O +func Test_blockwise_visual_o_O() + enew! + + exe "norm! 10i.\<Esc>Y4P3lj\<C-V>4l2jr " + exe "norm! gvO\<Esc>ra" + exe "norm! gvO\<Esc>rb" + exe "norm! gvo\<C-c>rc" + exe "norm! gvO\<C-c>rd" + + call assert_equal(['..........', + \ '...c d..', + \ '... ..', + \ '...a b..', + \ '..........'], getline(1, '$')) + + enew! +endfun + " Test Virtual replace mode. func Test_virtual_replace() throw 'skipped: TODO: ' + if exists('&t_kD') + let save_t_kD = &t_kD + endif + if exists('&t_kb') + let save_t_kb = &t_kb + endif exe "set t_kD=\<C-V>x7f t_kb=\<C-V>x08" enew! exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz" @@ -151,4 +184,96 @@ func Test_virtual_replace() call assert_equal(['AB......CDEFGHI.Jkl', \ 'AB IJKLMNO QRst'], getline(12, 13)) enew! + set noai bs&vim + if exists('save_t_kD') + let &t_kD = save_t_kD + endif + if exists('save_t_kb') + let &t_kb = save_t_kb + endif +endfunc + +" Test Virtual replace mode. +func Test_virtual_replace2() + enew! + set bs=2 + exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz" + call cursor(1,1) + " Test 1: Test that del deletes the newline + exe "normal gR0\<del> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" + call assert_equal(['0 1', + \ 'A', + \ 'BCDEFGHIJ', + \ ' KL', + \ 'MNO', + \ 'PQR', + \ ], getline(1, 6)) + " Test 2: + " a newline is not deleted, if no newline has been added in virtual replace mode + %d_ + call setline(1, ['abcd', 'efgh', 'ijkl']) + call cursor(2,1) + exe "norm! gR1234\<cr>5\<bs>\<bs>\<bs>" + call assert_equal(['abcd', + \ '123h', + \ 'ijkl'], getline(1, '$')) + " Test 3: + " a newline is deleted, if a newline has been inserted before in virtual replace mode + %d_ + call setline(1, ['abcd', 'efgh', 'ijkl']) + call cursor(2,1) + exe "norm! gR1234\<cr>\<cr>56\<bs>\<bs>\<bs>" + call assert_equal(['abcd', + \ '1234', + \ 'ijkl'], getline(1, '$')) + " Test 4: + " delete add a newline, delete it, add it again and check undo + %d_ + call setline(1, ['abcd', 'efgh', 'ijkl']) + call cursor(2,1) + " break undo sequence explicitly + let &ul = &ul + exe "norm! gR1234\<cr>\<bs>\<del>56\<cr>" + let &ul = &ul + call assert_equal(['abcd', + \ '123456', + \ ''], getline(1, '$')) + norm! u + call assert_equal(['abcd', + \ 'efgh', + \ 'ijkl'], getline(1, '$')) + " clean up + %d_ + set bs&vim +endfunc + +" Test for Visual mode not being reset causing E315 error. +func TriggerTheProblem() + " At this point there is no visual selection because :call reset it. + " Let's restore the selection: + normal gv + '<,'>del _ + try + exe "normal \<Esc>" + catch /^Vim\%((\a\+)\)\=:E315/ + echom 'Snap! E315 error!' + let g:msg = 'Snap! E315 error!' + endtry +endfunc + +func Test_visual_mode_reset() + set belloff=all + enew + let g:msg = "Everything's fine." + enew + setl buftype=nofile + call append(line('$'), 'Delete this line.') + + " NOTE: this has to be done by a call to a function because executing :del + " the ex-way will require the colon operator which resets the visual mode + " thus preventing the problem: + exe "normal! GV:call TriggerTheProblem()\<CR>" + call assert_equal("Everything's fine.", g:msg) + + set belloff& endfunc diff --git a/src/nvim/testdir/test_window_cmd.vim b/src/nvim/testdir/test_window_cmd.vim index 139d29a48b..ad60c8d3c7 100644 --- a/src/nvim/testdir/test_window_cmd.vim +++ b/src/nvim/testdir/test_window_cmd.vim @@ -17,7 +17,7 @@ func Test_window_cmd_ls0_with_split() endfunc func Test_window_cmd_cmdwin_with_vsp() - let efmt='Expected 0 but got %d (in ls=%d, %s window)' + let efmt = 'Expected 0 but got %d (in ls=%d, %s window)' for v in range(0, 2) exec "set ls=" . v vsplit @@ -417,4 +417,92 @@ func Test_window_newtab() endfunc +" Tests for adjusting window and contents +func GetScreenStr(row) + let str = "" + for c in range(1,3) + let str .= nr2char(screenchar(a:row, c)) + endfor + return str +endfunc + +func Test_window_contents() + enew! | only | new + call setline(1, range(1,256)) + + exe "norm! \<C-W>t\<C-W>=1Gzt\<C-W>w\<C-W>+" + redraw + let s3 = GetScreenStr(1) + wincmd p + call assert_equal(1, line("w0")) + call assert_equal('1 ', s3) + + exe "norm! \<C-W>t\<C-W>=50Gzt\<C-W>w\<C-W>+" + redraw + let s3 = GetScreenStr(1) + wincmd p + call assert_equal(50, line("w0")) + call assert_equal('50 ', s3) + + exe "norm! \<C-W>t\<C-W>=59Gzt\<C-W>w\<C-W>+" + redraw + let s3 = GetScreenStr(1) + wincmd p + call assert_equal(59, line("w0")) + call assert_equal('59 ', s3) + + bwipeout! + call test_garbagecollect_now() +endfunc + +func Test_access_freed_mem() + " This was accessing freed memory + au * 0 vs xxx + arg 0 + argadd + all + all + au! + bwipe xxx +endfunc + +func Test_visual_cleared_after_window_split() + new | only! + let smd_save = &showmode + set showmode + let ls_save = &laststatus + set laststatus=1 + call setline(1, ['a', 'b', 'c', 'd', '']) + norm! G + exe "norm! kkvk" + redraw + exe "norm! \<C-W>v" + redraw + " check if '-- VISUAL --' disappeared from command line + let columns = range(1, &columns) + let cmdlinechars = map(columns, 'nr2char(screenchar(&lines, v:val))') + let cmdline = join(cmdlinechars, '') + let cmdline_ltrim = substitute(cmdline, '^\s*', "", "") + let mode_shown = substitute(cmdline_ltrim, '\s*$', "", "") + call assert_equal('', mode_shown) + let &showmode = smd_save + let &laststatus = ls_save + bwipe! +endfunc + +func Test_winrestcmd() + 2split + 3vsplit + let a = winrestcmd() + call assert_equal(2, winheight(0)) + call assert_equal(3, winwidth(0)) + wincmd = + call assert_notequal(2, winheight(0)) + call assert_notequal(3, winwidth(0)) + exe a + call assert_equal(2, winheight(0)) + call assert_equal(3, winwidth(0)) + only +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/nvim/testdir/view_util.vim b/src/nvim/testdir/view_util.vim index eb92630761..29ea073f97 100644 --- a/src/nvim/testdir/view_util.vim +++ b/src/nvim/testdir/view_util.vim @@ -1,5 +1,10 @@ " Functions about view shared by several tests +" Only load this script once. +if exists('*ScreenLines') + finish +endif + " ScreenLines(lnum, width) or " ScreenLines([start, end], width) function! ScreenLines(lnum, width) abort @@ -18,6 +23,22 @@ function! ScreenLines(lnum, width) abort return lines endfunction +function! ScreenAttrs(lnum, width) abort + redraw! + if type(a:lnum) == v:t_list + let start = a:lnum[0] + let end = a:lnum[1] + else + let start = a:lnum + let end = a:lnum + endif + let attrs = [] + for l in range(start, end) + let attrs += [map(range(1, a:width), 'screenattr(l, v:val)')] + endfor + return attrs +endfunction + function! NewWindow(height, width) abort exe a:height . 'new' exe a:width . 'vsp' diff --git a/src/nvim/undo.c b/src/nvim/undo.c index 2055b4879e..f4eb50b3b5 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -2233,10 +2233,11 @@ static void u_undoredo(int undo, bool do_buf_event) * If the file is empty, there is an empty line 1 that we * should get rid of, by replacing it with the new line */ - if (empty_buffer && lnum == 0) - ml_replace((linenr_T)1, uep->ue_array[i], TRUE); - else + if (empty_buffer && lnum == 0) { + ml_replace((linenr_T)1, uep->ue_array[i], true); + } else { ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE); + } xfree(uep->ue_array[i]); } xfree((char_u *)uep->ue_array); @@ -2902,7 +2903,7 @@ void u_undoline(void) curbuf->b_u_line_lnum + 1, (linenr_T)0, FALSE) == FAIL) return; oldp = u_save_line(curbuf->b_u_line_lnum); - ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE); + ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true); changed_bytes(curbuf->b_u_line_lnum, 0); xfree(curbuf->b_u_line_ptr); curbuf->b_u_line_ptr = oldp; diff --git a/src/nvim/window.c b/src/nvim/window.c index 7582c837c8..8239061a0c 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2296,6 +2296,9 @@ winframe_remove ( if (frp2->fr_win != NULL) frp2->fr_win->w_frame = frp2->fr_parent; frp = frp2->fr_parent; + if (topframe->fr_child == frp2) { + topframe->fr_child = frp; + } xfree(frp2); frp2 = frp->fr_parent; @@ -2317,6 +2320,9 @@ winframe_remove ( break; } } + if (topframe->fr_child == frp) { + topframe->fr_child = frp2; + } xfree(frp); } } @@ -2959,7 +2965,6 @@ static int win_alloc_firstwin(win_T *oldwin) topframe = curwin->w_frame; topframe->fr_width = Columns; topframe->fr_height = Rows - p_ch; - topframe->fr_win = curwin; return OK; } @@ -3970,18 +3975,20 @@ win_remove ( tabpage_T *tp /* tab page "win" is in, NULL for current */ ) { - if (wp->w_prev != NULL) + if (wp->w_prev != NULL) { wp->w_prev->w_next = wp->w_next; - else if (tp == NULL) - firstwin = wp->w_next; - else + } else if (tp == NULL) { + firstwin = curtab->tp_firstwin = wp->w_next; + } else { tp->tp_firstwin = wp->w_next; - if (wp->w_next != NULL) + } + if (wp->w_next != NULL) { wp->w_next->w_prev = wp->w_prev; - else if (tp == NULL) - lastwin = wp->w_prev; - else + } else if (tp == NULL) { + lastwin = curtab->tp_lastwin = wp->w_prev; + } else { tp->tp_lastwin = wp->w_prev; + } } /* @@ -4015,12 +4022,18 @@ static void frame_insert(frame_T *before, frame_T *frp) */ static void frame_remove(frame_T *frp) { - if (frp->fr_prev != NULL) + if (frp->fr_prev != NULL) { frp->fr_prev->fr_next = frp->fr_next; - else + } else { frp->fr_parent->fr_child = frp->fr_next; - if (frp->fr_next != NULL) + // special case: topframe->fr_child == frp + if (topframe->fr_child == frp) { + topframe->fr_child = frp->fr_next; + } + } + if (frp->fr_next != NULL) { frp->fr_next->fr_prev = frp->fr_prev; + } } @@ -5489,12 +5502,10 @@ int switch_win(win_T **save_curwin, tabpage_T **save_curtab, win_T *win, tabpage return OK; } -/* - * Restore current tabpage and window saved by switch_win(), if still valid. - * When "no_display" is TRUE the display won't be affected, no redraw is - * triggered. - */ -void restore_win(win_T *save_curwin, tabpage_T *save_curtab, int no_display) +// Restore current tabpage and window saved by switch_win(), if still valid. +// When "no_display" is true the display won't be affected, no redraw is +// triggered. +void restore_win(win_T *save_curwin, tabpage_T *save_curtab, bool no_display) { if (save_curtab != NULL && valid_tabpage(save_curtab)) { if (no_display) { @@ -5609,7 +5620,7 @@ int match_add(win_T *wp, const char *const grp, const char *const pat, m->match.rmm_maxcol = 0; m->conceal_char = 0; if (conceal_char != NULL) { - m->conceal_char = (*mb_ptr2char)((const char_u *)conceal_char); + m->conceal_char = utf_ptr2char((const char_u *)conceal_char); } // Set up position matches |