mirror of
https://github.com/tmux/tmux.git
synced 2026-10-07 02:04:22 +00:00
Fix clear issue which lost C and A osc133 markers. Several cleanups.
This commit is contained in:
111
input.c
111
input.c
@@ -95,6 +95,14 @@ struct input_param {
|
||||
};
|
||||
};
|
||||
|
||||
/* Saved OSC 133 output marker. */
|
||||
struct input_osc_133_ctx {
|
||||
int running;
|
||||
u_int start;
|
||||
u_int col;
|
||||
u_int collected;
|
||||
};
|
||||
|
||||
/* Input parser context. */
|
||||
struct input_ctx {
|
||||
struct window_pane *wp;
|
||||
@@ -173,6 +181,9 @@ 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 *);
|
||||
static struct input_osc_133_ctx input_osc_133_save_marker(struct input_ctx *);
|
||||
static void input_osc_133_restore_marker(struct input_ctx *,
|
||||
const struct input_osc_133_ctx *);
|
||||
|
||||
/* Transition entry/exit handlers. */
|
||||
static void input_clear(struct input_ctx *);
|
||||
@@ -1466,6 +1477,7 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
struct screen *s = sctx->s;
|
||||
const struct input_table_entry *entry;
|
||||
struct options *oo;
|
||||
struct input_osc_133_ctx osc133 = {0};
|
||||
int i, n, m, ek, set, p;
|
||||
u_int cx, bg = ictx->cell.cell.bg;
|
||||
|
||||
@@ -1739,13 +1751,19 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
case -1:
|
||||
break;
|
||||
case 0:
|
||||
/* Erasing to the end clears the whole screen at 0,0. */
|
||||
if (s->cx == 0 && s->cy == 0)
|
||||
osc133 = input_osc_133_save_marker(ictx);
|
||||
screen_write_clearendofscreen(sctx, bg);
|
||||
input_osc_133_restore_marker(ictx, &osc133);
|
||||
break;
|
||||
case 1:
|
||||
screen_write_clearstartofscreen(sctx, bg);
|
||||
break;
|
||||
case 2:
|
||||
osc133 = input_osc_133_save_marker(ictx);
|
||||
screen_write_clearscreen(sctx, bg);
|
||||
input_osc_133_restore_marker(ictx, &osc133);
|
||||
break;
|
||||
case 3:
|
||||
if (input_get(ictx, 1, 0, 0) == 0) {
|
||||
@@ -3278,6 +3296,77 @@ input_osc_133_secondary_prompt(const char *p)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Record the first primary or secondary prompt marker on a line. */
|
||||
static void
|
||||
input_osc_133_mark_prompt(struct grid_line *gl, u_int col, const char *p)
|
||||
{
|
||||
if (gl == NULL || gl->flags &
|
||||
(GRID_LINE_START_PROMPT|GRID_LINE_SECOND_PROMPT))
|
||||
return;
|
||||
gl->osc133_data.prompt_col = col;
|
||||
if (input_osc_133_secondary_prompt(p))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
}
|
||||
|
||||
/* Save the running command's output start before clearing the screen. */
|
||||
static struct input_osc_133_ctx
|
||||
input_osc_133_save_marker(struct input_ctx *ictx)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct screen *s = ictx->ctx.s;
|
||||
struct grid *gd = s->grid;
|
||||
struct grid_line *gl;
|
||||
struct input_osc_133_ctx ctx = {0};
|
||||
u_int y;
|
||||
|
||||
if (wp == NULL || s != &wp->base || SCREEN_IS_ALTERNATE(s) ||
|
||||
(~wp->flags & PANE_CMDRUNNING))
|
||||
return (ctx);
|
||||
ctx.running = 1;
|
||||
ctx.start = UINT_MAX;
|
||||
ctx.collected = gd->scroll_collected;
|
||||
for (y = gd->hsize + gd->sy; y > 0; y--) {
|
||||
gl = grid_get_line(gd, y - 1);
|
||||
if ((gl->flags & GRID_LINE_START_OUTPUT) &&
|
||||
(~gl->flags & GRID_LINE_END_OUTPUT ||
|
||||
gl->osc133_data.out_end_col < gl->osc133_data.out_start_col) &&
|
||||
(~gl->flags & GRID_LINE_START_PROMPT ||
|
||||
gl->osc133_data.prompt_col <= gl->osc133_data.out_start_col)) {
|
||||
ctx.start = y - 1;
|
||||
ctx.col = gl->osc133_data.out_start_col;
|
||||
break;
|
||||
}
|
||||
if (gl->flags & (GRID_LINE_START_PROMPT|GRID_LINE_END_OUTPUT))
|
||||
break;
|
||||
}
|
||||
return (ctx);
|
||||
}
|
||||
|
||||
/* Restore the running command's output start if a screen clear removed it. */
|
||||
static void
|
||||
input_osc_133_restore_marker(struct input_ctx *ictx,
|
||||
const struct input_osc_133_ctx *ctx)
|
||||
{
|
||||
struct grid *gd = ictx->ctx.s->grid;
|
||||
struct grid_line *gl;
|
||||
u_int collected;
|
||||
|
||||
if (!ctx->running)
|
||||
return;
|
||||
collected = gd->scroll_collected - ctx->collected;
|
||||
if (ctx->start != UINT_MAX && ctx->start >= collected) {
|
||||
gl = grid_get_line(gd, ctx->start - collected);
|
||||
if ((gl->flags & GRID_LINE_START_OUTPUT) &&
|
||||
gl->osc133_data.out_start_col == ctx->col)
|
||||
return;
|
||||
}
|
||||
gl = grid_get_line(gd, gd->hsize);
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
gl->osc133_data.out_start_col = 0;
|
||||
}
|
||||
|
||||
/* Handle the OSC 133 sequence. */
|
||||
static void
|
||||
input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
@@ -3295,32 +3384,14 @@ input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
switch (*p) {
|
||||
case 'A':
|
||||
case 'N':
|
||||
if (gl != NULL) {
|
||||
if (!(gl->flags & (GRID_LINE_START_PROMPT|
|
||||
GRID_LINE_SECOND_PROMPT))) {
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
if (input_osc_133_secondary_prompt(p))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
}
|
||||
}
|
||||
input_osc_133_mark_prompt(gl, s->cx, p);
|
||||
if (wp != NULL) {
|
||||
wp->last_prompt_time = time(NULL);
|
||||
events_fire_pane("pane-shell-prompt", wp);
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
if (gl != NULL) {
|
||||
if (!(gl->flags & (GRID_LINE_START_PROMPT|
|
||||
GRID_LINE_SECOND_PROMPT))) {
|
||||
gl->osc133_data.prompt_col = s->cx;
|
||||
if (input_osc_133_secondary_prompt(p))
|
||||
gl->flags |= GRID_LINE_SECOND_PROMPT;
|
||||
else
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
}
|
||||
}
|
||||
input_osc_133_mark_prompt(gl, s->cx, p);
|
||||
break;
|
||||
case 'B':
|
||||
case 'I':
|
||||
|
||||
@@ -140,6 +140,103 @@ $TMUX send-keys -t :clear.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'PID TTY\n1 pts/0')" ] || exit 1
|
||||
$TMUX send-keys -t :clear.0 -X cancel || exit 1
|
||||
|
||||
# Select from either output line after clearing the screen.
|
||||
for view in normal unfolded; do
|
||||
for steps in 2 3; do
|
||||
if [ "$view" = unfolded ]; then
|
||||
$TMUX copy-mode -U -t :clear || exit 1
|
||||
else
|
||||
$TMUX copy-mode -t :clear || exit 1
|
||||
fi
|
||||
$TMUX send-keys -t :clear.0 -X -N "$steps" cursor-up || exit 1
|
||||
$TMUX send-keys -t :clear.0 C-o || exit 1
|
||||
[ "$($TMUX display-message -p -t :clear.0 '#{selection_present}')" = 1 ] || exit 1
|
||||
$TMUX set-buffer sentinel || exit 1
|
||||
$TMUX send-keys -t :clear.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'PID TTY\n1 pts/0')" ] || exit 1
|
||||
$TMUX send-keys -t :clear.0 -X cancel || exit 1
|
||||
done
|
||||
done
|
||||
|
||||
$TMUX set-option -g scroll-on-clear on || exit 1
|
||||
$TMUX new-window -d -n clearprompt "printf '\\033]133;A\\007p\\$ \\033]133;B\\007clear; echo hello; echo world\\n\\033]133;C\\007\\033[H\\033[2J\\033[3Jhello\\nworld\\n\\033]133;D;0\\007\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
for steps in 1 2; do
|
||||
$TMUX copy-mode -t :clearprompt || exit 1
|
||||
$TMUX send-keys -t :clearprompt.0 -X -N "$steps" cursor-up || exit 1
|
||||
$TMUX send-keys -t :clearprompt.0 C-o || exit 1
|
||||
[ "$($TMUX display-message -p -t :clearprompt.0 '#{selection_present}')" = 1 ] || exit 1
|
||||
$TMUX set-buffer sentinel || exit 1
|
||||
$TMUX send-keys -t :clearprompt.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'hello\nworld')" ] || exit 1
|
||||
$TMUX send-keys -t :clearprompt.0 -X cancel || exit 1
|
||||
done
|
||||
|
||||
# A screen clear must not pull earlier commands or plain scrollback into output.
|
||||
for integration in plain marked; do
|
||||
for erase in J 2J; do
|
||||
$TMUX set-option -g scroll-on-clear off || exit 1
|
||||
if [ "$integration" = marked ]; then
|
||||
prefix='\033]133;A\007old>\033]133;B\007seq\n\033]133;C\007'
|
||||
ending='\033]133;D;0\007'
|
||||
else
|
||||
prefix=
|
||||
ending=
|
||||
fi
|
||||
$TMUX new-window -d -n retained "printf '$prefix'; seq 1 40; printf '$ending\\033]133;A\\007p\\$ \\033]133;B\\007clear; echo hello; echo world\\n\\033]133;C\\007\\033[H\\033[${erase}hello\\nworld\\n\\033]133;D;0\\007\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
[ "$($TMUX display-message -p -t :retained.0 '#{history_size}')" -gt 0 ] || exit 1
|
||||
for steps in 0 1 2; do
|
||||
$TMUX copy-mode -t :retained || exit 1
|
||||
if [ "$steps" -gt 0 ]; then
|
||||
$TMUX send-keys -t :retained.0 -X -N "$steps" cursor-up || exit 1
|
||||
fi
|
||||
$TMUX send-keys -t :retained.0 C-o || exit 1
|
||||
[ "$($TMUX display-message -p -t :retained.0 '#{selection_present}')" = 1 ] || exit 1
|
||||
$TMUX set-buffer sentinel || exit 1
|
||||
$TMUX send-keys -t :retained.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'hello\nworld')" ] || exit 1
|
||||
$TMUX send-keys -t :retained.0 -X cancel || exit 1
|
||||
done
|
||||
$TMUX kill-window -t :retained || exit 1
|
||||
done
|
||||
done
|
||||
|
||||
# Preserve C when scroll-on-clear keeps the command's earlier output.
|
||||
$TMUX set-option -g scroll-on-clear on || exit 1
|
||||
$TMUX new-window -d -n preserve "printf '\\033]133;A\\007p\\$ \\033]133;B\\007echo before; clear; echo hello; echo world\\n\\033]133;C\\007before\\n\\033[H\\033[2Jhello\\nworld\\n\\033]133;D;0\\007\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :preserve || exit 1
|
||||
$TMUX set-buffer sentinel || exit 1
|
||||
$TMUX send-keys -t :preserve.0 -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'before\nhello\nworld')" ] || exit 1
|
||||
$TMUX send-keys -t :preserve.0 -X cancel || exit 1
|
||||
|
||||
# An unfinished command can be selected using its restored C without D.
|
||||
$TMUX set-option -g scroll-on-clear off || exit 1
|
||||
$TMUX new-window -d -n running "seq 1 40; printf '\\033]133;A\\007p\\$ \\033]133;B\\007clear; echo hello; echo world\\n\\033]133;C\\007\\033[H\\033[2Jhello\\nworld\\n'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :running || exit 1
|
||||
$TMUX send-keys -t :running.0 -X cursor-up || exit 1
|
||||
$TMUX send-keys -t :running.0 C-o || exit 1
|
||||
[ "$($TMUX display-message -p -t :running.0 '#{selection_present}')" = 1 ] || exit 1
|
||||
$TMUX set-buffer sentinel || exit 1
|
||||
$TMUX send-keys -t :running.0 -X copy-selection || exit 1
|
||||
[ "$($TMUX show-buffer)" = "$(printf 'hello\nworld')" ] || exit 1
|
||||
$TMUX send-keys -t :running.0 -X cancel || exit 1
|
||||
|
||||
# Do not infer output from a D which belongs to the first surviving prompt.
|
||||
$TMUX new-window -d -n prefix "printf 'prefix\\n\\033]133;A\\007p\\$ \\033]133;B\\007echo\\033]133;C\\007one\\033]133;D;0\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :prefix || exit 1
|
||||
$TMUX send-keys -t :prefix.0 -X cursor-up || exit 1
|
||||
$TMUX send-keys -t :prefix.0 C-o || exit 1
|
||||
[ "$($TMUX display-message -p -t :prefix.0 '#{selection_present}')" = 0 ] || exit 1
|
||||
$TMUX set-buffer sentinel || exit 1
|
||||
$TMUX send-keys -t :prefix.0 -X copy-output || exit 1
|
||||
[ "$($TMUX show-buffer)" = sentinel ] || exit 1
|
||||
$TMUX send-keys -t :prefix.0 -X cancel || exit 1
|
||||
|
||||
$TMUX new-window -d -n oneline "printf '\\033]133;A\\007p\\$ \\033]133;B\\007echo\\n\\033]133;C\\007one\\033]133;D;0\\007\\nseparator\\n\\033]133;A\\007p\\$ \\033]133;B\\007'; exec sleep 100" || exit 1
|
||||
sleep 1
|
||||
$TMUX copy-mode -t :oneline || exit 1
|
||||
|
||||
245
window-copy.c
245
window-copy.c
@@ -27,6 +27,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
struct window_copy_mode_data;
|
||||
struct window_copy_fold_request;
|
||||
|
||||
#define WINDOW_COPY_LINE_CONTROL 0x1
|
||||
#define WINDOW_COPY_LINE_MEMBER 0x2
|
||||
@@ -82,8 +83,8 @@ static void window_copy_write_line(struct window_mode_entry *,
|
||||
static void window_copy_write_lines(struct window_mode_entry *,
|
||||
struct screen_write_ctx *, u_int, u_int);
|
||||
static void window_copy_rebuild_backing(struct window_mode_entry *);
|
||||
static int window_copy_set_fold(struct window_mode_entry *, int, int,
|
||||
u_int, int);
|
||||
static int window_copy_set_fold(struct window_mode_entry *,
|
||||
const struct window_copy_fold_request *);
|
||||
static int window_copy_find_fold(struct window_mode_entry *, u_int,
|
||||
u_int *, u_int *);
|
||||
static void window_copy_cursor_source(struct window_mode_entry *, u_int *,
|
||||
@@ -285,6 +286,32 @@ struct window_copy_cmd_state {
|
||||
struct winlink *wl;
|
||||
};
|
||||
|
||||
enum window_copy_fold_action {
|
||||
WINDOW_COPY_FOLD_COLLAPSE,
|
||||
WINDOW_COPY_FOLD_EXPAND,
|
||||
WINDOW_COPY_FOLD_TOGGLE,
|
||||
};
|
||||
|
||||
struct window_copy_fold_request {
|
||||
enum window_copy_fold_action action;
|
||||
int all;
|
||||
u_int target;
|
||||
int command_end;
|
||||
};
|
||||
|
||||
/* State carried across source lines while rebuilding the folded screen. */
|
||||
struct window_copy_fold_ctx {
|
||||
u_int prompt_dy;
|
||||
u_int output_line;
|
||||
int collapsed;
|
||||
int command;
|
||||
int hiding;
|
||||
int tree;
|
||||
int in_output;
|
||||
int output_empty;
|
||||
int initial;
|
||||
};
|
||||
|
||||
struct window_copy_line {
|
||||
u_int source_line;
|
||||
u_int output_line;
|
||||
@@ -707,11 +734,12 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid_cell gc;
|
||||
struct osc133_data *osc133;
|
||||
u_int y, x, total, dy, prompt_dy = UINT_MAX;
|
||||
u_int output_line = UINT_MAX;
|
||||
int collapsed = 0, command = 0, hiding = 0, tree = 0;
|
||||
int in_output = 0, output_empty = 0;
|
||||
int initial = 0, was_hiding;
|
||||
struct window_copy_fold_ctx fold = {
|
||||
.prompt_dy = UINT_MAX,
|
||||
.output_line = UINT_MAX
|
||||
};
|
||||
u_int y, x, total, dy;
|
||||
int was_hiding;
|
||||
|
||||
if (src == NULL)
|
||||
return;
|
||||
@@ -751,7 +779,7 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
* The source begins in an existing command or its output. Treat its
|
||||
* first line as a synthetic command for the region before the first A.
|
||||
*/
|
||||
initial = 1;
|
||||
fold.initial = 1;
|
||||
|
||||
screen_write_start(&ctx, dst);
|
||||
/*
|
||||
@@ -764,21 +792,22 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
osc133 = &sgl->osc133_data;
|
||||
for (x = 0; x <= sgl->cellused; x++) {
|
||||
dy = dst->grid->hsize + dst->cy;
|
||||
was_hiding = hiding;
|
||||
if (!hiding)
|
||||
was_hiding = fold.hiding;
|
||||
if (!fold.hiding)
|
||||
/*
|
||||
* Row is visible. Records the source
|
||||
* row and current output-block identity
|
||||
* for cursor restoration, selection,
|
||||
* gutter drawing, and line numbers.
|
||||
*/
|
||||
window_copy_set_line(data, dy, y, output_line, 0);
|
||||
window_copy_set_line(data, dy, y,
|
||||
fold.output_line, 0);
|
||||
/*
|
||||
* Continue even if row is folded because
|
||||
* there may be markers to process.
|
||||
*/
|
||||
dgl = grid_get_line(dst->grid, dy);
|
||||
if (initial && y == 0 && x == 0)
|
||||
if (fold.initial && y == 0 && x == 0)
|
||||
/* Top line of buffer, no osc133 marker yet.
|
||||
* Attach controls to top line, make it a
|
||||
* "synthetic command" so top lines can fold.
|
||||
@@ -793,17 +822,19 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
*/
|
||||
dgl->flags |= GRID_LINE_START_OUTPUT;
|
||||
dgl->osc133_data.out_start_col = dst->cx;
|
||||
output_line = y;
|
||||
tree = 1; /* used to draw the | or L in gutter */
|
||||
in_output = 1;
|
||||
output_empty = 1;
|
||||
collapsed = data->source_flags[y] &
|
||||
fold.output_line = y;
|
||||
/* used to draw the | or L in gutter */
|
||||
fold.tree = 1;
|
||||
fold.in_output = 1;
|
||||
fold.output_empty = 1;
|
||||
fold.collapsed = data->source_flags[y] &
|
||||
WINDOW_COPY_FOLD_COLLAPSED;
|
||||
hiding = collapsed; /* Start/stop hiding cells */
|
||||
if (prompt_dy != UINT_MAX)
|
||||
/* Start/stop hiding cells */
|
||||
fold.hiding = fold.collapsed;
|
||||
if (fold.prompt_dy != UINT_MAX)
|
||||
/* Attach +/- controls to the prompt. */
|
||||
window_copy_set_control(data, prompt_dy,
|
||||
output_line, 1);
|
||||
window_copy_set_control(data,
|
||||
fold.prompt_dy, fold.output_line, 1);
|
||||
}
|
||||
if ((sgl->flags & GRID_LINE_END_OUTPUT) &&
|
||||
x == osc133->out_end_col) {
|
||||
@@ -819,56 +850,60 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
dgl->flags |= GRID_LINE_END_OUTPUT_STATUS;
|
||||
dgl->osc133_data.out_end_col = dst->cx;
|
||||
dgl->osc133_data.exit_status = osc133->exit_status;
|
||||
if (in_output && output_empty && prompt_dy != UINT_MAX) {
|
||||
line = window_copy_get_line_info(data, prompt_dy);
|
||||
if (fold.in_output && fold.output_empty &&
|
||||
fold.prompt_dy != UINT_MAX) {
|
||||
line = window_copy_get_line_info(data,
|
||||
fold.prompt_dy);
|
||||
if (line != NULL)
|
||||
/* No output to hide, no +/-. */
|
||||
line->flags &= ~WINDOW_COPY_LINE_EXPANDABLE;
|
||||
}
|
||||
in_output = 0;
|
||||
if (output_line == UINT_MAX && command) {
|
||||
fold.in_output = 0;
|
||||
if (fold.output_line == UINT_MAX &&
|
||||
fold.command) {
|
||||
/*
|
||||
* Saw osc133 B but not C marker.
|
||||
* This could be user pressed enter
|
||||
* or command like 'true' with no
|
||||
* output.
|
||||
*/
|
||||
output_line = y;
|
||||
tree = 1;
|
||||
fold.output_line = y;
|
||||
fold.tree = 1;
|
||||
/* Block is collapsed? */
|
||||
collapsed = data->source_flags[y] &
|
||||
fold.collapsed = data->source_flags[y] &
|
||||
WINDOW_COPY_FOLD_COLLAPSED;
|
||||
if (prompt_dy != UINT_MAX)
|
||||
if (fold.prompt_dy != UINT_MAX)
|
||||
/*
|
||||
* Make this a +/- control row
|
||||
* but without the +/- for now
|
||||
* since we don't know what
|
||||
* comes below.
|
||||
*/
|
||||
window_copy_set_control(data, prompt_dy,
|
||||
output_line, 0);
|
||||
window_copy_set_control(data,
|
||||
fold.prompt_dy,
|
||||
fold.output_line, 0);
|
||||
}
|
||||
if (prompt_dy != UINT_MAX &&
|
||||
if (fold.prompt_dy != UINT_MAX &&
|
||||
sgl->flags & GRID_LINE_END_OUTPUT_STATUS)
|
||||
/*
|
||||
* osc133 D, record exit status on the
|
||||
* command's prompt row.
|
||||
*/
|
||||
window_copy_set_exit_status(data, prompt_dy,
|
||||
osc133->exit_status);
|
||||
if (initial && prompt_dy == UINT_MAX)
|
||||
window_copy_set_exit_status(data,
|
||||
fold.prompt_dy, osc133->exit_status);
|
||||
if (fold.initial && fold.prompt_dy == UINT_MAX)
|
||||
/* At top of buffer before first osc A
|
||||
* marker use first line's fold state.
|
||||
*/
|
||||
hiding = data->source_flags[0] &
|
||||
fold.hiding = data->source_flags[0] &
|
||||
WINDOW_COPY_FOLD_COLLAPSED;
|
||||
else
|
||||
/*
|
||||
* Otherwise, use the current block's
|
||||
* fold state.
|
||||
*/
|
||||
hiding = collapsed;
|
||||
command = 0;
|
||||
fold.hiding = fold.collapsed;
|
||||
fold.command = 0;
|
||||
}
|
||||
/*
|
||||
* Process osc133 C and D before a following prompt
|
||||
@@ -879,10 +914,11 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
/* osc133 A ends region, starts new prompt. */
|
||||
dgl->flags |= GRID_LINE_START_PROMPT;
|
||||
dgl->osc133_data.prompt_col = dst->cx;
|
||||
prompt_dy = dy;
|
||||
output_line = UINT_MAX;
|
||||
collapsed = command = hiding = tree = 0;
|
||||
in_output = output_empty = 0;
|
||||
fold.prompt_dy = dy;
|
||||
fold.output_line = UINT_MAX;
|
||||
fold.collapsed = fold.command = 0;
|
||||
fold.hiding = fold.tree = 0;
|
||||
fold.in_output = fold.output_empty = 0;
|
||||
}
|
||||
if ((sgl->flags & GRID_LINE_SECOND_PROMPT) &&
|
||||
x == osc133->prompt_col) {
|
||||
@@ -895,44 +931,48 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
/* osc133 B marks start/continue of command. */
|
||||
dgl->flags |= GRID_LINE_START_COMMAND;
|
||||
dgl->osc133_data.cmd_col = dst->cx;
|
||||
command = 1;
|
||||
fold.command = 1;
|
||||
}
|
||||
/*
|
||||
* An osc133 A may expose the remainder of this source
|
||||
* line after a folded region.
|
||||
*/
|
||||
if (was_hiding && !hiding)
|
||||
window_copy_set_line(data, dy, y, output_line, 0);
|
||||
if (was_hiding && !fold.hiding)
|
||||
window_copy_set_line(data, dy, y,
|
||||
fold.output_line, 0);
|
||||
if (x == sgl->cellused)
|
||||
break;
|
||||
grid_get_cell(sgd, x, y, &gc);
|
||||
if (in_output && !(gc.flags & GRID_FLAG_PADDING))
|
||||
output_empty = 0;
|
||||
if (fold.in_output && !(gc.flags & GRID_FLAG_PADDING))
|
||||
fold.output_empty = 0;
|
||||
/* Separator text after D is also expandable. */
|
||||
if (!in_output && tree && output_line != UINT_MAX &&
|
||||
!(gc.flags & GRID_FLAG_PADDING) && prompt_dy != UINT_MAX)
|
||||
window_copy_set_control(data, prompt_dy, output_line, 1);
|
||||
if (!fold.in_output && fold.tree &&
|
||||
fold.output_line != UINT_MAX &&
|
||||
!(gc.flags & GRID_FLAG_PADDING) &&
|
||||
fold.prompt_dy != UINT_MAX)
|
||||
window_copy_set_control(data, fold.prompt_dy,
|
||||
fold.output_line, 1);
|
||||
/*
|
||||
* osc133 marker processing continues while folded, but
|
||||
* cell output does not.
|
||||
*/
|
||||
if (hiding)
|
||||
if (fold.hiding)
|
||||
continue;
|
||||
if (!(gc.flags & GRID_FLAG_PADDING)) {
|
||||
screen_write_cell(&ctx, &gc);
|
||||
if (tree)
|
||||
window_copy_set_line(data, dy, y, output_line,
|
||||
WINDOW_COPY_LINE_MEMBER);
|
||||
if (fold.tree)
|
||||
window_copy_set_line(data, dy, y,
|
||||
fold.output_line, WINDOW_COPY_LINE_MEMBER);
|
||||
}
|
||||
}
|
||||
if (!hiding && tree && sgl->cellused == 0 &&
|
||||
if (!fold.hiding && fold.tree && sgl->cellused == 0 &&
|
||||
~(sgl->flags) & (GRID_LINE_START_PROMPT |
|
||||
GRID_LINE_START_OUTPUT | GRID_LINE_END_OUTPUT))
|
||||
/* Mark empty visible lines so gutter tree continues */
|
||||
window_copy_set_line(data, dy, y, output_line,
|
||||
window_copy_set_line(data, dy, y, fold.output_line,
|
||||
WINDOW_COPY_LINE_MEMBER);
|
||||
if (y + 1 != total && !(sgl->flags & GRID_LINE_WRAPPED) &&
|
||||
(!hiding || (initial && y == 0))) {
|
||||
(!fold.hiding || (fold.initial && y == 0))) {
|
||||
/*
|
||||
* Hide folded line breaks, except after the initial
|
||||
* synthetic command line (top line of copy buffer).
|
||||
@@ -940,14 +980,14 @@ window_copy_rebuild_backing(struct window_mode_entry *wme)
|
||||
screen_write_carriagereturn(&ctx);
|
||||
screen_write_linefeed(&ctx, 0, 8);
|
||||
}
|
||||
if (initial && y == 0) {
|
||||
if (fold.initial && y == 0) {
|
||||
/*
|
||||
* Top line of buffer (which may not be a command)
|
||||
* becomes our "synthisied" commmand to anchor lines
|
||||
* folded below it up to first osc133 A.
|
||||
*/
|
||||
tree = 1;
|
||||
hiding = data->source_flags[0] &
|
||||
fold.tree = 1;
|
||||
fold.hiding = data->source_flags[0] &
|
||||
WINDOW_COPY_FOLD_COLLAPSED;
|
||||
}
|
||||
}
|
||||
@@ -2143,6 +2183,9 @@ window_copy_cmd_select_output(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
struct window_mode_entry *wme = cs->wme;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct window_copy_fold_request request = {
|
||||
.action = WINDOW_COPY_FOLD_EXPAND
|
||||
};
|
||||
struct grid_reader gr;
|
||||
void *buf;
|
||||
size_t len;
|
||||
@@ -2166,8 +2209,10 @@ window_copy_cmd_select_output(struct window_copy_cmd_state *cs)
|
||||
window_copy_set_all_folds(data, 0);
|
||||
window_copy_rebuild_backing(wme);
|
||||
} else if (data->fold_view &&
|
||||
data->source_flags[sy] & WINDOW_COPY_FOLD_COLLAPSED)
|
||||
window_copy_set_fold(wme, 0, 0, sy, 0);
|
||||
data->source_flags[sy] & WINDOW_COPY_FOLD_COLLAPSED) {
|
||||
request.target = sy;
|
||||
window_copy_set_fold(wme, &request);
|
||||
}
|
||||
if (!window_copy_source_position(wme, sx, sy, &bsx, &bsy) ||
|
||||
!window_copy_source_position(wme, ex, ey, &bex, &bey))
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
@@ -4304,12 +4349,13 @@ window_copy_restore_before(struct window_mode_entry *wme, u_int source_y)
|
||||
}
|
||||
|
||||
static int
|
||||
window_copy_set_fold(struct window_mode_entry *wme, int all, int collapse,
|
||||
u_int target, int command_end)
|
||||
window_copy_set_fold(struct window_mode_entry *wme,
|
||||
const struct window_copy_fold_request *request)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
u_int prompt = 0, source_x, source_y;
|
||||
u_int chosen = UINT_MAX, first_prompt, y;
|
||||
u_int target = request->target;
|
||||
int changed = 0, enabled = 0, found, initial;
|
||||
int wanted;
|
||||
|
||||
@@ -4335,22 +4381,22 @@ window_copy_set_fold(struct window_mode_entry *wme, int all, int collapse,
|
||||
enabled = 1;
|
||||
}
|
||||
found = window_copy_find_fold(wme, target, &prompt, &chosen);
|
||||
if (all) {
|
||||
wanted = collapse;
|
||||
if (wanted == -1)
|
||||
if (request->all) {
|
||||
wanted = (request->action == WINDOW_COPY_FOLD_COLLAPSE);
|
||||
if (request->action == WINDOW_COPY_FOLD_TOGGLE)
|
||||
wanted = !window_copy_any_fold_collapsed(data);
|
||||
changed = window_copy_set_all_folds(data, wanted);
|
||||
} else if (initial) {
|
||||
wanted = collapse;
|
||||
if (wanted == -1)
|
||||
wanted = (request->action == WINDOW_COPY_FOLD_COLLAPSE);
|
||||
if (request->action == WINDOW_COPY_FOLD_TOGGLE)
|
||||
wanted = !(data->source_flags[0] &
|
||||
WINDOW_COPY_FOLD_COLLAPSED);
|
||||
if (window_copy_set_source_folded(data, 0, wanted)) {
|
||||
changed = 1;
|
||||
}
|
||||
} else if (found && chosen != UINT_MAX) {
|
||||
wanted = collapse;
|
||||
if (wanted == -1)
|
||||
wanted = (request->action == WINDOW_COPY_FOLD_COLLAPSE);
|
||||
if (request->action == WINDOW_COPY_FOLD_TOGGLE)
|
||||
wanted = !(data->source_flags[chosen] &
|
||||
WINDOW_COPY_FOLD_COLLAPSED);
|
||||
if (window_copy_set_source_folded(data, chosen, wanted)) {
|
||||
@@ -4367,7 +4413,7 @@ window_copy_set_fold(struct window_mode_entry *wme, int all, int collapse,
|
||||
window_copy_clear_selection(wme);
|
||||
window_copy_clear_marks(wme);
|
||||
window_copy_rebuild_backing(wme);
|
||||
if (!command_end &&
|
||||
if (!request->command_end &&
|
||||
window_copy_restore_cursor(wme, source_x, source_y))
|
||||
return (1);
|
||||
if (initial && window_copy_restore_before(wme, 0))
|
||||
@@ -4385,8 +4431,13 @@ window_copy_set_fold(struct window_mode_entry *wme, int all, int collapse,
|
||||
static enum window_copy_cmd_action
|
||||
window_copy_cmd_collapse_output(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
if (window_copy_set_fold(cs->wme, args_has(cs->wargs, 'a'), 1,
|
||||
UINT_MAX, 0))
|
||||
struct window_copy_fold_request request = {
|
||||
.action = WINDOW_COPY_FOLD_COLLAPSE,
|
||||
.all = args_has(cs->wargs, 'a'),
|
||||
.target = UINT_MAX
|
||||
};
|
||||
|
||||
if (window_copy_set_fold(cs->wme, &request))
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@@ -4394,8 +4445,13 @@ window_copy_cmd_collapse_output(struct window_copy_cmd_state *cs)
|
||||
static enum window_copy_cmd_action
|
||||
window_copy_cmd_expand_output(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
if (window_copy_set_fold(cs->wme, args_has(cs->wargs, 'a'), 0,
|
||||
UINT_MAX, 0))
|
||||
struct window_copy_fold_request request = {
|
||||
.action = WINDOW_COPY_FOLD_EXPAND,
|
||||
.all = args_has(cs->wargs, 'a'),
|
||||
.target = UINT_MAX
|
||||
};
|
||||
|
||||
if (window_copy_set_fold(cs->wme, &request))
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@@ -4405,9 +4461,14 @@ window_copy_cmd_toggle_output(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
struct window_copy_mode_data *data = cs->wme->data;
|
||||
struct window_copy_line *line;
|
||||
struct window_copy_fold_request request = {
|
||||
.action = WINDOW_COPY_FOLD_TOGGLE,
|
||||
.all = args_has(cs->wargs, 'a'),
|
||||
.target = UINT_MAX
|
||||
};
|
||||
u_int current, current_prompt, target;
|
||||
u_int target_prompt, chosen, x, y;
|
||||
int command_end = 0, current_found;
|
||||
int current_found;
|
||||
int initial, target_found;
|
||||
|
||||
if (args_has(cs->wargs, 'm')) {
|
||||
@@ -4426,13 +4487,11 @@ window_copy_cmd_toggle_output(struct window_copy_cmd_state *cs)
|
||||
line->source_line, &target_prompt, &chosen);
|
||||
if (!target_found)
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
command_end = initial || !current_found ||
|
||||
request.command_end = initial || !current_found ||
|
||||
current_prompt != target_prompt;
|
||||
target = line->source_line;
|
||||
} else
|
||||
target = UINT_MAX;
|
||||
if (window_copy_set_fold(cs->wme, args_has(cs->wargs, 'a'), -1,
|
||||
target, command_end))
|
||||
request.target = line->source_line;
|
||||
}
|
||||
if (window_copy_set_fold(cs->wme, &request))
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@@ -7291,6 +7350,7 @@ window_copy_find_output_range(struct window_mode_entry *wme, u_int *sx,
|
||||
struct grid_line *gl;
|
||||
u_int cursor_x, cursor_y, prompt_x = 0;
|
||||
u_int prompt_y = UINT_MAX, y, total;
|
||||
u_int output_x = 0, output_y = UINT_MAX;
|
||||
int found_start = 0, found_end = 0;
|
||||
int next_prompt, in_range, found;
|
||||
|
||||
@@ -7303,6 +7363,12 @@ window_copy_find_output_range(struct window_mode_entry *wme, u_int *sx,
|
||||
total = gd->hsize + gd->sy;
|
||||
for (y = 0; y < total; y++) {
|
||||
gl = grid_get_line(gd, y);
|
||||
if ((gl->flags & GRID_LINE_START_OUTPUT) &&
|
||||
(y < cursor_y || (y == cursor_y &&
|
||||
gl->osc133_data.out_start_col <= cursor_x))) {
|
||||
output_x = gl->osc133_data.out_start_col;
|
||||
output_y = y;
|
||||
}
|
||||
if (~gl->flags & GRID_LINE_START_PROMPT)
|
||||
continue;
|
||||
if (y > cursor_y ||
|
||||
@@ -7311,11 +7377,18 @@ window_copy_find_output_range(struct window_mode_entry *wme, u_int *sx,
|
||||
prompt_y = y;
|
||||
prompt_x = gl->osc133_data.prompt_col;
|
||||
}
|
||||
/* C may survive without A, or have been restored after a clear. */
|
||||
if (output_y != UINT_MAX && (prompt_y == UINT_MAX ||
|
||||
output_y > prompt_y ||
|
||||
(output_y == prompt_y && output_x >= prompt_x))) {
|
||||
prompt_x = output_x;
|
||||
prompt_y = output_y;
|
||||
}
|
||||
if (prompt_y == UINT_MAX) {
|
||||
log_debug("%s: no osc133 prompt before cursor", __func__);
|
||||
log_debug("%s: no osc133 marker before cursor", __func__);
|
||||
return (0);
|
||||
}
|
||||
log_debug("%s: prompt at %u,%u", __func__, prompt_x, prompt_y);
|
||||
log_debug("%s: start at %u,%u", __func__, prompt_x, prompt_y);
|
||||
|
||||
for (y = prompt_y; y < total; y++) {
|
||||
gl = grid_get_line(gd, y);
|
||||
@@ -7336,6 +7409,8 @@ window_copy_find_output_range(struct window_mode_entry *wme, u_int *sx,
|
||||
}
|
||||
/* An output may end on the same line or the next prompt's. */
|
||||
if (found_start && gl->flags & GRID_LINE_END_OUTPUT &&
|
||||
(!next_prompt || gl->osc133_data.out_end_col <=
|
||||
gl->osc133_data.prompt_col) &&
|
||||
(y != prompt_y || gl->osc133_data.out_end_col >= prompt_x) &&
|
||||
(y != *sy || gl->osc133_data.out_end_col >= *sx)) {
|
||||
*ex = gl->osc133_data.out_end_col;
|
||||
|
||||
Reference in New Issue
Block a user