Add support for marking lines with a shell prompt based on the OSC 133

extension, from Munif Tanjim in GitHub issue 3596.
This commit is contained in:
nicm 2023-07-03 16:47:43 +00:00
parent ac43186dff
commit 43b841f188
4 changed files with 108 additions and 0 deletions

22
input.c
View File

@ -144,6 +144,7 @@ static void input_osc_104(struct input_ctx *, const char *);
static void input_osc_110(struct input_ctx *, const char *);
static void input_osc_111(struct input_ctx *, const char *);
static void input_osc_112(struct input_ctx *, const char *);
static void input_osc_133(struct input_ctx *, const char *);
/* Transition entry/exit handlers. */
static void input_clear(struct input_ctx *);
@ -2347,6 +2348,9 @@ input_exit_osc(struct input_ctx *ictx)
case 112:
input_osc_112(ictx, p);
break;
case 133:
input_osc_133(ictx, p);
break;
default:
log_debug("%s: unknown '%u'", __func__, option);
break;
@ -2736,6 +2740,24 @@ input_osc_112(struct input_ctx *ictx, const char *p)
screen_set_cursor_colour(ictx->ctx.s, -1);
}
/* Handle the OSC 133 sequence. */
static void
input_osc_133(struct input_ctx *ictx, const char *p)
{
struct grid *gd = ictx->ctx.s->grid;
u_int line = ictx->ctx.s->cy + gd->hsize;
struct grid_line *gl;
if (line > gd->hsize + gd->sy - 1)
return;
gl = grid_get_line(gd, line);
switch (*p) {
case 'A':
gl->flags |= GRID_LINE_START_PROMPT;
break;
}
}
/* Handle the OSC 52 sequence for setting the clipboard. */
static void

12
tmux.1
View File

@ -1787,6 +1787,7 @@ The following commands are supported in copy mode:
.It Li "middle-line" Ta "M" Ta "M-r"
.It Li "next-matching-bracket" Ta "%" Ta "M-C-f"
.It Li "next-paragraph" Ta "}" Ta "M-}"
.It Li "next-prompt" Ta "" Ta ""
.It Li "next-space" Ta "W" Ta ""
.It Li "next-space-end" Ta "E" Ta ""
.It Li "next-word" Ta "w" Ta ""
@ -1800,6 +1801,7 @@ The following commands are supported in copy mode:
.It Li "pipe-and-cancel [<command>] [<prefix>]" Ta "" Ta ""
.It Li "previous-matching-bracket" Ta "" Ta "M-C-b"
.It Li "previous-paragraph" Ta "{" Ta "M-{"
.It Li "previous-prompt" Ta "" Ta ""
.It Li "previous-space" Ta "B" Ta ""
.It Li "previous-word" Ta "b" Ta "M-b"
.It Li "rectangle-on" Ta "" Ta ""
@ -1849,6 +1851,16 @@ repeats the last search and
does the same but reverses the direction (forward becomes backward and backward
becomes forward).
.Pp
The
.Ql next-prompt
and
.Ql previous-prompt
move between shell prompts, but require the shell to emit an escape sequence
(\e033]133;A\e033\e\e) to tell
.Nm
where the prompts are located; if the shell does not do this, these commands
will do nothing.
.Pp
Copy commands may take an optional buffer prefix argument which is used
to generate the buffer name (the default is
.Ql buffer

1
tmux.h
View File

@ -671,6 +671,7 @@ struct colour_palette {
#define GRID_LINE_WRAPPED 0x1
#define GRID_LINE_EXTENDED 0x2
#define GRID_LINE_DEAD 0x4
#define GRID_LINE_START_PROMPT 0x8
/* Grid string flags. */
#define GRID_STRING_WITH_SEQUENCES 0x1

View File

@ -131,6 +131,7 @@ static void window_copy_cursor_previous_word_pos(struct window_mode_entry *,
const char *, u_int *, u_int *);
static void window_copy_cursor_previous_word(struct window_mode_entry *,
const char *, int);
static void window_copy_cursor_prompt(struct window_mode_entry *, int);
static void window_copy_scroll_up(struct window_mode_entry *, u_int);
static void window_copy_scroll_down(struct window_mode_entry *, u_int);
static void window_copy_rectangle_set(struct window_mode_entry *, int);
@ -2240,6 +2241,24 @@ window_copy_cmd_jump_to_mark(struct window_copy_cmd_state *cs)
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_next_prompt(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
window_copy_cursor_prompt(wme, 1);
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_previous_prompt(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
window_copy_cursor_prompt(wme, 0);
return (WINDOW_COPY_CMD_NOTHING);
}
static enum window_copy_cmd_action
window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
{
@ -2694,6 +2713,18 @@ static const struct {
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_jump_to_mark
},
{ .command = "next-prompt",
.minargs = 0,
.maxargs = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_next_prompt
},
{ .command = "previous-prompt",
.minargs = 0,
.maxargs = 0,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_previous_prompt
},
{ .command = "middle-line",
.minargs = 0,
.maxargs = 0,
@ -5357,6 +5388,48 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme,
window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
}
static void
window_copy_cursor_prompt(struct window_mode_entry *wme, int direction)
{
struct window_copy_mode_data *data = wme->data;
struct screen *s = data->backing;
struct grid *gd = s->grid;
u_int end_line;
u_int line = gd->hsize - data->oy + data->cy;
int add;
if (direction == 0) { /* up */
add = -1;
end_line = 0;
} else { /* down */
add = 1;
end_line = gd->hsize + gd->sy - 1;
}
if (line == end_line)
return;
for (;;) {
if (line == end_line)
return;
line += add;
if (grid_get_line(gd, line)->flags & GRID_LINE_START_PROMPT)
break;
}
data->cx = 0;
if (line > gd->hsize) {
data->cy = line - gd->hsize;
data->oy = 0;
} else {
data->cy = 0;
data->oy = gd->hsize - line;
}
window_copy_update_selection(wme, 1, 0);
window_copy_redraw_screen(wme);
}
static void
window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
{