From 040f8dbe00c3b511b870fe536a7bbed1e9c49045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 25 Nov 2021 17:34:41 +0100 Subject: [PATCH] osc8: handle LCF correctly When the client application has printed something to the last column, the cursor remains in that last column, but the LCF flag is set. The next time something is printed, we linewrap. This needs special consideration both when an OSC-8 URL is started, and closed, when LCF is set. Before this patch, emitting an OSC-8 URL while the cursor was in the last column (with LCF set) would incorrectly include the last character from that line, when the URL really should start at the next line. Furthermore, ending an OSC-8 URL with LCF set would inorrectly exclude the last character. This patch fixes this by using the will-be-printed-to coordinates (i.e. the next line) in the OSC-8 start/end coordinates. Note that this means that we _can_ point to uninitialized grid data (i.e. to a NULL-row). This should be ok though, since either something *will* be printed to that row before the URL is closed, or a cursor movement causes the URL to be closed while still being empty, which is a no-op. --- terminal.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/terminal.c b/terminal.c index 56abca3c..097a75f7 100644 --- a/terminal.c +++ b/terminal.c @@ -3363,7 +3363,6 @@ ascii_printer_fast(struct terminal *term, wchar_t wc) cell->wc = term->vt.last_printed = wc; cell->attrs = term->vt.attrs; - /* Advance cursor */ if (unlikely(++col >= term->cols)) { grid->cursor.lcf = true; @@ -3602,10 +3601,16 @@ term_osc8_open(struct terminal *term, uint64_t id, const char *uri) xassert(term->vt.osc8.uri == NULL); - term->vt.osc8.begin = (struct coord){ - .col = term->grid->cursor.point.col, - .row = grid_row_absolute(term->grid, term->grid->cursor.point.row), - }; + struct grid *grid = term->grid; + int col = grid->cursor.point.col; + int row = grid_row_absolute(grid, grid->cursor.point.row); + + if (grid->cursor.lcf) { + row = (row + 1) & (grid->num_rows - 1); + col = 0; + } + + term->vt.osc8.begin = (struct coord){.col = col, .row = row}; term->vt.osc8.id = id; term->vt.osc8.uri = xstrdup(uri); @@ -3623,11 +3628,17 @@ term_osc8_close(struct terminal *term) if (term->vt.osc8.uri[0] == '\0') goto done; + struct grid *grid = term->grid; + int col = grid->cursor.point.col; + int row = grid_row_absolute(grid, grid->cursor.point.row); + + if (grid->cursor.lcf) { + row = (row + 1) % (grid->num_rows - 1); + col = 0; + } + struct coord start = term->vt.osc8.begin; - struct coord end = (struct coord){ - .col = term->grid->cursor.point.col, - .row = grid_row_absolute(term->grid, term->grid->cursor.point.row), - }; + struct coord end = (struct coord){col, row}; if (start.row == end.row && start.col == end.col) { /* Zero-length URL, e.g: \E]8;;http://foo\E\\\E]8;;\E\\ */ @@ -3645,7 +3656,7 @@ term_osc8_close(struct terminal *term) while (true) { int end_col = r == end.row ? end.col : term->cols - 1; - struct row *row = term->grid->rows[r]; + struct row *row = grid->rows[r]; switch (term->conf->url.osc8_underline) { case OSC8_UNDERLINE_ALWAYS: @@ -3670,7 +3681,7 @@ term_osc8_close(struct terminal *term) break; r++; - r &= term->grid->num_rows - 1; + r &= grid->num_rows - 1; } done: