From 312b22300d9b78028885d284cab18c1776d651c0 Mon Sep 17 00:00:00 2001 From: saeedark Date: Wed, 8 Oct 2025 02:38:45 +0330 Subject: [PATCH] feat: ansi for pipe rows --- config.c | 4 + config.h | 2 + extract.c | 552 ++++++++++++++++++++++++++++++++++++++++++++++++-- extract.h | 3 +- input.c | 5 + key-binding.h | 1 + search.c | 4 +- selection.c | 2 +- terminal.c | 13 +- terminal.h | 3 + 10 files changed, 566 insertions(+), 23 deletions(-) diff --git a/config.c b/config.c index 4449d9c2..f4593086 100644 --- a/config.c +++ b/config.c @@ -132,6 +132,7 @@ static const char *const binding_action_map[] = { [BIND_ACTION_PIPE_VIEW] = "pipe-visible", [BIND_ACTION_PIPE_SELECTED] = "pipe-selected", [BIND_ACTION_PIPE_COMMAND_OUTPUT] = "pipe-command-output", + [BIND_ACTION_TOGGLE_ANSI_SELECTION] = "toggle-ansi-selection", [BIND_ACTION_SHOW_URLS_COPY] = "show-urls-copy", [BIND_ACTION_SHOW_URLS_LAUNCH] = "show-urls-launch", [BIND_ACTION_SHOW_URLS_PERSISTENT] = "show-urls-persistent", @@ -923,6 +924,9 @@ parse_section_main(struct context *ctx) else if (streq(key, "app-id")) return value_to_str(ctx, &conf->app_id); + else if (streq(key, "ansi-pipe")) + return value_to_bool(ctx, &conf->ansi_pipe); + else if (streq(key, "initial-window-size-pixels")) { if (!value_to_dimensions(ctx, &conf->size.width, &conf->size.height)) return false; diff --git a/config.h b/config.h index 37b3259f..f2b58602 100644 --- a/config.h +++ b/config.h @@ -416,6 +416,8 @@ struct config { char *utmp_helper_path; + bool ansi_pipe; + struct { enum fcft_scaling_filter fcft_filter; bool overflowing_glyphs; diff --git a/extract.c b/extract.c index cd9a0c95..8ae0489a 100644 --- a/extract.c +++ b/extract.c @@ -1,4 +1,5 @@ #include "extract.h" +#include "terminal.h" #include #define LOG_MODULE "extract" @@ -18,27 +19,122 @@ struct extraction_context { const struct row *last_row; const struct cell *last_cell; enum selection_kind selection_kind; + + bool rich; + bool bold; // 0 + bool dim; // 1 + bool italic; // 2 + bool underline; // 3 + bool blink; // 4 + bool reverse; // 5 + bool conceal; // 6 + bool strikethrough; // 7 + uint32_t fg; // 8 + uint32_t bg; // 9 + uint32_t un; // 3 + enum color_source fg_src; // 8 + enum color_source bg_src; // 9 + enum color_source un_src; // 3 + enum underline_style underline_style; // 3 + uint64_t url_id; // 10 }; -struct extraction_context * -extract_begin(enum selection_kind kind, bool strip_trailing_empty) -{ - struct extraction_context *ctx = malloc(sizeof(*ctx)); - if (unlikely(ctx == NULL)) { - LOG_ERRNO("malloc() failed"); - return NULL; +uint16_t +compare_attrs(struct extraction_context *ctx, struct attributes attrs, const struct row *row, int col) { + uint16_t diff = 0; + uint8_t idx; + + const struct row_data *extra = row->extra; + + idx = 0; + if (ctx->bold != attrs.bold) + diff |= 1 << idx; + + idx = 1; + if (ctx->dim != attrs.dim) + diff |= 1 << idx; + + idx = 2; + if (ctx->italic != attrs.italic) + diff |= 1 << idx; + + idx = 3; + if (ctx->underline != attrs.underline) + diff |= 1 << idx; + if (extra != NULL){ + for (size_t i = 0; i < extra->underline_ranges.count; i++){ + const struct row_range *range = &extra->underline_ranges.v[i]; + if (range->start <= col && col <= range->end){ + if (ctx->underline_style != range->underline.style){ + diff |= 1 << idx; + break; + } + if (ctx->un_src != range->underline.color_src){ + diff |= 1 << idx; + break; + } + if ((range->underline.color_src != COLOR_DEFAULT) && ctx->un != range->underline.color){ + diff |= 1 << idx; + break; + } + break; + } + } } - *ctx = (struct extraction_context){ - .selection_kind = kind, - .strip_trailing_empty = strip_trailing_empty, - }; - return ctx; + idx = 4; + if (ctx->blink != attrs.blink) + diff |= 1 << idx; + + idx = 5; + if (ctx->reverse != attrs.reverse) + diff |= 1 << idx; + + idx = 6; + if (ctx->conceal != attrs.conceal) + diff |= 1 << idx; + + idx = 7; + if (ctx->strikethrough != attrs.strikethrough) + diff |= 1 << idx; + + idx = 8; + if (ctx->fg_src != attrs.fg_src) + diff |= 1 << idx; + if ((attrs.fg_src != COLOR_DEFAULT) && ctx->fg != attrs.fg) + diff |= 1 << idx; + + idx = 9; + if (ctx->bg_src != attrs.bg_src) + diff |= 1 << idx; + if ((attrs.bg_src != COLOR_DEFAULT) && ctx->bg != attrs.bg) + diff |= 1 << idx; + + idx = 10; + + if (extra != NULL){ + bool found_one = false; + for (size_t i = 0; i < extra->uri_ranges.count; i++){ + const struct row_range *range = &extra->uri_ranges.v[i]; + if (range->start <= col && col <= range->end){ + found_one = true; + if (ctx->url_id != range->uri.id) + diff |= 1 << idx; + break; + } + } + if (!found_one && ctx->url_id) + diff |= 1 << idx; + } else if (ctx->url_id) { + diff |= 1 << idx; + } + + return diff; } + static bool -ensure_size(struct extraction_context *ctx, size_t additional_chars) -{ +ensure_size(struct extraction_context *ctx, size_t additional_chars) { while (ctx->size < ctx->idx + additional_chars) { size_t new_size = ctx->size == 0 ? 512 : ctx->size * 2; char32_t *new_buf = realloc(ctx->buf, new_size * sizeof(new_buf[0])); @@ -54,6 +150,413 @@ ensure_size(struct extraction_context *ctx, size_t additional_chars) return true; } + +bool +clear_rich_ctx(struct extraction_context *ctx) { + if (ctx->url_id){ + if (!ensure_size(ctx, 7)) + return false; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U']'; + ctx->buf[ctx->idx++] = U'8'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'\\'; + } + + if (ctx->bold + + ctx->dim + + ctx->italic + + ctx->underline + + ctx->blink + + ctx->reverse + + ctx->conceal + + ctx->strikethrough + + ctx->fg_src + + ctx->bg_src + + ctx->un_src + + ctx->underline_style + ) + { + if (!ensure_size(ctx, 4)) + return false; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'['; + ctx->buf[ctx->idx++] = U'0'; + ctx->buf[ctx->idx++] = U'm'; + } + + ctx->bold = false; + ctx->dim = false; + ctx->italic = false; + ctx->underline = false; + ctx->blink = false; + ctx->reverse = false; + ctx->conceal = false; + ctx->strikethrough = false; + ctx->fg = 0; + ctx->bg = 0; + ctx->un = 0; + ctx->fg_src = 0; + ctx->bg_src = 0; + ctx->un_src = 0; + ctx->underline_style = 0; + ctx->url_id = 0; + + return true; +} + +bool +init_x1b(bool *x1b, struct extraction_context *ctx) { + if (!(*x1b)) { + if (!ensure_size(ctx, 2)) + return false; + + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'['; + } else { + if (!ensure_size(ctx, 1)) + return false; + + ctx->buf[ctx->idx++] = U';'; + } + *x1b = true; + return true; +} + +bool +change_color_rich(enum color_source colour_src, uint32_t colour, struct extraction_context *ctx, uint8_t domain) +{ + switch (colour_src) { + case COLOR_DEFAULT: + if (!ensure_size(ctx, 2)) + return false; + ctx->buf[ctx->idx++] = U'0' + domain; + ctx->buf[ctx->idx++] = U'9'; + break; + case COLOR_BASE16: + xassert(domain != 0); + if (!ensure_size(ctx, 2 + (((domain + (6 * (colour > 7)))) > 9))) + return false; + if (((domain + (6 * (colour > 7)))) > 9) + ctx->buf[ctx->idx++] = U'1'; + ctx->buf[ctx->idx++] = U'0' + domain + (6 * (colour > 7)) - 10 * (((domain + (6 * (colour > 7)))) > 9); + ctx->buf[ctx->idx++] = U'0' + colour - (8 * (colour > 7)); + break; + case COLOR_BASE256: + if (!ensure_size(ctx, 6 + (colour > 9) + (colour > 99))) + return false; + ctx->buf[ctx->idx++] = U'0' + domain; + ctx->buf[ctx->idx++] = U'8'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U'5'; + ctx->buf[ctx->idx++] = U';'; + if (colour > 99) + ctx->buf[ctx->idx++] = U'0' + (colour / 100); + if (colour > 9) + ctx->buf[ctx->idx++] = U'0' + ((colour % 100) / 10); + ctx->buf[ctx->idx++] = U'0' + (colour % 10); + break; + case COLOR_RGB:; + uint8_t r = (colour >> 16) & 0xff; + uint8_t g = (colour >> 8) & 0xff; + uint8_t b = colour & 0xff; + if (!ensure_size(ctx, 8 + (r > 9) + (r > 99) + (g > 9) + (g > 99) + (b > 9) + (b > 99))) + return false; + ctx->buf[ctx->idx++] = U'0' + domain; + ctx->buf[ctx->idx++] = U'8'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U'2'; + ctx->buf[ctx->idx++] = U';'; + if (r > 99) + ctx->buf[ctx->idx++] = U'0' + (r / 100); + if (r > 9) + ctx->buf[ctx->idx++] = U'0' + ((r % 100) / 10); + ctx->buf[ctx->idx++] = U'0' + (r % 10); + ctx->buf[ctx->idx++] = U';'; + if (g > 99) + ctx->buf[ctx->idx++] = U'0' + (g / 100); + if (g > 9) + ctx->buf[ctx->idx++] = U'0' + ((g % 100) / 10); + ctx->buf[ctx->idx++] = U'0' + (g % 10); + ctx->buf[ctx->idx++] = U';'; + if (b > 99) + ctx->buf[ctx->idx++] = U'0' + (b / 100); + if (b > 9) + ctx->buf[ctx->idx++] = U'0' + ((b % 100) / 10); + ctx->buf[ctx->idx++] = U'0' + (b % 10); + break; + } + return true; +} + +bool +style_flip_rich(bool attr, uint8_t attr_idx, struct extraction_context *ctx) { + if (attr) { + if (!ensure_size(ctx, 1)) + return false; + ctx->buf[ctx->idx++] = U'0' + attr_idx; + } else { + if (!ensure_size(ctx, 2)) + return false; + ctx->buf[ctx->idx++] = U'2'; + ctx->buf[ctx->idx++] = U'0' + attr_idx; + } + return true; +} + +bool +add_rich_diff(struct extraction_context *ctx, struct attributes attrs, const struct row *row, int col, uint16_t diff) { + char idx; + bool x1b = false; + + /* dim and bod */ + idx = 0; + if (diff & 1 << idx || diff & 1 << (idx + 1)) { + x1b = true; + if (!ensure_size(ctx, 2)) + goto err; + + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'['; + + if ((!attrs.bold && !attrs.dim) || (attrs.bold ^ attrs.dim)) { + if (!ensure_size(ctx, 2 + (2 * (attrs.bold ^ attrs.dim)))) + goto err; + + ctx->buf[ctx->idx++] = U'2'; + ctx->buf[ctx->idx++] = U'2'; + if (attrs.bold ^ attrs.dim) { + ctx->buf[ctx->idx++] = U';'; + if (attrs.dim) { + ctx->buf[ctx->idx++] = U'2'; + } + else if (attrs.bold) { + ctx->buf[ctx->idx++] = U'1'; + } + } + } + ctx->dim = attrs.dim; + ctx->bold = attrs.bold; + } + + /* italic */ + idx = 2; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!style_flip_rich(attrs.italic, 3, ctx)) + goto err; + ctx->italic = attrs.italic; + } + + /* underline */ + idx = 3; + if (diff & 1 << idx) { + if (attrs.underline) { + const struct row_data *extra = row->extra; + if (extra != NULL) { + for (size_t i = 0; i < extra->underline_ranges.count; i++) { + const struct row_range *range = &extra->underline_ranges.v[i]; + if (range->start <= col && col <= range->end) { + if (ctx->underline_style != range->underline.style) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!ensure_size(ctx, 3)) + goto err; + ctx->buf[ctx->idx++] = U'4'; + ctx->buf[ctx->idx++] = U':'; + ctx->buf[ctx->idx++] = U'0' + range->underline.style; + } + + if ((ctx->un_src != range->underline.color_src) || ((range->underline.color_src != COLOR_DEFAULT) && ctx->un != range->underline.color)) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!change_color_rich(range->underline.color_src, range->underline.color, ctx, 5)) + goto err; + } + ctx->underline_style = range->underline.style; + ctx->un = range->underline.color; + ctx->un_src = range->underline.color_src; + break; + } + } + } else { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!ensure_size(ctx, 3)) + goto err; + ctx->buf[ctx->idx++] = U'4'; + ctx->buf[ctx->idx++] = U':'; + ctx->buf[ctx->idx++] = U'1'; + } + } else { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!ensure_size(ctx, 3)) + goto err; + ctx->buf[ctx->idx++] = U'4'; + ctx->buf[ctx->idx++] = U':'; + ctx->buf[ctx->idx++] = U'0'; + } + ctx->underline = attrs.underline; + } + + /* blink */ + idx = 4; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!style_flip_rich(attrs.blink, 5, ctx)) + goto err; + ctx->blink = attrs.blink; + } + + /* reverse */ + idx = 5; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!style_flip_rich(attrs.reverse, 7, ctx)) + goto err; + ctx->reverse = attrs.reverse; + } + + /* conceal */ + idx = 6; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!style_flip_rich(attrs.conceal, 8, ctx)) + goto err; + ctx->conceal = attrs.conceal; + } + + /* strikethrough */ + idx = 7; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + if (!style_flip_rich(attrs.strikethrough, 9, ctx)) + goto err; + ctx->strikethrough = attrs.strikethrough; + } + + /* foreground colour */ + idx = 8; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + + if (!change_color_rich(attrs.fg_src, attrs.fg, ctx, 3)) + goto err; + + ctx->fg = attrs.fg; + ctx->fg_src = attrs.fg_src; + } + + /* background colour */ + idx = 9; + if (diff & 1 << idx) { + if (!init_x1b(&x1b, ctx)) + goto err; + + if (!change_color_rich(attrs.bg_src, attrs.bg, ctx, 4)) + goto err; + + ctx->bg = attrs.bg; + ctx->bg_src = attrs.bg_src; + } + + if (x1b) { + if (!ensure_size(ctx, 1)) + goto err; + ctx->buf[ctx->idx++] = U'm'; + } + + idx = 10; + if (diff & 1 << idx) { + const struct row_data *extra = row->extra; + if (extra != NULL) { + char32_t *text; + bool found_one = false; + for (size_t i = 0; i < extra->uri_ranges.count; i++) { + const struct row_range *range = &extra->uri_ranges.v[i]; + if (range->start <= col && col <= range->end) { + found_one = true; + ctx->url_id = range->uri.id; + text = ambstoc32(range->uri.uri); + + if (!ensure_size(ctx, 7 + c32len(text))) + goto err; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U']'; + ctx->buf[ctx->idx++] = U'8'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U';'; + + for (size_t j = 0; j < c32len(text); j++) + ctx->buf[ctx->idx++] = text[j]; + + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'\\'; + + free(text); + break; + } + } + if (!found_one) { + if (!ensure_size(ctx, 7)) + goto err; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U']'; + ctx->buf[ctx->idx++] = U'8'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'\\'; + + ctx->url_id = 0; + } + } else { + if (!ensure_size(ctx, 7)) + goto err; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U']'; + ctx->buf[ctx->idx++] = U'8'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U';'; + ctx->buf[ctx->idx++] = U'\x1b'; + ctx->buf[ctx->idx++] = U'\\'; + + ctx->url_id = 0; + } + } + return true; + +err: + free(ctx->buf); + free(ctx); + return false; +} + +struct extraction_context * +extract_begin(enum selection_kind kind, bool strip_trailing_empty, bool rich) { + struct extraction_context *ctx = malloc(sizeof(*ctx)); + if (unlikely(ctx == NULL)){ + LOG_ERRNO("malloc() failed"); + return NULL; + } + + *ctx = (struct extraction_context){ + .selection_kind = kind, + .strip_trailing_empty = strip_trailing_empty, + .rich = rich, + }; + return ctx; +} + bool extract_finish_wide(struct extraction_context *ctx, char32_t **text, size_t *len) { @@ -111,6 +614,15 @@ extract_finish_wide(struct extraction_context *ctx, char32_t **text, size_t *len } } + if (ctx->rich){ + ctx->idx = ctx->idx - 1; + if (!clear_rich_ctx(ctx)) + goto err; + if (!ensure_size(ctx, 1)) + goto err; + ctx->buf[ctx->idx++] = U'\0'; + } + *text = ctx->buf; if (len != NULL) *len = ctx->idx - 1; @@ -157,12 +669,17 @@ extract_one(const struct terminal *term, const struct row *row, const struct cell *cell, int col, void *context) { struct extraction_context *ctx = context; + struct attributes attrs = cell->attrs; if (cell->wc >= CELL_SPACER) return true; if (ctx->last_row != NULL && row != ctx->last_row) { /* New row - determine if we should insert a newline or not */ + if (ctx->rich){ + if (!clear_rich_ctx(ctx)) + goto err; + } if (ctx->selection_kind != SELECTION_BLOCK) { if (ctx->last_row->linebreak || @@ -230,6 +747,13 @@ extract_one(const struct terminal *term, const struct row *row, ctx->newline_count = 0; ctx->empty_count = 0; + if (ctx->rich) + { + uint16_t rich_diff = compare_attrs(ctx, attrs, row, col); + if (rich_diff) + add_rich_diff(ctx, attrs, row, col, rich_diff); + } + if (cell->wc >= CELL_COMB_CHARS_LO && cell->wc <= CELL_COMB_CHARS_HI) { const struct composed *composed = composed_lookup( diff --git a/extract.h b/extract.h index 30bec494..d4cbbd2c 100644 --- a/extract.h +++ b/extract.h @@ -9,7 +9,7 @@ struct extraction_context; struct extraction_context *extract_begin( - enum selection_kind kind, bool strip_trailing_empty); + enum selection_kind kind, bool strip_trailing_empty, bool rich); bool extract_one( const struct terminal *term, const struct row *row, const struct cell *cell, @@ -19,3 +19,4 @@ bool extract_finish( struct extraction_context *context, char **text, size_t *len); bool extract_finish_wide( struct extraction_context *context, char32_t **text, size_t *len); + diff --git a/input.c b/input.c index 44a99e3b..1f792981 100644 --- a/input.c +++ b/input.c @@ -1,4 +1,5 @@ #include "input.h" +#include "key-binding.h" #include #include @@ -340,6 +341,10 @@ execute_binding(struct seat *seat, struct terminal *term, return true; } + case BIND_ACTION_TOGGLE_ANSI_SELECTION: + term->ansi_selection = !(term->ansi_selection); + break; + case BIND_ACTION_SHOW_URLS_COPY: case BIND_ACTION_SHOW_URLS_LAUNCH: case BIND_ACTION_SHOW_URLS_PERSISTENT: { diff --git a/key-binding.h b/key-binding.h index 5f0c1f1e..3bbd3ac3 100644 --- a/key-binding.h +++ b/key-binding.h @@ -33,6 +33,7 @@ enum bind_action_normal { BIND_ACTION_PIPE_VIEW, BIND_ACTION_PIPE_SELECTED, BIND_ACTION_PIPE_COMMAND_OUTPUT, + BIND_ACTION_TOGGLE_ANSI_SELECTION, BIND_ACTION_SHOW_URLS_COPY, BIND_ACTION_SHOW_URLS_LAUNCH, BIND_ACTION_SHOW_URLS_PERSISTENT, diff --git a/search.c b/search.c index dda84e6d..a5d0d341 100644 --- a/search.c +++ b/search.c @@ -874,7 +874,7 @@ search_extend_left(struct terminal *term, const struct coord *target) const bool move_cursor = term->search.cursor != 0; - struct extraction_context *ctx = extract_begin(SELECTION_NONE, false); + struct extraction_context *ctx = extract_begin(SELECTION_NONE, false, false); if (ctx == NULL) return; @@ -938,7 +938,7 @@ search_extend_right(struct terminal *term, const struct coord *target) const bool move_cursor = term->search.cursor == term->search.len; - struct extraction_context *ctx = extract_begin(SELECTION_NONE, false); + struct extraction_context *ctx = extract_begin(SELECTION_NONE, false, false); if (ctx == NULL) return; diff --git a/selection.c b/selection.c index d7aa617a..d28b6372 100644 --- a/selection.c +++ b/selection.c @@ -328,7 +328,7 @@ selection_to_text(const struct terminal *term) if (term->selection.coords.end.row == -1) return NULL; - struct extraction_context *ctx = extract_begin(term->selection.kind, true); + struct extraction_context *ctx = extract_begin(term->selection.kind, true, term->ansi_selection); if (ctx == NULL) return NULL; diff --git a/terminal.c b/terminal.c index 36f8513b..9bae107b 100644 --- a/terminal.c +++ b/terminal.c @@ -1400,6 +1400,9 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, .cb = shutdown_cb, .cb_data = shutdown_data, }, + .ansi_pipe = conf->ansi_pipe, + .ansi_selection = false, + .foot_exe = xstrdup(foot_exe), .cwd = xstrdup(cwd), .grapheme_shaping = conf->tweak.grapheme_shaping, @@ -4418,9 +4421,9 @@ 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, - int col_start, int col_end, char **text, size_t *len) + int col_start, int col_end, char **text, size_t *len, bool rich) { - struct extraction_context *ctx = extract_begin(SELECTION_NONE, true); + struct extraction_context *ctx = extract_begin(SELECTION_NONE, true, term->ansi_pipe); if (ctx == NULL) return false; @@ -4476,7 +4479,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, 0, term->cols, text, len); + return rows_to_text(term, start, end, 0, term->cols, text, len, true); } bool @@ -4484,7 +4487,7 @@ 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, 0, term->cols, text, len); + return rows_to_text(term, start, end, 0, term->cols, text, len, true); } bool @@ -4524,7 +4527,7 @@ term_command_output_to_text(const struct terminal *term, char **text, size_t *le if (start_row < 0) return false; - bool ret = rows_to_text(term, start_row, end_row, start_col, end_col, text, len); + bool ret = rows_to_text(term, start_row, end_row, start_col, end_col, text, len, true); if (!ret) return false; diff --git a/terminal.h b/terminal.h index 364d57b3..2967bf7c 100644 --- a/terminal.h +++ b/terminal.h @@ -807,6 +807,9 @@ struct terminal { bool ime_reenable_after_url_mode; const struct config_spawn_template *url_launch; + bool ansi_selection; + bool ansi_pipe; + #if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED bool ime_enabled; #endif