Merge branch 'master' of github.com:tmux/tmux

This commit is contained in:
Nicholas Marriott 2016-04-27 13:10:55 +01:00
commit fb4585bbe0
6 changed files with 182 additions and 71 deletions

View File

@ -140,12 +140,14 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" }, { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" },
{ MODEKEYCOPY_NEXTPAGE, "page-down" }, { MODEKEYCOPY_NEXTPAGE, "page-down" },
{ MODEKEYCOPY_NEXTPARAGRAPH, "next-paragraph" },
{ MODEKEYCOPY_NEXTSPACE, "next-space" }, { MODEKEYCOPY_NEXTSPACE, "next-space" },
{ MODEKEYCOPY_NEXTSPACEEND, "next-space-end" }, { MODEKEYCOPY_NEXTSPACEEND, "next-space-end" },
{ MODEKEYCOPY_NEXTWORD, "next-word" }, { MODEKEYCOPY_NEXTWORD, "next-word" },
{ MODEKEYCOPY_NEXTWORDEND, "next-word-end" }, { MODEKEYCOPY_NEXTWORDEND, "next-word-end" },
{ MODEKEYCOPY_OTHEREND, "other-end" }, { MODEKEYCOPY_OTHEREND, "other-end" },
{ MODEKEYCOPY_PREVIOUSPAGE, "page-up" }, { MODEKEYCOPY_PREVIOUSPAGE, "page-up" },
{ MODEKEYCOPY_PREVIOUSPARAGRAPH, "previous-paragraph" },
{ MODEKEYCOPY_PREVIOUSSPACE, "previous-space" }, { MODEKEYCOPY_PREVIOUSSPACE, "previous-space" },
{ MODEKEYCOPY_PREVIOUSWORD, "previous-word" }, { MODEKEYCOPY_PREVIOUSWORD, "previous-word" },
{ MODEKEYCOPY_RIGHT, "cursor-right" }, { MODEKEYCOPY_RIGHT, "cursor-right" },
@ -335,6 +337,8 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ 'q', 0, MODEKEYCOPY_CANCEL }, { 'q', 0, MODEKEYCOPY_CANCEL },
{ 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ 'w', 0, MODEKEYCOPY_NEXTWORD }, { 'w', 0, MODEKEYCOPY_NEXTWORD },
{ '{', 0, MODEKEYCOPY_PREVIOUSPARAGRAPH },
{ '}', 0, MODEKEYCOPY_NEXTPARAGRAPH },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT }, { KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN },
@ -483,6 +487,8 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ 't', 0, MODEKEYCOPY_JUMPTO }, { 't', 0, MODEKEYCOPY_JUMPTO },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE }, { 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION }, { 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION },
{ '{' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPARAGRAPH },
{ '}' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTPARAGRAPH },
{ KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN }, { KEYC_DOWN | KEYC_CTRL, 0, MODEKEYCOPY_SCROLLDOWN },
{ KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN }, { KEYC_DOWN | KEYC_ESCAPE, 0, MODEKEYCOPY_HALFPAGEDOWN },
{ KEYC_DOWN, 0, MODEKEYCOPY_DOWN }, { KEYC_DOWN, 0, MODEKEYCOPY_DOWN },

2
tmux.1
View File

@ -1029,6 +1029,7 @@ The following keys are supported as appropriate for the mode:
.It Li "Jump to backward" Ta "T" Ta "" .It Li "Jump to backward" Ta "T" Ta ""
.It Li "Jump to forward" Ta "t" Ta "" .It Li "Jump to forward" Ta "t" Ta ""
.It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next page" Ta "C-f" Ta "Page down"
.It Li "Next paragraph" Ta "}" Ta "M-}"
.It Li "Next space" Ta "W" Ta "" .It Li "Next space" Ta "W" Ta ""
.It Li "Next space, end of word" Ta "E" Ta "" .It Li "Next space, end of word" Ta "E" Ta ""
.It Li "Next word" Ta "w" Ta "" .It Li "Next word" Ta "w" Ta ""
@ -1036,6 +1037,7 @@ The following keys are supported as appropriate for the mode:
.It Li "Other end of selection" Ta "o" Ta "" .It Li "Other end of selection" Ta "o" Ta ""
.It Li "Paste buffer" Ta "p" Ta "C-y" .It Li "Paste buffer" Ta "p" Ta "C-y"
.It Li "Previous page" Ta "C-b" Ta "Page up" .It Li "Previous page" Ta "C-b" Ta "Page up"
.It Li "Previous paragraph" Ta "{" Ta "M-{"
.It Li "Previous space" Ta "B" Ta "" .It Li "Previous space" Ta "B" Ta ""
.It Li "Previous word" Ta "b" Ta "M-b" .It Li "Previous word" Ta "b" Ta "M-b"
.It Li "Quit mode" Ta "q" Ta "Escape" .It Li "Quit mode" Ta "q" Ta "Escape"

2
tmux.h
View File

@ -538,12 +538,14 @@ enum mode_key_cmd {
MODEKEYCOPY_LEFT, MODEKEYCOPY_LEFT,
MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_MIDDLELINE,
MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTPAGE,
MODEKEYCOPY_NEXTPARAGRAPH,
MODEKEYCOPY_NEXTSPACE, MODEKEYCOPY_NEXTSPACE,
MODEKEYCOPY_NEXTSPACEEND, MODEKEYCOPY_NEXTSPACEEND,
MODEKEYCOPY_NEXTWORD, MODEKEYCOPY_NEXTWORD,
MODEKEYCOPY_NEXTWORDEND, MODEKEYCOPY_NEXTWORDEND,
MODEKEYCOPY_OTHEREND, MODEKEYCOPY_OTHEREND,
MODEKEYCOPY_PREVIOUSPAGE, MODEKEYCOPY_PREVIOUSPAGE,
MODEKEYCOPY_PREVIOUSPARAGRAPH,
MODEKEYCOPY_PREVIOUSSPACE, MODEKEYCOPY_PREVIOUSSPACE,
MODEKEYCOPY_PREVIOUSWORD, MODEKEYCOPY_PREVIOUSWORD,
MODEKEYCOPY_RECTANGLETOGGLE, MODEKEYCOPY_RECTANGLETOGGLE,

View File

@ -33,14 +33,17 @@
* into a ternary tree. * into a ternary tree.
*/ */
void tty_keys_add1(struct tty_key **, const char *, key_code); static void tty_keys_add1(struct tty_key **, const char *, key_code);
void tty_keys_add(struct tty *, const char *, key_code); static void tty_keys_add(struct tty *, const char *, key_code);
void tty_keys_free1(struct tty_key *); static void tty_keys_free1(struct tty_key *);
struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t, static struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t,
size_t *); size_t *);
struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); static struct tty_key *tty_keys_find(struct tty *, const char *, size_t,
void tty_keys_callback(int, short, void *); size_t *);
int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); static int tty_keys_next1(struct tty *, const char *, size_t, key_code *,
size_t *);
static void tty_keys_callback(int, short, void *);
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *);
/* Default raw keys. */ /* Default raw keys. */
struct tty_default_key_raw { struct tty_default_key_raw {
@ -316,7 +319,7 @@ const struct tty_default_key_code tty_default_code_keys[] = {
}; };
/* Add key to tree. */ /* Add key to tree. */
void static void
tty_keys_add(struct tty *tty, const char *s, key_code key) tty_keys_add(struct tty *tty, const char *s, key_code key)
{ {
struct tty_key *tk; struct tty_key *tk;
@ -334,7 +337,7 @@ tty_keys_add(struct tty *tty, const char *s, key_code key)
} }
/* Add next node to the tree. */ /* Add next node to the tree. */
void static void
tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) tty_keys_add1(struct tty_key **tkp, const char *s, key_code key)
{ {
struct tty_key *tk; struct tty_key *tk;
@ -409,7 +412,7 @@ tty_keys_free(struct tty *tty)
} }
/* Free a single key. */ /* Free a single key. */
void static void
tty_keys_free1(struct tty_key *tk) tty_keys_free1(struct tty_key *tk)
{ {
if (tk->next != NULL) if (tk->next != NULL)
@ -422,7 +425,7 @@ tty_keys_free1(struct tty_key *tk)
} }
/* Lookup a key in the tree. */ /* Lookup a key in the tree. */
struct tty_key * static struct tty_key *
tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size) tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
{ {
*size = 0; *size = 0;
@ -430,7 +433,7 @@ tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size)
} }
/* Find the next node. */ /* Find the next node. */
struct tty_key * static struct tty_key *
tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
{ {
/* If the node is NULL, this is the end of the tree. No match. */ /* If the node is NULL, this is the end of the tree. No match. */
@ -460,6 +463,56 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
return (tty_keys_find1(tk, buf, len, size)); return (tty_keys_find1(tk, buf, len, size));
} }
/* Look up part of the next key. */
static int
tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key,
size_t *size)
{
struct tty_key *tk, *tk1;
struct utf8_data ud;
enum utf8_state more;
u_int i;
wchar_t wc;
log_debug("next key is %zu (%.*s)", len, (int)len, buf);
/* Empty buffer is a partial key. */
if (len == 0)
return (1);
/* Is this a known key? */
tk = tty_keys_find(tty, buf, len, size);
if (tk != NULL) {
tk1 = tk;
do
log_debug("keys in list: %#llx", tk->key);
while ((tk1 = tk1->next) != NULL);
*key = tk->key;
return (tk->next != NULL);
}
/* Is this valid UTF-8? */
more = utf8_open(&ud, (u_char)*buf);
if (more == UTF8_MORE) {
*size = ud.size;
if (len < ud.size)
return (1);
for (i = 1; i < ud.size; i++)
more = utf8_append(&ud, (u_char)buf[i]);
if (more != UTF8_DONE)
return (0);
if (utf8_combine(&ud, &wc) != UTF8_DONE)
return (0);
*key = wc;
log_debug("UTF-8 key %.*s %#llx", (int)ud.size, buf, *key);
return (0);
}
return (-1);
}
/* /*
* Process at least one key in the buffer and invoke tty->key_callback. Return * Process at least one key in the buffer and invoke tty->key_callback. Return
* 0 if there are no further keys, or 1 if there could be more in the buffer. * 0 if there are no further keys, or 1 if there could be more in the buffer.
@ -467,17 +520,12 @@ tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size)
key_code key_code
tty_keys_next(struct tty *tty) tty_keys_next(struct tty *tty)
{ {
struct tty_key *tk; struct timeval tv;
struct timeval tv; const char *buf;
const char *buf; size_t len, size;
size_t len, size; cc_t bspace;
cc_t bspace; int delay, expired = 0;
int delay, expired = 0; key_code key;
key_code key;
struct utf8_data ud;
enum utf8_state more;
u_int i;
wchar_t wc;
/* Get key buffer. */ /* Get key buffer. */
buf = EVBUFFER_DATA(tty->event->input); buf = EVBUFFER_DATA(tty->event->input);
@ -485,7 +533,7 @@ tty_keys_next(struct tty *tty)
if (len == 0) if (len == 0)
return (0); return (0);
log_debug("keys are %zu (%.*s)", len, (int) len, buf); log_debug("keys are %zu (%.*s)", len, (int)len, buf);
/* Is this a mouse key press? */ /* Is this a mouse key press? */
switch (tty_keys_mouse(tty, buf, len, &size)) { switch (tty_keys_mouse(tty, buf, len, &size)) {
@ -501,68 +549,65 @@ tty_keys_next(struct tty *tty)
goto partial_key; goto partial_key;
} }
/* Look for matching key string and return if found. */ first_key:
tk = tty_keys_find(tty, buf, len, &size); /* If escape is at the start, try without it. */
if (tk != NULL) { if (*buf == '\033') {
if (tk->next != NULL) switch (tty_keys_next1 (tty, buf + 1, len - 1, &key, &size)) {
case 0: /* found */
if (key != KEYC_UNKNOWN)
key |= KEYC_ESCAPE;
size++; /* include escape */
goto complete_key;
case -1: /* not found */
break;
case 1:
if (expired)
goto complete_key;
goto partial_key; goto partial_key;
key = tk->key; }
goto complete_key;
} }
/* Try to parse a key with an xterm-style modifier. */ /* Try with the escape. */
switch (tty_keys_next1 (tty, buf, len, &key, &size)) {
case 0: /* found */
goto complete_key;
case -1: /* not found */
break;
case 1:
if (expired)
goto complete_key;
goto partial_key;
}
/* Is this an an xterm(1) key? */
switch (xterm_keys_find(buf, len, &size, &key)) { switch (xterm_keys_find(buf, len, &size, &key)) {
case 0: /* found */ case 0: /* found */
goto complete_key; goto complete_key;
case -1: /* not found */ case -1: /* not found */
break; break;
case 1: case 1:
if (expired)
break;
goto partial_key; goto partial_key;
} }
first_key: /*
/* Is this a meta key? */ * If this starts with escape and is at least two keys, it must be
if (len >= 2 && buf[0] == '\033') { * complete even if the timer has not expired, because otherwise
if (buf[1] != '\033') { * tty_keys_next1 would have found a partial key. If just an escape
key = buf[1] | KEYC_ESCAPE; * alone, it needs to wait for the timer first.
*/
if (*buf == '\033') {
if (len >= 2) {
key = (u_char)buf[1] | KEYC_ESCAPE;
size = 2; size = 2;
goto complete_key; goto complete_key;
} }
if (!expired)
tk = tty_keys_find(tty, buf + 1, len - 1, &size);
if (tk != NULL && (!expired || tk->next == NULL)) {
size++; /* include escape */
if (tk->next != NULL)
goto partial_key;
key = tk->key;
if (key != KEYC_UNKNOWN)
key |= KEYC_ESCAPE;
goto complete_key;
}
}
/* Is this valid UTF-8? */
if ((more = utf8_open(&ud, (u_char)*buf) == UTF8_MORE)) {
size = ud.size;
if (len < size) {
if (expired)
goto discard_key;
goto partial_key; goto partial_key;
}
for (i = 1; i < size; i++)
more = utf8_append(&ud, (u_char)buf[i]);
if (more != UTF8_DONE)
goto discard_key;
if (utf8_combine(&ud, &wc) != UTF8_DONE)
goto discard_key;
key = wc;
log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key);
goto complete_key;
} }
/* No key found, take first. */ /* No longer key found, use the first character. */
key = (u_char)*buf; key = (u_char)*buf;
size = 1; size = 1;
@ -578,7 +623,7 @@ first_key:
goto complete_key; goto complete_key;
partial_key: partial_key:
log_debug("partial key %.*s", (int) len, buf); log_debug("partial key %.*s", (int)len, buf);
/* If timer is going, check for expiration. */ /* If timer is going, check for expiration. */
if (tty->flags & TTY_TIMER) { if (tty->flags & TTY_TIMER) {
@ -640,7 +685,7 @@ discard_key:
} }
/* Key timer callback. */ /* Key timer callback. */
void static void
tty_keys_callback(__unused int fd, __unused short events, void *data) tty_keys_callback(__unused int fd, __unused short events, void *data)
{ {
struct tty *tty = data; struct tty *tty = data;
@ -655,7 +700,7 @@ tty_keys_callback(__unused int fd, __unused short events, void *data)
* Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial * Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial
* (probably a mouse sequence but need more data). * (probably a mouse sequence but need more data).
*/ */
int static int
tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size)
{ {
struct mouse_event *m = &tty->mouse; struct mouse_event *m = &tty->mouse;

8
utf8.c
View File

@ -118,6 +118,14 @@ utf8_width(wchar_t wc)
width = wcwidth(wc); width = wcwidth(wc);
if (width < 0 || width > 0xff) { if (width < 0 || width > 0xff) {
log_debug("Unicode %04x, wcwidth() %d", wc, width); log_debug("Unicode %04x, wcwidth() %d", wc, width);
/*
* Many platforms have no width for relatively common
* characters (wcwidth() returns -1); assume width 1 in this
* case and hope for the best.
*/
if (width < 0)
return (1);
return (-1); return (-1);
} }
return (width); return (width);

View File

@ -27,6 +27,8 @@
struct screen *window_copy_init(struct window_pane *); struct screen *window_copy_init(struct window_pane *);
void window_copy_free(struct window_pane *); void window_copy_free(struct window_pane *);
void window_copy_pagedown(struct window_pane *); void window_copy_pagedown(struct window_pane *);
void window_copy_next_paragraph(struct window_pane *);
void window_copy_previous_paragraph(struct window_pane *);
void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_resize(struct window_pane *, u_int, u_int);
void window_copy_key(struct window_pane *, struct client *, struct session *, void window_copy_key(struct window_pane *, struct client *, struct session *,
key_code, struct mouse_event *); key_code, struct mouse_event *);
@ -403,6 +405,44 @@ window_copy_pagedown(struct window_pane *wp)
window_copy_redraw_screen(wp); window_copy_redraw_screen(wp);
} }
void
window_copy_previous_paragraph(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
u_int ox, oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
while (oy > 0 && window_copy_find_length(wp, oy) == 0)
oy--;
while (oy > 0 && window_copy_find_length(wp, oy) > 0)
oy--;
window_copy_scroll_to(wp, 0, oy);
}
void
window_copy_next_paragraph(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int maxy, ox, oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
maxy = screen_hsize(data->backing) + screen_size_y(s) - 1;
while (oy < maxy && window_copy_find_length(wp, oy) == 0)
oy++;
while (oy < maxy && window_copy_find_length(wp, oy) > 0)
oy++;
ox = window_copy_find_length(wp, oy);
window_copy_scroll_to(wp, ox, oy);
}
void void
window_copy_resize(struct window_pane *wp, u_int sx, u_int sy) window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
{ {
@ -548,6 +588,14 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess,
for (; np != 0; np--) for (; np != 0; np--)
window_copy_pagedown(wp); window_copy_pagedown(wp);
break; break;
case MODEKEYCOPY_PREVIOUSPARAGRAPH:
for (; np != 0; np--)
window_copy_previous_paragraph(wp);
break;
case MODEKEYCOPY_NEXTPARAGRAPH:
for (; np != 0; np--)
window_copy_next_paragraph(wp);
break;
case MODEKEYCOPY_HALFPAGEUP: case MODEKEYCOPY_HALFPAGEUP:
n = screen_size_y(s) / 2; n = screen_size_y(s) / 2;
for (; np != 0; np--) { for (; np != 0; np--) {