diff options
-rw-r--r-- | src/nvim/edit.c | 4 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 46 | ||||
-rw-r--r-- | src/nvim/memory.c | 2 | ||||
-rw-r--r-- | src/nvim/screen.c | 256 | ||||
-rw-r--r-- | src/nvim/window.c | 4 |
5 files changed, 172 insertions, 140 deletions
diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 3558bdea06..768d37bd01 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1508,7 +1508,7 @@ void edit_putchar(int c, int highlight) if (curwin->w_p_rl) { pc_col += curwin->w_grid.Columns - 1 - curwin->w_wcol; if (has_mbyte) { - int fix_col = mb_fix_col(&curwin->w_grid, pc_col, pc_row); + int fix_col = grid_fix_col(&curwin->w_grid, pc_col, pc_row); if (fix_col != pc_col) { grid_putchar(&curwin->w_grid, ' ', pc_row, fix_col, attr); @@ -1518,7 +1518,7 @@ void edit_putchar(int c, int highlight) } } else { pc_col += curwin->w_wcol; - if (mb_lefthalve(&curwin->w_grid, pc_row, pc_col)) + if (grid_lefthalve(&curwin->w_grid, pc_row, pc_col)) pc_status = PC_STATUS_LEFT; } diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index 775e5b24fc..73748154e7 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -1823,32 +1823,6 @@ const char *mb_unescape(const char **const pp) return NULL; } -/* - * Return true if the character at "row"/"col" on the screen is the left side - * of a double-width character. - * Caller must make sure "row" and "col" are not invalid! - */ -bool mb_lefthalve(ScreenGrid *grid, int row, int col) -{ - return utf_off2cells(grid, grid->LineOffset[row] + col, - grid->LineOffset[row] + grid->Columns) > 1; -} - -/* - * Correct a position on the screen, if it's the right half of a double-wide - * char move it to the left half. Returns the corrected column. - */ -int mb_fix_col(ScreenGrid *grid, int col, int row) -{ - col = check_col(grid, col); - row = check_row(grid, row); - if (grid->ScreenLines != NULL && col > 0 - && grid->ScreenLines[grid->LineOffset[row] + col][0] == 0) { - return col - 1; - } - return col; -} - /* * Skip the Vim specific head of a 'encoding' name. @@ -2525,23 +2499,3 @@ char_u * string_convert_ext(const vimconv_T *const vcp, char_u *ptr, return retval; } - -// Check bounds for column number -static int check_col(ScreenGrid *grid, int col) -{ - if (col < 0) - return 0; - if (col >= grid->Columns) - return grid->Columns - 1; - return col; -} - -// Check bounds for row number -static int check_row(ScreenGrid *grid, int row) -{ - if (row < 0) - return 0; - if (row >= grid->Rows) - return grid->Rows - 1; - return row; -} diff --git a/src/nvim/memory.c b/src/nvim/memory.c index ce914b43f9..d38079ca72 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -699,7 +699,7 @@ void free_all_mem(void) } // free screenlines (can't display anything now!) - free_screengrid(&default_grid); + screen_free_all_mem(); clear_hl_tables(false); list_free_log(); diff --git a/src/nvim/screen.c b/src/nvim/screen.c index dca11fd49e..063363755a 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -121,8 +121,12 @@ #define W_ENDCOL(wp) (wp->w_wincol + wp->w_width) #define W_ENDROW(wp) (wp->w_winrow + wp->w_height) -// Get the offset for the current line buffer when redrawing a line for a grid -#define GRID_TMPLINE(grid) ((grid)->Rows * (grid)->Columns) + +// temporary buffer for rendering a single screenline, so it can be +// comparared with previous contents to calulate smallest delta. +static size_t linebuf_size = 0; +static schar_T *linebuf_char = NULL; +static sattr_T *linebuf_attr = NULL; static match_T search_hl; /* used for 'hlsearch' highlight matching */ @@ -502,7 +506,7 @@ void update_single_line(win_T *wp, linenr_T lnum) int j; // Don't do anything if the screen structures are (not yet) valid. - if (wp->w_grid.ScreenLines == NULL || updating_screen) { + if (linebuf_char == NULL || updating_screen) { return; } updating_screen = true; @@ -516,6 +520,8 @@ void update_single_line(win_T *wp, linenr_T lnum) start_search_hl(); prepare_search_hl(wp, lnum); update_window_hl(wp, false); + // allocate window grid if not already + win_grid_alloc(wp, false); win_line(wp, lnum, row, row + wp->w_lines[j].wl_size, false, false); end_search_hl(); break; @@ -1774,15 +1780,15 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T * 6. set highlighting for the Visual area an other text */ col = 0; - off = (int)GRID_TMPLINE(grid); + off = 0; /* * 1. Add the cmdwin_type for the command-line window * Ignores 'rightleft', this window is never right-left. */ if (cmdwin_type != 0 && wp == curwin) { - schar_from_ascii(grid->ScreenLines[off], cmdwin_type); - grid->ScreenAttrs[off] = win_hl_attr(wp, HLF_AT); + schar_from_ascii(linebuf_char[off], cmdwin_type); + linebuf_attr[off] = win_hl_attr(wp, HLF_AT); col++; } @@ -1798,7 +1804,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++) { - schar_from_ascii(grid->ScreenLines[off + wp->w_width - i - 1 - col], buf[i]); + schar_from_ascii(linebuf_char[off + wp->w_width - i - 1 - col], buf[i]); } } else { copy_text_attr(off + col, buf, fdc, win_hl_attr(wp, HLF_FC)); @@ -1808,10 +1814,10 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T # define RL_MEMSET(p, v, l) if (wp->w_p_rl) \ for (ri = 0; ri < l; ++ri) \ - grid->ScreenAttrs[off + (wp->w_width - (p) - (l)) + ri] = v; \ + linebuf_attr[off + (wp->w_width - (p) - (l)) + ri] = v; \ else \ for (ri = 0; ri < l; ++ri) \ - grid->ScreenAttrs[off + (p) + ri] = v + linebuf_attr[off + (p) + ri] = v /* Set all attributes of the 'number' or 'relativenumber' column and the * text */ @@ -1877,7 +1883,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T txtcol = col; /* remember where text starts */ - // 5. move the text to grid->ScreenLines[off]. Fill up with "fill_fold". + // 5. move the text to linebuf_char[off]. Fill up with "fill_fold". // Right-left text is put in columns 0 - number-col, normal text is put // in columns number-col - window-width. int idx; @@ -1895,8 +1901,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T // if(col + cells > wp->w_width - (wp->w_p_rl ? col : 0)) { break; } // This is obvious wrong. If Vim ever fixes this, solve for "cells" again // in the correct condition. - int maxcells = wp->w_width - col - (wp->w_p_rl ? col : 0); - int cells = line_putchar(&s, &grid->ScreenLines[idx], maxcells, wp->w_p_rl); + int maxcells = grid->Columns - col - (wp->w_p_rl ? col : 0); + int cells = line_putchar(&s, &linebuf_char[idx], maxcells, wp->w_p_rl); if (cells == -1) { break; } @@ -1913,7 +1919,7 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T while (col < wp->w_width - (wp->w_p_rl ? txtcol : 0) ) { - schar_copy(grid->ScreenLines[off+col++], sc); + schar_copy(linebuf_char[off+col++], sc); } if (text != buf) @@ -1977,8 +1983,8 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T txtcol -= wp->w_leftcol; } if (txtcol >= 0 && txtcol < wp->w_width) { - grid->ScreenAttrs[off + txtcol] = - hl_combine_attr(grid->ScreenAttrs[off + txtcol], win_hl_attr(wp, HLF_MC)); + linebuf_attr[off + txtcol] = + hl_combine_attr(linebuf_attr[off + txtcol], win_hl_attr(wp, HLF_MC)); } txtcol = old_txtcol; j = wp->w_p_cc_cols[++i]; @@ -1992,13 +1998,14 @@ static void fold_line(win_T *wp, long fold_count, foldinfo_T *foldinfo, linenr_T txtcol -= wp->w_skipcol; else txtcol -= wp->w_leftcol; - if (txtcol >= 0 && txtcol < wp->w_width) - grid->ScreenAttrs[off + txtcol] = hl_combine_attr( - grid->ScreenAttrs[off + txtcol], win_hl_attr(wp, HLF_CUC)); + if (txtcol >= 0 && txtcol < wp->w_width) { + linebuf_attr[off + txtcol] = hl_combine_attr( + linebuf_attr[off + txtcol], win_hl_attr(wp, HLF_CUC)); + } } - grid_move_line(grid, row, 0, grid->Columns, grid->Columns, false, wp, - wp->w_hl_attr_normal, false); + grid_put_linebuf(grid, row, 0, grid->Columns, grid->Columns, false, wp, + wp->w_hl_attr_normal, false); /* * Update w_cline_height and w_cline_folded if the cursor line was @@ -2023,8 +2030,8 @@ static void copy_text_attr(int off, char_u *buf, int len, int attr) int i; for (i = 0; i < len; i++) { - schar_from_ascii(default_grid.ScreenLines[off + i], buf[i]); - default_grid.ScreenAttrs[off + i] = attr; + schar_from_ascii(linebuf_char[off + i], buf[i]); + linebuf_attr[off + i] = attr; } } @@ -2099,7 +2106,6 @@ win_line ( bool number_only // only update the number column ) { - unsigned off; // offset in ScreenLines/ScreenAttrs int c = 0; // init for GCC long vcol = 0; // virtual column (for tabs) long vcol_sbr = -1; // virtual column after showbreak @@ -2238,9 +2244,6 @@ win_line ( row = startrow; - // allocate window grid if not already - win_grid_alloc(wp, true); - if (!number_only) { // To speed up the loop below, set extra_check when there is linebreak, // trailing white space and/or syntax processing to be done. @@ -2676,11 +2679,11 @@ win_line ( cur = cur->next; } - off = (unsigned)GRID_TMPLINE(grid); + unsigned off = 0; // Offset relative start of line int col = 0; // Visual column on screen. if (wp->w_p_rl) { // Rightleft window: process the text in the normal direction, but put - // it in grid->ScreenLines[off] from right to left. Start at the + // it in linebuf_char[off] from right to left. Start at the // rightmost column of the window. col = grid->Columns - 1; off += col; @@ -2901,8 +2904,8 @@ win_line ( && lnum == wp->w_cursor.lnum && vcol >= (long)wp->w_virtcol && filler_todo <= 0) || (number_only && draw_state > WL_NR)) { - grid_move_line(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp, - wp->w_hl_attr_normal, false); + grid_put_linebuf(grid, row, 0, col, -grid->Columns, wp->w_p_rl, wp, + wp->w_hl_attr_normal, false); // Pretend we have finished updating the window. Except when // 'cursorcolumn' is set. if (wp->w_p_cuc) { @@ -3846,7 +3849,7 @@ win_line ( col += n; } else { // Add a blank character to highlight. - schar_from_ascii(grid->ScreenLines[off], ' '); + schar_from_ascii(linebuf_char[off], ' '); } if (area_attr == 0) { /* Use attributes from match with highest priority among @@ -3877,7 +3880,7 @@ win_line ( if (wp->w_p_cul && lnum == wp->w_cursor.lnum) { eol_attr = hl_combine_attr(win_hl_attr(wp, HLF_CUL), eol_attr); } - grid->ScreenAttrs[off] = eol_attr; + linebuf_attr[off] = eol_attr; if (wp->w_p_rl) { --col; --off; @@ -3971,14 +3974,14 @@ win_line ( } } if (*s.p != NUL) { - cells = line_putchar(&s, &grid->ScreenLines[off], grid->Columns - col, + cells = line_putchar(&s, &linebuf_char[off], grid->Columns - col, false); } } delay_virttext = false; if (cells == -1) { - schar_from_ascii(grid->ScreenLines[off], ' '); + schar_from_ascii(linebuf_char[off], ' '); cells = 1; } col += cells * col_stride; @@ -4000,9 +4003,9 @@ win_line ( attr = hl_combine_attr(attr, line_attr); - grid->ScreenAttrs[off] = attr; + linebuf_attr[off] = attr; if (cells == 2) { - grid->ScreenAttrs[off+1] = attr; + linebuf_attr[off+1] = attr; } off += cells * col_stride; @@ -4020,12 +4023,12 @@ win_line ( // terminal buffers may need to highlight beyond the end of the // logical line while (col < grid->Columns) { - schar_from_ascii(grid->ScreenLines[off], ' '); - grid->ScreenAttrs[off++] = term_attrs[vcol++]; + schar_from_ascii(linebuf_char[off], ' '); + linebuf_attr[off++] = term_attrs[vcol++]; col++; } } - grid_move_line(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp, + grid_put_linebuf(grid, row, 0, col, grid->Columns, wp->w_p_rl, wp, wp->w_hl_attr_normal, false); row++; @@ -4106,22 +4109,23 @@ win_line ( --col; } if (mb_utf8) { - schar_from_cc(grid->ScreenLines[off], mb_c, u8cc); + schar_from_cc(linebuf_char[off], mb_c, u8cc); } else { - schar_from_ascii(grid->ScreenLines[off], c); + schar_from_ascii(linebuf_char[off], c); } if (multi_attr) { - grid->ScreenAttrs[off] = multi_attr; + linebuf_attr[off] = multi_attr; multi_attr = 0; - } else - grid->ScreenAttrs[off] = char_attr; + } else { + linebuf_attr[off] = char_attr; + } if (has_mbyte && (*mb_char2cells)(mb_c) > 1) { // Need to fill two screen columns. off++; col++; // UTF-8: Put a 0 in the second screen char. - grid->ScreenLines[off][0] = 0; + linebuf_char[off][0] = 0; if (draw_state > WL_NR && filler_todo <= 0) { vcol++; } @@ -4241,8 +4245,8 @@ win_line ( && row != endrow - 1 // Not the last line being displayed. && grid->Columns == Columns // Window spans the width of the screen. && !wp->w_p_rl; // Not right-to-left. - grid_move_line(grid, row, 0, col - boguscols, grid->Columns, wp->w_p_rl, - wp, wp->w_hl_attr_normal, wrap); + grid_put_linebuf(grid, row, 0, col - boguscols, grid->Columns, wp->w_p_rl, + wp, wp->w_hl_attr_normal, wrap); if (wrap) { // Force a redraw of the first column of the next line. grid->ScreenAttrs[grid->LineOffset[row + 1]] = -1; @@ -4276,7 +4280,7 @@ win_line ( } col = 0; - off = (unsigned)GRID_TMPLINE(grid); + off = 0; if (wp->w_p_rl) { col = grid->Columns - 1; /* col is not used if breaking! */ off += col; @@ -4323,15 +4327,15 @@ static int grid_char_needs_redraw(ScreenGrid *grid, int off_from, int off_to, int cols) { return (cols > 0 - && ((schar_cmp(grid->ScreenLines[off_from], grid->ScreenLines[off_to]) - || grid->ScreenAttrs[off_from] != grid->ScreenAttrs[off_to] - || (utf_off2cells(grid, off_from, off_from + cols) > 1 - && schar_cmp(grid->ScreenLines[off_from + 1], + && ((schar_cmp(linebuf_char[off_from], grid->ScreenLines[off_to]) + || linebuf_attr[off_from] != grid->ScreenAttrs[off_to] + || (line_off2cells(linebuf_char, off_from, off_from + cols) > 1 + && schar_cmp(linebuf_char[off_from + 1], grid->ScreenLines[off_to + 1]))) || p_wd < 0)); } -/// Move one "cooked" line to the window grid, but only the characters that +/// Move one buffered line to the window grid, but only the characters that /// have actually changed. Handle insert/delete character. /// "coloff" gives the first column on the grid for this line. /// "endcol" gives the columns where valid characters are. @@ -4342,9 +4346,9 @@ static int grid_char_needs_redraw(ScreenGrid *grid, int off_from, int off_to, /// When FALSE and "clear_width" > 0, clear columns "endcol" to "clear_width" /// If "wrap" is true, then hint to the UI that "row" contains a line /// which has wrapped into the next row. -static void grid_move_line(ScreenGrid *grid, int row, int coloff, int endcol, - int clear_width, int rlflag, win_T *wp, int bg_attr, - bool wrap) +static void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int endcol, + int clear_width, int rlflag, win_T *wp, + int bg_attr, bool wrap) { unsigned off_from; unsigned off_to; @@ -4372,18 +4376,12 @@ static void grid_move_line(ScreenGrid *grid, int row, int coloff, int endcol, if (!ui_is_external(kUIMultigrid) && grid != &default_grid) { row += grid->OffsetRow; coloff += grid->OffsetColumn; - memcpy(default_grid.ScreenLines + GRID_TMPLINE(&default_grid), - grid->ScreenLines + GRID_TMPLINE(grid), - sizeof(schar_T) * grid->Columns); - memcpy(default_grid.ScreenAttrs + GRID_TMPLINE(&default_grid), - grid->ScreenAttrs + GRID_TMPLINE(grid), - sizeof(sattr_T) * grid->Columns); grid = &default_grid; } - off_from = (unsigned)GRID_TMPLINE(grid); + off_from = 0; off_to = grid->LineOffset[row] + coloff; - max_off_from = off_from + grid->Columns; + max_off_from = linebuf_size; max_off_to = grid->LineOffset[row] + grid->Columns; if (rlflag) { @@ -4409,8 +4407,8 @@ static void grid_move_line(ScreenGrid *grid, int row, int coloff, int endcol, if (bg_attr) { for (int c = col; c < endcol; c++) { - grid->ScreenAttrs[off_from+c] = - hl_combine_attr(bg_attr, grid->ScreenAttrs[off_from+c]); + linebuf_attr[off_from+c] = + hl_combine_attr(bg_attr, linebuf_attr[off_from+c]); } } @@ -4419,7 +4417,7 @@ static void grid_move_line(ScreenGrid *grid, int row, int coloff, int endcol, while (col < endcol) { char_cells = 1; if (col + 1 < endcol) { - char_cells = utf_off2cells(grid, off_from, max_off_from); + char_cells = line_off2cells(linebuf_char, off_from, max_off_from); } redraw_this = redraw_next; redraw_next = grid_char_needs_redraw(grid, off_from + char_cells, @@ -4438,23 +4436,23 @@ static void grid_move_line(ScreenGrid *grid, int row, int coloff, int endcol, // char over the left halve of an existing one if (col + char_cells == endcol && ((char_cells == 1 - && utf_off2cells(grid, off_to, max_off_to) > 1) + && grid_off2cells(grid, off_to, max_off_to) > 1) || (char_cells == 2 - && utf_off2cells(grid, off_to, max_off_to) == 1 - && utf_off2cells(grid, off_to + 1, max_off_to) > 1))) { + && grid_off2cells(grid, off_to, max_off_to) == 1 + && grid_off2cells(grid, off_to + 1, max_off_to) > 1))) { clear_next = true; } - schar_copy(grid->ScreenLines[off_to], grid->ScreenLines[off_from]); + schar_copy(grid->ScreenLines[off_to], linebuf_char[off_from]); if (char_cells == 2) { - schar_copy(grid->ScreenLines[off_to+1], grid->ScreenLines[off_from+1]); + schar_copy(grid->ScreenLines[off_to+1], linebuf_char[off_from+1]); } - grid->ScreenAttrs[off_to] = grid->ScreenAttrs[off_from]; + grid->ScreenAttrs[off_to] = linebuf_attr[off_from]; // For simplicity set the attributes of second half of a // double-wide character equal to the first half. if (char_cells == 2) { - grid->ScreenAttrs[off_to + 1] = grid->ScreenAttrs[off_from]; + grid->ScreenAttrs[off_to + 1] = linebuf_attr[off_from]; } } @@ -5257,6 +5255,52 @@ static void schar_copy(char_u *sc1, char_u *sc2) STRLCPY(sc1, sc2, sizeof(schar_T)); } +static int line_off2cells(schar_T *line, size_t off, size_t max_off) +{ + return (off + 1 < max_off && line[off + 1][0] == 0) ? 2 : 1; +} + +/// Return number of display cells for char at ScreenLines[off]. +/// We make sure that the offset used is less than "max_off". +static int grid_off2cells(ScreenGrid *grid, size_t off, size_t max_off) +{ + return line_off2cells(grid->ScreenLines, off, max_off); +} + +/// Return true if the character at "row"/"col" on the screen is the left side +/// of a double-width character. +/// +/// Caller must make sure "row" and "col" are not invalid! +bool grid_lefthalve(ScreenGrid *grid, int row, int col) +{ + if (!ui_is_external(kUIMultigrid)) { + row += grid->OffsetRow; + col += grid->OffsetColumn; + grid = &default_grid; + } + + return grid_off2cells(grid, grid->LineOffset[row] + col, + grid->LineOffset[row] + grid->Columns) > 1; +} + +/// Correct a position on the screen, if it's the right half of a double-wide +/// char move it to the left half. Returns the corrected column. +int grid_fix_col(ScreenGrid *grid, int col, int row) +{ + int coloff = 0; + if (!ui_is_external(kUIMultigrid)) { + row += grid->OffsetRow; + coloff = grid->OffsetColumn; + grid = &default_grid; + } + + col += coloff; + if (grid->ScreenLines != NULL && col > 0 + && grid->ScreenLines[grid->LineOffset[row] + col][0] == 0) { + return col - 1 - coloff; + } + return col - coloff; +} /// output a single character directly to the grid and update ScreenLines. void grid_putchar(ScreenGrid *grid, int c, int row, int col, int attr) @@ -5363,7 +5407,7 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, /* When drawing over the right halve of a double-wide char clear out the * left halve. Only needed in a terminal. */ - if (col > 0 && col < grid->Columns && mb_fix_col(grid, col, row) != col) { + if (col > 0 && col < grid->Columns && grid_fix_col(grid, col, row) != col) { schar_from_ascii(grid->ScreenLines[off - 1], ' '); grid->ScreenAttrs[off - 1] = 0; // redraw the previous cell, make it empty @@ -5438,10 +5482,11 @@ void grid_puts_len(ScreenGrid *grid, char_u *text, int textlen, int row, clear_next_cell = false; } else if ((len < 0 ? ptr[mbyte_blen] == NUL : ptr + mbyte_blen >= text + len) - && ((mbyte_cells == 1 && utf_off2cells(grid, off, max_off) > 1) + && ((mbyte_cells == 1 + && grid_off2cells(grid, off, max_off) > 1) || (mbyte_cells == 2 - && utf_off2cells(grid, off, max_off) == 1 - && utf_off2cells(grid, off + 1, max_off) > 1))) { + && grid_off2cells(grid, off, max_off) == 1 + && grid_off2cells(grid, off + 1, max_off) > 1))) { clear_next_cell = true; } @@ -5826,10 +5871,11 @@ void grid_fill(ScreenGrid *grid, int start_row, int end_row, int start_col, // out the left halve. When drawing over the left halve of a // double wide-char clear out the right halve. Only needed in a // terminal. - if (start_col > 0 && mb_fix_col(grid, start_col, row) != start_col) { + if (start_col > 0 && grid_fix_col(grid, start_col, row) != start_col) { grid_puts_len(grid, (char_u *)" ", 1, row, start_col - 1, 0); } - if (end_col < grid->Columns && mb_fix_col(grid, end_col, row) != end_col) { + if (end_col < grid->Columns + && grid_fix_col(grid, end_col, row) != end_col) { grid_puts_len(grid, (char_u *)" ", 1, row, end_col, 0); } } @@ -5936,20 +5982,30 @@ void win_grid_alloc(win_T *wp, int doclear) columns = wp->w_width; } - if (grid->ScreenLines == NULL + // TODO(bfredl): floating windows should force this to true + bool want_allocation = ui_is_external(kUIMultigrid); + bool has_allocation = (grid->ScreenLines != NULL); + + if ((has_allocation != want_allocation) || grid->Rows != rows || grid->Columns != columns) { - grid_alloc(grid, rows, columns, doclear); - win_free_lsize(wp); - win_alloc_lines(wp); + if (want_allocation) { + grid_alloc(grid, rows, columns, !doclear); + win_free_lsize(wp); + win_alloc_lines(wp); + } else { + // Single grid mode, all rendering will be redirected to default_grid. + // Only keep track of the size and offset of the window. + grid_free(grid); + grid->Rows = rows; + grid->Columns = columns; + } grid->was_resized = true; } grid->OffsetRow = wp->w_winrow; grid->OffsetColumn = wp->w_wincol; - grid_assign_handle(grid); - // send grid resize event if: // - a grid was just resized // - screen_resize was called and all grid sizes must be sent @@ -6116,17 +6172,39 @@ void grid_alloc(ScreenGrid *grid, int rows, int columns, bool copy) } } } - free_screengrid(grid); + grid_free(grid); *grid = new; -} + // Share a single scratch buffer for all grids, by + // ensuring it is as wide as the widest grid. + if (linebuf_size < (size_t)columns) { + xfree(linebuf_char); + xfree(linebuf_attr); + linebuf_char = xmalloc(columns * sizeof(schar_T)); + linebuf_attr = xmalloc(columns * sizeof(sattr_T)); + linebuf_size = columns; + } +} -void free_screengrid(ScreenGrid *grid) +void grid_free(ScreenGrid *grid) { xfree(grid->ScreenLines); xfree(grid->ScreenAttrs); xfree(grid->LineOffset); xfree(grid->LineWraps); + + grid->ScreenLines = NULL; + grid->ScreenAttrs = NULL; + grid->LineOffset = NULL; + grid->LineWraps = NULL; +} + +/// Doesn't allow reinit, so must only be called by free_all_mem! +void screen_free_all_mem(void) +{ + grid_free(&default_grid); + xfree(linebuf_char); + xfree(linebuf_attr); } /// Clear tab_page_click_defs table diff --git a/src/nvim/window.c b/src/nvim/window.c index ba44d7334f..3d11076a40 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -3990,7 +3990,7 @@ void win_free_grid(win_T *wp, bool reinit) ui_call_grid_destroy(wp->w_grid.handle); wp->w_grid.handle = 0; } - free_screengrid(&wp->w_grid); + grid_free(&wp->w_grid); if (reinit) { // if a float is turned into a split and back into a float, the grid // data structure will be reused @@ -4100,7 +4100,7 @@ void win_alloc_lines(win_T *wp) { wp->w_lines_valid = 0; assert(wp->w_grid.Rows >= 0); - wp->w_lines = xcalloc(wp->w_grid.Rows + 1, sizeof(wline_T)); + wp->w_lines = xcalloc(MAX(wp->w_grid.Rows + 1, Rows), sizeof(wline_T)); } /* |