Remove code to put exit-code on right and go for just simple ! on left of +.

This commit is contained in:
Michael Grant
2026-07-22 11:33:46 +01:00
parent f44246c764
commit f0eaa5e9d6
3 changed files with 106 additions and 118 deletions

View File

@@ -114,10 +114,6 @@ static const char *options_table_theme_list[] = {
static const char *options_table_copy_mode_line_numbers_list[] = {
"off", "default", "absolute", "relative", "hybrid", NULL
};
static const char *options_table_copy_mode_collapse_controls_list[] = {
"always", "never", "on-demand", NULL
};
/* Status line format. */
#define OPTIONS_TABLE_STATUS_FORMAT1 \
"#[align=left range=left #{E:status-left-style}]" \
@@ -1376,22 +1372,11 @@ const struct options_table_entry options_table[] = {
.text = "Style of search matches in copy mode."
},
{ .name = "copy-mode-collapse-controls",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_copy_mode_collapse_controls_list,
.default_num = 2,
.text = "When OSC 133 output collapse controls are shown in copy mode."
},
{ .name = "copy-mode-exit-status-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#[align=right]"
"#{?exit_status_present,#[bg=themeyellow]#[fg=themeblack]"
"#{?exit_status_current,#[fg=themewhite],}(#{exit_status})"
"#[bg=themeyellow]#[fg=themeblack],}",
.text = "Format of OSC 133 exit status in copy mode."
.default_str = "#{?exit_status,#[fg=themered]!, }",
.text = "Format of OSC 133 exit status indicator in copy mode."
},
{ .name = "copy-mode-current-match-style",

28
tmux.1
View File

@@ -5778,15 +5778,18 @@ section.
Format of the position indicator in copy mode.
.Pp
.It Ic copy\-mode\-exit\-status\-format Ar format
Format of the OSC 133 exit status shown beside commands in copy mode.
Format of the OSC 133 exit status indicator in the copy-mode gutter.
The default displays a theme red
.Ql !
for a nonzero status and a space otherwise.
The gutter grows to fit the expanded format.
The format is drawn to the left of the collapse control, and its alignment
applies within that area.
The format is expanded with
.Ql exit_status
and
.Ql exit_status_present ,
which is set only when the OSC 133 end-of-output marker includes a status.
The
.Ql exit_status_current
format is set when the cursor is on the command line.
.Pp
.It Ic copy\-mode\-position\-style Ar style
Set the style of the position indicator in copy mode.
@@ -5850,23 +5853,6 @@ and
.Ic hybrid ,
they use absolute line numbers.
.Pp
.It Xo Ic copy\-mode\-collapse\-controls
.Op Ic always | never | on\-demand
.Xc
Choose when OSC 133 output collapse controls are shown in copy mode.
.Ic always
shows the control column in every copy-mode view;
.Ic never
does not show it, although collapse key bindings and commands still work; and
.Ic on\-demand
shows it after entering copy mode with
.Fl U
or
.Fl c ,
or after output is changed with a copy-mode command or key binding.
The default is
.Ic on\-demand .
.Pp
.It Xo Ic mode\-keys
.Op Ic vi | emacs
.Xc

View File

@@ -28,13 +28,10 @@
struct window_copy_mode_data;
#define WINDOW_COPY_CONTROLS_ALWAYS 0
#define WINDOW_COPY_CONTROLS_NEVER 1
#define WINDOW_COPY_CONTROLS_ON_DEMAND 2
#define WINDOW_COPY_LINE_CONTROL 0x1
#define WINDOW_COPY_LINE_MEMBER 0x2
#define WINDOW_COPY_LINE_INITIAL 0x4
#define WINDOW_COPY_LINE_OUTPUT 0x8
static const char *window_copy_key_table(struct window_mode_entry *);
static void window_copy_command(struct window_mode_entry *, struct client *,
@@ -72,7 +69,6 @@ static int window_copy_line_number_is_absolute(struct window_mode_entry *);
static int window_copy_line_numbers_active(struct window_mode_entry *);
static u_int window_copy_line_number_width(struct window_mode_entry *);
static u_int window_copy_left_margin(struct window_mode_entry *);
static int window_copy_controls_visible(struct window_mode_entry *);
static u_int window_copy_cursor_offset(struct window_mode_entry *, u_int,
u_int);
static u_int window_copy_cursor_unoffset(struct window_mode_entry *, u_int,
@@ -335,6 +331,7 @@ struct window_copy_mode_data {
int output_gutter;
int output_controls;
int top_output;
u_int output_status_width;
enum {
SEL_CHAR, /* select one char at a time */
@@ -506,7 +503,7 @@ window_copy_set_line(struct window_copy_mode_data *data, u_int y,
static void
window_copy_set_control(struct window_copy_mode_data *data, u_int y,
u_int output_line)
u_int output_line, int output)
{
struct window_copy_line *line;
@@ -515,6 +512,8 @@ window_copy_set_control(struct window_copy_mode_data *data, u_int y,
return;
line->output_line = output_line;
line->flags |= WINDOW_COPY_LINE_CONTROL;
if (output)
line->flags |= WINDOW_COPY_LINE_OUTPUT;
}
static void
@@ -530,6 +529,56 @@ window_copy_set_exit_status(struct window_copy_mode_data *data, u_int y,
line->exit_status_present = 1;
}
static char *
window_copy_expand_exit_status(struct window_mode_entry *wme,
struct window_copy_line *line)
{
struct format_tree *ft;
const char *value;
char *expanded;
/*
* This is called while rebuilding the backing grid, before the copy
* cursor and viewport have been restored for the new grid.
*/
ft = format_create(NULL, NULL, 0, 0);
format_add(ft, "exit_status", "0");
format_add(ft, "exit_status_present", "0");
if (line->exit_status_present) {
format_add(ft, "exit_status", "%hhu", line->exit_status);
format_add(ft, "exit_status_present", "1");
}
value = options_get_string(wme->wp->window->options,
"copy-mode-exit-status-format");
expanded = format_expand(ft, value);
format_free(ft);
return (expanded);
}
static void
window_copy_update_exit_status_width(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
struct window_copy_line *line;
char *expanded;
u_int width, y;
data->output_status_width = 0;
if (!data->output_gutter || data->lines == NULL)
return;
width = 1;
for (y = 0; y < data->line_count; y++) {
line = &data->lines[y];
if (~line->flags & WINDOW_COPY_LINE_CONTROL)
continue;
expanded = window_copy_expand_exit_status(wme, line);
if (format_width(expanded) > width)
width = format_width(expanded);
free(expanded);
}
data->output_status_width = width;
}
static int
window_copy_any_output_collapsed(struct window_copy_mode_data *data)
{
@@ -613,19 +662,6 @@ window_copy_set_all_output(struct window_copy_mode_data *data, int collapse)
return (changed);
}
static int
window_copy_controls_visible(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
int controls;
controls = options_get_number(wme->wp->window->options,
"copy-mode-collapse-controls");
return (controls == WINDOW_COPY_CONTROLS_ALWAYS ||
(controls == WINDOW_COPY_CONTROLS_ON_DEMAND &&
data->output_controls));
}
/* Recreate the backing screen with any collapsed OSC 133 output omitted. */
static void
window_copy_rebuild_backing(struct window_mode_entry *wme)
@@ -656,6 +692,7 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
data->line_count = 0;
data->backing = dst;
data->output_gutter = 0;
data->output_status_width = 0;
return;
}
sgd = src->grid;
@@ -719,7 +756,7 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
collapsed = data->outputs[y];
hiding = collapsed;
if (prompt_dy != UINT_MAX)
window_copy_set_control(data, prompt_dy, output_line);
window_copy_set_control(data, prompt_dy, output_line, 1);
}
if ((sgl->flags & GRID_LINE_END_OUTPUT) &&
x == osc133->out_end_col) {
@@ -734,7 +771,7 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
collapsed = data->outputs[y];
if (prompt_dy != UINT_MAX)
window_copy_set_control(data, prompt_dy,
output_line);
output_line, 0);
}
if (end_prompt_dy != UINT_MAX &&
sgl->flags & GRID_LINE_END_OUTPUT_STATUS)
@@ -781,7 +818,8 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
free(data->backing);
}
data->backing = dst;
data->output_gutter = window_copy_controls_visible(wme);
data->output_gutter = data->output_controls;
window_copy_update_exit_status_width(wme);
}
/*
@@ -967,9 +1005,7 @@ window_copy_init(struct window_mode_entry *wme,
screen_size_y(data->source), sizeof *data->outputs);
data->output_count = screen_hsize(data->source) +
screen_size_y(data->source);
data->output_controls = args_has(args, 'c') || args_has(args, 'U') ||
options_get_number(wp->window->options,
"copy-mode-collapse-controls") == WINDOW_COPY_CONTROLS_ALWAYS;
data->output_controls = args_has(args, 'c') || args_has(args, 'U');
if (args_has(args, 'c'))
window_copy_set_all_output(data, 1);
window_copy_rebuild_backing(wme);
@@ -5924,9 +5960,12 @@ static u_int
window_copy_left_margin(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
u_int width = 0;
return (window_copy_line_number_width(wme) +
(data->output_gutter ? 3 : 0));
if (data->output_gutter)
width = data->output_status_width + 2;
return (window_copy_line_number_width(wme) + width);
}
static u_int
@@ -6031,13 +6070,12 @@ window_copy_write_line(struct window_mode_entry *wme,
u_int width, line_width, gutter_width, backing_y;
u_int absolute, line_number, content_sx;
const char *value;
char *expanded, *exit_status, *position;
char *expanded, *status;
struct format_tree *ft;
struct window_copy_line *status_line;
int current, mode;
line_width = window_copy_line_number_width(wme);
gutter_width = data->output_gutter ? 3 : 0;
gutter_width = data->output_gutter ? data->output_status_width + 2 : 0;
width = line_width + gutter_width;
if (width >= sx)
content_sx = 1;
@@ -6045,9 +6083,6 @@ window_copy_write_line(struct window_mode_entry *wme,
content_sx = sx - width;
else
content_sx = sx;
backing_y = hsize - data->oy + py;
current = (py == data->cy);
screen_write_cursormove(ctx, 0, py, 0);
ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
@@ -6066,6 +6101,8 @@ window_copy_write_line(struct window_mode_entry *wme,
style_apply(&cur_ln_gc, oo,
"copy-mode-current-line-number-style", ft);
cur_ln_gc.flags |= GRID_FLAG_NOPALETTE;
current = (py == data->cy);
backing_y = hsize - data->oy + py;
absolute = backing_y + 1;
if (data->lines != NULL && backing_y < data->line_count)
absolute = data->lines[backing_y].source_line + 1;
@@ -6093,6 +6130,7 @@ window_copy_write_line(struct window_mode_entry *wme,
struct grid_cell control_gc;
struct window_copy_line *line, *next;
char control = ' ';
u_int i;
line = NULL;
if (data->lines != NULL && backing_y < data->line_count)
@@ -6100,13 +6138,15 @@ window_copy_write_line(struct window_mode_entry *wme,
if (line != NULL &&
line->flags & WINDOW_COPY_LINE_CONTROL) {
if (line->flags &
WINDOW_COPY_LINE_INITIAL)
WINDOW_COPY_LINE_INITIAL) {
control = data->top_output ? '+' : '-';
else if (data->outputs[
line->output_line])
control = '+';
else
control = '-';
} else if (line->flags & WINDOW_COPY_LINE_OUTPUT &&
line->output_line < data->output_count) {
if (data->outputs[line->output_line])
control = '+';
else
control = '-';
}
} else if (line != NULL &&
line->flags & WINDOW_COPY_LINE_MEMBER) {
next = NULL;
@@ -6120,66 +6160,42 @@ window_copy_write_line(struct window_mode_entry *wme,
control = 'x'; /* ACS | character */
}
screen_write_cursormove(ctx, line_width, py, 0);
screen_write_putc(ctx, current ? &cur_ln_gc : &ln_gc, ' ');
if (control == ' ')
for (i = 0; i < gutter_width; i++)
screen_write_putc(ctx, current ? &cur_ln_gc : &ln_gc, ' ');
else {
if (control != ' ') {
screen_write_cursormove(ctx,
line_width + data->output_status_width, py, 0);
memcpy(&control_gc, current ? &cur_ln_gc : &ln_gc,
sizeof control_gc);
if (control == 'x' || control == 'm')
control_gc.attr |= GRID_ATTR_CHARSET;
screen_write_putc(ctx, &control_gc, control);
}
screen_write_putc(ctx, current ? &cur_ln_gc : &ln_gc, ' ');
if (line != NULL &&
line->flags & WINDOW_COPY_LINE_CONTROL) {
status = window_copy_expand_exit_status(wme, line);
screen_write_cursormove(ctx, line_width, py, 0);
format_draw(ctx, current ? &cur_ln_gc : &ln_gc,
data->output_status_width, status, NULL, 0);
free(status);
}
}
}
window_copy_write_one(wme, ctx, width, py, hsize - data->oy + py,
content_sx, &mgc, &cgc, &mkgc);
exit_status = NULL;
status_line = window_copy_get_line_info(data, backing_y);
if (data->output_gutter && status_line != NULL &&
status_line->exit_status_present) {
format_add(ft, "exit_status", "%hhu", status_line->exit_status);
format_add(ft, "exit_status_present", "1");
format_add(ft, "exit_status_current", "%d", current);
value = options_get_string(oo, "copy-mode-exit-status-format");
if (*value != '\0') {
exit_status = format_expand(ft, value);
if (*exit_status == '\0') {
free(exit_status);
exit_status = NULL;
}
}
}
position = NULL;
if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
value = options_get_string(oo, "copy-mode-position-format");
if (*value != '\0') {
position = format_expand(ft, value);
if (*position == '\0') {
free(position);
position = NULL;
expanded = format_expand(ft, value);
if (*expanded != '\0') {
screen_write_cursormove(ctx, width, 0, 0);
format_draw(ctx, &gc, content_sx, expanded, NULL, 0);
}
free(expanded);
}
}
if (exit_status != NULL && position != NULL)
xasprintf(&expanded, "%s %s", exit_status, position);
else if (exit_status != NULL)
expanded = xstrdup(exit_status);
else if (position != NULL)
expanded = xstrdup(position);
else
expanded = NULL;
if (expanded != NULL) {
screen_write_cursormove(ctx, width, py, 0);
format_draw(ctx, &gc, content_sx, expanded, NULL, 0);
free(expanded);
}
free(exit_status);
free(position);
if (py == data->cy && data->cx >= content_sx) {
screen_write_cursormove(ctx, window_copy_cursor_offset(wme,
@@ -6278,6 +6294,7 @@ window_copy_style_changed(struct window_mode_entry *wme)
if (data->screen.sel != NULL)
window_copy_set_selection(wme, 0, 1);
window_copy_update_exit_status_width(wme);
window_copy_redraw_screen(wme);
}