From f8e875a7cddaac91818b98993d17a96d09a5b4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 10:35:30 +0100 Subject: [PATCH 01/10] term: move row->prompt_marker into new struct, row->shell_integration --- grid.c | 10 +++++----- input.c | 4 ++-- osc.c | 2 +- terminal.c | 2 +- terminal.h | 5 +++-- 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/grid.c b/grid.c index ea103c65..19322cbf 100644 --- a/grid.c +++ b/grid.c @@ -231,7 +231,7 @@ grid_snapshot(const struct grid *grid) clone_row->cells = xmalloc(grid->num_cols * sizeof(clone_row->cells[0])); clone_row->linebreak = row->linebreak; clone_row->dirty = row->dirty; - clone_row->prompt_marker = row->prompt_marker; + clone_row->shell_integration = row->shell_integration; for (int c = 0; c < grid->num_cols; c++) clone_row->cells[c] = row->cells[c]; @@ -366,7 +366,7 @@ grid_row_alloc(int cols, bool initialize) row->dirty = false; row->linebreak = false; row->extra = NULL; - row->prompt_marker = false; + row->shell_integration.prompt_marker = false; if (initialize) { row->cells = xcalloc(cols, sizeof(row->cells[0])); @@ -425,7 +425,7 @@ grid_resize_without_reflow( new_row->dirty = old_row->dirty; new_row->linebreak = false; - new_row->prompt_marker = old_row->prompt_marker; + new_row->shell_integration = old_row->shell_integration; if (new_cols > old_cols) { /* Clear "new" columns */ @@ -587,7 +587,7 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row, /* Scrollback is full, need to reuse a row */ grid_row_reset_extra(new_row); new_row->linebreak = false; - new_row->prompt_marker = false; + new_row->shell_integration.prompt_marker = false; tll_foreach(old_grid->sixel_images, it) { if (it->item.pos.row == *row_idx) { @@ -920,7 +920,7 @@ grid_resize_and_reflow( xassert(from + amount <= old_cols); if (from == 0) - new_row->prompt_marker = old_row->prompt_marker; + new_row->shell_integration = old_row->shell_integration; memcpy( &new_row->cells[new_col_idx], &old_row->cells[from], diff --git a/input.c b/input.c index dc0eec93..5cdf513f 100644 --- a/input.c +++ b/input.c @@ -377,7 +377,7 @@ execute_binding(struct seat *seat, struct terminal *term, const struct row *row = grid->rows[r_abs]; xassert(row != NULL); - if (!row->prompt_marker) + if (!row->shell_integration.prompt_marker) continue; grid->view = r_abs; @@ -409,7 +409,7 @@ execute_binding(struct seat *seat, struct terminal *term, const struct row *row = grid->rows[r_abs]; xassert(row != NULL); - if (!row->prompt_marker) { + if (!row->shell_integration.prompt_marker) { if (r_abs == grid->offset + term->rows - 1) { /* We’ve reached the bottom of the scrollback */ break; diff --git a/osc.c b/osc.c index ba08964c..a54946ff 100644 --- a/osc.c +++ b/osc.c @@ -893,7 +893,7 @@ osc_dispatch(struct terminal *term) term->grid->cursor.point.row, term->grid->cursor.point.col); - term->grid->cur_row->prompt_marker = true; + term->grid->cur_row->shell_integration.prompt_marker = true; break; case 'B': diff --git a/terminal.c b/terminal.c index f63aaaa7..33666e6a 100644 --- a/terminal.c +++ b/terminal.c @@ -1825,7 +1825,7 @@ erase_line(struct terminal *term, struct row *row) { erase_cell_range(term, row, 0, term->cols - 1); row->linebreak = false; - row->prompt_marker = false; + row->shell_integration.prompt_marker = false; } void diff --git a/terminal.h b/terminal.h index 0dca0f48..76b52566 100644 --- a/terminal.h +++ b/terminal.h @@ -121,8 +121,9 @@ struct row { bool dirty; bool linebreak; - /* Shell integration */ - bool prompt_marker; + struct { + bool prompt_marker; + } shell_integration; }; struct sixel { From e9607de5ae2eaf1a57924bb282a660150eca6eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 10:46:46 +0100 Subject: [PATCH 02/10] osc: store column of FTCS_COMMAND_{EXECUTED,FINISHED} in row struct --- grid.c | 4 ++++ osc.c | 10 ++++++++-- terminal.c | 2 ++ terminal.h | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/grid.c b/grid.c index 19322cbf..f14580ad 100644 --- a/grid.c +++ b/grid.c @@ -367,6 +367,8 @@ grid_row_alloc(int cols, bool initialize) row->linebreak = false; row->extra = NULL; row->shell_integration.prompt_marker = false; + row->shell_integration.cmd_start = -1; + row->shell_integration.cmd_end = -1; if (initialize) { row->cells = xcalloc(cols, sizeof(row->cells[0])); @@ -588,6 +590,8 @@ _line_wrap(struct grid *old_grid, struct row **new_grid, struct row *row, grid_row_reset_extra(new_row); new_row->linebreak = false; new_row->shell_integration.prompt_marker = false; + new_row->shell_integration.cmd_start = -1; + new_row->shell_integration.cmd_end = -1; tll_foreach(old_grid->sixel_images, it) { if (it->item.pos.row == *row_idx) { diff --git a/osc.c b/osc.c index a54946ff..5da8666f 100644 --- a/osc.c +++ b/osc.c @@ -901,11 +901,17 @@ osc_dispatch(struct terminal *term) break; case 'C': - LOG_DBG("FTCS_COMMAND_EXECUTED"); + LOG_DBG("FTCS_COMMAND_EXECUTED: %dx%d", + term->grid->cursor.point.row, + term->grid->cursor.point.col); + term->grid->cur_row->shell_integration.cmd_start = term->grid->cursor.point.col; break; case 'D': - LOG_DBG("FTCS_COMMAND_FINISHED"); + LOG_DBG("FTCS_COMMAND_FINISHED: %dx%d", + term->grid->cursor.point.row, + term->grid->cursor.point.col); + term->grid->cur_row->shell_integration.cmd_end = term->grid->cursor.point.col; break; } break; diff --git a/terminal.c b/terminal.c index 33666e6a..4152724a 100644 --- a/terminal.c +++ b/terminal.c @@ -1826,6 +1826,8 @@ erase_line(struct terminal *term, struct row *row) erase_cell_range(term, row, 0, term->cols - 1); row->linebreak = false; row->shell_integration.prompt_marker = false; + row->shell_integration.cmd_start = -1; + row->shell_integration.cmd_end = -1; } void diff --git a/terminal.h b/terminal.h index 76b52566..1e3a724e 100644 --- a/terminal.h +++ b/terminal.h @@ -123,6 +123,8 @@ struct row { struct { bool prompt_marker; + int cmd_start; /* Column, -1 if unset */ + int cmd_end; /* Column, -1 if unset */ } shell_integration; }; From 1c70a84fde80405e0b6658722af8bc3fb54f225d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 11:45:23 +0100 Subject: [PATCH 03/10] config: add pipe-command-output key-binding --- config.c | 1 + input.c | 7 +++- key-binding.h | 1 + terminal.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++--- terminal.h | 2 ++ 5 files changed, 99 insertions(+), 5 deletions(-) diff --git a/config.c b/config.c index e3d531c2..3728826f 100644 --- a/config.c +++ b/config.c @@ -111,6 +111,7 @@ static const char *const binding_action_map[] = { [BIND_ACTION_PIPE_SCROLLBACK] = "pipe-scrollback", [BIND_ACTION_PIPE_VIEW] = "pipe-visible", [BIND_ACTION_PIPE_SELECTED] = "pipe-selected", + [BIND_ACTION_PIPE_COMMAND_OUTPUT] = "pipe-command-output", [BIND_ACTION_SHOW_URLS_COPY] = "show-urls-copy", [BIND_ACTION_SHOW_URLS_LAUNCH] = "show-urls-launch", [BIND_ACTION_SHOW_URLS_PERSISTENT] = "show-urls-persistent", diff --git a/input.c b/input.c index 5cdf513f..166ad70b 100644 --- a/input.c +++ b/input.c @@ -227,7 +227,8 @@ execute_binding(struct seat *seat, struct terminal *term, break; /* FALLTHROUGH */ case BIND_ACTION_PIPE_VIEW: - case BIND_ACTION_PIPE_SELECTED: { + case BIND_ACTION_PIPE_SELECTED: + case BIND_ACTION_PIPE_COMMAND_OUTPUT: { if (binding->aux->type != BINDING_AUX_PIPE) return true; @@ -269,6 +270,10 @@ execute_binding(struct seat *seat, struct terminal *term, len = text != NULL ? strlen(text) : 0; break; + case BIND_ACTION_PIPE_COMMAND_OUTPUT: + success = term_command_output_to_text(term, &text, &len); + break; + default: BUG("Unhandled action type"); success = false; diff --git a/key-binding.h b/key-binding.h index 050c80a6..ba841efa 100644 --- a/key-binding.h +++ b/key-binding.h @@ -32,6 +32,7 @@ enum bind_action_normal { BIND_ACTION_PIPE_SCROLLBACK, BIND_ACTION_PIPE_VIEW, BIND_ACTION_PIPE_SELECTED, + BIND_ACTION_PIPE_COMMAND_OUTPUT, BIND_ACTION_SHOW_URLS_COPY, BIND_ACTION_SHOW_URLS_LAUNCH, BIND_ACTION_SHOW_URLS_PERSISTENT, diff --git a/terminal.c b/terminal.c index 4152724a..a328783f 100644 --- a/terminal.c +++ b/terminal.c @@ -3613,7 +3613,7 @@ term_surface_kind(const struct terminal *term, const struct wl_surface *surface) static bool rows_to_text(const struct terminal *term, int start, int end, - char **text, size_t *len) + int col_start, int col_end, char **text, size_t *len) { struct extraction_context *ctx = extract_begin(SELECTION_NONE, true); if (ctx == NULL) @@ -3626,15 +3626,20 @@ rows_to_text(const struct terminal *term, int start, int end, const struct row *row = term->grid->rows[r]; xassert(row != NULL); - for (int c = 0; c < term->cols; c++) + const int c_end = r == end ? col_end : term->cols; + + for (int c = col_start; c < c_end; c++) { if (!extract_one(term, row, &row->cells[c], c, ctx)) goto out; + } if (r == end) break; r++; r &= grid_rows - 1; + + col_start = 0; } out: @@ -3666,7 +3671,7 @@ term_scrollback_to_text(const struct terminal *term, char **text, size_t *len) end += term->grid->num_rows; } - return rows_to_text(term, start, end, text, len); + return rows_to_text(term, start, end, 0, term->cols, text, len); } bool @@ -3674,7 +3679,87 @@ term_view_to_text(const struct terminal *term, char **text, size_t *len) { int start = grid_row_absolute_in_view(term->grid, 0); int end = grid_row_absolute_in_view(term->grid, term->rows - 1); - return rows_to_text(term, start, end, text, len); + return rows_to_text(term, start, end, 0, term->cols, text, len); +} + +bool +term_command_output_to_text(const struct terminal *term, char **text, size_t *len) +{ + int start_row = -1; + int end_row = -1; + int start_col = -1; + int end_col = -1; + + const struct grid *grid = term->grid; + const int sb_end = grid_row_absolute(grid, term->rows - 1); + int r = (sb_end - 1 + grid->num_rows) & (grid->num_rows - 1); + + while (start_row < 0 && r != sb_end) { + const struct row *row = grid->rows[r]; + if (row == NULL) + break; + + if (row->shell_integration.cmd_end >= 0) { + end_row = r; + end_col = row->shell_integration.cmd_end; + } + + if (end_row >= 0 && row->shell_integration.cmd_start >= 0) { + start_row = r; + start_col = row->shell_integration.cmd_start; + } + + r = (r - 1 + grid->num_rows) & (grid->num_rows - 1); + } + + if (start_row < 0) + return false; + + bool ret = rows_to_text(term, start_row, end_row, start_col, end_col, text, len); + if (!ret) + return false; + + /* + * If the FTCS_COMMAND_FINISHED marker was emitted at the *first* + * column, then the *entire* previous line is part of the command + * output. *Including* the newline, if any. + * + * Since rows_to_text() doesn’t extract the column + * FTCS_COMMAND_FINISHED was emitted at (that would be wrong - + * FTCS_COMMAND_FINISHED is emitted *after* the command output, + * not at its last character), the extraction logic will not see + * the last newline (this is true for all non-line-wise selection + * types), and the extracted text will *not* end with a newline. + * + * Here we try to compensate for that. Note that if ‘end_col’ is + * not 0, then the command output only covers a partial row, and + * thus we do *not* want to append a newline. + */ + + if (end_col > 0) { + /* Command output covers partial row - don’t append newline */ + return true; + } + + int next_to_last_row = (end_row - 1 + grid->num_rows) & (grid->num_rows - 1); + const struct row *row = grid->rows[next_to_last_row]; + + /* Add newline if last row has a hard linebreak */ + if (row->linebreak) { + char *new_text = xrealloc(*text, *len + 1 + 1); + + if (new_text == NULL) { + /* Ignore failure - use text as is (without inserting newline) */ + return true; + } + + *text = new_text; + (*len)++; + (*text)[*len - 1] = '\n'; + (*text)[*len] = '\0'; + } + + return true; } bool diff --git a/terminal.h b/terminal.h index 1e3a724e..35127e3c 100644 --- a/terminal.h +++ b/terminal.h @@ -847,6 +847,8 @@ bool term_scrollback_to_text( const struct terminal *term, char **text, size_t *len); bool term_view_to_text( const struct terminal *term, char **text, size_t *len); +bool term_command_output_to_text( + const struct terminal *term, char **text, size_t *len); bool term_ime_is_enabled(const struct terminal *term); void term_ime_enable(struct terminal *term); From f2a8368759f5968eff460ca2f30d600cbcc26839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 11:45:51 +0100 Subject: [PATCH 04/10] foot.ini: add pipe-command-output key binding --- foot.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/foot.ini b/foot.ini index 55eb42de..42a71e58 100644 --- a/foot.ini +++ b/foot.ini @@ -158,6 +158,7 @@ # pipe-visible=[sh -c "xurls | fuzzel | xargs -r firefox"] none # pipe-scrollback=[sh -c "xurls | fuzzel | xargs -r firefox"] none # pipe-selected=[xargs -r firefox] none +# pipe-command-output=[sh -c "cat - > /tmp/foot-cmd-out.txt"] none # Write output of last command to /tmp/foot-cmd-out.txt (requires shell integration) # show-urls-launch=Control+Shift+o # show-urls-copy=none # show-urls-persistent=none From 0fed2451eae01922c8fcbb40ab35b32ac3d655a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 11:50:43 +0100 Subject: [PATCH 05/10] doc: foot.ini: document pipe-command-output --- doc/foot.ini.5.scd | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/doc/foot.ini.5.scd b/doc/foot.ini.5.scd index 1c87db53..14999a8b 100644 --- a/doc/foot.ini.5.scd +++ b/doc/foot.ini.5.scd @@ -844,11 +844,12 @@ e.g. *search-start=none*. *fullscreen* Toggles the fullscreen state. Default: _none_. -*pipe-visible*, *pipe-scrollback*, *pipe-selected* - Pipes the currently visible text, the entire scrollback, or the - currently selected text to an external tool. The syntax for this - option is a bit special; the first part of the value is the - command to execute enclosed in "[]", followed by the binding(s). +*pipe-visible*, *pipe-scrollback*, *pipe-selected*, *pipe-command-output* + Pipes the currently visible text, the entire scrollback, the + currently selected text, or the last command's output to an + external tool. The syntax for this option is a bit special; the + first part of the value is the command to execute enclosed in + "[]", followed by the binding(s). You can configure multiple pipes as long as the command strings are different and the key bindings are unique. @@ -856,10 +857,17 @@ e.g. *search-start=none*. Note that the command is *not* automatically run inside a shell; use *sh -c "command line"* if you need that. - Example: - *pipe-visible=[sh -c "xurls | uniq | tac | fuzzel | xargs -r + Example #1: + + # Extract currently visible URLs, let user choose one (via + fuzzel), then launch firefox with the selected URL++ +*pipe-visible=[sh -c "xurls | uniq | tac | fuzzel | xargs -r firefox"] Control+Print* + Example #2: + # Write scrollback content to /tmp/foot-scrollback.txt++ +*pipe-scrollback=[sh -c "cat - > /tmp/foot-scrollback.txt"] + Control+Shift+Print* Default: _none_ *show-urls-launch* From d7dbb91e65d375e2ea496ea7a921bfcd9e3d8c1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 11:51:27 +0100 Subject: [PATCH 06/10] changelog: pipe-command-output --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2233fd9e..55ac7e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ of floating windows to be constrained to multiples of the cell size. * Support for custom (i.e. other than ctrl/shift/alt/super) modifiers in key bindings ([#1348][1348]). +* `pipe-command-output` key binding. [1348]: https://codeberg.org/dnkl/foot/issues/1348 From 1393942de38fa6ece726fd861cc15e2a5a369fbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 12:17:55 +0100 Subject: [PATCH 07/10] readme, doc/foot.1: document shell-integration:command-output tracking --- README.md | 36 ++++++++++++++++++++++++++++++++++++ doc/foot.1.scd | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/README.md b/README.md index b1cfb37d..c1be7476 100644 --- a/README.md +++ b/README.md @@ -359,6 +359,42 @@ See the [wiki](https://codeberg.org/dnkl/foot/wiki#user-content-jumping-between-prompts) for details, and examples for other shells. +### Piping last command’s output + +The key binding `pipe-command-output` can pipe the last command’s +output to an application of your choice (similar to the other `pipe-*` +key bindings): + +```ini +[key-bindings] +pipe-command-output=[sh -c "f=$(mktemp); cat - > $f; footclient emacsclient -nw $f; rm $f"] Control+Shift+g +``` + +When pressing ctrl+shift+g, the last +command’s output is written to a temporary file, then an emacsclient +is started in a new footclient instance. The temporary file is removed +after the footclient instance has closed. + +For this to work, the shell must emit an OSC-133;C (`\E]133;C\E\\`) +sequence before command output starts, and an OSC-133;D +(`\E]133;D\E\\`) when the command output ends. + +In fish, one way to do this is to add `preexec` and `postexec` hooks: + +```fish +function foot_cmd_start --on-event fish_preexec + echo -en "\e]133;C\e\\" +end + +function foot_cmd_end --on-event fish_postexec + echo -en "\e]133;D\e\\" +end +``` + +See the +[wiki](https://codeberg.org/dnkl/foot/wiki#user-content-piping-last-commands-output) +for details, and examples for other shells + ## Alt/meta diff --git a/doc/foot.1.scd b/doc/foot.1.scd index 385f9721..8e2fb313 100644 --- a/doc/foot.1.scd +++ b/doc/foot.1.scd @@ -424,6 +424,38 @@ See the wiki (https://codeberg.org/dnkl/foot/wiki#user-content-jumping-between-prompts) for details, and examples for other shells. +## Piping last command’s output + +The key binding *pipe-command-output* can pipe the last command’s +output to an application of your choice (similar to the other +*pipe-\** key bindings): + + *\[key-bindings\]++ +pipe-command-output=[sh -c "f=$(mktemp); cat - > $f; footclient emacsclient -nw $f; rm $f"] Control+Shift+g* + +When pressing *ctrl*+*shift*+*g*, the last command’s output is written +to a temporary file, then an emacsclient is started in a new +footclient instance. The temporary file is removed after the +footclient instance has closed. + +For this to work, the shell must emit an OSC-133;C (*\\E]133;C\\E\\\\*) +sequence before command output starts, and an OSC-133;D +(*\\E]133;D\\E\\\\*) when the command output ends. + +In fish, one way to do this is to add _preexec_ and _postexec_ hooks: + + *function foot_cmd_start --on-event fish_preexec + echo -en "\\e]133;C\\e\\\\" + end* + + *function foot_cmd_end --on-event fish_postexec + echo -en "\\e]133;D\\e\\\\" + end* + +See the wiki +(https://codeberg.org/dnkl/foot/wiki#user-content-piping-last-commands-output) +for details, and examples for other shells + # TERMINFO Client applications use the terminfo identifier specified by the From d5308a0493bb69167aacf54a8eb98f2e92a046dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 13:06:24 +0100 Subject: [PATCH 08/10] =?UTF-8?q?term:=20command=5Foutput=5Fto=5Ftext():?= =?UTF-8?q?=20don=E2=80=99t=20skip=20FTCS=5FCOMMAND=5FFINISHED=20on=20last?= =?UTF-8?q?=20row?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- terminal.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/terminal.c b/terminal.c index a328783f..5d6c956d 100644 --- a/terminal.c +++ b/terminal.c @@ -3692,9 +3692,10 @@ term_command_output_to_text(const struct terminal *term, char **text, size_t *le const struct grid *grid = term->grid; const int sb_end = grid_row_absolute(grid, term->rows - 1); - int r = (sb_end - 1 + grid->num_rows) & (grid->num_rows - 1); + const int sb_start = (sb_end + 1) & (grid->num_rows - 1); + int r = sb_end; - while (start_row < 0 && r != sb_end) { + while (start_row < 0) { const struct row *row = grid->rows[r]; if (row == NULL) break; @@ -3709,6 +3710,9 @@ term_command_output_to_text(const struct terminal *term, char **text, size_t *le start_col = row->shell_integration.cmd_start; } + if (r == sb_start) + break; + r = (r - 1 + grid->num_rows) & (grid->num_rows - 1); } From 110a6dd6f080686f85df9dff16fbb06fe2f57a81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 13:49:38 +0100 Subject: [PATCH 09/10] grid: resize without reflow: truncate shell_integration.cmd_{start,end} This ensures the cmd start/end columns are valid in the new grid. --- grid.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/grid.c b/grid.c index f14580ad..e0e357dc 100644 --- a/grid.c +++ b/grid.c @@ -427,7 +427,9 @@ grid_resize_without_reflow( new_row->dirty = old_row->dirty; new_row->linebreak = false; - new_row->shell_integration = old_row->shell_integration; + new_row->shell_integration.prompt_marker = old_row->shell_integration.prompt_marker; + new_row->shell_integration.cmd_start = min(old_row->shell_integration.cmd_start, new_cols - 1); + new_row->shell_integration.cmd_end = min(old_row->shell_integration.cmd_end, new_cols - 1); if (new_cols > old_cols) { /* Clear "new" columns */ From 231e6eb3f10c80ce6fb151d44814504c3ce00e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Thu, 8 Dec 2022 13:50:30 +0100 Subject: [PATCH 10/10] grid: resize with reflow: reflow FTCS_COMMAND_{EXECUTED,FINISHED} --- grid.c | 56 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/grid.c b/grid.c index e0e357dc..e7cdedc5 100644 --- a/grid.c +++ b/grid.c @@ -1,5 +1,6 @@ #include "grid.h" +#include #include #include @@ -837,35 +838,26 @@ grid_resize_and_reflow( int end; bool tp_break = false; bool uri_break = false; + bool ftcs_break = false; - /* - * Set end-coordinate for this chunk, by finding the next - * point-of-interest on this row. - * - * If there are no more tracking points, or URI ranges, - * the end-coordinate will be at the end of the row, - */ - if (range != range_terminator) { - int uri_col = (range->start >= start ? range->start : range->end) + 1; + /* Figure out where to end this chunk */ + { + const int uri_col = range != range_terminator + ? ((range->start >= start ? range->start : range->end) + 1) + : INT_MAX; + const int tp_col = tp != NULL ? tp->col + 1 : INT_MAX; + const int ftcs_col = old_row->shell_integration.cmd_start >= start + ? old_row->shell_integration.cmd_start + 1 + : old_row->shell_integration.cmd_end >= start + ? old_row->shell_integration.cmd_end + 1 + : INT_MAX; - if (tp != NULL) { - int tp_col = tp->col + 1; - end = min(tp_col, uri_col); + end = min(col_count, min(min(tp_col, uri_col), ftcs_col)); - tp_break = end == tp_col; - uri_break = end == uri_col; - LOG_DBG("tp+uri break at %d (%d, %d)", end, tp_col, uri_col); - } else { - end = uri_col; - uri_break = true; - LOG_DBG("uri break at %d", end); - } - } else if (tp != NULL) { - end = tp->col + 1; - tp_break = true; - LOG_DBG("TP break at %d", end); - } else - end = col_count; + uri_break = end == uri_col; + tp_break = end == tp_col; + ftcs_break = end == ftcs_col; + } int cols = end - start; xassert(cols > 0); @@ -926,7 +918,7 @@ grid_resize_and_reflow( xassert(from + amount <= old_cols); if (from == 0) - new_row->shell_integration = old_row->shell_integration; + new_row->shell_integration.prompt_marker = old_row->shell_integration.prompt_marker; memcpy( &new_row->cells[new_col_idx], &old_row->cells[from], @@ -985,6 +977,16 @@ grid_resize_and_reflow( } } + if (ftcs_break) { + xassert(old_row->shell_integration.cmd_start == start + cols - 1 || + old_row->shell_integration.cmd_end == start + cols - 1); + + if (old_row->shell_integration.cmd_start == start + cols - 1) + new_row->shell_integration.cmd_start = new_col_idx - 1; + if (old_row->shell_integration.cmd_end == start + cols - 1) + new_row->shell_integration.cmd_end = new_col_idx - 1; + } + left -= cols; start += cols; }