diff options
| author | Björn Linse <bjorn.linse@gmail.com> | 2018-02-10 11:03:59 +0100 |
|---|---|---|
| committer | Björn Linse <bjorn.linse@gmail.com> | 2018-06-13 10:11:11 +0200 |
| commit | d8e18c96a904667ce60366be22dbdf248006ff2e (patch) | |
| tree | d4d71e26b159e59b15ef2b210453baae4be0b3c8 /src/nvim | |
| parent | 315b7f8632076d882d498fc0bfab21a87ca75acb (diff) | |
| download | rneovim-d8e18c96a904667ce60366be22dbdf248006ff2e.tar.gz rneovim-d8e18c96a904667ce60366be22dbdf248006ff2e.tar.bz2 rneovim-d8e18c96a904667ce60366be22dbdf248006ff2e.zip | |
screen: use UTF-8 representation
Store text in ScreenLines as UTF-8, so it can be sent as-is to the UI
layer. `utfc_char2bytes(off,buf)` is removed, as `ScreenLines[off]` now
already contains this representation.
To recover the codepoints that the screen arrays previously contained, use
utfc_ptr2char (or utf_ptr2char to ignore composing chars).
NB: This commit does NOT change how screen.c processes incoming UTF-8 data
from buffers, cmdline, messages etc. Any algorithm that operates on UCS-4
(like arabic shaping, treatment of non-printable chars)
is left unchanged for now.
Diffstat (limited to 'src/nvim')
| -rw-r--r-- | src/nvim/eval.c | 5 | ||||
| -rw-r--r-- | src/nvim/globals.h | 55 | ||||
| -rw-r--r-- | src/nvim/mbyte.c | 25 | ||||
| -rw-r--r-- | src/nvim/mouse.c | 9 | ||||
| -rw-r--r-- | src/nvim/screen.c | 924 |
5 files changed, 358 insertions, 660 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 30c17af8c9..9ce354a0c5 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -13994,10 +13994,7 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr) c = -1; } else { off = LineOffset[row] + col; - if (enc_utf8 && ScreenLinesUC[off] != 0) - c = ScreenLinesUC[off]; - else - c = ScreenLines[off]; + c = utf_ptr2char(ScreenLines[off]); } rettv->vval.v_number = c; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 51bc3f1289..20e5353b51 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -131,38 +131,39 @@ typedef off_t off_T; /* * The characters and attributes cached for the screen. */ -typedef char_u schar_T; -typedef unsigned short sattr_T; - -/* - * The characters that are currently on the screen are kept in ScreenLines[]. - * It is a single block of characters, the size of the screen plus one line. - * The attributes for those characters are kept in ScreenAttrs[]. - * - * "LineOffset[n]" is the offset from ScreenLines[] for the start of line 'n'. - * The same value is used for ScreenLinesUC[] and ScreenAttrs[]. - * - * Note: before the screen is initialized and when out of memory these can be - * NULL. - */ +typedef char_u schar_T[(MAX_MCO+1) * 4 + 1]; +typedef int16_t sattr_T; + +/// ScreenLines[] contains a copy of the whole screen, as it currently is +/// displayed. It is a single block of screen cells, the size of the screen +/// plus one line. The extra line used as a buffer while redrawing a window +/// line, so it can be compared with the previous state of that line. This way +/// we can avoid sending bigger updates than neccessary to the Ul layer. +/// +/// Screen cells are stored as NUL-terminated UTF-8 strings, and a cell can +/// contain up to MAX_MCO composing characters after the base character. +/// The composing characters are to be drawn on top of the original character. +/// The content after the NUL is not defined (so comparison must be done a +/// single cell at a time). Double-width characters are stored in the left cell, +/// and the right cell should only contain the empty string. When a part of the +/// screen is cleared, the cells should be filled with a single whitespace char. +/// +/// ScreenAttrs[] contains the highlighting attribute for each cell. +/// LineOffset[n] is the offset from ScreenLines[] and ScreenAttrs[] for the +/// start of line 'n'. These offsets are in general not linear, as full screen +/// scrolling is implemented by rotating the offsets in the LineOffset array. +/// LineWraps[] is an array of boolean flags indicating if the screen line wraps +/// to the next line. It can only be true if a window occupies the entire screen +/// width. +/// +/// +/// Note: before the screen is initialized and when out of memory these can be +/// NULL. EXTERN schar_T *ScreenLines INIT(= NULL); EXTERN sattr_T *ScreenAttrs INIT(= NULL); EXTERN unsigned *LineOffset INIT(= NULL); EXTERN char_u *LineWraps INIT(= NULL); /* line wraps to next line */ -/* - * When using Unicode characters (in UTF-8 encoding) the character in - * ScreenLinesUC[] contains the Unicode for the character at this position, or - * NUL when the character in ScreenLines[] is to be used (ASCII char). - * The composing characters are to be drawn on top of the original character. - * ScreenLinesC[0][off] is only to be used when ScreenLinesUC[off] != 0. - * Note: These three are only allocated when enc_utf8 is set! - */ -EXTERN u8char_T *ScreenLinesUC INIT(= NULL); /* decoded UTF-8 characters */ -EXTERN u8char_T *ScreenLinesC[MAX_MCO]; /* composing characters */ -EXTERN int Screen_mco INIT(= 0); /* value of p_mco used when - allocating ScreenLinesC[] */ - EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */ EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */ diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 05e326104b..472c1ee9f6 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -560,7 +560,7 @@ size_t mb_string2cells(const char_u *str) /// We make sure that the offset used is less than "max_off". int utf_off2cells(unsigned off, unsigned max_off) { - return (off + 1 < max_off && ScreenLines[off + 1] == 0) ? 2 : 1; + return (off + 1 < max_off && ScreenLines[off + 1][0] == 0) ? 2 : 1; } /// Convert a UTF-8 byte sequence to a wide character @@ -790,27 +790,6 @@ int utfc_ptr2char_len(const char_u *p, int *pcc, int maxlen) #undef ISCOMPOSING } -/* - * Convert the character at screen position "off" to a sequence of bytes. - * Includes the composing characters. - * "buf" must at least have the length MB_MAXBYTES + 1. - * Only to be used when ScreenLinesUC[off] != 0. - * Returns the produced number of bytes. - */ -int utfc_char2bytes(int off, char_u *buf) -{ - int len; - int i; - - len = utf_char2bytes(ScreenLinesUC[off], buf); - for (i = 0; i < Screen_mco; ++i) { - if (ScreenLinesC[i][off] == 0) - break; - len += utf_char2bytes(ScreenLinesC[i][off], buf + len); - } - return len; -} - /// Get the length of a UTF-8 byte sequence representing a single codepoint /// /// @param[in] p UTF-8 string. @@ -1853,7 +1832,7 @@ int mb_fix_col(int col, int row) col = check_col(col); row = check_row(row); if (ScreenLines != NULL && col > 0 - && ScreenLines[LineOffset[row] + col] == 0) { + && ScreenLines[LineOffset[row] + col][0] == 0) { return col - 1; } return col; diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 6f636f643a..96d20b6a32 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -108,12 +108,13 @@ retnomove: goto retnomove; // ugly goto... // Remember the character under the mouse, it might be a '-' or '+' in the - // fold column. + // fold column. NB: only works for ASCII chars! if (row >= 0 && row < Rows && col >= 0 && col <= Columns - && ScreenLines != NULL) - mouse_char = ScreenLines[LineOffset[row] + (unsigned)col]; - else + && ScreenLines != NULL) { + mouse_char = ScreenLines[LineOffset[row] + (unsigned)col][0]; + } else { mouse_char = ' '; + } old_curwin = curwin; old_cursor = curwin->w_cursor; diff --git a/src/nvim/screen.c b/src/nvim/screen.c index f36d408b25..cf9a72715b 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -1,83 +1,65 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -/* - * screen.c: code for displaying on the screen - * - * Output to the screen (console, terminal emulator or GUI window) is minimized - * by remembering what is already on the screen, and only updating the parts - * that changed. - * - * ScreenLines[off] Contains a copy of the whole screen, as it is currently - * displayed (excluding text written by external commands). - * ScreenAttrs[off] Contains the associated attributes. - * LineOffset[row] Contains the offset into ScreenLines*[] and ScreenAttrs[] - * for each line. - * LineWraps[row] Flag for each line whether it wraps to the next line. - * - * For double-byte characters, two consecutive bytes in ScreenLines[] can form - * one character which occupies two display cells. - * For UTF-8 a multi-byte character is converted to Unicode and stored in - * ScreenLinesUC[]. ScreenLines[] contains the first byte only. For an ASCII - * character without composing chars ScreenLinesUC[] will be 0 and - * ScreenLinesC[][] is not used. When the character occupies two display - * cells the next byte in ScreenLines[] is 0. - * ScreenLinesC[][] contain up to 'maxcombine' composing characters - * (drawn on top of the first character). There is 0 after the last one used. - * - * The screen_*() functions write to the screen and handle updating - * ScreenLines[]. - * - * update_screen() is the function that updates all windows and status lines. - * It is called form the main loop when must_redraw is non-zero. It may be - * called from other places when an immediate screen update is needed. - * - * The part of the buffer that is displayed in a window is set with: - * - w_topline (first buffer line in window) - * - w_topfill (filler lines above the first line) - * - w_leftcol (leftmost window cell in window), - * - w_skipcol (skipped window cells of first line) - * - * Commands that only move the cursor around in a window, do not need to take - * action to update the display. The main loop will check if w_topline is - * valid and update it (scroll the window) when needed. - * - * Commands that scroll a window change w_topline and must call - * check_cursor() to move the cursor into the visible part of the window, and - * call redraw_later(VALID) to have the window displayed by update_screen() - * later. - * - * Commands that change text in the buffer must call changed_bytes() or - * changed_lines() to mark the area that changed and will require updating - * later. The main loop will call update_screen(), which will update each - * window that shows the changed buffer. This assumes text above the change - * can remain displayed as it is. Text after the change may need updating for - * scrolling, folding and syntax highlighting. - * - * Commands that change how a window is displayed (e.g., setting 'list') or - * invalidate the contents of a window in another way (e.g., change fold - * settings), must call redraw_later(NOT_VALID) to have the whole window - * redisplayed by update_screen() later. - * - * Commands that change how a buffer is displayed (e.g., setting 'tabstop') - * must call redraw_curbuf_later(NOT_VALID) to have all the windows for the - * buffer redisplayed by update_screen() later. - * - * Commands that change highlighting and possibly cause a scroll too must call - * redraw_later(SOME_VALID) to update the whole window but still use scrolling - * to avoid redrawing everything. But the length of displayed lines must not - * change, use NOT_VALID then. - * - * Commands that move the window position must call redraw_later(NOT_VALID). - * TODO: should minimize redrawing by scrolling when possible. - * - * Commands that change everything (e.g., resizing the screen) must call - * redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). - * - * Things that are handled indirectly: - * - When messages scroll the screen up, msg_scrolled will be set and - * update_screen() called to redraw. - */ +// screen.c: code for displaying on the screen +// +// Output to the screen (console, terminal emulator or GUI window) is minimized +// by remembering what is already on the screen, and only updating the parts +// that changed. +// +// The screen_*() functions write to the screen and handle updating +// ScreenLines[]. +// +// update_screen() is the function that updates all windows and status lines. +// It is called from the main loop when must_redraw is non-zero. It may be +// called from other places when an immediate screen update is needed. +// +// The part of the buffer that is displayed in a window is set with: +// - w_topline (first buffer line in window) +// - w_topfill (filler lines above the first line) +// - w_leftcol (leftmost window cell in window), +// - w_skipcol (skipped window cells of first line) +// +// Commands that only move the cursor around in a window, do not need to take +// action to update the display. The main loop will check if w_topline is +// valid and update it (scroll the window) when needed. +// +// Commands that scroll a window change w_topline and must call +// check_cursor() to move the cursor into the visible part of the window, and +// call redraw_later(VALID) to have the window displayed by update_screen() +// later. +// +// Commands that change text in the buffer must call changed_bytes() or +// changed_lines() to mark the area that changed and will require updating +// later. The main loop will call update_screen(), which will update each +// window that shows the changed buffer. This assumes text above the change +// can remain displayed as it is. Text after the change may need updating for +// scrolling, folding and syntax highlighting. +// +// Commands that change how a window is displayed (e.g., setting 'list') or +// invalidate the contents of a window in another way (e.g., change fold +// settings), must call redraw_later(NOT_VALID) to have the whole window +// redisplayed by update_screen() later. +// +// Commands that change how a buffer is displayed (e.g., setting 'tabstop') +// must call redraw_curbuf_later(NOT_VALID) to have all the windows for the +// buffer redisplayed by update_screen() later. +// +// Commands that change highlighting and possibly cause a scroll too must call +// redraw_later(SOME_VALID) to update the whole window but still use scrolling +// to avoid redrawing everything. But the length of displayed lines must not +// change, use NOT_VALID then. +// +// Commands that move the window position must call redraw_later(NOT_VALID). +// TODO(neovim): should minimize redrawing by scrolling when possible. +// +// Commands that change everything (e.g., resizing the screen) must call +// redraw_all_later(NOT_VALID) or redraw_all_later(CLEAR). +// +// Things that are handled indirectly: +// - When messages scroll the screen up, msg_scrolled will be set and +// update_screen() called to redraw. +/// #include <assert.h> #include <inttypes.h> @@ -1752,9 +1734,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T * Ignores 'rightleft', this window is never right-left. */ if (cmdwin_type != 0 && wp == curwin) { - ScreenLines[off] = cmdwin_type; + schar_from_ascii(ScreenLines[off], cmdwin_type); ScreenAttrs[off] = win_hl_attr(wp, HLF_AT); - ScreenLinesUC[off] = 0; col++; } @@ -1770,7 +1751,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T win_hl_attr(wp, HLF_FC)); // reverse the fold column for (i = 0; i < fdc; i++) { - ScreenLines[off + wp->w_width - i - 1 - col] = buf[i]; + schar_from_ascii(ScreenLines[off + wp->w_width - i - 1 - col], buf[i]); } } else { copy_text_attr(off + col, buf, fdc, win_hl_attr(wp, HLF_FC)); @@ -1854,111 +1835,76 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T * Right-left text is put in columns 0 - number-col, normal text is put * in columns number-col - window-width. */ - if (has_mbyte) { - int cells; - int u8c, u8cc[MAX_MCO]; - int i; - int idx; - int c_len; - char_u *p; - int prev_c = 0; /* previous Arabic character */ - int prev_c1 = 0; /* first composing char for prev_c */ - - if (wp->w_p_rl) - idx = off; - else - idx = off + col; - - /* Store multibyte characters in ScreenLines[] et al. correctly. */ - for (p = text; *p != NUL; ) { - cells = (*mb_ptr2cells)(p); - c_len = (*mb_ptr2len)(p); - if (col + cells > wp->w_width - - (wp->w_p_rl ? col : 0) - ) - break; - ScreenLines[idx] = *p; - if (enc_utf8) { - u8c = utfc_ptr2char(p, u8cc); - if (*p < 0x80 && u8cc[0] == 0) { - ScreenLinesUC[idx] = 0; - prev_c = u8c; - } else { - if (p_arshape && !p_tbidi && arabic_char(u8c)) { - /* Do Arabic shaping. */ - int pc, pc1, nc; - int pcc[MAX_MCO]; - int firstbyte = *p; + int cells; + int u8c, u8cc[MAX_MCO]; + int idx; + int c_len; + char_u *p; + int prev_c = 0; // previous Arabic character + int prev_c1 = 0; // first composing char for prev_c - /* The idea of what is the previous and next - * character depends on 'rightleft'. */ - if (wp->w_p_rl) { - pc = prev_c; - pc1 = prev_c1; - nc = utf_ptr2char(p + c_len); - prev_c1 = u8cc[0]; - } else { - pc = utfc_ptr2char(p + c_len, pcc); - nc = prev_c; - pc1 = pcc[0]; - } - prev_c = u8c; + if (wp->w_p_rl) { + idx = off; + } else { + idx = off + col; + } - u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], - pc, pc1, nc); - ScreenLines[idx] = firstbyte; - } else - prev_c = u8c; - /* Non-BMP character: display as ? or fullwidth ?. */ - ScreenLinesUC[idx] = u8c; - for (i = 0; i < Screen_mco; ++i) { - ScreenLinesC[i][idx] = u8cc[i]; - if (u8cc[i] == 0) - break; - } + // Store multibyte characters in ScreenLines[] et al. correctly. + for (p = text; *p != NUL; ) { + cells = (*mb_ptr2cells)(p); + c_len = (*mb_ptr2len)(p); + if (col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) { + break; + } + u8c = utfc_ptr2char(p, u8cc); + if (*p < 0x80 && u8cc[0] == 0) { + schar_from_ascii(ScreenLines[idx], *p); + prev_c = u8c; + } else { + if (p_arshape && !p_tbidi && arabic_char(u8c)) { + // Do Arabic shaping. + int pc, pc1, nc; + int pcc[MAX_MCO]; + int firstbyte = *p; + + // The idea of what is the previous and next + // character depends on 'rightleft'. + if (wp->w_p_rl) { + pc = prev_c; + pc1 = prev_c1; + nc = utf_ptr2char(p + c_len); + prev_c1 = u8cc[0]; + } else { + pc = utfc_ptr2char(p + c_len, pcc); + nc = prev_c; + pc1 = pcc[0]; } - if (cells > 1) - ScreenLines[idx + 1] = 0; - } else if (cells > 1) { - // Double-width character. - ScreenLines[idx + 1] = p[1]; + prev_c = u8c; + + u8c = arabic_shape(u8c, &firstbyte, &u8cc[0], pc, pc1, nc); + } else { + prev_c = u8c; } - col += cells; - idx += cells; - p += c_len; + schar_from_cc(ScreenLines[idx], u8c, u8cc); } - } else { - len = (int)STRLEN(text); - if (len > wp->w_width - col) - len = wp->w_width - col; - if (len > 0) { - if (wp->w_p_rl) - STRNCPY(current_ScreenLine, text, len); - else - STRNCPY(current_ScreenLine + col, text, len); - col += len; + if (cells > 1) { + ScreenLines[idx + 1][0] = 0; } + col += cells; + idx += cells; + p += c_len; } /* Fill the rest of the line with the fold filler */ if (wp->w_p_rl) col -= txtcol; + + schar_T sc; + schar_from_char(sc, fill_fold); while (col < wp->w_width - (wp->w_p_rl ? txtcol : 0) ) { - if (enc_utf8) { - if (fill_fold >= 0x80) { - ScreenLinesUC[off + col] = fill_fold; - ScreenLinesC[0][off + col] = 0; - ScreenLines[off + col] = 0x80; // avoid storing zero - } else { - ScreenLinesUC[off + col] = 0; - ScreenLines[off + col] = fill_fold; - } - col++; - } else { - ScreenLines[off + col++] = fill_fold; - } + schar_copy(ScreenLines[off+col++], sc); } if (text != buf) @@ -2059,18 +2005,18 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T } } -/* - * Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". - */ + +/// Copy "buf[len]" to ScreenLines["off"] and set attributes to "attr". +/// +/// Only works for ASCII text! static void copy_text_attr(int off, char_u *buf, int len, int attr) { int i; - memmove(ScreenLines + off, buf, (size_t)len); - if (enc_utf8) - memset(ScreenLinesUC + off, 0, sizeof(u8char_T) * (size_t)len); - for (i = 0; i < len; ++i) + for (i = 0; i < len; i++) { + schar_from_ascii(ScreenLines[off + i], buf[i]); ScreenAttrs[off + i] = attr; + } } /* @@ -3129,13 +3075,6 @@ win_line ( mb_utf8 = true; c = 0xc0; } - } else { - /* if this is a DBCS character, put it in "mb_c" */ - mb_l = MB_BYTE2LEN(c); - if (mb_l >= n_extra) - mb_l = 1; - else if (mb_l > 1) - mb_c = (c << 8) + p_extra[1]; } if (mb_l == 0) /* at the NUL at end-of-line */ mb_l = 1; @@ -3195,8 +3134,9 @@ win_line ( if (utf_iscomposing(mb_c)) { int i; - for (i = Screen_mco - 1; i > 0; --i) + for (i = MAX_MCO - 1; i > 0; i--) { u8cc[i] = u8cc[i - 1]; + } u8cc[0] = mb_c; mb_c = ' '; } @@ -3880,10 +3820,8 @@ win_line ( off += n; col += n; } else { - /* Add a blank character to highlight. */ - ScreenLines[off] = ' '; - if (enc_utf8) - ScreenLinesUC[off] = 0; + // Add a blank character to highlight. + schar_from_ascii(ScreenLines[off], ' '); } if (area_attr == 0) { /* Use attributes from match with highest priority among @@ -3978,13 +3916,11 @@ win_line ( int mc_attr = win_hl_attr(wp, HLF_MC); while (col < wp->w_width) { - ScreenLines[off] = ' '; - if (enc_utf8) - ScreenLinesUC[off] = 0; - ++col; - if (draw_color_col) - draw_color_col = advance_color_col(VCOL_HLC, - &color_cols); + schar_from_ascii(ScreenLines[off], ' '); + col++; + if (draw_color_col) { + draw_color_col = advance_color_col(VCOL_HLC, &color_cols); + } if (wp->w_p_cuc && VCOL_HLC == (long)wp->w_virtcol) { ScreenAttrs[off++] = cuc_attr; @@ -4006,10 +3942,7 @@ win_line ( // terminal buffers may need to highlight beyond the end of the // logical line while (col < wp->w_width) { - ScreenLines[off] = ' '; - if (enc_utf8) { - ScreenLinesUC[off] = 0; - } + schar_from_ascii(ScreenLines[off], ' '); ScreenAttrs[off++] = term_attrs[vcol++]; col++; } @@ -4088,20 +4021,10 @@ win_line ( --off; --col; } - ScreenLines[off] = c; if (mb_utf8) { - ScreenLinesUC[off] = mb_c; - if ((c & 0xff) == 0) { - ScreenLines[off] = 0x80; // Avoid storing zero. - } - for (int i = 0; i < Screen_mco; i++) { - ScreenLinesC[i][off] = u8cc[i]; - if (u8cc[i] == 0) { - break; - } - } + schar_from_cc(ScreenLines[off], mb_c, u8cc); } else { - ScreenLinesUC[off] = 0; + schar_from_ascii(ScreenLines[off], c); } if (multi_attr) { ScreenAttrs[off] = multi_attr; @@ -4113,13 +4036,8 @@ win_line ( // Need to fill two screen columns. off++; col++; - if (enc_utf8) { - // UTF-8: Put a 0 in the second screen char. - ScreenLines[off] = 0; - } else { - // DBCS: Put second byte in the second screen char. - ScreenLines[off] = mb_c & 0xff; - } + // UTF-8: Put a 0 in the second screen char. + ScreenLines[off][0] = 0; if (draw_state > WL_NR && filler_todo <= 0) { vcol++; } @@ -4297,12 +4215,11 @@ win_line ( /* When there is a multi-byte character, just output a * space to keep it simple. */ - if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[ - screen_row - - 1] + (Columns - 1)]) > 1) { + if (ScreenLines[LineOffset[screen_row - 1] + + (Columns - 1)][1] != 0) { ui_putc(' '); } else { - ui_putc(ScreenLines[LineOffset[screen_row - 1] + (Columns - 1)]); + ui_puts(ScreenLines[LineOffset[screen_row - 1] + (Columns - 1)]); } /* force a redraw of the first char on the next line */ ScreenAttrs[LineOffset[screen_row]] = (sattr_T)-1; @@ -4347,23 +4264,6 @@ win_line ( /* - * Return if the composing characters at "off_from" and "off_to" differ. - * Only to be used when ScreenLinesUC[off_from] != 0. - */ -static int comp_char_differs(int off_from, int off_to) -{ - int i; - - for (i = 0; i < Screen_mco; ++i) { - if (ScreenLinesC[i][off_from] != ScreenLinesC[i][off_to]) - return TRUE; - if (ScreenLinesC[i][off_from] == 0) - break; - } - return FALSE; -} - -/* * Check whether the given character needs redrawing: * - the (first byte of the) character is different * - the attributes are different @@ -4373,13 +4273,11 @@ static int comp_char_differs(int off_from, int off_to) static int char_needs_redraw(int off_from, int off_to, int cols) { return (cols > 0 - && (ScreenLines[off_from] != ScreenLines[off_to] - || ScreenAttrs[off_from] != ScreenAttrs[off_to] - || ScreenLinesUC[off_from] != ScreenLinesUC[off_to] - || (ScreenLinesUC[off_from] != 0 - && comp_char_differs(off_from, off_to)) - || (utf_off2cells(off_from, off_from + cols) > 1 - && ScreenLines[off_from + 1] != ScreenLines[off_to + 1]) + && ((schar_cmp(ScreenLines[off_from], ScreenLines[off_to]) + || ScreenAttrs[off_from] != ScreenAttrs[off_to] + || ((*mb_off2cells)(off_from, off_from + cols) > 1 + && schar_cmp(ScreenLines[off_from + 1], + ScreenLines[off_to + 1]))) || p_wd < 0)); } @@ -4427,9 +4325,9 @@ static void screen_line(int row, int coloff, int endcol, if (rlflag) { /* Clear rest first, because it's left of the text. */ if (clear_width > 0) { - while (col <= endcol && ScreenLines[off_to] == ' ' + while (col <= endcol && ScreenLines[off_to][0] == ' ' + && ScreenLines[off_to][1] == NUL && ScreenAttrs[off_to] == bg_attr - && (!enc_utf8 || ScreenLinesUC[off_to] == 0) ) { ++off_to; ++col; @@ -4466,54 +4364,24 @@ static void screen_line(int row, int coloff, int endcol, if (redraw_this) { - if (enc_dbcs != 0) { - /* Check if overwriting a double-byte with a single-byte or - * the other way around requires another character to be - * redrawn. For UTF-8 this isn't needed, because comparing - * ScreenLinesUC[] is sufficient. */ - if (char_cells == 1 - && col + 1 < endcol - && (*mb_off2cells)(off_to, max_off_to) > 1) { - /* Writing a single-cell character over a double-cell - * character: need to redraw the next cell. */ - ScreenLines[off_to + 1] = 0; - redraw_next = TRUE; - } else if (char_cells == 2 - && col + 2 < endcol - && (*mb_off2cells)(off_to, max_off_to) == 1 - && (*mb_off2cells)(off_to + 1, max_off_to) > 1) { - /* Writing the second half of a double-cell character over - * a double-cell character: need to redraw the second - * cell. */ - ScreenLines[off_to + 2] = 0; - redraw_next = TRUE; - } - } - /* When writing a single-width character over a double-width - * character and at the end of the redrawn text, need to clear out - * the right halve of the old character. - * Also required when writing the right halve of a double-width - * char over the left halve of an existing one. */ + // When writing a single-width character over a double-width + // character and at the end of the redrawn text, need to clear out + // the right halve of the old character. + // Also required when writing the right halve of a double-width + // char over the left halve of an existing one if (has_mbyte && col + char_cells == endcol && ((char_cells == 1 && (*mb_off2cells)(off_to, max_off_to) > 1) || (char_cells == 2 && (*mb_off2cells)(off_to, max_off_to) == 1 - && (*mb_off2cells)(off_to + 1, max_off_to) > 1))) - clear_next = TRUE; - - ScreenLines[off_to] = ScreenLines[off_from]; - if (enc_utf8) { - ScreenLinesUC[off_to] = ScreenLinesUC[off_from]; - if (ScreenLinesUC[off_from] != 0) { - int i; + && (*mb_off2cells)(off_to + 1, max_off_to) > 1))) { + clear_next = true; + } - for (i = 0; i < Screen_mco; ++i) - ScreenLinesC[i][off_to] = ScreenLinesC[i][off_from]; - } + schar_copy(ScreenLines[off_to], ScreenLines[off_from]); + if (char_cells == 2) { + schar_copy(ScreenLines[off_to+1], ScreenLines[off_from+1]); } - if (char_cells == 2) - ScreenLines[off_to + 1] = ScreenLines[off_from + 1]; ScreenAttrs[off_to] = ScreenAttrs[off_from]; /* For simplicity set the attributes of second half of a @@ -4521,10 +4389,7 @@ static void screen_line(int row, int coloff, int endcol, if (char_cells == 2) ScreenAttrs[off_to + 1] = ScreenAttrs[off_from]; - if (enc_dbcs != 0 && char_cells == 2) - screen_char_2(off_to, row, col + coloff); - else - screen_char(off_to, row, col + coloff); + screen_char(off_to, row, col + coloff); } off_to += CHAR_CELLS; @@ -4535,20 +4400,15 @@ static void screen_line(int row, int coloff, int endcol, if (clear_next) { /* Clear the second half of a double-wide character of which the left * half was overwritten with a single-wide character. */ - ScreenLines[off_to] = ' '; - if (enc_utf8) - ScreenLinesUC[off_to] = 0; + schar_from_ascii(ScreenLines[off_to], ' '); screen_char(off_to, row, col + coloff); } - if (clear_width > 0 - && !rlflag - ) { - - /* blank out the rest of the line */ - while (col < clear_width && ScreenLines[off_to] == ' ' + if (clear_width > 0 && !rlflag) { + // blank out the rest of the line + while (col < clear_width && ScreenLines[off_to][0] == ' ' + && ScreenLines[off_to][1] == NUL && ScreenAttrs[off_to] == bg_attr - && (!enc_utf8 || ScreenLinesUC[off_to] == 0) ) { ++off_to; ++col; @@ -4564,22 +4424,14 @@ static void screen_line(int row, int coloff, int endcol, if (clear_width > 0) { // For a window that's left of another, draw the separator char. if (col + coloff < Columns && wp->w_vsep_width > 0) { - int c; + int c = fillchar_vsep(wp, &hl); + schar_T sc; + schar_from_char(sc, c); - c = fillchar_vsep(wp, &hl); - if (ScreenLines[off_to] != (schar_T)c - || (enc_utf8 && (int)ScreenLinesUC[off_to] - != (c >= 0x80 ? c : 0)) + if (schar_cmp(ScreenLines[off_to], sc) || ScreenAttrs[off_to] != hl) { - ScreenLines[off_to] = c; + schar_copy(ScreenLines[off_to], sc); ScreenAttrs[off_to] = hl; - if (enc_utf8) { - if (c >= 0x80) { - ScreenLinesUC[off_to] = c; - ScreenLinesC[0][off_to] = 0; - } else - ScreenLinesUC[off_to] = 0; - } screen_char(off_to, row, col + coloff); } } else @@ -5279,6 +5131,50 @@ theend: entered = FALSE; } +// Low-level functions to manipulate invidual character cells on the +// screen grid. + +/// Put a ASCII character in a screen cell. +static void schar_from_ascii(char_u *p, const char c) +{ + p[0] = c; + p[1] = 0; +} + +/// Put a unicode character in a screen cell. +static int schar_from_char(char_u *p, int c) +{ + int len = utf_char2bytes(c, p); + p[len] = NUL; + return len; +} + +/// Put a unicode char, and up to MAX_MCO composing chars, in a screen cell. +static int schar_from_cc(char_u *p, int c, int u8cc[MAX_MCO]) +{ + int len = utf_char2bytes(c, p); + for (int i = 0; i < MAX_MCO; i++) { + if (u8cc[i] == 0) { + break; + } + len += utf_char2bytes(u8cc[i], p + len); + } + p[len] = 0; + return len; +} + +/// compare the contents of two screen cells. +static int schar_cmp(char_u *sc1, char_u *sc2) +{ + return STRNCMP(sc1, sc2, sizeof(schar_T)); +} + +/// copy the contents of screen cell `sc2` into cell `sc1` +static void schar_copy(char_u *sc1, char_u *sc2) +{ + STRLCPY(sc1, sc2, sizeof(schar_T)); +} + /* * Output a single character directly to the screen and update ScreenLines. @@ -5287,12 +5183,7 @@ void screen_putchar(int c, int row, int col, int attr) { char_u buf[MB_MAXBYTES + 1]; - if (has_mbyte) - buf[(*mb_char2bytes)(c, buf)] = NUL; - else { - buf[0] = c; - buf[1] = NUL; - } + buf[(*mb_char2bytes)(c, buf)] = NUL; screen_puts(buf, row, col, attr); } @@ -5308,35 +5199,12 @@ void screen_getbytes(int row, int col, char_u *bytes, int *attrp) if (ScreenLines != NULL && row < screen_Rows && col < screen_Columns) { off = LineOffset[row] + col; *attrp = ScreenAttrs[off]; - bytes[0] = ScreenLines[off]; - bytes[1] = NUL; - - if (ScreenLinesUC[off] != 0) { - bytes[utfc_char2bytes(off, bytes)] = NUL; - } + schar_copy(bytes, ScreenLines[off]); } } /* - * Return TRUE if composing characters for screen posn "off" differs from - * composing characters in "u8cc". - * Only to be used when ScreenLinesUC[off] != 0. - */ -static int screen_comp_differs(int off, int *u8cc) -{ - int i; - - for (i = 0; i < Screen_mco; ++i) { - if (ScreenLinesC[i][off] != (u8char_T)u8cc[i]) - return TRUE; - if (u8cc[i] == 0) - break; - } |