/* Delete characters. */ void grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx) { u_int sx; px = grid_view_x(gd, px); py = grid_view_y(gd, py); sx = grid_view_x(gd, gd->sx); grid_move_cells(gd, px, px + nx, py, sx - px - nx); grid_clear(gd, sx - nx, py, px + nx - (sx - nx), 1); }
/* Insert characters. */ void grid_view_insert_cells(struct grid *gd, u_int px, u_int py, u_int nx) { u_int sx; px = grid_view_x(gd, px); py = grid_view_y(gd, py); sx = grid_view_x(gd, gd->sx); if (px == sx - 1) grid_clear(gd, px, py, 1, 1); else grid_move_cells(gd, px + nx, px, py, sx - px - nx); }
/* Join line below onto this one. */ static void grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, u_int width, int already) { struct grid_line *gl, *from = NULL; struct grid_cell gc; u_int lines, left, i, to, line, want = 0; u_int at; int wrapped = 1; /* * Add a new target line. */ if (!already) { to = target->sy; gl = grid_reflow_move(target, &gd->linedata[yy]); } else { to = target->sy - 1; gl = &target->linedata[to]; } at = gl->cellused; /* * Loop until no more to consume or the target line is full. */ lines = 0; for (;;) { /* * If this is now the last line, there is nothing more to be * done. */ if (yy + 1 + lines == gd->hsize + gd->sy) break; line = yy + 1 + lines; /* If the next line is empty, skip it. */ if (~gd->linedata[line].flags & GRID_LINE_WRAPPED) wrapped = 0; if (gd->linedata[line].cellused == 0) { if (!wrapped) break; lines++; continue; } /* * Is the destination line now full? Copy the first character * separately because we need to leave "from" set to the last * line if this line is full. */ grid_get_cell1(&gd->linedata[line], 0, &gc); if (width + gc.data.width > sx) break; width += gc.data.width; grid_set_cell(target, at, to, &gc); at++; /* Join as much more as possible onto the current line. */ from = &gd->linedata[line]; for (want = 1; want < from->cellused; want++) { grid_get_cell1(from, want, &gc); if (width + gc.data.width > sx) break; width += gc.data.width; grid_set_cell(target, at, to, &gc); at++; } lines++; /* * If this line wasn't wrapped or we didn't consume the entire * line, don't try to join any further lines. */ if (!wrapped || want != from->cellused || width == sx) break; } if (lines == 0) return; /* * If we didn't consume the entire final line, then remove what we did * consume. If we consumed the entire line and it wasn't wrapped, * remove the wrap flag from this line. */ left = from->cellused - want; if (left != 0) { grid_move_cells(gd, 0, want, yy + lines, left, 8); from->cellsize = from->cellused = left; lines--; } else if (!wrapped) gl->flags &= ~GRID_LINE_WRAPPED; /* Remove the lines that were completely consumed. */ for (i = yy + 1; i < yy + 1 + lines; i++) { free(gd->linedata[i].celldata); free(gd->linedata[i].extddata); grid_reflow_dead(&gd->linedata[i]); } /* Adjust scroll position. */ if (gd->hscrolled > to + lines) gd->hscrolled -= lines; else if (gd->hscrolled > to) gd->hscrolled = to; }
/* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc, const struct utf8_data *utf8data) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; struct grid_utf8 gu; u_int width, xx; struct grid_cell tmp_gc, *tmp_gcp; int insert = 0; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; /* Find character width. */ if (gc->flags & GRID_FLAG_UTF8) width = utf8data->width; else width = 1; /* * If this is a wide character and there is no room on the screen, for * the entire character, don't print it. */ if (!(s->mode & MODE_WRAP) && (width > 1 && (width > screen_size_x(s) || (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width)))) return; /* * If the width is zero, combine onto the previous character, if * there is space. */ if (width == 0) { if (screen_write_combine(ctx, utf8data) == 0) { screen_write_initctx(ctx, &ttyctx, 0); tty_write(tty_cmd_utf8character, &ttyctx); } return; } /* Initialise the redraw context, saving the last cell. */ screen_write_initctx(ctx, &ttyctx, 1); /* If in insert mode, make space for the cells. */ if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) { xx = screen_size_x(s) - s->cx - width; grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); insert = 1; } /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ } /* Sanity checks. */ if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) || s->cy > screen_size_y(s) - 1) return; /* Handle overwriting of UTF-8 characters. */ screen_write_overwrite(ctx, width); /* * If the new character is UTF-8 wide, fill in padding cells. Have * already ensured there is enough room. */ for (xx = s->cx + 1; xx < s->cx + width; xx++) { tmp_gcp = grid_view_get_cell(gd, xx, s->cy); if (tmp_gcp != NULL) tmp_gcp->flags |= GRID_FLAG_PADDING; } /* Set the cell. */ grid_view_set_cell(gd, s->cx, s->cy, gc); if (gc->flags & GRID_FLAG_UTF8) { /* Construct UTF-8 and write it. */ grid_utf8_set(&gu, utf8data); grid_view_set_utf8(gd, s->cx, s->cy, &gu); } /* Move the cursor. */ s->cx += width; /* Draw to the screen if necessary. */ if (insert) { ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } ttyctx.utf8 = &gu; if (screen_check_selection(s, s->cx - width, s->cy)) { memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); tmp_gc.data = gc->data; tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmp_gc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); } else { ttyctx.cell = gc; tty_write(tty_cmd_cell, &ttyctx); } }
/* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; u_int width, xx, last; struct grid_cell tmp_gc, now_gc; int insert, skip, selected; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; width = gc->data.width; /* * If this is a wide character and there is no room on the screen, for * the entire character, don't print it. */ if (!(s->mode & MODE_WRAP) && (width > 1 && (width > screen_size_x(s) || (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width)))) return; /* * If the width is zero, combine onto the previous character, if * there is space. */ if (width == 0) { if (screen_write_combine(ctx, &gc->data) == 0) { screen_write_initctx(ctx, &ttyctx); tty_write(tty_cmd_utf8character, &ttyctx); } return; } /* Initialise the redraw context. */ screen_write_initctx(ctx, &ttyctx); /* If in insert mode, make space for the cells. */ if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) { xx = screen_size_x(s) - s->cx - width; grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); insert = 1; } else insert = 0; skip = !insert; /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ skip = 0; } /* Sanity check cursor position. */ if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1) return; /* Handle overwriting of UTF-8 characters. */ grid_view_get_cell(gd, s->cx, s->cy, &now_gc); if (screen_write_overwrite(ctx, &now_gc, width)) skip = 0; /* * If the new character is UTF-8 wide, fill in padding cells. Have * already ensured there is enough room. */ for (xx = s->cx + 1; xx < s->cx + width; xx++) { grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell); skip = 0; } /* If no change, do not draw. */ if (skip) skip = (memcmp(&now_gc, gc, sizeof now_gc) == 0); /* Update the selection the flag and set the cell. */ selected = screen_check_selection(s, s->cx, s->cy); if (selected && ~gc->flags & GRID_FLAG_SELECTED) { skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags |= GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!selected && gc->flags & GRID_FLAG_SELECTED) { skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags &= ~GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!skip) grid_view_set_cell(gd, s->cx, s->cy, gc); /* * Move the cursor. If not wrapping, stick at the last character and * replace it. */ last = !(s->mode & MODE_WRAP); if (s->cx <= screen_size_x(s) - last - width) s->cx += width; else s->cx = screen_size_x(s) - last; /* Create space for character in insert mode. */ if (insert) { ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } /* Save last cell if it will be needed. */ if (!skip && ctx->wp != NULL && ttyctx.ocx > ctx->wp->sx - width) screen_write_save_last(ctx, &ttyctx); /* Write to the screen. */ if (selected) { memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); utf8_copy(&tmp_gc.data, &gc->data); tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; tmp_gc.flags = gc->flags; tmp_gc.flags &= ~(GRID_FLAG_FGRGB|GRID_FLAG_BGRGB); tmp_gc.flags &= ~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmp_gc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); } else if (!skip) { ttyctx.cell = gc; tty_write(tty_cmd_cell, &ttyctx); } }
/* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; u_int width, xx, last; u_int sx = screen_size_x(s), sy = screen_size_y(s); struct grid_line *gl; struct grid_cell tmp_gc, now_gc; struct grid_cell_entry *gce; int insert, skip, selected, wrapped = 0; ctx->cells++; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; width = gc->data.width; /* * If this is a wide character and there is no room on the screen, for * the entire character, don't print it. */ if (!(s->mode & MODE_WRAP) && (width > 1 && (width > sx || (s->cx != sx && s->cx > sx - width)))) return; /* * If the width is zero, combine onto the previous character, if * there is space. */ if (width == 0) { if (screen_write_combine(ctx, &gc->data) == 0) { screen_write_initctx(ctx, &ttyctx); tty_write(tty_cmd_utf8character, &ttyctx); } return; } /* Initialise the redraw context. */ screen_write_initctx(ctx, &ttyctx); /* If in insert mode, make space for the cells. */ if ((s->mode & MODE_INSERT) && s->cx <= sx - width) { xx = sx - s->cx - width; grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); insert = 1; } else insert = 0; skip = !insert; /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > sx - width) { screen_write_flush(ctx); screen_write_save_last(ctx, &ttyctx); screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ skip = 0; wrapped = 1; } /* Sanity check cursor position. */ if (s->cx > sx - width || s->cy > sy - 1) return; /* Handle overwriting of UTF-8 characters. */ gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (gl->flags & GRID_LINE_EXTENDED) { grid_view_get_cell(gd, s->cx, s->cy, &now_gc); if (screen_write_overwrite(ctx, &now_gc, width)) skip = 0; } /* * If the new character is UTF-8 wide, fill in padding cells. Have * already ensured there is enough room. */ for (xx = s->cx + 1; xx < s->cx + width; xx++) { grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell); skip = 0; } /* If no change, do not draw. */ if (skip) { if (s->cx >= gl->cellsize) skip = grid_cells_equal(gc, &grid_default_cell); else { gce = &gl->celldata[s->cx]; if (gce->flags & GRID_FLAG_EXTENDED) skip = 0; else if (gc->flags != (gce->flags & ~GRID_FLAG_EXTENDED)) skip = 0; else if (gc->attr != gce->data.attr) skip = 0; else if (gc->fg != gce->data.fg) skip = 0; else if (gc->bg != gce->data.bg) skip = 0; else if (gc->data.width != 1 || gce->data.data != gc->data.data[0]) skip = 0; } } /* Update the selection the flag and set the cell. */ selected = screen_check_selection(s, s->cx, s->cy); if (selected && ~gc->flags & GRID_FLAG_SELECTED) { skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags |= GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!selected && gc->flags & GRID_FLAG_SELECTED) { skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags &= ~GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!skip) grid_view_set_cell(gd, s->cx, s->cy, gc); /* * Move the cursor. If not wrapping, stick at the last character and * replace it. */ last = !(s->mode & MODE_WRAP); if (s->cx <= sx - last - width) s->cx += width; else s->cx = sx - last; /* Create space for character in insert mode. */ if (insert) { if (!wrapped) screen_write_flush(ctx); ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } /* Write to the screen. */ if (selected) { memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); utf8_copy(&tmp_gc.data, &gc->data); tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; tmp_gc.flags = gc->flags; screen_write_flush(ctx); ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); ctx->written++; } else if (!skip) { if (wrapped) { ttyctx.cell = gc; tty_write(tty_cmd_cell, &ttyctx); ctx->written++; } else { /* * If wp is NULL, we are not updating the terminal and * don't care about actually writing the cells * (tty_write will just return). So don't even bother * allocating the dirty array. */ if (ctx->wp != NULL && s->dirty == NULL) { log_debug("%s: allocating %u bits", __func__, s->dirtysize); s->dirty = bit_alloc(s->dirtysize); } if (s->dirty != NULL) { bit_set(s->dirty, screen_dirty_bit(s, ttyctx.ocx, ttyctx.ocy)); ctx->dirty++; } } } else ctx->skipped++; }
/* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct tty_ctx ttyctx; u_int width, xx, last; struct grid_cell tmp_gc; int insert; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; width = gc->data.width; /* * If this is a wide character and there is no room on the screen, for * the entire character, don't print it. */ if (!(s->mode & MODE_WRAP) && (width > 1 && (width > screen_size_x(s) || (s->cx != screen_size_x(s) && s->cx > screen_size_x(s) - width)))) return; /* * If the width is zero, combine onto the previous character, if * there is space. */ if (width == 0) { if (screen_write_combine(ctx, &gc->data) == 0) { screen_write_initctx(ctx, &ttyctx, 0); tty_write(tty_cmd_utf8character, &ttyctx); } return; } /* Initialise the redraw context, saving the last cell. */ screen_write_initctx(ctx, &ttyctx, 1); /* If in insert mode, make space for the cells. */ if ((s->mode & MODE_INSERT) && s->cx <= screen_size_x(s) - width) { xx = screen_size_x(s) - s->cx - width; grid_move_cells(s->grid, s->cx + width, s->cx, s->cy, xx); insert = 1; } else insert = 0; /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) { screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ } /* Sanity check cursor position. */ if (s->cx > screen_size_x(s) - width || s->cy > screen_size_y(s) - 1) return; /* Handle overwriting of UTF-8 characters. */ screen_write_overwrite(ctx, width); /* * If the new character is UTF-8 wide, fill in padding cells. Have * already ensured there is enough room. */ memcpy(&tmp_gc, &grid_default_cell, sizeof tmp_gc); tmp_gc.flags |= GRID_FLAG_PADDING; tmp_gc.data.width = 0; for (xx = s->cx + 1; xx < s->cx + width; xx++) grid_view_set_cell(gd, xx, s->cy, &tmp_gc); /* Set the cell. */ grid_view_set_cell(gd, s->cx, s->cy, gc); /* * Move the cursor. If not wrapping, stick at the last character and * replace it. */ last = !(s->mode & MODE_WRAP); if (s->cx <= screen_size_x(s) - last - width) s->cx += width; else s->cx = screen_size_x(s) - last; /* Draw to the screen if necessary. */ if (insert) { ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } if (screen_check_selection(s, s->cx - width, s->cy)) { memcpy(&tmp_gc, &s->sel.cell, sizeof tmp_gc); utf8_copy(&tmp_gc.data, &gc->data); tmp_gc.attr = tmp_gc.attr & ~GRID_ATTR_CHARSET; tmp_gc.attr |= gc->attr & GRID_ATTR_CHARSET; tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256); tmp_gc.flags |= s->sel.cell.flags & (GRID_FLAG_FG256|GRID_FLAG_BG256); ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); } else { ttyctx.cell = gc; tty_write(tty_cmd_cell, &ttyctx); } }