Handle OSC 9;4 progress bar sequence and store in format variables, from

Eric Dorland in GitHub issue 4954.
This commit is contained in:
nicm
2026-04-03 09:14:27 +00:00
parent 7497db6e37
commit bdd78ce38e
4 changed files with 112 additions and 1 deletions

View File

@@ -2248,6 +2248,38 @@ format_cb_pane_pipe_pid(struct format_tree *ft)
return (value); return (value);
} }
/* Callback for pane_pb_progress. */
static void *
format_cb_pane_pb_progress(struct format_tree *ft)
{
char *value = NULL;
if (ft->wp != NULL)
xasprintf(&value, "%d", ft->wp->base.progress_bar.progress);
return (value);
}
/* Callback for pane_pb_state. */
static void *
format_cb_pane_pb_state(struct format_tree *ft)
{
if (ft->wp != NULL) {
switch (ft->wp->base.progress_bar.state) {
case PROGRESS_BAR_HIDDEN:
return xstrdup("hidden");
case PROGRESS_BAR_NORMAL:
return xstrdup("normal");
case PROGRESS_BAR_ERROR:
return xstrdup("error");
case PROGRESS_BAR_INDETERMINATE:
return xstrdup("indeterminate");
case PROGRESS_BAR_PAUSED:
return xstrdup("paused");
}
}
return (NULL);
}
/* Callback for pane_right. */ /* Callback for pane_right. */
static void * static void *
format_cb_pane_right(struct format_tree *ft) format_cb_pane_right(struct format_tree *ft)
@@ -3331,6 +3363,12 @@ static const struct format_table_entry format_table[] = {
{ "pane_path", FORMAT_TABLE_STRING, { "pane_path", FORMAT_TABLE_STRING,
format_cb_pane_path format_cb_pane_path
}, },
{ "pane_pb_progress", FORMAT_TABLE_STRING,
format_cb_pane_pb_progress
},
{ "pane_pb_state", FORMAT_TABLE_STRING,
format_cb_pane_pb_state
},
{ "pane_pid", FORMAT_TABLE_STRING, { "pane_pid", FORMAT_TABLE_STRING,
format_cb_pane_pid format_cb_pane_pid
}, },

57
input.c
View File

@@ -164,6 +164,7 @@ static void input_reset_cell(struct input_ctx *);
static void input_report_current_theme(struct input_ctx *); static void input_report_current_theme(struct input_ctx *);
static void input_osc_4(struct input_ctx *, const char *); static void input_osc_4(struct input_ctx *, const char *);
static void input_osc_8(struct input_ctx *, const char *); static void input_osc_8(struct input_ctx *, const char *);
static void input_osc_9(struct input_ctx *, const char *);
static void input_osc_10(struct input_ctx *, const char *); static void input_osc_10(struct input_ctx *, const char *);
static void input_osc_11(struct input_ctx *, const char *); static void input_osc_11(struct input_ctx *, const char *);
static void input_osc_12(struct input_ctx *, const char *); static void input_osc_12(struct input_ctx *, const char *);
@@ -2636,6 +2637,9 @@ input_exit_osc(struct input_ctx *ictx)
case 8: case 8:
input_osc_8(ictx, p); input_osc_8(ictx, p);
break; break;
case 9:
input_osc_9(ictx, p);
break;
case 10: case 10:
input_osc_10(ictx, p); input_osc_10(ictx, p);
break; break;
@@ -2904,6 +2908,57 @@ bad:
free(id); free(id);
} }
/* Helper to handle setting the progress bar and redrawing. */
static void
input_set_progress_bar(struct input_ctx *ictx, enum progress_bar_state state,
int p)
{
screen_set_progress_bar(ictx->ctx.s, state, p);
if (ictx->wp != NULL) {
server_redraw_window_borders(ictx->wp->window);
server_status_window(ictx->wp->window);
}
}
/* Handle the OSC 9;4 sequence for progress bars. */
static void
input_osc_9(struct input_ctx *ictx, const char *p)
{
const char *pb = p;
enum progress_bar_state state;
int progress = 0;
if (*pb++ != '4')
return;
if (*pb == '\0' || (*pb == ';' && pb[1] == '\0'))
return;
if (*pb++ != ';')
return;
if (*pb < '0' || *pb > '4')
goto bad;
state = *pb++ - '0';
if (*pb == '\0' || (*pb == ';' && pb[1] == '\0')) {
input_set_progress_bar(ictx, state, -1);
return;
}
if (*pb++ != ';')
goto bad;
while (*pb >= '0' && *pb <= '9') {
if (progress > 100)
goto bad;
progress = progress * 10 + *pb++ - '0';
}
if (*pb != '\0' || progress < 0 || progress > 100)
goto bad;
input_set_progress_bar(ictx, state, progress);
return;
bad:
log_debug("bad OSC 9;4 %s", p);
}
/* Handle the OSC 10 sequence for setting and querying foreground colour. */ /* Handle the OSC 10 sequence for setting and querying foreground colour. */
static void static void
@@ -3114,7 +3169,7 @@ input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
return (0); return (0);
} }
len = (strlen(end) / 4) * 3; len = ((strlen(end) + 3) / 4) * 3;
if (len == 0) if (len == 0)
return (0); return (0);

2
tmux.1
View File

@@ -6380,6 +6380,8 @@ The following variables are available, where appropriate:
.It Li "pane_pid" Ta "" Ta "PID of first process in pane" .It Li "pane_pid" Ta "" Ta "PID of first process in pane"
.It Li "pane_pipe" Ta "" Ta "1 if pane is being piped" .It Li "pane_pipe" Ta "" Ta "1 if pane is being piped"
.It Li "pane_pipe_pid" Ta "" Ta "PID of pipe process, if any" .It Li "pane_pipe_pid" Ta "" Ta "PID of pipe process, if any"
.It Li "pane_pb_state" Ta "" Ta "Pane progress bar state, one of hidden, normal, error, indeterminate, paused (can be set by application)"
.It Li "pane_pb_progress" Ta "" Ta "Pane progress bar progress percentage (can be set by application)"
.It Li "pane_right" Ta "" Ta "Right of pane" .It Li "pane_right" Ta "" Ta "Right of pane"
.It Li "pane_search_string" Ta "" Ta "Last search string in copy mode" .It Li "pane_search_string" Ta "" Ta "Last search string in copy mode"
.It Li "pane_start_command" Ta "" Ta "Command pane started with" .It Li "pane_start_command" Ta "" Ta "Command pane started with"

16
tmux.h
View File

@@ -920,6 +920,20 @@ enum screen_cursor_style {
SCREEN_CURSOR_BAR SCREEN_CURSOR_BAR
}; };
/* Progress bar, OSC 9;4. */
enum progress_bar_state {
PROGRESS_BAR_HIDDEN = 0,
PROGRESS_BAR_NORMAL = 1,
PROGRESS_BAR_ERROR = 2,
PROGRESS_BAR_INDETERMINATE = 3,
PROGRESS_BAR_PAUSED = 4
};
struct progress_bar {
enum progress_bar_state state;
int progress;
};
/* Virtual screen. */ /* Virtual screen. */
struct screen_sel; struct screen_sel;
struct screen_titles; struct screen_titles;
@@ -956,6 +970,7 @@ struct screen {
struct screen_write_cline *write_list; struct screen_write_cline *write_list;
struct hyperlinks *hyperlinks; struct hyperlinks *hyperlinks;
struct progress_bar progress_bar;
}; };
/* Screen write context. */ /* Screen write context. */
@@ -3233,6 +3248,7 @@ int screen_set_title(struct screen *, const char *);
void screen_set_path(struct screen *, const char *); void screen_set_path(struct screen *, const char *);
void screen_push_title(struct screen *); void screen_push_title(struct screen *);
void screen_pop_title(struct screen *); void screen_pop_title(struct screen *);
void screen_set_progress_bar(struct screen *, enum progress_bar_state, int);
void screen_resize(struct screen *, u_int, u_int, int); void screen_resize(struct screen *, u_int, u_int, int);
void screen_resize_cursor(struct screen *, u_int, u_int, int, int, int); void screen_resize_cursor(struct screen *, u_int, u_int, int, int, int);
void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int, void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int,