diff --git a/format.c b/format.c index 3b58bde3..2d9c6a36 100644 --- a/format.c +++ b/format.c @@ -2262,6 +2262,38 @@ format_cb_pane_pipe_pid(struct format_tree *ft) 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. */ static void * format_cb_pane_right(struct format_tree *ft) @@ -3349,6 +3381,12 @@ static const struct format_table_entry format_table[] = { { "pane_path", FORMAT_TABLE_STRING, 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, format_cb_pane_pid }, diff --git a/input.c b/input.c index 707328dc..671f5788 100644 --- a/input.c +++ b/input.c @@ -164,6 +164,7 @@ static void input_reset_cell(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_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_11(struct input_ctx *, const char *); static void input_osc_12(struct input_ctx *, const char *); @@ -2673,6 +2674,9 @@ input_exit_osc(struct input_ctx *ictx) case 8: input_osc_8(ictx, p); break; + case 9: + input_osc_9(ictx, p); + break; case 10: input_osc_10(ictx, p); break; @@ -2941,6 +2945,57 @@ bad: 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. */ static void @@ -3151,7 +3206,7 @@ input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out, return (0); } - len = (strlen(end) / 4) * 3; + len = ((strlen(end) + 3) / 4) * 3; if (len == 0) return (0); diff --git a/screen.c b/screen.c index a07a8e8c..8a9fa178 100644 --- a/screen.c +++ b/screen.c @@ -131,6 +131,7 @@ screen_reinit(struct screen *s) image_free_all(s); #endif + screen_set_progress_bar(s, PROGRESS_BAR_HIDDEN, 0); screen_reset_hyperlinks(s); } @@ -296,6 +297,19 @@ screen_pop_title(struct screen *s) } } +/* + * Set the progress bar state and progress. The progress will not be updated + * if p is negative. + */ +void +screen_set_progress_bar(struct screen *s, enum progress_bar_state pbs, int p) +{ + s->progress_bar.state = pbs; + if (p >= 0 && pbs != PROGRESS_BAR_INDETERMINATE) + s->progress_bar.progress = p; +} + + /* Resize screen with options. */ void screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow, diff --git a/tmux.1 b/tmux.1 index a643b64e..d7a33038 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6382,6 +6382,8 @@ The following variables are available, where appropriate: .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_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_search_string" Ta "" Ta "Last search string in copy mode" .It Li "pane_start_command" Ta "" Ta "Command pane started with" diff --git a/tmux.h b/tmux.h index f42dec56..4290576c 100644 --- a/tmux.h +++ b/tmux.h @@ -947,6 +947,20 @@ enum screen_cursor_style { 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. */ struct screen_sel; struct screen_titles; @@ -988,6 +1002,7 @@ struct screen { struct screen_write_cline *write_list; struct hyperlinks *hyperlinks; + struct progress_bar progress_bar; }; /* Screen write context. */ @@ -3282,6 +3297,7 @@ int screen_set_title(struct screen *, const char *); void screen_set_path(struct screen *, const char *); void screen_push_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_cursor(struct screen *, u_int, u_int, int, int, int); void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int, diff --git a/tty-keys.c b/tty-keys.c index 8fc51174..05ec63c8 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1383,7 +1383,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) copy[end] = '\0'; /* Convert from base64. */ - needed = (end / 4) * 3; + needed = ((end + 3) / 4) * 3; if (needed == 0) { free(copy); return (0);