mirror of
https://github.com/tmux/tmux.git
synced 2024-12-12 17:38:48 +00:00
Support UTF-8 entry into the command prompt.
This commit is contained in:
parent
a81685bfac
commit
8b804fb589
316
status.c
316
status.c
@ -662,18 +662,21 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
|
||||
struct format_tree *ft;
|
||||
int keys;
|
||||
time_t t;
|
||||
char *tmp;
|
||||
|
||||
ft = format_create(NULL, 0);
|
||||
format_defaults(ft, c, NULL, NULL, NULL);
|
||||
|
||||
t = time(NULL);
|
||||
tmp = format_expand_time(ft, input, t);
|
||||
|
||||
status_message_clear(c);
|
||||
status_prompt_clear(c);
|
||||
|
||||
c->prompt_string = format_expand_time(ft, msg, t);
|
||||
|
||||
c->prompt_buffer = format_expand_time(ft, input, t);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->prompt_buffer = utf8_fromcstr(tmp);
|
||||
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
||||
|
||||
c->prompt_callbackfn = callbackfn;
|
||||
c->prompt_freefn = freefn;
|
||||
@ -692,6 +695,7 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
|
||||
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
|
||||
free(tmp);
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
@ -723,22 +727,26 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
time_t t;
|
||||
char *tmp;
|
||||
|
||||
ft = format_create(NULL, 0);
|
||||
format_defaults(ft, c, NULL, NULL, NULL);
|
||||
|
||||
t = time(NULL);
|
||||
tmp = format_expand_time(ft, input, t);
|
||||
|
||||
free(c->prompt_string);
|
||||
c->prompt_string = format_expand_time(ft, msg, t);
|
||||
|
||||
free(c->prompt_buffer);
|
||||
c->prompt_buffer = format_expand_time(ft, input, t);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->prompt_buffer = utf8_fromcstr(tmp);
|
||||
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
||||
|
||||
c->prompt_hindex = 0;
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
|
||||
free(tmp);
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
@ -746,57 +754,80 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
|
||||
int
|
||||
status_prompt_redraw(struct client *c)
|
||||
{
|
||||
struct screen_write_ctx ctx;
|
||||
struct session *s = c->session;
|
||||
struct screen old_status;
|
||||
size_t i, size, left, len, off;
|
||||
struct grid_cell gc;
|
||||
struct screen_write_ctx ctx;
|
||||
struct session *s = c->session;
|
||||
struct screen old_status;
|
||||
u_int i, offset, left, start, pcursor, pwidth, width;
|
||||
struct grid_cell gc, cursorgc;
|
||||
|
||||
if (c->tty.sx == 0 || c->tty.sy == 0)
|
||||
return (0);
|
||||
memcpy(&old_status, &c->status, sizeof old_status);
|
||||
screen_init(&c->status, c->tty.sx, 1, 0);
|
||||
|
||||
len = screen_write_strlen("%s", c->prompt_string);
|
||||
if (len > c->tty.sx)
|
||||
len = c->tty.sx;
|
||||
off = 0;
|
||||
|
||||
/* Change colours for command mode. */
|
||||
if (c->prompt_mdata.mode == 1)
|
||||
style_apply(&gc, s->options, "message-command-style");
|
||||
else
|
||||
style_apply(&gc, s->options, "message-style");
|
||||
|
||||
memcpy(&cursorgc, &gc, sizeof cursorgc);
|
||||
cursorgc.attr ^= GRID_ATTR_REVERSE;
|
||||
|
||||
start = screen_write_strlen("%s", c->prompt_string);
|
||||
if (start > c->tty.sx)
|
||||
start = c->tty.sx;
|
||||
|
||||
screen_write_start(&ctx, NULL, &c->status);
|
||||
|
||||
screen_write_cursormove(&ctx, 0, 0);
|
||||
screen_write_nputs(&ctx, len, &gc, "%s", c->prompt_string);
|
||||
screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string);
|
||||
while (c->status.cx < screen_size_x(&c->status))
|
||||
screen_write_putc(&ctx, &gc, ' ');
|
||||
screen_write_cursormove(&ctx, start, 0);
|
||||
|
||||
left = c->tty.sx - len;
|
||||
if (left != 0) {
|
||||
size = screen_write_strlen("%s", c->prompt_buffer);
|
||||
if (c->prompt_index >= left) {
|
||||
off = c->prompt_index - left + 1;
|
||||
if (c->prompt_index == size)
|
||||
left--;
|
||||
size = left;
|
||||
left = c->tty.sx - start;
|
||||
if (left == 0)
|
||||
goto finished;
|
||||
|
||||
pcursor = utf8_strwidth(c->prompt_buffer, c->prompt_index);
|
||||
pwidth = utf8_strwidth(c->prompt_buffer, -1);
|
||||
if (pcursor >= left) {
|
||||
/*
|
||||
* The cursor would be outside the screen so start drawing
|
||||
* with it on the right.
|
||||
*/
|
||||
offset = (pcursor - left) + 1;
|
||||
pwidth = left;
|
||||
} else
|
||||
offset = 0;
|
||||
if (pwidth > left)
|
||||
pwidth = left;
|
||||
|
||||
width = 0;
|
||||
for (i = 0; c->prompt_buffer[i].size != 0; i++) {
|
||||
if (width < offset) {
|
||||
width += c->prompt_buffer[i].width;
|
||||
continue;
|
||||
}
|
||||
screen_write_nputs(&ctx, left, &gc, "%s", c->prompt_buffer +
|
||||
off);
|
||||
if (width >= offset + pwidth)
|
||||
break;
|
||||
width += c->prompt_buffer[i].width;
|
||||
if (width > offset + pwidth)
|
||||
break;
|
||||
|
||||
for (i = len + size; i < c->tty.sx; i++)
|
||||
screen_write_putc(&ctx, &gc, ' ');
|
||||
if (i != c->prompt_index) {
|
||||
utf8_copy(&gc.data, &c->prompt_buffer[i]);
|
||||
screen_write_cell(&ctx, &gc);
|
||||
} else {
|
||||
utf8_copy(&cursorgc.data, &c->prompt_buffer[i]);
|
||||
screen_write_cell(&ctx, &cursorgc);
|
||||
}
|
||||
}
|
||||
if (c->status.cx < screen_size_x(&c->status) && c->prompt_index >= i)
|
||||
screen_write_putc(&ctx, &cursorgc, ' ');
|
||||
|
||||
finished:
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
/* Apply fake cursor. */
|
||||
off = len + c->prompt_index - off;
|
||||
grid_view_get_cell(c->status.grid, off, 0, &gc);
|
||||
gc.attr ^= GRID_ATTR_REVERSE;
|
||||
grid_view_set_cell(c->status.grid, off, 0, &gc);
|
||||
|
||||
if (grid_compare(c->status.grid, old_status.grid) == 0) {
|
||||
screen_free(&old_status);
|
||||
return (0);
|
||||
@ -805,19 +836,37 @@ status_prompt_redraw(struct client *c)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Is this a separator? */
|
||||
static int
|
||||
status_prompt_in_list(const char *ws, const struct utf8_data *ud)
|
||||
{
|
||||
if (ud->size != 1 || ud->width != 1)
|
||||
return (0);
|
||||
return (strchr(ws, *ud->data) != NULL);
|
||||
}
|
||||
|
||||
/* Is this a space? */
|
||||
static int
|
||||
status_prompt_space(const struct utf8_data *ud)
|
||||
{
|
||||
if (ud->size != 1 || ud->width != 1)
|
||||
return (0);
|
||||
return (*ud->data == ' ');
|
||||
}
|
||||
|
||||
/* Handle keys in prompt. */
|
||||
void
|
||||
status_prompt_key(struct client *c, key_code key)
|
||||
{
|
||||
struct session *sess = c->session;
|
||||
struct options *oo = sess->options;
|
||||
struct options *oo = c->session->options;
|
||||
struct paste_buffer *pb;
|
||||
char *s, *first, *last, word[64], swapc;
|
||||
const char *histstr, *bufdata, *wsep = NULL;
|
||||
char *s, word[64];
|
||||
const char *histstr, *bufdata, *ws = NULL;
|
||||
u_char ch;
|
||||
size_t size, n, off, idx, bufsize;
|
||||
size_t size, n, off, idx, bufsize, used;
|
||||
struct utf8_data tmp, *first, *last, *ud;
|
||||
|
||||
size = strlen(c->prompt_buffer);
|
||||
size = utf8_strlen(c->prompt_buffer);
|
||||
switch (mode_key_lookup(&c->prompt_mdata, key, NULL, NULL)) {
|
||||
case MODEKEYEDIT_CURSORLEFT:
|
||||
if (c->prompt_index > 0) {
|
||||
@ -856,7 +905,7 @@ status_prompt_key(struct client *c, key_code key)
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_COMPLETE:
|
||||
if (*c->prompt_buffer == '\0')
|
||||
if (c->prompt_buffer[0].size == 0)
|
||||
break;
|
||||
|
||||
idx = c->prompt_index;
|
||||
@ -864,40 +913,50 @@ status_prompt_key(struct client *c, key_code key)
|
||||
idx--;
|
||||
|
||||
/* Find the word we are in. */
|
||||
first = c->prompt_buffer + idx;
|
||||
while (first > c->prompt_buffer && *first != ' ')
|
||||
first = &c->prompt_buffer[idx];
|
||||
while (first > c->prompt_buffer && !status_prompt_space(first))
|
||||
first--;
|
||||
while (*first == ' ')
|
||||
while (first->size != 0 && status_prompt_space(first))
|
||||
first++;
|
||||
last = c->prompt_buffer + idx;
|
||||
while (*last != '\0' && *last != ' ')
|
||||
last = &c->prompt_buffer[idx];
|
||||
while (last->size != 0 && !status_prompt_space(last))
|
||||
last++;
|
||||
while (*last == ' ')
|
||||
while (last > c->prompt_buffer && status_prompt_space(last))
|
||||
last--;
|
||||
if (*last != '\0')
|
||||
if (last->size != 0)
|
||||
last++;
|
||||
if (last <= first ||
|
||||
((size_t) (last - first)) > (sizeof word) - 1)
|
||||
if (last <= first)
|
||||
break;
|
||||
memcpy(word, first, last - first);
|
||||
word[last - first] = '\0';
|
||||
|
||||
used = 0;
|
||||
for (ud = first; ud < last; ud++) {
|
||||
if (used + ud->size >= sizeof word)
|
||||
break;
|
||||
memcpy(word + used, ud->data, ud->size);
|
||||
used += ud->size;
|
||||
}
|
||||
if (ud != last)
|
||||
break;
|
||||
word[used] = '\0';
|
||||
|
||||
/* And try to complete it. */
|
||||
if ((s = status_prompt_complete(sess, word)) == NULL)
|
||||
if ((s = status_prompt_complete(c->session, word)) == NULL)
|
||||
break;
|
||||
|
||||
/* Trim out word. */
|
||||
n = size - (last - c->prompt_buffer) + 1; /* with \0 */
|
||||
memmove(first, last, n);
|
||||
memmove(first, last, n * sizeof *c->prompt_buffer);
|
||||
size -= last - first;
|
||||
|
||||
/* Insert the new word. */
|
||||
size += strlen(s);
|
||||
off = first - c->prompt_buffer;
|
||||
c->prompt_buffer = xrealloc(c->prompt_buffer, size + 1);
|
||||
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 1,
|
||||
sizeof *c->prompt_buffer);
|
||||
first = c->prompt_buffer + off;
|
||||
memmove(first + strlen(s), first, n);
|
||||
memcpy(first, s, strlen(s));
|
||||
memmove(first + strlen(s), first, n * sizeof *c->prompt_buffer);
|
||||
for (idx = 0; idx < strlen(s); idx++)
|
||||
utf8_set(&first[idx], s[idx]);
|
||||
|
||||
c->prompt_index = (first - c->prompt_buffer) + strlen(s);
|
||||
free(s);
|
||||
@ -907,11 +966,12 @@ status_prompt_key(struct client *c, key_code key)
|
||||
case MODEKEYEDIT_BACKSPACE:
|
||||
if (c->prompt_index != 0) {
|
||||
if (c->prompt_index == size)
|
||||
c->prompt_buffer[--c->prompt_index] = '\0';
|
||||
c->prompt_buffer[--c->prompt_index].size = 0;
|
||||
else {
|
||||
memmove(c->prompt_buffer + c->prompt_index - 1,
|
||||
c->prompt_buffer + c->prompt_index,
|
||||
size + 1 - c->prompt_index);
|
||||
(size + 1 - c->prompt_index) *
|
||||
sizeof *c->prompt_buffer);
|
||||
c->prompt_index--;
|
||||
}
|
||||
c->flags |= CLIENT_STATUS;
|
||||
@ -922,38 +982,39 @@ status_prompt_key(struct client *c, key_code key)
|
||||
if (c->prompt_index != size) {
|
||||
memmove(c->prompt_buffer + c->prompt_index,
|
||||
c->prompt_buffer + c->prompt_index + 1,
|
||||
size + 1 - c->prompt_index);
|
||||
(size + 1 - c->prompt_index) *
|
||||
sizeof *c->prompt_buffer);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_DELETELINE:
|
||||
case MODEKEYEDIT_SWITCHMODESUBSTITUTELINE:
|
||||
*c->prompt_buffer = '\0';
|
||||
c->prompt_buffer[0].size = 0;
|
||||
c->prompt_index = 0;
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_DELETETOENDOFLINE:
|
||||
case MODEKEYEDIT_SWITCHMODECHANGELINE:
|
||||
if (c->prompt_index < size) {
|
||||
c->prompt_buffer[c->prompt_index] = '\0';
|
||||
c->prompt_buffer[c->prompt_index].size = 0;
|
||||
c->flags |= CLIENT_STATUS;
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_DELETEWORD:
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
ws = options_get_string(oo, "word-separators");
|
||||
idx = c->prompt_index;
|
||||
|
||||
/* Find a non-separator. */
|
||||
while (idx != 0) {
|
||||
idx--;
|
||||
if (!strchr(wsep, c->prompt_buffer[idx]))
|
||||
if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the separator at the beginning of the word. */
|
||||
while (idx != 0) {
|
||||
idx--;
|
||||
if (strchr(wsep, c->prompt_buffer[idx])) {
|
||||
if (status_prompt_in_list(ws, &c->prompt_buffer[idx])) {
|
||||
/* Go back to the word. */
|
||||
idx++;
|
||||
break;
|
||||
@ -962,53 +1023,55 @@ status_prompt_key(struct client *c, key_code key)
|
||||
|
||||
memmove(c->prompt_buffer + idx,
|
||||
c->prompt_buffer + c->prompt_index,
|
||||
size + 1 - c->prompt_index);
|
||||
(size + 1 - c->prompt_index) *
|
||||
sizeof *c->prompt_buffer);
|
||||
memset(c->prompt_buffer + size - (c->prompt_index - idx),
|
||||
'\0', c->prompt_index - idx);
|
||||
'\0', (c->prompt_index - idx) * sizeof *c->prompt_buffer);
|
||||
c->prompt_index = idx;
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_NEXTSPACE:
|
||||
wsep = " ";
|
||||
ws = " ";
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_NEXTWORD:
|
||||
if (wsep == NULL)
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
if (ws == NULL)
|
||||
ws = options_get_string(oo, "word-separators");
|
||||
|
||||
/* Find a separator. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
idx = ++c->prompt_index;
|
||||
if (status_prompt_in_list(ws, &c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the word right after the separation. */
|
||||
/* Find the word right after the separator. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (!strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
idx = ++c->prompt_index;
|
||||
if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_NEXTSPACEEND:
|
||||
wsep = " ";
|
||||
ws = " ";
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_NEXTWORDEND:
|
||||
if (wsep == NULL)
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
if (ws == NULL)
|
||||
ws = options_get_string(oo, "word-separators");
|
||||
|
||||
/* Find a word. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (!strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
idx = ++c->prompt_index;
|
||||
if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the separator at the end of the word. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
idx = ++c->prompt_index;
|
||||
if (status_prompt_in_list(ws, &c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1020,23 +1083,23 @@ status_prompt_key(struct client *c, key_code key)
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_PREVIOUSSPACE:
|
||||
wsep = " ";
|
||||
ws = " ";
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_PREVIOUSWORD:
|
||||
if (wsep == NULL)
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
if (ws == NULL)
|
||||
ws = options_get_string(oo, "word-separators");
|
||||
|
||||
/* Find a non-separator. */
|
||||
while (c->prompt_index != 0) {
|
||||
c->prompt_index--;
|
||||
if (!strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
idx = --c->prompt_index;
|
||||
if (!status_prompt_in_list(ws, &c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the separator at the beginning of the word. */
|
||||
while (c->prompt_index != 0) {
|
||||
c->prompt_index--;
|
||||
if (strchr(wsep, c->prompt_buffer[c->prompt_index])) {
|
||||
idx = --c->prompt_index;
|
||||
if (status_prompt_in_list(ws, &c->prompt_buffer[idx])) {
|
||||
/* Go back to the word. */
|
||||
c->prompt_index++;
|
||||
break;
|
||||
@ -1050,8 +1113,8 @@ status_prompt_key(struct client *c, key_code key)
|
||||
if (histstr == NULL)
|
||||
break;
|
||||
free(c->prompt_buffer);
|
||||
c->prompt_buffer = xstrdup(histstr);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->prompt_buffer = utf8_fromcstr(histstr);
|
||||
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_HISTORYDOWN:
|
||||
@ -1059,8 +1122,8 @@ status_prompt_key(struct client *c, key_code key)
|
||||
if (histstr == NULL)
|
||||
break;
|
||||
free(c->prompt_buffer);
|
||||
c->prompt_buffer = xstrdup(histstr);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->prompt_buffer = utf8_fromcstr(histstr);
|
||||
c->prompt_index = utf8_strlen(c->prompt_buffer);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_PASTE:
|
||||
@ -1069,20 +1132,28 @@ status_prompt_key(struct client *c, key_code key)
|
||||
bufdata = paste_buffer_data(pb, &bufsize);
|
||||
for (n = 0; n < bufsize; n++) {
|
||||
ch = (u_char)bufdata[n];
|
||||
if (ch < 32 || ch == 127)
|
||||
if (ch < 32 || ch >= 127)
|
||||
break;
|
||||
}
|
||||
|
||||
c->prompt_buffer = xrealloc(c->prompt_buffer, size + n + 1);
|
||||
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1,
|
||||
sizeof *c->prompt_buffer);
|
||||
if (c->prompt_index == size) {
|
||||
memcpy(c->prompt_buffer + c->prompt_index, bufdata, n);
|
||||
for (idx = 0; idx < n; idx++) {
|
||||
ud = &c->prompt_buffer[c->prompt_index + idx];
|
||||
utf8_set(ud, bufdata[idx]);
|
||||
}
|
||||
c->prompt_index += n;
|
||||
c->prompt_buffer[c->prompt_index] = '\0';
|
||||
c->prompt_buffer[c->prompt_index].size = 0;
|
||||
} else {
|
||||
memmove(c->prompt_buffer + c->prompt_index + n,
|
||||
c->prompt_buffer + c->prompt_index,
|
||||
size + 1 - c->prompt_index);
|
||||
memcpy(c->prompt_buffer + c->prompt_index, bufdata, n);
|
||||
(size + 1 - c->prompt_index) *
|
||||
sizeof *c->prompt_buffer);
|
||||
for (idx = 0; idx < n; idx++) {
|
||||
ud = &c->prompt_buffer[c->prompt_index + idx];
|
||||
utf8_set(ud, bufdata[idx]);
|
||||
}
|
||||
c->prompt_index += n;
|
||||
}
|
||||
|
||||
@ -1093,42 +1164,55 @@ status_prompt_key(struct client *c, key_code key)
|
||||
if (idx < size)
|
||||
idx++;
|
||||
if (idx >= 2) {
|
||||
swapc = c->prompt_buffer[idx - 2];
|
||||
c->prompt_buffer[idx - 2] = c->prompt_buffer[idx - 1];
|
||||
c->prompt_buffer[idx - 1] = swapc;
|
||||
utf8_copy(&tmp, &c->prompt_buffer[idx - 2]);
|
||||
utf8_copy(&c->prompt_buffer[idx - 2],
|
||||
&c->prompt_buffer[idx - 1]);
|
||||
utf8_copy(&c->prompt_buffer[idx - 1], &tmp);
|
||||
c->prompt_index = idx;
|
||||
c->flags |= CLIENT_STATUS;
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_ENTER:
|
||||
if (*c->prompt_buffer != '\0')
|
||||
status_prompt_add_history(c->prompt_buffer);
|
||||
if (c->prompt_callbackfn(c->prompt_data, c->prompt_buffer) == 0)
|
||||
s = utf8_tocstr(c->prompt_buffer);
|
||||
if (*s != '\0')
|
||||
status_prompt_add_history(s);
|
||||
if (c->prompt_callbackfn(c->prompt_data, s) == 0)
|
||||
status_prompt_clear(c);
|
||||
free(s);
|
||||
break;
|
||||
case MODEKEYEDIT_CANCEL:
|
||||
if (c->prompt_callbackfn(c->prompt_data, NULL) == 0)
|
||||
status_prompt_clear(c);
|
||||
break;
|
||||
case MODEKEY_OTHER:
|
||||
if (key <= 0x1f || key >= 0x7f)
|
||||
if (key <= 0x1f || key >= KEYC_BASE)
|
||||
break;
|
||||
c->prompt_buffer = xrealloc(c->prompt_buffer, size + 2);
|
||||
if (utf8_split(key, &tmp) != UTF8_DONE)
|
||||
break;
|
||||
|
||||
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + 2,
|
||||
sizeof *c->prompt_buffer);
|
||||
|
||||
if (c->prompt_index == size) {
|
||||
c->prompt_buffer[c->prompt_index++] = key;
|
||||
c->prompt_buffer[c->prompt_index] = '\0';
|
||||
utf8_copy(&c->prompt_buffer[c->prompt_index], &tmp);
|
||||
c->prompt_index++;
|
||||
c->prompt_buffer[c->prompt_index].size = 0;
|
||||
} else {
|
||||
memmove(c->prompt_buffer + c->prompt_index + 1,
|
||||
c->prompt_buffer + c->prompt_index,
|
||||
size + 1 - c->prompt_index);
|
||||
c->prompt_buffer[c->prompt_index++] = key;
|
||||
(size + 1 - c->prompt_index) *
|
||||
sizeof *c->prompt_buffer);
|
||||
utf8_copy(&c->prompt_buffer[c->prompt_index], &tmp);
|
||||
c->prompt_index++;
|
||||
}
|
||||
|
||||
if (c->prompt_flags & PROMPT_SINGLE) {
|
||||
if (c->prompt_callbackfn(c->prompt_data,
|
||||
c->prompt_buffer) == 0)
|
||||
s = utf8_tocstr(c->prompt_buffer);
|
||||
if (strlen(s) != 1)
|
||||
status_prompt_clear(c);
|
||||
else if (c->prompt_callbackfn(c->prompt_data, s) == 0)
|
||||
status_prompt_clear(c);
|
||||
free(s);
|
||||
}
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
@ -1247,7 +1331,7 @@ status_prompt_complete_prefix(const char **list, u_int size)
|
||||
|
||||
/* Complete word. */
|
||||
static char *
|
||||
status_prompt_complete(struct session *sess, const char *s)
|
||||
status_prompt_complete(struct session *session, const char *s)
|
||||
{
|
||||
const char **list = NULL, *colon;
|
||||
u_int size = 0, i;
|
||||
@ -1300,7 +1384,7 @@ status_prompt_complete(struct session *sess, const char *s)
|
||||
|
||||
colon = "";
|
||||
if (*s == ':') {
|
||||
RB_FOREACH(wl, winlinks, &sess->windows) {
|
||||
RB_FOREACH(wl, winlinks, &session->windows) {
|
||||
xasprintf(&tmp, ":%s", wl->window->name);
|
||||
if (strncmp(tmp, s, strlen(s)) == 0){
|
||||
list = xreallocarray(list, size + 1,
|
||||
|
4
tmux.h
4
tmux.h
@ -1300,7 +1300,7 @@ struct client {
|
||||
TAILQ_HEAD(, message_entry) message_log;
|
||||
|
||||
char *prompt_string;
|
||||
char *prompt_buffer;
|
||||
struct utf8_data *prompt_buffer;
|
||||
size_t prompt_index;
|
||||
int (*prompt_callbackfn)(void *, const char *);
|
||||
void (*prompt_freefn)(void *);
|
||||
@ -2345,6 +2345,8 @@ enum utf8_state utf8_combine(const struct utf8_data *, wchar_t *);
|
||||
enum utf8_state utf8_split(wchar_t, struct utf8_data *);
|
||||
int utf8_strvis(char *, const char *, size_t, int);
|
||||
char *utf8_sanitize(const char *);
|
||||
size_t utf8_strlen(const struct utf8_data *);
|
||||
u_int utf8_strwidth(const struct utf8_data *, ssize_t);
|
||||
struct utf8_data *utf8_fromcstr(const char *);
|
||||
char *utf8_tocstr(struct utf8_data *);
|
||||
u_int utf8_cstrwidth(const char *);
|
||||
|
27
utf8.c
27
utf8.c
@ -236,6 +236,33 @@ utf8_sanitize(const char *src)
|
||||
return (dst);
|
||||
}
|
||||
|
||||
/* Get UTF-8 buffer length. */
|
||||
size_t
|
||||
utf8_strlen(const struct utf8_data *s)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; s[i].size != 0; i++)
|
||||
/* nothing */;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/* Get UTF-8 string width. */
|
||||
u_int
|
||||
utf8_strwidth(const struct utf8_data *s, ssize_t n)
|
||||
{
|
||||
ssize_t i;
|
||||
u_int width;
|
||||
|
||||
width = 0;
|
||||
for (i = 0; s[i].size != 0; i++) {
|
||||
if (n != -1 && n == i)
|
||||
break;
|
||||
width += s[i].width;
|
||||
}
|
||||
return (width);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a string into a buffer of UTF-8 characters. Terminated by size == 0.
|
||||
* Caller frees.
|
||||
|
Loading…
Reference in New Issue
Block a user