mirror of
https://github.com/tmux/tmux.git
synced 2026-10-11 04:44:25 +00:00
Fix wrapped output selections and recognize single-character vi selections.
This commit is contained in:
@@ -72,4 +72,49 @@ wait_editor selection
|
|||||||
[ "$($TMUX display-message -p -t edit:0 '#{selection_present}')" = 1 ] || exit 1
|
[ "$($TMUX display-message -p -t edit:0 '#{selection_present}')" = 1 ] || exit 1
|
||||||
|
|
||||||
$TMUX send-keys -t edit:0 -X cancel || exit 1
|
$TMUX send-keys -t edit:0 -X cancel || exit 1
|
||||||
|
|
||||||
|
# Both active and stopped single-character selections use the editor binding.
|
||||||
|
printf 'o' >"$DIR/expected" || exit 1
|
||||||
|
for keys in emacs vi; do
|
||||||
|
$TMUX set-option -w -t edit:0 mode-keys "$keys" || exit 1
|
||||||
|
case "$keys" in
|
||||||
|
emacs) binding=e ;;
|
||||||
|
vi) binding=M-e ;;
|
||||||
|
esac
|
||||||
|
for state in active stopped; do
|
||||||
|
name="$keys-$state"
|
||||||
|
$TMUX set-option -g editor "sh $DIR/editor.sh $name" || exit 1
|
||||||
|
$TMUX copy-mode -t edit:0 || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 -X search-backward one || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 -X begin-selection || exit 1
|
||||||
|
if [ "$keys" = emacs ]; then
|
||||||
|
$TMUX send-keys -t edit:0 -X cursor-right || exit 1
|
||||||
|
fi
|
||||||
|
if [ "$state" = stopped ]; then
|
||||||
|
$TMUX send-keys -t edit:0 -X stop-selection || exit 1
|
||||||
|
fi
|
||||||
|
[ "$($TMUX display-message -p -t edit:0 \
|
||||||
|
'#{selection_present}')" = 1 ] || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 "$binding" || exit 1
|
||||||
|
wait_editor "$name"
|
||||||
|
cmp "$DIR/expected" "$DIR/$name" || exit 1
|
||||||
|
[ "$($TMUX show-buffer)" = sentinel ] || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 -X cancel || exit 1
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# An empty emacs selection still opens the output.
|
||||||
|
printf 'one\ntwo\n' >"$DIR/expected" || exit 1
|
||||||
|
$TMUX set-option -w -t edit:0 mode-keys emacs || exit 1
|
||||||
|
$TMUX set-option -g editor "sh $DIR/editor.sh empty" || exit 1
|
||||||
|
$TMUX copy-mode -t edit:0 || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 -X search-backward one || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 -X begin-selection || exit 1
|
||||||
|
[ "$($TMUX display-message -p -t edit:0 '#{selection_present}')" = 0 ] ||
|
||||||
|
exit 1
|
||||||
|
$TMUX send-keys -t edit:0 e || exit 1
|
||||||
|
wait_editor empty
|
||||||
|
cmp "$DIR/expected" "$DIR/empty" || exit 1
|
||||||
|
$TMUX send-keys -t edit:0 -X cancel || exit 1
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -157,4 +157,16 @@ expected=$(printf 'one\n_')
|
|||||||
check_output newline "${expected%_}"
|
check_output newline "${expected%_}"
|
||||||
check_selection newline "${expected%_}"
|
check_selection newline "${expected%_}"
|
||||||
|
|
||||||
|
# Wrapped cells keep spaces, even when D splits a wrapped line.
|
||||||
|
for payload in 'one' 'one ' 'one ' ' ' 'long-output '; do
|
||||||
|
seq="${prompt}\033]133;C\007${payload}\033]133;D;0\007"
|
||||||
|
start_pane_history wrapped 8 20 "${seq} separator"
|
||||||
|
check_output wrapped "$payload"
|
||||||
|
check_selection wrapped "$payload"
|
||||||
|
$TMUX resize-window -t wrapped: -x 80 || exit 1
|
||||||
|
$TMUX resize-window -t wrapped: -x 8 || exit 1
|
||||||
|
check_output wrapped "$payload"
|
||||||
|
check_selection wrapped "$payload"
|
||||||
|
done
|
||||||
|
|
||||||
exit $exit_status
|
exit $exit_status
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ static void window_copy_copy_selection(struct window_mode_entry *,
|
|||||||
const char *, int, int);
|
const char *, int, int);
|
||||||
static void window_copy_append_selection(struct window_mode_entry *);
|
static void window_copy_append_selection(struct window_mode_entry *);
|
||||||
static void window_copy_clear_selection(struct window_mode_entry *);
|
static void window_copy_clear_selection(struct window_mode_entry *);
|
||||||
|
static u_int window_copy_copy_line_length(struct window_mode_entry *, u_int,
|
||||||
|
int *);
|
||||||
static void window_copy_copy_line(struct window_mode_entry *, char **,
|
static void window_copy_copy_line(struct window_mode_entry *, char **,
|
||||||
size_t *, u_int, u_int, u_int);
|
size_t *, u_int, u_int, u_int);
|
||||||
static int window_copy_in_set(struct window_mode_entry *, u_int, u_int,
|
static int window_copy_in_set(struct window_mode_entry *, u_int, u_int,
|
||||||
@@ -1123,6 +1125,7 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
|
|||||||
u_int position, limit;
|
u_int position, limit;
|
||||||
struct grid_line *gl;
|
struct grid_line *gl;
|
||||||
time_t t;
|
time_t t;
|
||||||
|
int keys;
|
||||||
|
|
||||||
gl = grid_get_line(data->backing->grid, hsize - data->oy);
|
gl = grid_get_line(data->backing->grid, hsize - data->oy);
|
||||||
t = grid_line_time(gl);
|
t = grid_line_time(gl);
|
||||||
@@ -1156,7 +1159,9 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
|
|||||||
format_add(ft, "selection_active", "1");
|
format_add(ft, "selection_active", "1");
|
||||||
else
|
else
|
||||||
format_add(ft, "selection_active", "0");
|
format_add(ft, "selection_active", "0");
|
||||||
if (data->endselx != data->selx || data->endsely != data->sely)
|
keys = options_get_number(wme->wp->window->options, "mode-keys");
|
||||||
|
if (keys == MODEKEY_VI || data->endselx != data->selx ||
|
||||||
|
data->endsely != data->sely)
|
||||||
format_add(ft, "selection_present", "1");
|
format_add(ft, "selection_present", "1");
|
||||||
else
|
else
|
||||||
format_add(ft, "selection_present", "0");
|
format_add(ft, "selection_present", "0");
|
||||||
@@ -1610,6 +1615,7 @@ window_copy_cmd_select_output(struct window_copy_cmd_state *cs)
|
|||||||
size_t len;
|
size_t len;
|
||||||
u_int sx, sy, ex, ey, total, last;
|
u_int sx, sy, ex, ey, total, last;
|
||||||
int all = args_has(cs->wargs, 'a');
|
int all = args_has(cs->wargs, 'a');
|
||||||
|
int wrapped;
|
||||||
|
|
||||||
if (all) {
|
if (all) {
|
||||||
sx = sy = 0;
|
sx = sy = 0;
|
||||||
@@ -1631,12 +1637,19 @@ window_copy_cmd_select_output(struct window_copy_cmd_state *cs)
|
|||||||
window_copy_start_selection(wme);
|
window_copy_start_selection(wme);
|
||||||
if (options_get_number(wme->wp->window->options, "mode-keys") ==
|
if (options_get_number(wme->wp->window->options, "mode-keys") ==
|
||||||
MODEKEY_VI) {
|
MODEKEY_VI) {
|
||||||
last = window_copy_find_length(wme, ey);
|
last = window_copy_copy_line_length(wme, ey, NULL);
|
||||||
if (ex > last)
|
if (ex > last)
|
||||||
ex = last;
|
ex = last;
|
||||||
grid_reader_start(&gr, data->backing->grid, ex, ey);
|
if (ex == 0 && ey > 0) {
|
||||||
grid_reader_cursor_left(&gr, 1);
|
ey--;
|
||||||
grid_reader_get_cursor(&gr, &ex, &ey);
|
ex = window_copy_copy_line_length(wme, ey, &wrapped);
|
||||||
|
if (wrapped && ex > 0)
|
||||||
|
ex--;
|
||||||
|
} else {
|
||||||
|
grid_reader_start(&gr, data->backing->grid, ex, ey);
|
||||||
|
grid_reader_cursor_left(&gr, 1);
|
||||||
|
grid_reader_get_cursor(&gr, &ex, &ey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window_copy_scroll_to(wme, ex, ey, 1);
|
window_copy_scroll_to(wme, ex, ey, 1);
|
||||||
return (WINDOW_COPY_CMD_REDRAW);
|
return (WINDOW_COPY_CMD_REDRAW);
|
||||||
@@ -6467,7 +6480,7 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
|
|||||||
size_t off;
|
size_t off;
|
||||||
u_int i, xx, yy, sx, sy, ex, ey, ey_last;
|
u_int i, xx, yy, sx, sy, ex, ey, ey_last;
|
||||||
u_int firstsx, lastex, restex, restsx, selx;
|
u_int firstsx, lastex, restex, restsx, selx;
|
||||||
int keys;
|
int keys, wrapped;
|
||||||
|
|
||||||
if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
|
if (data->screen.sel == NULL && data->lineflag == LINE_SEL_NONE) {
|
||||||
buf = window_copy_match_at_cursor(data);
|
buf = window_copy_match_at_cursor(data);
|
||||||
@@ -6500,7 +6513,7 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Trim ex to end of line. */
|
/* Trim ex to end of line. */
|
||||||
ey_last = window_copy_find_length(wme, ey);
|
ey_last = window_copy_copy_line_length(wme, ey, &wrapped);
|
||||||
if (ex > ey_last)
|
if (ex > ey_last)
|
||||||
ex = ey_last;
|
ex = ey_last;
|
||||||
|
|
||||||
@@ -6571,8 +6584,7 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
|
|||||||
}
|
}
|
||||||
/* Remove final \n (unless at end in vi mode). */
|
/* Remove final \n (unless at end in vi mode). */
|
||||||
if (keys == MODEKEY_EMACS || lastex <= ey_last) {
|
if (keys == MODEKEY_EMACS || lastex <= ey_last) {
|
||||||
if (~grid_get_line(data->backing->grid, ey)->flags &
|
if (!wrapped || lastex != ey_last)
|
||||||
GRID_LINE_WRAPPED || lastex != ey_last)
|
|
||||||
off -= 1;
|
off -= 1;
|
||||||
}
|
}
|
||||||
*len = off;
|
*len = off;
|
||||||
@@ -6709,6 +6721,27 @@ window_copy_append_selection(struct window_mode_entry *wme)
|
|||||||
free(bufname);
|
free(bufname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the length for copying, preserving spaces on wrapped lines. */
|
||||||
|
static u_int
|
||||||
|
window_copy_copy_line_length(struct window_mode_entry *wme, u_int sy,
|
||||||
|
int *wrapped)
|
||||||
|
{
|
||||||
|
struct window_copy_mode_data *data = wme->data;
|
||||||
|
struct grid *gd = data->backing->grid;
|
||||||
|
struct grid_line *gl = grid_get_line(gd, sy);
|
||||||
|
u_int length;
|
||||||
|
int line_wrapped;
|
||||||
|
|
||||||
|
line_wrapped = (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx);
|
||||||
|
if (wrapped != NULL)
|
||||||
|
*wrapped = line_wrapped;
|
||||||
|
if (line_wrapped)
|
||||||
|
length = gl->cellsize;
|
||||||
|
else
|
||||||
|
length = window_copy_find_length(wme, sy);
|
||||||
|
return (length);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
|
window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
|
||||||
u_int sy, u_int sx, u_int ex)
|
u_int sy, u_int sx, u_int ex)
|
||||||
@@ -6716,27 +6749,15 @@ window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
|
|||||||
struct window_copy_mode_data *data = wme->data;
|
struct window_copy_mode_data *data = wme->data;
|
||||||
struct grid *gd = data->backing->grid;
|
struct grid *gd = data->backing->grid;
|
||||||
struct grid_cell gc;
|
struct grid_cell gc;
|
||||||
struct grid_line *gl;
|
|
||||||
struct utf8_data ud;
|
struct utf8_data ud;
|
||||||
u_int i, xx, wrapped = 0;
|
u_int i, xx;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
int wrapped;
|
||||||
|
|
||||||
if (sx > ex)
|
if (sx > ex)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
xx = window_copy_copy_line_length(wme, sy, &wrapped);
|
||||||
* Work out if the line was wrapped at the screen edge and all of it is
|
|
||||||
* on screen.
|
|
||||||
*/
|
|
||||||
gl = grid_get_line(gd, sy);
|
|
||||||
if (gl->flags & GRID_LINE_WRAPPED && gl->cellsize <= gd->sx)
|
|
||||||
wrapped = 1;
|
|
||||||
|
|
||||||
/* If the line was wrapped, don't strip spaces (use the full length). */
|
|
||||||
if (wrapped)
|
|
||||||
xx = gl->cellsize;
|
|
||||||
else
|
|
||||||
xx = window_copy_find_length(wme, sy);
|
|
||||||
if (ex > xx)
|
if (ex > xx)
|
||||||
ex = xx;
|
ex = xx;
|
||||||
if (sx > xx)
|
if (sx > xx)
|
||||||
|
|||||||
Reference in New Issue
Block a user