diff --git a/config.def.h b/config.def.h index c5914c3..952efed 100644 --- a/config.def.h +++ b/config.def.h @@ -378,8 +378,8 @@ static MouseShortcut mshortcuts[] = { { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} }, #endif // SCROLLBACK_MOUSE_PATCH #if SCROLLBACK_MOUSE_ALTSCREEN_PATCH || REFLOW_PATCH - { XK_NO_MOD, Button4, kscrollup, {.i = 1}, 0, S_PRI }, - { XK_NO_MOD, Button5, kscrolldown, {.i = 1}, 0, S_PRI }, + { XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, S_PRI }, + { XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, S_PRI }, { XK_ANY_MOD, Button4, ttysend, {.s = "\031"}, 0, S_ALT }, { XK_ANY_MOD, Button5, ttysend, {.s = "\005"}, 0, S_ALT }, #else @@ -467,6 +467,10 @@ static Shortcut shortcuts[] = { #if INVERT_PATCH { TERMMOD, XK_X, invert, { 0 } }, #endif // INVERT_PATCH + #if OSC133_PATCH + { ControlMask, XK_Page_Up, scrolltoprompt, {.i = -1}, S_PRI }, + { ControlMask, XK_Page_Down, scrolltoprompt, {.i = 1}, S_PRI }, + #endif // OSC133_PATCH }; /* diff --git a/patch/osc133.c b/patch/osc133.c new file mode 100644 index 0000000..6baa82a --- /dev/null +++ b/patch/osc133.c @@ -0,0 +1,29 @@ +void +scrolltoprompt(const Arg *arg) +{ + int x, y; + #if REFLOW_PATCH + int top = term.scr - term.histf; + #else + int top = term.scr - term.histn; + #endif // REFLOW_PATCH + int bot = term.scr + term.row-1; + int dy = arg->i; + Line line; + + if (!dy || tisaltscr()) + return; + + for (y = dy; y >= top && y <= bot; y += dy) { + for (line = TLINE(y), x = 0; x < term.col; x++) { + if (line[x].mode & ATTR_FTCS_PROMPT) + goto scroll; + } + } + +scroll: + if (dy < 0) + kscrollup(&((Arg){ .i = -y })); + else + kscrolldown(&((Arg){ .i = y })); +} diff --git a/patch/osc133.h b/patch/osc133.h new file mode 100644 index 0000000..f5a6c45 --- /dev/null +++ b/patch/osc133.h @@ -0,0 +1 @@ +static void scrolltoprompt(const Arg *); diff --git a/patch/x_include.c b/patch/x_include.c index 73a709a..30b77da 100644 --- a/patch/x_include.c +++ b/patch/x_include.c @@ -46,4 +46,7 @@ #endif #if XRESOURCES_PATCH #include "xresources.c" -#endif \ No newline at end of file +#endif +#if OSC133_PATCH +#include "osc133.c" +#endif diff --git a/patch/x_include.h b/patch/x_include.h index b94317c..78290e1 100644 --- a/patch/x_include.h +++ b/patch/x_include.h @@ -41,3 +41,6 @@ #if XRESOURCES_PATCH #include "xresources.h" #endif +#if OSC133_PATCH +#include "osc133.h" +#endif diff --git a/patches.def.h b/patches.def.h index cb1b958..65d883c 100644 --- a/patches.def.h +++ b/patches.def.h @@ -301,6 +301,13 @@ */ #define OPENURLONCLICK_PATCH 0 +/* This patch allows jumping between prompts by utilizing the OSC 133 escape sequence + * emitted by shells. Must be used with either reflow or scrollback patch. + * + * https://codeberg.org/dnkl/foot#jumping-between-prompts + */ +#define OSC133_PATCH 0 + /* Reflow. * Allows st to be resized without cutting off text when the terminal window is made larger again. * Text wraps when the terminal window is made smaller. diff --git a/sixel.c b/sixel.c index ad6f6bc..208fc4c 100644 --- a/sixel.c +++ b/sixel.c @@ -261,10 +261,10 @@ sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, sixel_image_t *image = &st->image; int x, y; sixel_color_no_t *src; - sixel_color_t *dst; - int color; + sixel_color_t *dst, color; int w, h; int i, j, cols, numimages; + char trans; ImageList *im, *next, *tail; if (!image->data) @@ -311,7 +311,6 @@ sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, im->clipmask = NULL; im->cw = cw; im->ch = ch; - im->transparent = st->transparent; } if (!im || !im->pixels) { for (im = *newimages; im; im = next) { @@ -324,11 +323,15 @@ sixel_parser_finalize(sixel_state_t *st, ImageList **newimages, int cx, int cy, return -1; } dst = (sixel_color_t *)im->pixels; - for (j = 0; j < im->height && y < h; j++, y++) { + for (trans = 0, j = 0; j < im->height && y < h; j++, y++) { src = st->image.data + image->width * y; - for (x = 0; x < w; x++) - *dst++ = st->image.palette[*src++]; + for (x = 0; x < w; x++) { + color = st->image.palette[*src++]; + trans |= (color == 0); + *dst++ = color; + } } + im->transparent = (st->transparent && trans); } return numimages; diff --git a/st.c b/st.c index 4721ee2..7b25227 100644 --- a/st.c +++ b/st.c @@ -2603,8 +2603,8 @@ strhandle(void) { defaultcs, "cursor" } }; #if SIXEL_PATCH - ImageList *im, *newimages, *next, *tail; - int i, x1, y1, x2, y2, numimages; + ImageList *im, *newimages, *next, *tail = NULL; + int i, x1, y1, x2, y2, y, numimages; int cx, cy; Line line; #if SCROLLBACK_PATCH || REFLOW_PATCH @@ -2699,6 +2699,25 @@ strhandle(void) tfulldirt(); } return; + #if OSC133_PATCH + case 133: + if (narg < 2) + break; + switch (*strescseq.args[1]) { + case 'A': + term.c.attr.mode |= ATTR_FTCS_PROMPT; + break; + /* We don't handle these arguments yet */ + case 'B': + case 'C': + case 'D': + break; + default: + fprintf(stderr, "erresc: unknown OSC 133 argument: %c\n", *strescseq.args[1]); + break; + } + return; + #endif // OSC133_PATCH } break; case 'k': /* old title set compatibility */ @@ -2729,15 +2748,33 @@ strhandle(void) y1 = newimages->y; x2 = x1 + newimages->cols; y2 = y1 + numimages; - if (newimages->transparent) { - for (tail = term.images; tail && tail->next; tail = tail->next); - } else { - for (tail = NULL, im = term.images; im; im = next) { + /* Delete the old images that are covered by the new image(s). We also need + * to check if they have already been deleted before adding the new ones. */ + if (term.images) { + char transparent[numimages]; + for (i = 0, im = newimages; im; im = im->next, i++) { + transparent[i] = im->transparent; + } + for (im = term.images; im; im = next) { next = im->next; - if (im->x >= x1 && im->x + im->cols <= x2 && - im->y >= y1 && im->y <= y2) { - delete_image(im); - continue; + if (im->y >= y1 && im->y < y2) { + y = im->y - scr; + if (y >= 0 && y < term.row && term.dirty[y]) { + line = term.line[y]; + j = MIN(im->x + im->cols, term.col); + for (i = im->x; i < j; i++) { + if (line[i].mode & ATTR_SIXEL) + break; + } + if (i == j) { + delete_image(im); + continue; + } + } + if (im->x >= x1 && im->x + im->cols <= x2 && !transparent[im->y - y1]) { + delete_image(im); + continue; + } } tail = im; } @@ -3431,6 +3468,9 @@ check_control_code: } tsetchar(u, &term.c.attr, term.c.x, term.c.y); + #if OSC133_PATCH + term.c.attr.mode &= ~ATTR_FTCS_PROMPT; + #endif // OSC133_PATCH term.lastc = u; if (width == 2) { diff --git a/st.h b/st.h index 95d1be1..cd6982e 100644 --- a/st.h +++ b/st.h @@ -70,6 +70,9 @@ enum glyph_attribute { ATTR_HIGHLIGHT = 1 << 17, #endif // KEYBOARDSELECT_PATCH ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT, + #if OSC133_PATCH + ATTR_FTCS_PROMPT = 1 << 18, /* OSC 133 ; A ST */ + #endif // OSC133_PATCH }; #if SIXEL_PATCH