mirror of
https://github.com/tmux/tmux.git
synced 2026-04-01 09:49:28 +00:00
Rewrite tty_draw_line to be simpler and not to check overlay ranges.
This commit is contained in:
@@ -195,6 +195,7 @@ dist_tmux_SOURCES = \
|
|||||||
tmux.h \
|
tmux.h \
|
||||||
tmux-protocol.h \
|
tmux-protocol.h \
|
||||||
tty-acs.c \
|
tty-acs.c \
|
||||||
|
tty-draw.c \
|
||||||
tty-features.c \
|
tty-features.c \
|
||||||
tty-keys.c \
|
tty-keys.c \
|
||||||
tty-term.c \
|
tty-term.c \
|
||||||
|
|||||||
2
grid.c
2
grid.c
@@ -235,7 +235,7 @@ grid_check_y(struct grid *gd, const char *from, u_int py)
|
|||||||
int
|
int
|
||||||
grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
|
grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
|
||||||
{
|
{
|
||||||
int flags1 = gc1->flags, flags2 = gc2->flags;;
|
int flags1 = gc1->flags, flags2 = gc2->flags;
|
||||||
|
|
||||||
if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
|
if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
|
||||||
return (0);
|
return (0);
|
||||||
|
|||||||
6
tmux.h
6
tmux.h
@@ -2522,6 +2522,8 @@ void tty_reset(struct tty *);
|
|||||||
void tty_region_off(struct tty *);
|
void tty_region_off(struct tty *);
|
||||||
void tty_margin_off(struct tty *);
|
void tty_margin_off(struct tty *);
|
||||||
void tty_cursor(struct tty *, u_int, u_int);
|
void tty_cursor(struct tty *, u_int, u_int);
|
||||||
|
int tty_fake_bce(const struct tty *, const struct grid_cell *, u_int);
|
||||||
|
void tty_repeat_space(struct tty *, u_int);
|
||||||
void tty_clipboard_query(struct tty *);
|
void tty_clipboard_query(struct tty *);
|
||||||
void tty_putcode(struct tty *, enum tty_code_code);
|
void tty_putcode(struct tty *, enum tty_code_code);
|
||||||
void tty_putcode_i(struct tty *, enum tty_code_code, int);
|
void tty_putcode_i(struct tty *, enum tty_code_code, int);
|
||||||
@@ -2546,7 +2548,11 @@ void tty_repeat_requests(struct tty *, int);
|
|||||||
void tty_stop_tty(struct tty *);
|
void tty_stop_tty(struct tty *);
|
||||||
void tty_set_title(struct tty *, const char *);
|
void tty_set_title(struct tty *, const char *);
|
||||||
void tty_set_path(struct tty *, const char *);
|
void tty_set_path(struct tty *, const char *);
|
||||||
|
void tty_default_attributes(struct tty *, const struct grid_cell *,
|
||||||
|
struct colour_palette *, u_int, struct hyperlinks *);
|
||||||
void tty_update_mode(struct tty *, int, struct screen *);
|
void tty_update_mode(struct tty *, int, struct screen *);
|
||||||
|
|
||||||
|
/* tty-draw.c */
|
||||||
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
|
void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int,
|
||||||
u_int, u_int, const struct grid_cell *, struct colour_palette *);
|
u_int, u_int, const struct grid_cell *, struct colour_palette *);
|
||||||
|
|
||||||
|
|||||||
302
tty-draw.c
Normal file
302
tty-draw.c
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
enum tty_draw_line_state {
|
||||||
|
TTY_DRAW_LINE_FIRST,
|
||||||
|
TTY_DRAW_LINE_FLUSH,
|
||||||
|
TTY_DRAW_LINE_NEW1,
|
||||||
|
TTY_DRAW_LINE_NEW2,
|
||||||
|
TTY_DRAW_LINE_EMPTY,
|
||||||
|
TTY_DRAW_LINE_SAME,
|
||||||
|
TTY_DRAW_LINE_PAD,
|
||||||
|
TTY_DRAW_LINE_DONE
|
||||||
|
};
|
||||||
|
static const char* tty_draw_line_states[] = {
|
||||||
|
"FIRST",
|
||||||
|
"FLUSH",
|
||||||
|
"NEW1",
|
||||||
|
"NEW2",
|
||||||
|
"EMPTY",
|
||||||
|
"SAME",
|
||||||
|
"PAD",
|
||||||
|
"DONE"
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Clear part of the line. */
|
||||||
|
static void
|
||||||
|
tty_draw_line_clear(struct tty *tty, u_int px, u_int py, u_int nx,
|
||||||
|
const struct grid_cell *defaults, u_int bg, int wrapped)
|
||||||
|
{
|
||||||
|
/* Nothing to clear. */
|
||||||
|
if (nx == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If genuine BCE is available, can try escape sequences. */
|
||||||
|
if (!wrapped && nx >= 10 && !tty_fake_bce(tty, defaults, bg)) {
|
||||||
|
/* Off the end of the line, use EL if available. */
|
||||||
|
if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) {
|
||||||
|
tty_cursor(tty, px, py);
|
||||||
|
tty_putcode(tty, TTYC_EL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At the start of the line. Use EL1. */
|
||||||
|
if (px == 0 && tty_term_has(tty->term, TTYC_EL1)) {
|
||||||
|
tty_cursor(tty, px + nx - 1, py);
|
||||||
|
tty_putcode(tty, TTYC_EL1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Section of line. Use ECH if possible. */
|
||||||
|
if (tty_term_has(tty->term, TTYC_ECH)) {
|
||||||
|
tty_cursor(tty, px, py);
|
||||||
|
tty_putcode_i(tty, TTYC_ECH, nx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Couldn't use an escape sequence, use spaces. */
|
||||||
|
if (px != 0 || !wrapped)
|
||||||
|
tty_cursor(tty, px, py);
|
||||||
|
if (nx == 1)
|
||||||
|
tty_putc(tty, ' ');
|
||||||
|
else if (nx == 2)
|
||||||
|
tty_putn(tty, " ", 2, 2);
|
||||||
|
else
|
||||||
|
tty_repeat_space(tty, nx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is this cell empty? */
|
||||||
|
static u_int
|
||||||
|
tty_draw_line_get_empty(struct grid_cell *gc, u_int nx)
|
||||||
|
{
|
||||||
|
u_int empty = 0;
|
||||||
|
|
||||||
|
if (gc->data.width != 1 && gc->data.width > nx)
|
||||||
|
empty = nx;
|
||||||
|
else if (gc->attr == 0 && gc->link == 0) {
|
||||||
|
if (gc->flags & GRID_FLAG_CLEARED)
|
||||||
|
empty = 1;
|
||||||
|
else if (gc->flags & GRID_FLAG_TAB)
|
||||||
|
empty = gc->data.width;
|
||||||
|
else if (gc->data.size == 1 && *gc->data.data == ' ')
|
||||||
|
empty = 1;
|
||||||
|
}
|
||||||
|
return (empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a line from screen to tty. */
|
||||||
|
void
|
||||||
|
tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||||
|
u_int atx, u_int aty, const struct grid_cell *defaults,
|
||||||
|
struct colour_palette *palette)
|
||||||
|
{
|
||||||
|
struct grid *gd = s->grid;
|
||||||
|
struct grid_cell gc, last;
|
||||||
|
struct grid_line *gl;
|
||||||
|
u_int i, j, last_i, cx, ex, width;
|
||||||
|
u_int cellsize, bg;
|
||||||
|
int flags, empty, wrapped = 0;
|
||||||
|
char buf[1000];
|
||||||
|
size_t len;
|
||||||
|
enum tty_draw_line_state current_state, next_state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* py is the line in the screen to draw. px is the start x and nx is
|
||||||
|
* the width to draw. atx,aty is the line on the terminal to draw it.
|
||||||
|
*/
|
||||||
|
log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__, px, py, nx,
|
||||||
|
atx, aty);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clamp the width to cellsize - note this is not cellused, because
|
||||||
|
* there may be empty background cells after it (from BCE).
|
||||||
|
*/
|
||||||
|
cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
|
||||||
|
if (screen_size_x(s) > cellsize)
|
||||||
|
ex = cellsize;
|
||||||
|
else {
|
||||||
|
ex = screen_size_x(s);
|
||||||
|
if (px > ex)
|
||||||
|
return;
|
||||||
|
if (px + nx > ex)
|
||||||
|
nx = ex - px;
|
||||||
|
}
|
||||||
|
if (ex < nx)
|
||||||
|
ex = nx;
|
||||||
|
log_debug("%s: drawing %u-%u,%u (end %u) at %u,%u; defaults: fg=%d, "
|
||||||
|
"bg=%d", __func__, px, px + nx, py, ex, atx, aty, defaults->fg,
|
||||||
|
defaults->bg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is padding at the start, we must have truncated a wide
|
||||||
|
* character. Clear it.
|
||||||
|
*/
|
||||||
|
cx = 0;
|
||||||
|
for (i = px; i < px + nx; i++) {
|
||||||
|
grid_view_get_cell(gd, i, py, &gc);
|
||||||
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||||||
|
break;
|
||||||
|
cx++;
|
||||||
|
}
|
||||||
|
if (cx != 0) {
|
||||||
|
/* Find the previous cell for the background colour. */
|
||||||
|
for (i = px + 1; i > 0; i--) {
|
||||||
|
grid_view_get_cell(gd, i - 1, py, &gc);
|
||||||
|
if (~gc.flags & GRID_FLAG_PADDING)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == 0)
|
||||||
|
bg = gc.bg;
|
||||||
|
else
|
||||||
|
bg = defaults->bg;
|
||||||
|
tty_attributes(tty, &last, defaults, palette, s->hyperlinks);
|
||||||
|
log_debug("%s: clearing %u padding cells", __func__, cx);
|
||||||
|
tty_draw_line_clear(tty, atx, aty, cx, defaults, bg, 0);
|
||||||
|
if (cx == ex)
|
||||||
|
return;
|
||||||
|
atx += cx;
|
||||||
|
px += cx;
|
||||||
|
nx -= cx;
|
||||||
|
ex -= cx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Did the previous line wrap on to this one? */
|
||||||
|
if (py != 0 && atx == 0 && tty->cx >= tty->sx && nx == tty->sx) {
|
||||||
|
gl = grid_get_line(gd, gd->hsize + py - 1);
|
||||||
|
if (gl->flags & GRID_LINE_WRAPPED)
|
||||||
|
wrapped = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Turn off cursor while redrawing and reset region and margins. */
|
||||||
|
flags = (tty->flags & TTY_NOCURSOR);
|
||||||
|
tty->flags |= TTY_NOCURSOR;
|
||||||
|
tty_update_mode(tty, tty->mode, s);
|
||||||
|
tty_region_off(tty);
|
||||||
|
tty_margin_off(tty);
|
||||||
|
|
||||||
|
/* Start with the default cell as the last cell. */
|
||||||
|
memcpy(&last, &grid_default_cell, sizeof last);
|
||||||
|
last.bg = defaults->bg;
|
||||||
|
tty_default_attributes(tty, defaults, palette, 8, s->hyperlinks);
|
||||||
|
|
||||||
|
/* Loop over each character in the range. */
|
||||||
|
last_i = i = 0;
|
||||||
|
len = 0;
|
||||||
|
width = 0;
|
||||||
|
current_state = TTY_DRAW_LINE_FIRST;
|
||||||
|
for (;;) {
|
||||||
|
/* Work out the next state. */
|
||||||
|
if (i == nx) {
|
||||||
|
/*
|
||||||
|
* If this is the last cell, we are done. But we need to
|
||||||
|
* go through the loop again to flush anything in
|
||||||
|
* the buffer.
|
||||||
|
*/
|
||||||
|
empty = 0;
|
||||||
|
next_state = TTY_DRAW_LINE_DONE;
|
||||||
|
} else {
|
||||||
|
/* Get the current cell. */
|
||||||
|
grid_view_get_cell(gd, px + i, py, &gc);
|
||||||
|
|
||||||
|
/* Work out the the empty width. */
|
||||||
|
if (i >= ex)
|
||||||
|
empty = 1;
|
||||||
|
else
|
||||||
|
empty = tty_draw_line_get_empty(&gc, nx - i);
|
||||||
|
|
||||||
|
/* Work out the next state. */
|
||||||
|
if (empty != 0)
|
||||||
|
next_state = TTY_DRAW_LINE_EMPTY;
|
||||||
|
else if (current_state == TTY_DRAW_LINE_FIRST)
|
||||||
|
next_state = TTY_DRAW_LINE_SAME;
|
||||||
|
else if (gc.flags & GRID_FLAG_PADDING)
|
||||||
|
next_state = TTY_DRAW_LINE_PAD;
|
||||||
|
else if (grid_cells_look_equal(&gc, &last)) {
|
||||||
|
if (gc.data.size > (sizeof buf) - len)
|
||||||
|
next_state = TTY_DRAW_LINE_FLUSH;
|
||||||
|
else
|
||||||
|
next_state = TTY_DRAW_LINE_SAME;
|
||||||
|
} else if (current_state == TTY_DRAW_LINE_NEW1)
|
||||||
|
next_state = TTY_DRAW_LINE_NEW2;
|
||||||
|
else
|
||||||
|
next_state = TTY_DRAW_LINE_NEW1;
|
||||||
|
}
|
||||||
|
log_debug("%s: cell %u empty %u, bg %u; state: current %s, "
|
||||||
|
"next %s", __func__, px + i, empty, gc.bg,
|
||||||
|
tty_draw_line_states[current_state],
|
||||||
|
tty_draw_line_states[next_state]);
|
||||||
|
|
||||||
|
/* If the state has changed, flush any collected data. */
|
||||||
|
if (next_state != current_state) {
|
||||||
|
if (current_state == TTY_DRAW_LINE_EMPTY) {
|
||||||
|
tty_attributes(tty, &last, defaults, palette,
|
||||||
|
s->hyperlinks);
|
||||||
|
tty_draw_line_clear(tty, atx + last_i, aty,
|
||||||
|
i - last_i, defaults, last.bg, wrapped);
|
||||||
|
wrapped = 0;
|
||||||
|
} else if (next_state != TTY_DRAW_LINE_SAME &&
|
||||||
|
len != 0) {
|
||||||
|
tty_attributes(tty, &last, defaults, palette,
|
||||||
|
s->hyperlinks);
|
||||||
|
if (atx + i - width != 0 || !wrapped)
|
||||||
|
tty_cursor(tty, atx + i - width, aty);
|
||||||
|
if (~last.attr & GRID_ATTR_CHARSET)
|
||||||
|
tty_putn(tty, buf, len, width);
|
||||||
|
else {
|
||||||
|
for (j = 0; j < len; j++)
|
||||||
|
tty_putc(tty, buf[j]);
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
width = 0;
|
||||||
|
wrapped = 0;
|
||||||
|
}
|
||||||
|
last_i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append the cell if it is not empty and not padding. */
|
||||||
|
if (next_state != TTY_DRAW_LINE_EMPTY &&
|
||||||
|
next_state != TTY_DRAW_LINE_PAD) {
|
||||||
|
memcpy(buf + len, gc.data.data, gc.data.size);
|
||||||
|
len += gc.data.size;
|
||||||
|
width += gc.data.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is the last cell, we are done. */
|
||||||
|
if (next_state == TTY_DRAW_LINE_DONE)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Otherwise move to the next. */
|
||||||
|
current_state = next_state;
|
||||||
|
memcpy(&last, &gc, sizeof last);
|
||||||
|
if (empty != 0)
|
||||||
|
i += empty;
|
||||||
|
else
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tty->flags = (tty->flags & ~TTY_NOCURSOR)|flags;
|
||||||
|
tty_update_mode(tty, tty->mode, s);
|
||||||
|
}
|
||||||
|
|
||||||
196
tty.c
196
tty.c
@@ -61,15 +61,10 @@ static void tty_region(struct tty *, u_int, u_int);
|
|||||||
static void tty_margin_pane(struct tty *, const struct tty_ctx *);
|
static void tty_margin_pane(struct tty *, const struct tty_ctx *);
|
||||||
static void tty_margin(struct tty *, u_int, u_int);
|
static void tty_margin(struct tty *, u_int, u_int);
|
||||||
static int tty_large_region(struct tty *, const struct tty_ctx *);
|
static int tty_large_region(struct tty *, const struct tty_ctx *);
|
||||||
static int tty_fake_bce(const struct tty *, const struct grid_cell *,
|
|
||||||
u_int);
|
|
||||||
static void tty_redraw_region(struct tty *, const struct tty_ctx *);
|
static void tty_redraw_region(struct tty *, const struct tty_ctx *);
|
||||||
static void tty_emulate_repeat(struct tty *, enum tty_code_code,
|
static void tty_emulate_repeat(struct tty *, enum tty_code_code,
|
||||||
enum tty_code_code, u_int);
|
enum tty_code_code, u_int);
|
||||||
static void tty_repeat_space(struct tty *, u_int);
|
|
||||||
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
|
static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int);
|
||||||
static void tty_default_attributes(struct tty *, const struct grid_cell *,
|
|
||||||
struct colour_palette *, u_int, struct hyperlinks *);
|
|
||||||
static int tty_check_overlay(struct tty *, u_int, u_int);
|
static int tty_check_overlay(struct tty *, u_int, u_int);
|
||||||
static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
|
static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int,
|
||||||
struct overlay_ranges *);
|
struct overlay_ranges *);
|
||||||
@@ -912,7 +907,7 @@ tty_emulate_repeat(struct tty *tty, enum tty_code_code code,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
tty_repeat_space(struct tty *tty, u_int n)
|
tty_repeat_space(struct tty *tty, u_int n)
|
||||||
{
|
{
|
||||||
static char s[500];
|
static char s[500];
|
||||||
@@ -1071,7 +1066,7 @@ tty_large_region(__unused struct tty *tty, const struct tty_ctx *ctx)
|
|||||||
* Return if BCE is needed but the terminal doesn't have it - it'll need to be
|
* Return if BCE is needed but the terminal doesn't have it - it'll need to be
|
||||||
* emulated.
|
* emulated.
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
tty_fake_bce(const struct tty *tty, const struct grid_cell *gc, u_int bg)
|
tty_fake_bce(const struct tty *tty, const struct grid_cell *gc, u_int bg)
|
||||||
{
|
{
|
||||||
if (tty_term_flag(tty->term, TTYC_BCE))
|
if (tty_term_flag(tty->term, TTYC_BCE))
|
||||||
@@ -1463,191 +1458,6 @@ tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx,
|
|||||||
c->overlay_check(c, c->overlay_data, px, py, nx, r);
|
c->overlay_check(c, c->overlay_data, px, py, nx, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
|
||||||
u_int atx, u_int aty, const struct grid_cell *defaults,
|
|
||||||
struct colour_palette *palette)
|
|
||||||
{
|
|
||||||
struct grid *gd = s->grid;
|
|
||||||
struct grid_cell gc, last;
|
|
||||||
const struct grid_cell *gcp;
|
|
||||||
struct grid_line *gl;
|
|
||||||
struct client *c = tty->client;
|
|
||||||
struct overlay_ranges r;
|
|
||||||
u_int i, j, ux, sx, width, hidden, eux, nxx;
|
|
||||||
u_int cellsize;
|
|
||||||
int flags, cleared = 0, wrapped = 0;
|
|
||||||
char buf[512];
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__,
|
|
||||||
px, py, nx, atx, aty);
|
|
||||||
log_debug("%s: defaults: fg=%d, bg=%d", __func__, defaults->fg,
|
|
||||||
defaults->bg);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* py is the line in the screen to draw.
|
|
||||||
* px is the start x and nx is the width to draw.
|
|
||||||
* atx,aty is the line on the terminal to draw it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
flags = (tty->flags & TTY_NOCURSOR);
|
|
||||||
tty->flags |= TTY_NOCURSOR;
|
|
||||||
tty_update_mode(tty, tty->mode, s);
|
|
||||||
|
|
||||||
tty_region_off(tty);
|
|
||||||
tty_margin_off(tty);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clamp the width to cellsize - note this is not cellused, because
|
|
||||||
* there may be empty background cells after it (from BCE).
|
|
||||||
*/
|
|
||||||
sx = screen_size_x(s);
|
|
||||||
if (nx > sx)
|
|
||||||
nx = sx;
|
|
||||||
cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
|
|
||||||
if (sx > cellsize)
|
|
||||||
sx = cellsize;
|
|
||||||
if (sx > tty->sx)
|
|
||||||
sx = tty->sx;
|
|
||||||
if (sx > nx)
|
|
||||||
sx = nx;
|
|
||||||
ux = 0;
|
|
||||||
|
|
||||||
if (py == 0)
|
|
||||||
gl = NULL;
|
|
||||||
else
|
|
||||||
gl = grid_get_line(gd, gd->hsize + py - 1);
|
|
||||||
if (gl == NULL ||
|
|
||||||
(~gl->flags & GRID_LINE_WRAPPED) ||
|
|
||||||
atx != 0 ||
|
|
||||||
tty->cx < tty->sx ||
|
|
||||||
nx < tty->sx) {
|
|
||||||
if (nx < tty->sx &&
|
|
||||||
atx == 0 &&
|
|
||||||
px + sx != nx &&
|
|
||||||
tty_term_has(tty->term, TTYC_EL1) &&
|
|
||||||
!tty_fake_bce(tty, defaults, 8) &&
|
|
||||||
c->overlay_check == NULL) {
|
|
||||||
tty_default_attributes(tty, defaults, palette, 8,
|
|
||||||
s->hyperlinks);
|
|
||||||
tty_cursor(tty, nx - 1, aty);
|
|
||||||
tty_putcode(tty, TTYC_EL1);
|
|
||||||
cleared = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log_debug("%s: wrapped line %u", __func__, aty);
|
|
||||||
wrapped = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&last, &grid_default_cell, sizeof last);
|
|
||||||
len = 0;
|
|
||||||
width = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < sx; i++) {
|
|
||||||
grid_view_get_cell(gd, px + i, py, &gc);
|
|
||||||
gcp = tty_check_codeset(tty, &gc);
|
|
||||||
if (len != 0 &&
|
|
||||||
(!tty_check_overlay(tty, atx + ux + width, aty) ||
|
|
||||||
(gcp->attr & GRID_ATTR_CHARSET) ||
|
|
||||||
gcp->flags != last.flags ||
|
|
||||||
gcp->attr != last.attr ||
|
|
||||||
gcp->fg != last.fg ||
|
|
||||||
gcp->bg != last.bg ||
|
|
||||||
gcp->us != last.us ||
|
|
||||||
gcp->link != last.link ||
|
|
||||||
ux + width + gcp->data.width > nx ||
|
|
||||||
(sizeof buf) - len < gcp->data.size)) {
|
|
||||||
tty_attributes(tty, &last, defaults, palette,
|
|
||||||
s->hyperlinks);
|
|
||||||
if (last.flags & GRID_FLAG_CLEARED) {
|
|
||||||
log_debug("%s: %zu cleared", __func__, len);
|
|
||||||
tty_clear_line(tty, defaults, aty, atx + ux,
|
|
||||||
width, last.bg);
|
|
||||||
} else {
|
|
||||||
if (!wrapped || atx != 0 || ux != 0)
|
|
||||||
tty_cursor(tty, atx + ux, aty);
|
|
||||||
tty_putn(tty, buf, len, width);
|
|
||||||
}
|
|
||||||
ux += width;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
width = 0;
|
|
||||||
wrapped = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gcp->flags & GRID_FLAG_SELECTED)
|
|
||||||
screen_select_cell(s, &last, gcp);
|
|
||||||
else
|
|
||||||
memcpy(&last, gcp, sizeof last);
|
|
||||||
|
|
||||||
tty_check_overlay_range(tty, atx + ux, aty, gcp->data.width,
|
|
||||||
&r);
|
|
||||||
hidden = 0;
|
|
||||||
for (j = 0; j < OVERLAY_MAX_RANGES; j++)
|
|
||||||
hidden += r.nx[j];
|
|
||||||
hidden = gcp->data.width - hidden;
|
|
||||||
if (hidden != 0 && hidden == gcp->data.width) {
|
|
||||||
if (~gcp->flags & GRID_FLAG_PADDING)
|
|
||||||
ux += gcp->data.width;
|
|
||||||
} else if (hidden != 0 || ux + gcp->data.width > nx) {
|
|
||||||
if (~gcp->flags & GRID_FLAG_PADDING) {
|
|
||||||
tty_attributes(tty, &last, defaults, palette,
|
|
||||||
s->hyperlinks);
|
|
||||||
for (j = 0; j < OVERLAY_MAX_RANGES; j++) {
|
|
||||||
if (r.nx[j] == 0)
|
|
||||||
continue;
|
|
||||||
/* Effective width drawn so far. */
|
|
||||||
eux = r.px[j] - atx;
|
|
||||||
if (eux < nx) {
|
|
||||||
tty_cursor(tty, r.px[j], aty);
|
|
||||||
nxx = nx - eux;
|
|
||||||
if (r.nx[j] > nxx)
|
|
||||||
r.nx[j] = nxx;
|
|
||||||
tty_repeat_space(tty, r.nx[j]);
|
|
||||||
ux = eux + r.nx[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (gcp->attr & GRID_ATTR_CHARSET) {
|
|
||||||
tty_attributes(tty, &last, defaults, palette,
|
|
||||||
s->hyperlinks);
|
|
||||||
tty_cursor(tty, atx + ux, aty);
|
|
||||||
for (j = 0; j < gcp->data.size; j++)
|
|
||||||
tty_putc(tty, gcp->data.data[j]);
|
|
||||||
ux += gcp->data.width;
|
|
||||||
} else if (~gcp->flags & GRID_FLAG_PADDING) {
|
|
||||||
memcpy(buf + len, gcp->data.data, gcp->data.size);
|
|
||||||
len += gcp->data.size;
|
|
||||||
width += gcp->data.width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (len != 0 && ((~last.flags & GRID_FLAG_CLEARED) || last.bg != 8)) {
|
|
||||||
tty_attributes(tty, &last, defaults, palette, s->hyperlinks);
|
|
||||||
if (last.flags & GRID_FLAG_CLEARED) {
|
|
||||||
log_debug("%s: %zu cleared (end)", __func__, len);
|
|
||||||
tty_clear_line(tty, defaults, aty, atx + ux, width,
|
|
||||||
last.bg);
|
|
||||||
} else {
|
|
||||||
if (!wrapped || atx != 0 || ux != 0)
|
|
||||||
tty_cursor(tty, atx + ux, aty);
|
|
||||||
tty_putn(tty, buf, len, width);
|
|
||||||
}
|
|
||||||
ux += width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cleared && ux < nx) {
|
|
||||||
log_debug("%s: %u to end of line (%zu cleared)", __func__,
|
|
||||||
nx - ux, len);
|
|
||||||
tty_default_attributes(tty, defaults, palette, 8,
|
|
||||||
s->hyperlinks);
|
|
||||||
tty_clear_line(tty, defaults, aty, atx + ux, nx - ux, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags;
|
|
||||||
tty_update_mode(tty, tty->mode, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_SIXEL
|
#ifdef ENABLE_SIXEL
|
||||||
/* Update context for client. */
|
/* Update context for client. */
|
||||||
static int
|
static int
|
||||||
@@ -3203,7 +3013,7 @@ tty_default_colours(struct grid_cell *gc, struct window_pane *wp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
|
tty_default_attributes(struct tty *tty, const struct grid_cell *defaults,
|
||||||
struct colour_palette *palette, u_int bg, struct hyperlinks *hl)
|
struct colour_palette *palette, u_int bg, struct hyperlinks *hl)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user