diff options
| author | bfredl <bjorn.linse@gmail.com> | 2023-11-06 14:52:27 +0100 |
|---|---|---|
| committer | bfredl <bjorn.linse@gmail.com> | 2023-11-17 12:58:57 +0100 |
| commit | b522cb1ac3fbdf6e68eed5d0b6e1cbeaf3ac2254 (patch) | |
| tree | 434ec27e069ba57406ce9f6d194627e95c3d315c /src | |
| parent | 20ec4c776a07492c2e3b995e10b40b1cdb52bc7a (diff) | |
| download | rneovim-b522cb1ac3fbdf6e68eed5d0b6e1cbeaf3ac2254.tar.gz rneovim-b522cb1ac3fbdf6e68eed5d0b6e1cbeaf3ac2254.tar.bz2 rneovim-b522cb1ac3fbdf6e68eed5d0b6e1cbeaf3ac2254.zip | |
refactor(grid): make screen rendering more multibyte than ever before
Problem: buffer text with composing chars are converted from UTF-8
to an array of up to seven UTF-32 values and then converted back
to UTF-8 strings.
Solution: Convert buffer text directly to UTF-8 based schar_T values.
The limit of the text size is now in schar_T bytes, which is currently
31+1 but easily could be raised as it no longer multiplies the size
of the entire screen grid when not used, the full size is only required
for temporary scratch buffers.
Also does some general cleanup to win_line text handling, which was
unnecessarily complicated due to multibyte rendering being an "opt-in"
feature long ago. Nowadays, a char is just a char, regardless if it consists
of one ASCII byte or multiple bytes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/change.c | 11 | ||||
| -rw-r--r-- | src/nvim/charset.c | 19 | ||||
| -rw-r--r-- | src/nvim/digraph.c | 2 | ||||
| -rw-r--r-- | src/nvim/drawline.c | 261 | ||||
| -rw-r--r-- | src/nvim/edit.c | 17 | ||||
| -rw-r--r-- | src/nvim/eval.c | 2 | ||||
| -rw-r--r-- | src/nvim/eval/funcs.c | 33 | ||||
| -rw-r--r-- | src/nvim/ex_cmds.c | 110 | ||||
| -rw-r--r-- | src/nvim/grid.c | 65 | ||||
| -rw-r--r-- | src/nvim/grid_defs.h | 6 | ||||
| -rw-r--r-- | src/nvim/insexpand.c | 2 | ||||
| -rw-r--r-- | src/nvim/lua/stdlib.c | 2 | ||||
| -rw-r--r-- | src/nvim/match.c | 2 | ||||
| -rw-r--r-- | src/nvim/mbyte.c | 123 | ||||
| -rw-r--r-- | src/nvim/mbyte.h | 1 | ||||
| -rw-r--r-- | src/nvim/message.c | 10 | ||||
| -rw-r--r-- | src/nvim/option_vars.h | 1 | ||||
| -rw-r--r-- | src/nvim/spellsuggest.c | 2 |
18 files changed, 269 insertions, 400 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c index 58718811bc..aa58779f5b 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -665,7 +665,7 @@ void ins_bytes_len(char *p, size_t len) /// convert bytes to a character. void ins_char(int c) { - char buf[MB_MAXBYTES + 1]; + char buf[MB_MAXCHAR + 1]; size_t n = (size_t)utf_char2bytes(c, buf); // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte. @@ -869,12 +869,9 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) // If 'delcombine' is set and deleting (less than) one character, only // delete the last combining character. - if (p_deco && use_delcombine - && utfc_ptr2len(oldp + col) >= count) { - int cc[MAX_MCO]; - - (void)utfc_ptr2char(oldp + col, cc); - if (cc[0] != NUL) { + if (p_deco && use_delcombine && utfc_ptr2len(oldp + col) >= count) { + char *p0 = oldp + col; + if (utf_composinglike(p0, p0 + utf_ptr2len(p0))) { // Find the last composing char, there can be several. int n = col; do { diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 0adcc09ec7..5dfc9c444d 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -302,15 +302,13 @@ size_t transstr_len(const char *const s, bool untab) while (*p) { const size_t l = (size_t)utfc_ptr2len(p); if (l > 1) { - int pcc[MAX_MCO + 1]; - pcc[0] = utfc_ptr2char(p, &pcc[1]); - - if (vim_isprintc(pcc[0])) { + if (vim_isprintc(utf_ptr2char(p))) { len += l; } else { - for (size_t i = 0; i < ARRAY_SIZE(pcc) && pcc[i]; i++) { + for (size_t off = 0; off < l; off += (size_t)utf_ptr2len(p + off)) { + int c = utf_ptr2char(p + off); char hexbuf[9]; - len += transchar_hex(hexbuf, pcc[i]); + len += transchar_hex(hexbuf, c); } } p += l; @@ -349,16 +347,15 @@ size_t transstr_buf(const char *const s, const ssize_t slen, char *const buf, co if (buf_p + l > buf_e) { break; // Exceeded `buf` size. } - int pcc[MAX_MCO + 1]; - pcc[0] = utfc_ptr2char(p, &pcc[1]); - if (vim_isprintc(pcc[0])) { + if (vim_isprintc(utf_ptr2char(p))) { memmove(buf_p, p, l); buf_p += l; } else { - for (size_t i = 0; i < ARRAY_SIZE(pcc) && pcc[i]; i++) { + for (size_t off = 0; off < l; off += (size_t)utf_ptr2len(p + off)) { + int c = utf_ptr2char(p + off); char hexbuf[9]; // <up to 6 bytes>NUL - const size_t hexlen = transchar_hex(hexbuf, pcc[i]); + const size_t hexlen = transchar_hex(hexbuf, c); if (buf_p + hexlen > buf_e) { break; } diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index bc0ce99c5e..1bff78f90a 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -1654,7 +1654,7 @@ static void registerdigraph(int char1, int char2, int n) bool check_digraph_chars_valid(int char1, int char2) { if (char2 == 0) { - char msg[MB_MAXBYTES + 1]; + char msg[MB_MAXCHAR + 1]; msg[utf_char2bytes(char1, msg)] = NUL; semsg(_(e_digraph_must_be_just_two_characters_str), msg); return false; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 11b4e55c5c..0cfab5cec9 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -228,14 +228,12 @@ static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells const char *p = *pp; int cells = utf_ptr2cells(p); int c_len = utfc_ptr2len(p); - int u8c, u8cc[MAX_MCO]; assert(maxcells > 0); if (cells > maxcells) { dest[0] = schar_from_ascii(' '); return 1; } - u8c = utfc_ptr2char(p, u8cc); if (*p == TAB) { cells = MIN(tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array), maxcells); } @@ -247,16 +245,14 @@ static int line_putchar(buf_T *buf, const char **pp, schar_T *dest, int maxcells for (int c = 0; c < cells; c++) { dest[c] = schar_from_ascii(' '); } - goto done; - } else if ((uint8_t)(*p) < 0x80 && u8cc[0] == 0) { - dest[0] = schar_from_ascii(*p); } else { - dest[0] = schar_from_cc(u8c, u8cc); - } - if (cells > 1) { - dest[1] = 0; + int u8c; + dest[0] = utfc_ptr2schar(p, &u8c); + if (cells > 1) { + dest[1] = 0; + } } -done: + *pp += c_len; return cells; } @@ -946,16 +942,6 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t } } -static bool check_mb_utf8(int *c, int *u8cc) -{ - if (utf_char2len(*c) > 1) { - *u8cc = 0; - *c = 0xc0; - return true; - } - return false; -} - static colnr_T get_trailcol(win_T *wp, const char *ptr, const char *line) { colnr_T trailcol = MAXCOL; @@ -1051,7 +1037,6 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl { winlinevars_T wlv; // variables passed between functions - int c = 0; // init for GCC colnr_T vcol_prev = -1; // "wlv.vcol" of previous character char *line; // current line char *ptr; // current position in "line" @@ -1096,8 +1081,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl int multi_attr = 0; // attributes desired by multibyte int mb_l = 1; // multi-byte byte length int mb_c = 0; // decoded multi-byte character - bool mb_utf8 = false; // screen char is UTF-8 char - int u8cc[MAX_MCO]; // composing UTF-8 chars + schar_T mb_schar; // complete screen char int change_start = MAXCOL; // first col of changed area int change_end = -1; // last col of changed area bool in_multispace = false; // in multiple consecutive spaces @@ -1951,34 +1935,25 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // For the '$' of the 'list' option, n_extra == 1, p_extra == "". if (wlv.n_extra > 0) { if (wlv.c_extra != NUL || (wlv.n_extra == 1 && wlv.c_final != NUL)) { - c = (wlv.n_extra == 1 && wlv.c_final != NUL) ? wlv.c_final : wlv.c_extra; - mb_c = c; // doesn't handle non-utf-8 multi-byte! - mb_utf8 = check_mb_utf8(&c, u8cc); + mb_c = (wlv.n_extra == 1 && wlv.c_final != NUL) ? wlv.c_final : wlv.c_extra; + mb_schar = schar_from_char(mb_c); + wlv.n_extra--; } else { assert(wlv.p_extra != NULL); - c = (uint8_t)(*wlv.p_extra); - mb_c = c; - // If the UTF-8 character is more than one byte: - // Decode it into "mb_c". mb_l = utfc_ptr2len(wlv.p_extra); - mb_utf8 = false; - if (mb_l > wlv.n_extra) { - mb_l = 1; - } else if (mb_l > 1) { - mb_c = utfc_ptr2char(wlv.p_extra, u8cc); - mb_utf8 = true; - c = 0xc0; - } - if (mb_l == 0) { // at the NUL at end-of-line + mb_schar = utfc_ptr2schar(wlv.p_extra, &mb_c); + // mb_l=0 at the end-of-line NUL + if (mb_l > wlv.n_extra || mb_l == 0) { mb_l = 1; } // If a double-width char doesn't fit display a '>' in the last column. + // Don't advance the pointer but put the character at the start of the next line. if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) { - c = '>'; - mb_c = c; + mb_c = '>'; mb_l = 1; (void)mb_l; + mb_schar = schar_from_ascii(mb_c); multi_attr = win_hl_attr(wp, HLF_AT); if (wlv.cul_attr) { @@ -1986,18 +1961,11 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl ? hl_combine_attr(wlv.cul_attr, multi_attr) : hl_combine_attr(multi_attr, wlv.cul_attr); } - - // put the pointer back to output the double-width - // character at the start of the next line. - wlv.n_extra++; - wlv.p_extra--; } else { - wlv.n_extra -= mb_l - 1; - wlv.p_extra += mb_l - 1; + wlv.n_extra -= mb_l; + wlv.p_extra += mb_l; } - wlv.p_extra++; } - wlv.n_extra--; // Only restore search_attr and area_attr after "n_extra" in // the next screen line is also done. @@ -2026,58 +1994,40 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } } else if (has_fold) { // skip writing the buffer line itself - c = NUL; + mb_c = NUL; } else { - int c0; char *prev_ptr = ptr; - // Get a character from the line itself. - c0 = c = (uint8_t)(*ptr); - mb_c = c; - - if (c == NUL) { + // first byte of next char + int c0 = (uint8_t)(*ptr); + if (c0 == NUL) { // no more cells to skip wlv.skip_cells = 0; } - // If the UTF-8 character is more than one byte: Decode it - // into "mb_c". + // Get a character from the line itself. mb_l = utfc_ptr2len(ptr); - mb_utf8 = false; - if (mb_l > 1) { - mb_c = utfc_ptr2char(ptr, u8cc); - // Overlong encoded ASCII or ASCII with composing char - // is displayed normally, except a NUL. - if (mb_c < 0x80) { - c0 = c = mb_c; - } - mb_utf8 = true; - - // At start of the line we can have a composing char. - // Draw it as a space with a composing char. - if (utf_iscomposing(mb_c)) { - for (int i = MAX_MCO - 1; i > 0; i--) { - u8cc[i] = u8cc[i - 1]; - } - u8cc[0] = mb_c; - mb_c = ' '; - } + mb_schar = utfc_ptr2schar(ptr, &mb_c); + + // Overlong encoded ASCII or ASCII with composing char + // is displayed normally, except a NUL. + if (mb_l > 1 && mb_c < 0x80) { + c0 = mb_c; } - if ((mb_l == 1 && c >= 0x80) + if ((mb_l == 1 && c0 >= 0x80) || (mb_l >= 1 && mb_c == 0) || (mb_l > 1 && (!vim_isprintc(mb_c)))) { // Illegal UTF-8 byte: display as <xx>. - // Non-BMP character : display as ? or fullwidth ?. + // Non-printable character : display as ? or fullwidth ?. transchar_hex(wlv.extra, mb_c); if (wp->w_p_rl) { // reverse rl_mirror_ascii(wlv.extra, NULL); } wlv.p_extra = wlv.extra; - c = (uint8_t)(*wlv.p_extra); mb_c = mb_ptr2char_adv((const char **)&wlv.p_extra); - mb_utf8 = (c >= 0x80); + mb_schar = schar_from_char(mb_c); wlv.n_extra = (int)strlen(wlv.p_extra); wlv.c_extra = NUL; wlv.c_final = NUL; @@ -2093,10 +2043,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // last column; the character is displayed at the start of the // next line. if (wlv.col >= grid->cols - 1 && utf_char2cells(mb_c) == 2) { - c = '>'; - mb_c = c; - mb_utf8 = false; + mb_c = '>'; mb_l = 1; + mb_schar = schar_from_ascii(mb_c); multi_attr = win_hl_attr(wp, HLF_AT); // Put pointer back so that the character will be // displayed at the start of the next line. @@ -2112,15 +2061,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl wlv.n_extra = 1; wlv.c_extra = MB_FILLER_CHAR; wlv.c_final = NUL; - c = ' '; + mb_c = ' '; + mb_l = 1; + mb_schar = schar_from_ascii(mb_c); if (area_attr == 0 && search_attr == 0) { wlv.n_attr = wlv.n_extra + 1; wlv.extra_attr = win_hl_attr(wp, HLF_AT); saved_attr2 = wlv.char_attr; // save current attr } - mb_c = c; - mb_utf8 = false; - mb_l = 1; } ptr++; @@ -2159,11 +2107,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // no concealing past the end of the line, it interferes // with line highlighting. - if (c == NUL) { - syntax_flags = 0; - } else { - syntax_flags = get_syntax_info(&syntax_seqnr); - } + syntax_flags = (mb_c == 0) ? 0 : get_syntax_info(&syntax_seqnr); } if (has_decor && v > 0) { @@ -2198,7 +2142,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl spell_attr = 0; // do not calculate cap_col at the end of the line or when // only white space is following - if (c != 0 && (*skipwhite(prev_ptr) != NUL) && can_spell) { + if (mb_c != 0 && (*skipwhite(prev_ptr) != NUL) && can_spell) { char *p; hlf_T spell_hlf = HLF_COUNT; v -= mb_l - 1; @@ -2272,13 +2216,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // // So only allow to linebreak, once we have found chars not in // 'breakat' in the line. - if (wp->w_p_lbr && !wlv.need_lbr && c != NUL + if (wp->w_p_lbr && !wlv.need_lbr && mb_c != NUL && !vim_isbreak((uint8_t)(*ptr))) { wlv.need_lbr = true; } // Found last space before word: check for line break. - if (wp->w_p_lbr && c0 == c && wlv.need_lbr - && vim_isbreak(c) && !vim_isbreak((uint8_t)(*ptr))) { + if (wp->w_p_lbr && c0 == mb_c && mb_c < 128 && wlv.need_lbr + && vim_isbreak(mb_c) && !vim_isbreak((uint8_t)(*ptr))) { int mb_off = utf_head_off(line, ptr - 1); char *p = ptr - (mb_off + 1); chartabsize_T cts; @@ -2289,33 +2233,33 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl wlv.n_extra = win_lbr_chartabsize(&cts, NULL) - 1; clear_chartabsize_arg(&cts); - if (on_last_col && c != TAB) { + if (on_last_col && mb_c != TAB) { // Do not continue search/match highlighting over the // line break, but for TABs the highlighting should // include the complete width of the character search_attr = 0; } - if (c == TAB && wlv.n_extra + wlv.col > grid->cols) { + if (mb_c == TAB && wlv.n_extra + wlv.col > grid->cols) { wlv.n_extra = tabstop_padding(wlv.vcol, wp->w_buffer->b_p_ts, wp->w_buffer->b_p_vts_array) - 1; } wlv.c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; wlv.c_final = NUL; - if (ascii_iswhite(c)) { - if (c == TAB) { + if (mb_c < 128 && ascii_iswhite(mb_c)) { + if (mb_c == TAB) { // See "Tab alignment" below. FIX_FOR_BOGUSCOLS; } if (!wp->w_p_list) { - c = ' '; + mb_c = ' '; + mb_schar = schar_from_ascii(mb_c); } } } if (wp->w_p_list) { - in_multispace = c == ' ' && (*ptr == ' ' - || (prev_ptr > line && prev_ptr[-1] == ' ')); + in_multispace = mb_c == ' ' && (*ptr == ' ' || (prev_ptr > line && prev_ptr[-1] == ' ')); if (!in_multispace) { multispace_pos = 0; } @@ -2325,61 +2269,56 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // But not when the character is followed by a composing // character (use mb_l to check that). if (wp->w_p_list - && ((((c == 160 && mb_l == 1) - || (mb_utf8 - && ((mb_c == 160 && mb_l == 2) - || (mb_c == 0x202f && mb_l == 3)))) + && ((((mb_c == 160 && mb_l == 2) || (mb_c == 0x202f && mb_l == 3)) && wp->w_p_lcs_chars.nbsp) - || (c == ' ' + || (mb_c == ' ' && mb_l == 1 && (wp->w_p_lcs_chars.space || (in_multispace && wp->w_p_lcs_chars.multispace != NULL)) && ptr - line >= leadcol && ptr - line <= trailcol))) { if (in_multispace && wp->w_p_lcs_chars.multispace != NULL) { - c = wp->w_p_lcs_chars.multispace[multispace_pos++]; + mb_c = wp->w_p_lcs_chars.multispace[multispace_pos++]; if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) { multispace_pos = 0; } } else { - c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp; + mb_c = (mb_c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp; } wlv.n_attr = 1; wlv.extra_attr = win_hl_attr(wp, HLF_0); saved_attr2 = wlv.char_attr; // save current attr - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); + mb_schar = schar_from_char(mb_c); } - if (c == ' ' && ((trailcol != MAXCOL && ptr > line + trailcol) - || (leadcol != 0 && ptr < line + leadcol))) { + if (mb_c == ' ' && mb_l == 1 && ((trailcol != MAXCOL && ptr > line + trailcol) + || (leadcol != 0 && ptr < line + leadcol))) { if (leadcol != 0 && in_multispace && ptr < line + leadcol && wp->w_p_lcs_chars.leadmultispace != NULL) { - c = wp->w_p_lcs_chars.leadmultispace[multispace_pos++]; + mb_c = wp->w_p_lcs_chars.leadmultispace[multispace_pos++]; if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) { multispace_pos = 0; } } else if (ptr > line + trailcol && wp->w_p_lcs_chars.trail) { - c = wp->w_p_lcs_chars.trail; + mb_c = wp->w_p_lcs_chars.trail; } else if (ptr < line + leadcol && wp->w_p_lcs_chars.lead) { - c = wp->w_p_lcs_chars.lead; + mb_c = wp->w_p_lcs_chars.lead; } else if (leadcol != 0 && wp->w_p_lcs_chars.space) { - c = wp->w_p_lcs_chars.space; + mb_c = wp->w_p_lcs_chars.space; } wlv.n_attr = 1; wlv.extra_attr = win_hl_attr(wp, HLF_0); saved_attr2 = wlv.char_attr; // save current attr - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); + mb_schar = schar_from_char(mb_c); } } // Handling of non-printable characters. - if (!vim_isprintc(c)) { + if (!vim_isprintc(mb_c)) { // when getting a character from the file, we may have to // turn it into something else on the way to putting it on the screen. - if (c == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { + if (mb_c == TAB && (!wp->w_p_list || wp->w_p_lcs_chars.tab1)) { int tab_len = 0; colnr_T vcol_adjusted = wlv.vcol; // removed showbreak length char *const sbr = get_showbreak_value(wp); @@ -2422,7 +2361,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl if (wlv.n_extra > 0) { len += wlv.n_extra - tab_len; } - c = wp->w_p_lcs_chars.tab1; + mb_c = wp->w_p_lcs_chars.tab1; p = get_extra_buf((size_t)len + 1); memset(p, ' ', (size_t)len); p[len] = NUL; @@ -2470,11 +2409,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } } - mb_utf8 = false; // don't draw as UTF-8 if (wp->w_p_list) { - c = (wlv.n_extra == 0 && wp->w_p_lcs_chars.tab3) - ? wp->w_p_lcs_chars.tab3 - : wp->w_p_lcs_chars.tab1; + mb_c = (wlv.n_extra == 0 && wp->w_p_lcs_chars.tab3) + ? wp->w_p_lcs_chars.tab3 : wp->w_p_lcs_chars.tab1; if (wp->w_p_lbr && wlv.p_extra != NULL && *wlv.p_extra != NUL) { wlv.c_extra = NUL; // using p_extra from above } else { @@ -2484,14 +2421,13 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl wlv.n_attr = tab_len + 1; wlv.extra_attr = win_hl_attr(wp, HLF_0); saved_attr2 = wlv.char_attr; // save current attr - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); } else { wlv.c_final = NUL; wlv.c_extra = ' '; - c = ' '; + mb_c = ' '; } - } else if (c == NUL + mb_schar = schar_from_char(mb_c); + } else if (mb_c == NUL && (wp->w_p_list || ((wlv.fromcol >= 0 || fromcol_prev >= 0) && wlv.tocol > wlv.vcol @@ -2515,20 +2451,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl wlv.n_extra = 0; } if (wp->w_p_list && wp->w_p_lcs_chars.eol > 0) { - c = wp->w_p_lcs_chars.eol; + mb_c = wp->w_p_lcs_chars.eol; } else { - c = ' '; + mb_c = ' '; } lcs_eol_one = -1; ptr--; // put it back at the NUL wlv.extra_attr = win_hl_attr(wp, HLF_AT); wlv.n_attr = 1; - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); - } else if (c != NUL) { - wlv.p_extra = transchar_buf(wp->w_buffer, c); + mb_schar = schar_from_char(mb_c); + } else if (mb_c != NUL) { + wlv.p_extra = transchar_buf(wp->w_buffer, mb_c); if (wlv.n_extra == 0) { - wlv.n_extra = byte2cells(c) - 1; + wlv.n_extra = byte2cells(mb_c) - 1; } if ((dy_flags & DY_UHEX) && wp->w_p_rl) { rl_mirror_ascii(wlv.p_extra, NULL); // reverse "<12>" @@ -2538,7 +2473,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl if (wp->w_p_lbr) { char *p; - c = (uint8_t)(*wlv.p_extra); + mb_c = (uint8_t)(*wlv.p_extra); p = get_extra_buf((size_t)wlv.n_extra + 1); memset(p, ' ', (size_t)wlv.n_extra); strncpy(p, // NOLINT(runtime/printf) @@ -2547,20 +2482,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl p[wlv.n_extra] = NUL; wlv.p_extra = p; } else { - wlv.n_extra = byte2cells(c) - 1; - c = (uint8_t)(*wlv.p_extra++); + wlv.n_extra = byte2cells(mb_c) - 1; + mb_c = (uint8_t)(*wlv.p_extra++); } wlv.n_attr = wlv.n_extra + 1; wlv.extra_attr = win_hl_attr(wp, HLF_8); saved_attr2 = wlv.char_attr; // save current attr - mb_utf8 = false; // don't draw as UTF-8 + mb_schar = schar_from_ascii(mb_c); } else if (VIsual_active && (VIsual_mode == Ctrl_V || VIsual_mode == 'v') && virtual_active() && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol && wlv.col < grid->cols) { - c = ' '; + mb_c = ' '; + mb_schar = schar_from_char(mb_c); ptr--; // put it back at the NUL } } @@ -2580,18 +2516,18 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // First time at this concealed item: display one // character. if (has_match_conc && match_conc) { - c = match_conc; + mb_c = match_conc; } else if (decor_conceal && decor_state.conceal_char) { - c = decor_state.conceal_char; + mb_c = decor_state.conceal_char; if (decor_state.conceal_attr) { wlv.char_attr = decor_state.conceal_attr; } } else if (syn_get_sub_char() != NUL) { - c = syn_get_sub_char(); + mb_c = syn_get_sub_char(); } else if (wp->w_p_lcs_chars.conceal != NUL) { - c = wp->w_p_lcs_chars.conceal; + mb_c = wp->w_p_lcs_chars.conceal; } else { - c = ' '; + mb_c = ' '; } prev_syntax_id = syntax_seqnr; @@ -2610,8 +2546,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl is_concealing = true; wlv.skip_cells = 1; } - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); + mb_schar = schar_from_char(mb_c); } else { prev_syntax_id = 0; is_concealing = false; @@ -2654,8 +2589,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl && (wp->w_p_wrap ? (wp->w_skipcol > 0 && wlv.row == 0) : wp->w_leftcol > 0) && wlv.filler_todo <= 0 && wlv.draw_state > WL_STC - && c != NUL) { - c = wp->w_p_lcs_chars.prec; + && mb_c != NUL) { + mb_c = wp->w_p_lcs_chars.prec; lcs_prec_todo = NUL; if (utf_char2cells(mb_c) > 1) { // Double-width character being overwritten by the "precedes" @@ -2666,15 +2601,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl wlv.n_attr = 2; wlv.extra_attr = win_hl_attr(wp, HLF_AT); } - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); + mb_schar = schar_from_char(mb_c); saved_attr3 = wlv.char_attr; // save current attr wlv.char_attr = win_hl_attr(wp, HLF_AT); // overwriting char_attr n_attr3 = 1; } // At end of the text line or just after the last character. - if (c == NUL && eol_hl_off == 0) { + if (mb_c == NUL && eol_hl_off == 0) { // flag to indicate whether prevcol equals startcol of search_hl or // one of the matches bool prevcol_hl_flag = get_prevcol_hl_flag(wp, &screen_search_hl, @@ -2728,7 +2662,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl } // At end of the text line. - if (c == NUL) { + if (mb_c == NUL) { // Highlight 'cursorcolumn' & 'colorcolumn' past end of the line. if (wp->w_p_wrap) { v = wlv.startrow == 0 ? wp->w_skipcol : 0; @@ -2874,10 +2808,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl || lcs_eol_one > 0 || (wlv.n_extra > 0 && (wlv.c_extra != NUL || *wlv.p_extra != NUL)) || has_more_inline_virt(&wlv, v)) { - c = wp->w_p_lcs_chars.ext; + mb_c = wp->w_p_lcs_chars.ext; wlv.char_attr = win_hl_attr(wp, HLF_AT); - mb_c = c; - mb_utf8 = check_mb_utf8(&c, u8cc); + mb_schar = schar_from_char(mb_c); } } @@ -2923,11 +2856,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool number_onl // Skip characters that are left of the screen for 'nowrap'. if (wlv.draw_state < WL_LINE || wlv.skip_cells <= 0) { // Store the character. - if (mb_utf8) { - linebuf_char[wlv.off] = schar_from_cc(mb_c, u8cc); - } else { - linebuf_char[wlv.off] = schar_from_ascii((char)c); - } + linebuf_char[wlv.off] = mb_schar; if (multi_attr) { linebuf_attr[wlv.off] = multi_attr; multi_attr = 0; diff --git a/src/nvim/edit.c b/src/nvim/edit.c index ce547b55fe..eb5ea2c873 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1462,7 +1462,7 @@ void edit_putchar(int c, bool highlight) pc_status = PC_STATUS_SET; } - char buf[MB_MAXBYTES + 1]; + char buf[MB_MAXCHAR + 1]; grid_line_puts(pc_col, buf, utf_char2bytes(c, buf), attr); grid_line_flush(); } @@ -2176,7 +2176,7 @@ void insertchar(int c, int flags, int second_indent) int cc; if ((cc = utf_char2len(c)) > 1) { - char buf[MB_MAXBYTES + 1]; + char buf[MB_MAXCHAR + 1]; utf_char2bytes(c, buf); buf[cc] = NUL; @@ -3681,7 +3681,6 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) int cc; int temp = 0; // init for GCC bool did_backspace = false; - int cpc[MAX_MCO]; // composing characters bool call_fix_indent = false; // can't delete anything in an empty file @@ -3910,15 +3909,15 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (State & REPLACE_FLAG) { replace_do_bs(-1); } else { - const int l_p_deco = p_deco; - if (l_p_deco) { - (void)utfc_ptr2char(get_cursor_pos_ptr(), cpc); + bool has_composing = false; + if (p_deco) { + char *p0 = get_cursor_pos_ptr(); + has_composing = utf_composinglike(p0, p0 + utf_ptr2len(p0)); } (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_p_deco && cpc[0] != NUL) { + // move the cursor back. Don't back up before the base character. + if (has_composing) { inc_cursor(); } if (revins_chars) { diff --git a/src/nvim/eval.c b/src/nvim/eval.c index ed70091077..c073f30547 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -7117,7 +7117,7 @@ dict_T *get_vim_var_dict(int idx) FUNC_ATTR_PURE /// Set v:char to character "c". void set_vim_var_char(int c) { - char buf[MB_MAXBYTES + 1]; + char buf[MB_MAXCHAR + 1]; buf[utf_char2bytes(c, buf)] = NUL; set_vim_var_string(VV_CHAR, buf, -1); diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index c6909245af..8ef208f291 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5134,7 +5134,7 @@ static void f_nr2char(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) return; } - char buf[MB_MAXBYTES]; + char buf[MB_MAXCHAR]; const int len = utf_char2bytes((int)num, buf); rettv->v_type = VAR_STRING; @@ -6891,7 +6891,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (row < 0 || row >= grid->rows || col < 0 || col >= grid->cols) { c = -1; } else { - char buf[MB_MAXBYTES + 1]; + char buf[MAX_SCHAR_SIZE + 1]; schar_get(buf, grid_getchar(grid, row, col, NULL)); c = utf_ptr2char(buf); } @@ -6907,24 +6907,22 @@ static void f_screenchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) ScreenGrid *grid; screenchar_adjust(&grid, &row, &col); |