/* Convert cells into a string. */ char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) { const struct grid_cell *gc; struct utf8_data ud; char *buf; size_t len, off; u_int xx; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); len = 128; buf = xmalloc(len); off = 0; for (xx = px; xx < px + nx; xx++) { gc = grid_peek_cell(gd, xx, py); if (gc->flags & GRID_FLAG_PADDING) continue; grid_cell_get(gc, &ud); while (len < off + ud.size + 1) { buf = xrealloc(buf, 2, len); len *= 2; } memcpy(buf + off, ud.data, ud.size); off += ud.size; } while (off > 0 && buf[off - 1] == ' ') off--; buf[off] = '\0'; return (buf); }
/* Combine a UTF-8 zero-width character onto the previous. */ int screen_write_combine(struct screen_write_ctx *ctx, const struct utf8_data *ud) { struct screen *s = ctx->s; struct grid *gd = s->grid; struct grid_cell *gc; struct utf8_data ud1; /* Can't combine if at 0. */ if (s->cx == 0) return (-1); /* Empty data is out. */ if (ud->size == 0) fatalx("UTF-8 data empty"); /* Retrieve the previous cell. */ gc = grid_view_get_cell(gd, s->cx - 1, s->cy); grid_cell_get(gc, &ud1); /* Check there is enough space. */ if (ud1.size + ud->size > sizeof ud1.data) return (-1); /* Append the data and set the cell. */ memcpy(ud1.data + ud1.size, ud->data, ud->size); ud1.size += ud->size; grid_cell_set(gc, &ud1); return (0); }
/* Copy from another screen. */ void screen_write_copy(struct screen_write_ctx *ctx, struct screen *src, u_int px, u_int py, u_int nx, u_int ny) { struct screen *s = ctx->s; struct grid *gd = src->grid; struct grid_line *gl; const struct grid_cell *gc; struct utf8_data ud; u_int xx, yy, cx, cy, ax, bx; cx = s->cx; cy = s->cy; for (yy = py; yy < py + ny; yy++) { gl = &gd->linedata[yy]; if (yy < gd->hsize + gd->sy) { /* * Find start and end position and copy between * them. Limit to the real end of the line then use a * clear EOL only if copying to the end, otherwise * could overwrite whatever is there already. */ if (px > gl->cellsize) ax = gl->cellsize; else ax = px; if (px + nx == gd->sx && px + nx > gl->cellsize) bx = gl->cellsize; else bx = px + nx; for (xx = ax; xx < bx; xx++) { if (xx >= gl->cellsize) gc = &grid_default_cell; else gc = &gl->celldata[xx]; grid_cell_get(gc, &ud); screen_write_cell(ctx, gc); } if (px + nx == gd->sx && px + nx > gl->cellsize) screen_write_clearendofline(ctx); } else screen_write_clearline(ctx); cy++; screen_write_cursormove(ctx, cx, cy); } }
/* Convert cells into a string. */ char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, struct grid_cell **lastgc, int with_codes, int escape_c0, int trim) { const struct grid_cell *gc; static struct grid_cell lastgc1; struct utf8_data ud; const char* data; char *buf, code[128]; size_t len, off, size, codelen; u_int xx; const struct grid_line *gl; if (lastgc != NULL && *lastgc == NULL) { memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1); *lastgc = &lastgc1; } len = 128; buf = xmalloc(len); off = 0; gl = grid_peek_line(gd, py); for (xx = px; xx < px + nx; xx++) { if (gl == NULL || xx >= gl->cellsize) break; gc = &gl->celldata[xx]; if (gc->flags & GRID_FLAG_PADDING) continue; grid_cell_get(gc, &ud); if (with_codes) { grid_string_cells_code(*lastgc, gc, code, sizeof code, escape_c0); codelen = strlen(code); memcpy(*lastgc, gc, sizeof *gc); } else codelen = 0; data = ud.data; size = ud.size; if (escape_c0 && size == 1 && *data == '\\') { data = "\\\\"; size = 2; } while (len < off + size + codelen + 1) { buf = xrealloc(buf, 2, len); len *= 2; } if (codelen != 0) { memcpy(buf + off, code, codelen); off += codelen; } memcpy(buf + off, data, size); off += size; } if (trim) { while (off > 0 && buf[off - 1] == ' ') off--; } buf[off] = '\0'; return (buf); }
/* 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, *tmp_gcp; struct utf8_data ud; int insert; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; width = grid_cell_width(gc); /* * 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) { grid_cell_get(gc, &ud); if (screen_write_combine(ctx, &ud) == 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. */ 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); /* * 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); grid_cell_get(gc, &ud); grid_cell_set(&tmp_gc, &ud); 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); } }