multigrid: introduce grid abstraction

This commit is contained in:
Björn Linse 2017-11-05 11:33:31 +01:00
parent ccbcd390d4
commit c9b559a030
6 changed files with 94 additions and 71 deletions

View File

@ -128,12 +128,6 @@ typedef off_t off_T;
# endif
#endif
/*
* The characters and attributes cached for the screen.
*/
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
@ -167,6 +161,8 @@ EXTERN char_u *LineWraps INIT(= NULL); /* line wraps to next line */
EXTERN int screen_Rows INIT(= 0); /* actual size of ScreenLines[] */
EXTERN int screen_Columns INIT(= 0); /* actual size of ScreenLines[] */
EXTERN ScreenGrid default_grid INIT(= { 0 });
/*
* When vgetc() is called, it sets mod_mask to the set of modifiers that are
* held down based on the MOD_MASK_* symbols that are read first.

View File

@ -19,13 +19,6 @@
#define MB_BYTE2LEN(b) utf8len_tab[b]
#define MB_BYTE2LEN_CHECK(b) (((b) < 0 || (b) > 255) ? 1 : utf8len_tab[b])
/// Maximum value for 'maxcombine'
///
/// At most that number of composing characters may be attached to the leading
/// character by various `utfc_*` functions. Note that some functions do not
/// have this limit.
enum { MAX_MCO = 6 };
// max length of an unicode char
#define MB_MAXCHAR 6

View File

@ -698,8 +698,8 @@ void free_all_mem(void)
buf = bufref_valid(&bufref) ? nextbuf : firstbuf;
}
/* screenlines (can't display anything now!) */
free_screenlines();
// free screenlines (can't display anything now!)
free_screengrid(&default_grid);
clear_hl_tables(false);
list_free_log();

View File

@ -149,9 +149,12 @@ void update_topline(void)
bool check_botline = false;
long save_so = p_so;
// need to have w_grid.Rows/Columns updated
win_grid_alloc(curwin, false);
// If there is no valid screen and when the window height is zero just use
// the cursor line.
if (!screen_valid(true) || curwin->w_height == 0) {
if (!screen_valid(true) || curwin->w_grid.Rows == 0) {
curwin->w_topline = curwin->w_cursor.lnum;
curwin->w_botline = curwin->w_topline;
curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;

View File

@ -130,6 +130,10 @@ static foldinfo_T win_foldinfo; /* info for 'foldcolumn' */
static schar_T *current_ScreenLine;
StlClickDefinition *tab_page_click_defs = NULL;
int grid_Rows = 0;
int grid_Columns = 0;
long tab_page_click_defs_size = 0;
// for line_putchar. Contains the state that needs to be remembered from
@ -5883,8 +5887,6 @@ int screen_valid(int doclear)
*/
void screenalloc(bool doclear)
{
int new_row, old_row;
int len;
static bool entered = false; // avoid recursiveness
int retry_count = 0;
@ -5892,7 +5894,7 @@ retry:
// Allocation of the screen buffers is done only when the size changes and
// when Rows and Columns have been set and we have started doing full
// screen stuff.
if ((ScreenLines != NULL
if ((default_grid.ScreenLines != NULL
&& Rows == screen_Rows
&& Columns == screen_Columns
)
@ -5938,13 +5940,7 @@ retry:
if (aucmd_win != NULL)
win_free_lsize(aucmd_win);
// Allocate space for an extra row as scratch space, so that a redrawn
// line can be compared with the previous screen line state.
size_t ncells = (size_t)((Rows+1) * Columns);
schar_T *new_ScreenLines = xmalloc(ncells * sizeof(*new_ScreenLines));
sattr_T *new_ScreenAttrs = xmalloc(ncells * sizeof(*new_ScreenAttrs));
unsigned *new_LineOffset = xmalloc((size_t)(Rows * sizeof(*new_LineOffset)));
char_u *new_LineWraps = xmalloc((size_t)(Rows * sizeof(*new_LineWraps)));
alloc_grid(&default_grid, Rows, Columns, !doclear);
StlClickDefinition *new_tab_page_click_defs = xcalloc(
(size_t)Columns, sizeof(*new_tab_page_click_defs));
@ -5955,46 +5951,11 @@ retry:
win_alloc_lines(aucmd_win);
}
for (new_row = 0; new_row < Rows; new_row++) {
new_LineOffset[new_row] = new_row * Columns;
new_LineWraps[new_row] = false;
clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
xfree(tab_page_click_defs);
// If the screen is not going to be cleared, copy as much as
// possible from the old screen to the new one and clear the rest
// (used when resizing the window at the "--more--" prompt or when
// executing an external command, for the GUI).
if (!doclear) {
for (int col = 0; col < Columns; col++) {
schar_from_ascii(new_ScreenLines[new_row * Columns + col], ' ');
}
memset(new_ScreenAttrs + new_row * Columns,
0, (size_t)Columns * sizeof(*new_ScreenAttrs));
old_row = new_row + (screen_Rows - Rows);
if (old_row >= 0 && ScreenLines != NULL) {
if (screen_Columns < Columns) {
len = screen_Columns;
} else {
len = Columns;
}
set_screengrid(&default_grid);
memmove(new_ScreenLines + new_LineOffset[new_row],
ScreenLines + LineOffset[old_row],
(size_t)len * sizeof(schar_T));
memmove(new_ScreenAttrs + new_LineOffset[new_row],
ScreenAttrs + LineOffset[old_row],
(size_t)len * sizeof(new_ScreenAttrs[0]));
}
}
}
// Use the last line of the screen for the current line.
current_ScreenLine = new_ScreenLines + Rows * Columns;
free_screenlines();
ScreenLines = new_ScreenLines;
ScreenAttrs = new_ScreenAttrs;
LineOffset = new_LineOffset;
LineWraps = new_LineWraps;
tab_page_click_defs = new_tab_page_click_defs;
tab_page_click_defs_size = Columns;
@ -6023,14 +5984,66 @@ retry:
}
}
void free_screenlines(void)
void alloc_grid(ScreenGrid *grid, int Rows, int Columns, bool copy)
{
xfree(ScreenLines);
xfree(ScreenAttrs);
xfree(LineOffset);
xfree(LineWraps);
clear_tab_page_click_defs(tab_page_click_defs, tab_page_click_defs_size);
xfree(tab_page_click_defs);
int new_row, old_row;
ScreenGrid new = { 0 };
size_t ncells = (size_t)((Rows+1) * Columns);
new.ScreenLines = xmalloc(ncells * sizeof(schar_T));
new.ScreenAttrs = xmalloc(ncells * sizeof(sattr_T));
new.LineOffset = xmalloc((size_t)(Rows * sizeof(unsigned)));
new.LineWraps = xmalloc((size_t)(Rows * sizeof(char_u)));
new.Rows = Rows;
new.Columns = Columns;
for (new_row = 0; new_row < Rows; new_row++) {
new.LineOffset[new_row] = new_row * Columns;
new.LineWraps[new_row] = false;
if (copy) {
// If the screen is not going to be cleared, copy as much as
// possible from the old screen to the new one and clear the rest
// (used when resizing the window at the "--more--" prompt or when
// executing an external command, for the GUI).
memset(new.ScreenLines + new_row * Columns,
' ', (size_t)Columns * sizeof(schar_T));
memset(new.ScreenAttrs + new_row * Columns,
0, (size_t)Columns * sizeof(sattr_T));
old_row = new_row + (grid->Rows - Rows);
if (old_row >= 0 && grid->ScreenLines != NULL) {
int len = MIN(grid->Columns, Columns);
memmove(new.ScreenLines + new.LineOffset[new_row],
grid->ScreenLines + grid->LineOffset[old_row],
(size_t)len * sizeof(schar_T));
memmove(new.ScreenAttrs + new.LineOffset[new_row],
grid->ScreenAttrs + grid->LineOffset[old_row],
(size_t)len * sizeof(sattr_T));
}
}
}
free_screengrid(grid);
*grid = new;
}
void free_screengrid(ScreenGrid *grid)
{
xfree(grid->ScreenLines);
xfree(grid->ScreenAttrs);
xfree(grid->LineOffset);
xfree(grid->LineWraps);
}
void set_screengrid(ScreenGrid *grid)
{
ScreenLines = grid->ScreenLines;
ScreenAttrs = grid->ScreenAttrs;
LineOffset = grid->LineOffset;
LineWraps = grid->LineWraps;
grid_Rows = grid->Rows;
grid_Columns = grid->Columns;
current_ScreenLine = ScreenLines + grid_Rows * grid_Columns;
}
/// Clear tab_page_click_defs table

View File

@ -15,4 +15,22 @@ typedef uint32_t u8char_T;
typedef struct expand expand_T;
#define MAX_MCO 6 // maximum value for 'maxcombine'
// The characters and attributes cached for the screen.
typedef char_u schar_T[(MAX_MCO+1) * 4 + 1];
typedef int16_t sattr_T;
// TODO(bfredl): find me a good home
typedef struct {
schar_T *ScreenLines;
sattr_T *ScreenAttrs;
unsigned *LineOffset;
char_u *LineWraps;
int Rows;
int Columns;
} ScreenGrid;
#endif // NVIM_TYPES_H