Annotation of src/usr.bin/tmux/input.c, Revision 1.66
1.66 ! nicm 1: /* $OpenBSD: input.c,v 1.65 2014/01/31 11:17:20 nicm Exp $ */
1.1 nicm 2:
3: /*
4: * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15: * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/types.h>
20:
21: #include <stdlib.h>
22: #include <string.h>
23:
24: #include "tmux.h"
25:
1.28 nicm 26: /*
27: * Based on the description by Paul Williams at:
28: *
29: * http://vt100.net/emu/dec_ansi_parser
30: *
31: * With the following changes:
32: *
33: * - 7-bit only.
34: *
35: * - Support for UTF-8.
36: *
37: * - OSC (but not APC) may be terminated by \007 as well as ST.
38: *
39: * - A state for APC similar to OSC. Some terminals appear to use this to set
40: * the title.
41: *
42: * - A state for the screen \033k...\033\\ sequence to rename a window. This is
43: * pretty stupid but not supporting it is more trouble than it is worth.
1.37 nicm 44: *
45: * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46: * be passed to the underlying teminal(s).
1.28 nicm 47: */
48:
49: /* Helper functions. */
1.52 nicm 50: struct input_transition;
1.28 nicm 51: int input_split(struct input_ctx *);
52: int input_get(struct input_ctx *, u_int, int, int);
53: void input_reply(struct input_ctx *, const char *, ...);
1.52 nicm 54: void input_set_state(struct window_pane *, const struct input_transition *);
1.28 nicm 55:
56: /* Transition entry/exit handlers. */
57: void input_clear(struct input_ctx *);
58: void input_enter_osc(struct input_ctx *);
59: void input_exit_osc(struct input_ctx *);
60: void input_enter_apc(struct input_ctx *);
61: void input_exit_apc(struct input_ctx *);
62: void input_enter_rename(struct input_ctx *);
63: void input_exit_rename(struct input_ctx *);
64:
65: /* Input state handlers. */
66: int input_print(struct input_ctx *);
67: int input_intermediate(struct input_ctx *);
68: int input_parameter(struct input_ctx *);
69: int input_input(struct input_ctx *);
70: int input_c0_dispatch(struct input_ctx *);
71: int input_esc_dispatch(struct input_ctx *);
72: int input_csi_dispatch(struct input_ctx *);
1.64 nicm 73: void input_csi_dispatch_rm(struct input_ctx *);
74: void input_csi_dispatch_rm_private(struct input_ctx *);
75: void input_csi_dispatch_sm(struct input_ctx *);
76: void input_csi_dispatch_sm_private(struct input_ctx *);
1.65 nicm 77: void input_csi_dispatch_winops(struct input_ctx *);
1.28 nicm 78: void input_csi_dispatch_sgr(struct input_ctx *);
1.37 nicm 79: int input_dcs_dispatch(struct input_ctx *);
1.28 nicm 80: int input_utf8_open(struct input_ctx *);
81: int input_utf8_add(struct input_ctx *);
82: int input_utf8_close(struct input_ctx *);
83:
84: /* Command table comparison function. */
85: int input_table_compare(const void *, const void *);
86:
87: /* Command table entry. */
88: struct input_table_entry {
89: int ch;
90: const char *interm;
91: int type;
1.1 nicm 92: };
93:
1.28 nicm 94: /* Escape commands. */
95: enum input_esc_type {
96: INPUT_ESC_DECALN,
97: INPUT_ESC_DECKPAM,
98: INPUT_ESC_DECKPNM,
99: INPUT_ESC_DECRC,
100: INPUT_ESC_DECSC,
101: INPUT_ESC_HTS,
102: INPUT_ESC_IND,
103: INPUT_ESC_NEL,
104: INPUT_ESC_RI,
105: INPUT_ESC_RIS,
106: INPUT_ESC_SCSOFF_G0,
107: INPUT_ESC_SCSON_G0,
108: };
1.1 nicm 109:
1.28 nicm 110: /* Escape command table. */
111: const struct input_table_entry input_esc_table[] = {
112: { '0', "(", INPUT_ESC_SCSOFF_G0 },
113: { '7', "", INPUT_ESC_DECSC },
114: { '8', "", INPUT_ESC_DECRC },
115: { '8', "#", INPUT_ESC_DECALN },
116: { '=', "", INPUT_ESC_DECKPAM },
117: { '>', "", INPUT_ESC_DECKPNM },
118: { 'B', "(", INPUT_ESC_SCSON_G0 },
119: { 'D', "", INPUT_ESC_IND },
120: { 'E', "", INPUT_ESC_NEL },
121: { 'H', "", INPUT_ESC_HTS },
122: { 'M', "", INPUT_ESC_RI },
123: { 'c', "", INPUT_ESC_RIS },
124: };
1.1 nicm 125:
1.28 nicm 126: /* Control (CSI) commands. */
127: enum input_csi_type {
128: INPUT_CSI_CBT,
1.43 nicm 129: INPUT_CSI_CNL,
130: INPUT_CSI_CPL,
1.28 nicm 131: INPUT_CSI_CUB,
132: INPUT_CSI_CUD,
133: INPUT_CSI_CUF,
134: INPUT_CSI_CUP,
135: INPUT_CSI_CUU,
136: INPUT_CSI_DA,
1.50 nicm 137: INPUT_CSI_DA_TWO,
1.28 nicm 138: INPUT_CSI_DCH,
1.39 nicm 139: INPUT_CSI_DECSCUSR,
1.28 nicm 140: INPUT_CSI_DECSTBM,
141: INPUT_CSI_DL,
142: INPUT_CSI_DSR,
1.56 nicm 143: INPUT_CSI_ECH,
1.28 nicm 144: INPUT_CSI_ED,
145: INPUT_CSI_EL,
146: INPUT_CSI_HPA,
147: INPUT_CSI_ICH,
148: INPUT_CSI_IL,
1.42 nicm 149: INPUT_CSI_RCP,
1.28 nicm 150: INPUT_CSI_RM,
151: INPUT_CSI_RM_PRIVATE,
1.42 nicm 152: INPUT_CSI_SCP,
1.28 nicm 153: INPUT_CSI_SGR,
154: INPUT_CSI_SM,
155: INPUT_CSI_SM_PRIVATE,
156: INPUT_CSI_TBC,
157: INPUT_CSI_VPA,
1.65 nicm 158: INPUT_CSI_WINOPS,
1.28 nicm 159: };
1.1 nicm 160:
1.28 nicm 161: /* Control (CSI) command table. */
162: const struct input_table_entry input_csi_table[] = {
163: { '@', "", INPUT_CSI_ICH },
164: { 'A', "", INPUT_CSI_CUU },
165: { 'B', "", INPUT_CSI_CUD },
166: { 'C', "", INPUT_CSI_CUF },
167: { 'D', "", INPUT_CSI_CUB },
1.43 nicm 168: { 'E', "", INPUT_CSI_CNL },
169: { 'F', "", INPUT_CSI_CPL },
1.28 nicm 170: { 'G', "", INPUT_CSI_HPA },
171: { 'H', "", INPUT_CSI_CUP },
172: { 'J', "", INPUT_CSI_ED },
173: { 'K', "", INPUT_CSI_EL },
174: { 'L', "", INPUT_CSI_IL },
175: { 'M', "", INPUT_CSI_DL },
176: { 'P', "", INPUT_CSI_DCH },
1.56 nicm 177: { 'X', "", INPUT_CSI_ECH },
1.28 nicm 178: { 'Z', "", INPUT_CSI_CBT },
179: { 'c', "", INPUT_CSI_DA },
1.50 nicm 180: { 'c', ">", INPUT_CSI_DA_TWO },
1.28 nicm 181: { 'd', "", INPUT_CSI_VPA },
182: { 'f', "", INPUT_CSI_CUP },
183: { 'g', "", INPUT_CSI_TBC },
184: { 'h', "", INPUT_CSI_SM },
185: { 'h', "?", INPUT_CSI_SM_PRIVATE },
186: { 'l', "", INPUT_CSI_RM },
187: { 'l', "?", INPUT_CSI_RM_PRIVATE },
188: { 'm', "", INPUT_CSI_SGR },
189: { 'n', "", INPUT_CSI_DSR },
1.39 nicm 190: { 'q', " ", INPUT_CSI_DECSCUSR },
1.28 nicm 191: { 'r', "", INPUT_CSI_DECSTBM },
1.42 nicm 192: { 's', "", INPUT_CSI_SCP },
1.65 nicm 193: { 't', "", INPUT_CSI_WINOPS },
1.42 nicm 194: { 'u', "", INPUT_CSI_RCP },
1.28 nicm 195: };
1.1 nicm 196:
1.28 nicm 197: /* Input transition. */
198: struct input_transition {
199: int first;
200: int last;
1.1 nicm 201:
1.28 nicm 202: int (*handler)(struct input_ctx *);
203: const struct input_state *state;
204: };
1.1 nicm 205:
1.28 nicm 206: /* Input state. */
207: struct input_state {
208: const char *name;
209: void (*enter)(struct input_ctx *);
210: void (*exit)(struct input_ctx *);
211: const struct input_transition *transitions;
212: };
1.1 nicm 213:
1.28 nicm 214: /* State transitions available from all states. */
215: #define INPUT_STATE_ANYWHERE \
216: { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
217: { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
218: { 0x1b, 0x1b, NULL, &input_state_esc_enter }
219:
220: /* Forward declarations of state tables. */
221: const struct input_transition input_state_ground_table[];
222: const struct input_transition input_state_esc_enter_table[];
223: const struct input_transition input_state_esc_intermediate_table[];
224: const struct input_transition input_state_csi_enter_table[];
225: const struct input_transition input_state_csi_parameter_table[];
226: const struct input_transition input_state_csi_intermediate_table[];
227: const struct input_transition input_state_csi_ignore_table[];
228: const struct input_transition input_state_dcs_enter_table[];
229: const struct input_transition input_state_dcs_parameter_table[];
230: const struct input_transition input_state_dcs_intermediate_table[];
231: const struct input_transition input_state_dcs_handler_table[];
1.37 nicm 232: const struct input_transition input_state_dcs_escape_table[];
1.28 nicm 233: const struct input_transition input_state_dcs_ignore_table[];
234: const struct input_transition input_state_osc_string_table[];
235: const struct input_transition input_state_apc_string_table[];
236: const struct input_transition input_state_rename_string_table[];
237: const struct input_transition input_state_consume_st_table[];
238: const struct input_transition input_state_utf8_three_table[];
239: const struct input_transition input_state_utf8_two_table[];
240: const struct input_transition input_state_utf8_one_table[];
241:
242: /* ground state definition. */
243: const struct input_state input_state_ground = {
244: "ground",
245: NULL, NULL,
246: input_state_ground_table
247: };
1.1 nicm 248:
1.28 nicm 249: /* esc_enter state definition. */
250: const struct input_state input_state_esc_enter = {
251: "esc_enter",
252: input_clear, NULL,
253: input_state_esc_enter_table
254: };
1.1 nicm 255:
1.28 nicm 256: /* esc_intermediate state definition. */
257: const struct input_state input_state_esc_intermediate = {
258: "esc_intermediate",
259: NULL, NULL,
260: input_state_esc_intermediate_table
261: };
1.1 nicm 262:
1.28 nicm 263: /* csi_enter state definition. */
264: const struct input_state input_state_csi_enter = {
265: "csi_enter",
266: input_clear, NULL,
267: input_state_csi_enter_table
268: };
1.1 nicm 269:
1.28 nicm 270: /* csi_parameter state definition. */
271: const struct input_state input_state_csi_parameter = {
272: "csi_parameter",
273: NULL, NULL,
274: input_state_csi_parameter_table
275: };
1.1 nicm 276:
1.28 nicm 277: /* csi_intermediate state definition. */
278: const struct input_state input_state_csi_intermediate = {
279: "csi_intermediate",
280: NULL, NULL,
281: input_state_csi_intermediate_table
282: };
1.1 nicm 283:
1.28 nicm 284: /* csi_ignore state definition. */
285: const struct input_state input_state_csi_ignore = {
286: "csi_ignore",
287: NULL, NULL,
288: input_state_csi_ignore_table
289: };
1.1 nicm 290:
1.28 nicm 291: /* dcs_enter state definition. */
292: const struct input_state input_state_dcs_enter = {
293: "dcs_enter",
294: input_clear, NULL,
295: input_state_dcs_enter_table
296: };
1.1 nicm 297:
1.28 nicm 298: /* dcs_parameter state definition. */
299: const struct input_state input_state_dcs_parameter = {
300: "dcs_parameter",
301: NULL, NULL,
302: input_state_dcs_parameter_table
303: };
1.1 nicm 304:
1.28 nicm 305: /* dcs_intermediate state definition. */
306: const struct input_state input_state_dcs_intermediate = {
307: "dcs_intermediate",
308: NULL, NULL,
309: input_state_dcs_intermediate_table
310: };
1.1 nicm 311:
1.28 nicm 312: /* dcs_handler state definition. */
313: const struct input_state input_state_dcs_handler = {
314: "dcs_handler",
1.37 nicm 315: NULL, NULL,
1.28 nicm 316: input_state_dcs_handler_table
317: };
1.1 nicm 318:
1.37 nicm 319: /* dcs_escape state definition. */
320: const struct input_state input_state_dcs_escape = {
321: "dcs_escape",
322: NULL, NULL,
323: input_state_dcs_escape_table
324: };
325:
1.28 nicm 326: /* dcs_ignore state definition. */
327: const struct input_state input_state_dcs_ignore = {
328: "dcs_ignore",
329: NULL, NULL,
330: input_state_dcs_ignore_table
331: };
1.1 nicm 332:
1.28 nicm 333: /* osc_string state definition. */
334: const struct input_state input_state_osc_string = {
335: "osc_string",
336: input_enter_osc, input_exit_osc,
337: input_state_osc_string_table
338: };
1.1 nicm 339:
1.28 nicm 340: /* apc_string state definition. */
341: const struct input_state input_state_apc_string = {
342: "apc_string",
343: input_enter_apc, input_exit_apc,
344: input_state_apc_string_table
345: };
1.1 nicm 346:
1.28 nicm 347: /* rename_string state definition. */
348: const struct input_state input_state_rename_string = {
349: "rename_string",
350: input_enter_rename, input_exit_rename,
351: input_state_rename_string_table
352: };
1.1 nicm 353:
1.28 nicm 354: /* consume_st state definition. */
355: const struct input_state input_state_consume_st = {
356: "consume_st",
357: NULL, NULL,
358: input_state_consume_st_table
359: };
1.1 nicm 360:
1.28 nicm 361: /* utf8_three state definition. */
362: const struct input_state input_state_utf8_three = {
363: "utf8_three",
364: NULL, NULL,
365: input_state_utf8_three_table
366: };
1.1 nicm 367:
1.28 nicm 368: /* utf8_two state definition. */
369: const struct input_state input_state_utf8_two = {
370: "utf8_two",
371: NULL, NULL,
372: input_state_utf8_two_table
373: };
1.1 nicm 374:
1.28 nicm 375: /* utf8_one state definition. */
376: const struct input_state input_state_utf8_one = {
377: "utf8_one",
378: NULL, NULL,
379: input_state_utf8_one_table
380: };
1.1 nicm 381:
1.28 nicm 382: /* ground state table. */
383: const struct input_transition input_state_ground_table[] = {
384: INPUT_STATE_ANYWHERE,
385:
386: { 0x00, 0x17, input_c0_dispatch, NULL },
387: { 0x19, 0x19, input_c0_dispatch, NULL },
388: { 0x1c, 0x1f, input_c0_dispatch, NULL },
389: { 0x20, 0x7e, input_print, NULL },
390: { 0x7f, 0x7f, NULL, NULL },
391: { 0x80, 0xc1, input_print, NULL },
392: { 0xc2, 0xdf, input_utf8_open, &input_state_utf8_one },
393: { 0xe0, 0xef, input_utf8_open, &input_state_utf8_two },
394: { 0xf0, 0xf4, input_utf8_open, &input_state_utf8_three },
395: { 0xf5, 0xff, input_print, NULL },
1.1 nicm 396:
1.28 nicm 397: { -1, -1, NULL, NULL }
398: };
1.13 nicm 399:
1.28 nicm 400: /* esc_enter state table. */
401: const struct input_transition input_state_esc_enter_table[] = {
402: INPUT_STATE_ANYWHERE,
403:
404: { 0x00, 0x17, input_c0_dispatch, NULL },
405: { 0x19, 0x19, input_c0_dispatch, NULL },
406: { 0x1c, 0x1f, input_c0_dispatch, NULL },
407: { 0x20, 0x2f, input_intermediate, &input_state_esc_intermediate },
408: { 0x30, 0x4f, input_esc_dispatch, &input_state_ground },
409: { 0x50, 0x50, NULL, &input_state_dcs_enter },
410: { 0x51, 0x57, input_esc_dispatch, &input_state_ground },
411: { 0x58, 0x58, NULL, &input_state_consume_st },
412: { 0x59, 0x59, input_esc_dispatch, &input_state_ground },
413: { 0x5a, 0x5a, input_esc_dispatch, &input_state_ground },
414: { 0x5b, 0x5b, NULL, &input_state_csi_enter },
415: { 0x5c, 0x5c, input_esc_dispatch, &input_state_ground },
416: { 0x5d, 0x5d, NULL, &input_state_osc_string },
417: { 0x5e, 0x5e, NULL, &input_state_consume_st },
418: { 0x5f, 0x5f, NULL, &input_state_apc_string },
419: { 0x60, 0x6a, input_esc_dispatch, &input_state_ground },
420: { 0x6b, 0x6b, NULL, &input_state_rename_string },
1.29 nicm 421: { 0x6c, 0x7e, input_esc_dispatch, &input_state_ground },
1.28 nicm 422: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 423:
1.28 nicm 424: { -1, -1, NULL, NULL }
425: };
1.1 nicm 426:
1.28 nicm 427: /* esc_interm state table. */
428: const struct input_transition input_state_esc_intermediate_table[] = {
429: INPUT_STATE_ANYWHERE,
430:
431: { 0x00, 0x17, input_c0_dispatch, NULL },
432: { 0x19, 0x19, input_c0_dispatch, NULL },
433: { 0x1c, 0x1f, input_c0_dispatch, NULL },
434: { 0x20, 0x2f, input_intermediate, NULL },
435: { 0x30, 0x7e, input_esc_dispatch, &input_state_ground },
436: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 437:
1.28 nicm 438: { -1, -1, NULL, NULL }
439: };
1.1 nicm 440:
1.28 nicm 441: /* csi_enter state table. */
442: const struct input_transition input_state_csi_enter_table[] = {
443: INPUT_STATE_ANYWHERE,
444:
445: { 0x00, 0x17, input_c0_dispatch, NULL },
446: { 0x19, 0x19, input_c0_dispatch, NULL },
447: { 0x1c, 0x1f, input_c0_dispatch, NULL },
448: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
449: { 0x30, 0x39, input_parameter, &input_state_csi_parameter },
450: { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
451: { 0x3b, 0x3b, input_parameter, &input_state_csi_parameter },
452: { 0x3c, 0x3f, input_intermediate, &input_state_csi_parameter },
453: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
454: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 455:
1.28 nicm 456: { -1, -1, NULL, NULL }
457: };
1.1 nicm 458:
1.28 nicm 459: /* csi_parameter state table. */
460: const struct input_transition input_state_csi_parameter_table[] = {
461: INPUT_STATE_ANYWHERE,
462:
463: { 0x00, 0x17, input_c0_dispatch, NULL },
464: { 0x19, 0x19, input_c0_dispatch, NULL },
465: { 0x1c, 0x1f, input_c0_dispatch, NULL },
466: { 0x20, 0x2f, input_intermediate, &input_state_csi_intermediate },
467: { 0x30, 0x39, input_parameter, NULL },
468: { 0x3a, 0x3a, NULL, &input_state_csi_ignore },
469: { 0x3b, 0x3b, input_parameter, NULL },
470: { 0x3c, 0x3f, NULL, &input_state_csi_ignore },
471: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
472: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 473:
1.28 nicm 474: { -1, -1, NULL, NULL }
475: };
1.1 nicm 476:
1.28 nicm 477: /* csi_intermediate state table. */
478: const struct input_transition input_state_csi_intermediate_table[] = {
479: INPUT_STATE_ANYWHERE,
480:
481: { 0x00, 0x17, input_c0_dispatch, NULL },
482: { 0x19, 0x19, input_c0_dispatch, NULL },
483: { 0x1c, 0x1f, input_c0_dispatch, NULL },
484: { 0x20, 0x2f, input_intermediate, NULL },
485: { 0x30, 0x3f, NULL, &input_state_csi_ignore },
486: { 0x40, 0x7e, input_csi_dispatch, &input_state_ground },
487: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 488:
1.28 nicm 489: { -1, -1, NULL, NULL }
490: };
1.1 nicm 491:
1.28 nicm 492: /* csi_ignore state table. */
493: const struct input_transition input_state_csi_ignore_table[] = {
494: INPUT_STATE_ANYWHERE,
495:
496: { 0x00, 0x17, input_c0_dispatch, NULL },
497: { 0x19, 0x19, input_c0_dispatch, NULL },
498: { 0x1c, 0x1f, input_c0_dispatch, NULL },
499: { 0x20, 0x3f, NULL, NULL },
500: { 0x40, 0x7e, NULL, &input_state_ground },
501: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 502:
1.28 nicm 503: { -1, -1, NULL, NULL }
504: };
1.1 nicm 505:
1.28 nicm 506: /* dcs_enter state table. */
507: const struct input_transition input_state_dcs_enter_table[] = {
508: INPUT_STATE_ANYWHERE,
509:
510: { 0x00, 0x17, NULL, NULL },
511: { 0x19, 0x19, NULL, NULL },
512: { 0x1c, 0x1f, NULL, NULL },
513: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
514: { 0x30, 0x39, input_parameter, &input_state_dcs_parameter },
515: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
516: { 0x3b, 0x3b, input_parameter, &input_state_dcs_parameter },
517: { 0x3c, 0x3f, input_intermediate, &input_state_dcs_parameter },
1.37 nicm 518: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 519: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 520:
1.28 nicm 521: { -1, -1, NULL, NULL }
522: };
1.1 nicm 523:
1.28 nicm 524: /* dcs_parameter state table. */
525: const struct input_transition input_state_dcs_parameter_table[] = {
526: INPUT_STATE_ANYWHERE,
527:
528: { 0x00, 0x17, NULL, NULL },
529: { 0x19, 0x19, NULL, NULL },
530: { 0x1c, 0x1f, NULL, NULL },
531: { 0x20, 0x2f, input_intermediate, &input_state_dcs_intermediate },
532: { 0x30, 0x39, input_parameter, NULL },
533: { 0x3a, 0x3a, NULL, &input_state_dcs_ignore },
534: { 0x3b, 0x3b, input_parameter, NULL },
535: { 0x3c, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 536: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 537: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 538:
1.28 nicm 539: { -1, -1, NULL, NULL }
540: };
1.1 nicm 541:
1.28 nicm 542: /* dcs_interm state table. */
543: const struct input_transition input_state_dcs_intermediate_table[] = {
544: INPUT_STATE_ANYWHERE,
545:
546: { 0x00, 0x17, NULL, NULL },
547: { 0x19, 0x19, NULL, NULL },
548: { 0x1c, 0x1f, NULL, NULL },
549: { 0x20, 0x2f, input_intermediate, NULL },
550: { 0x30, 0x3f, NULL, &input_state_dcs_ignore },
1.37 nicm 551: { 0x40, 0x7e, input_input, &input_state_dcs_handler },
1.28 nicm 552: { 0x7f, 0xff, NULL, NULL },
1.1 nicm 553:
1.28 nicm 554: { -1, -1, NULL, NULL }
555: };
1.1 nicm 556:
1.28 nicm 557: /* dcs_handler state table. */
558: const struct input_transition input_state_dcs_handler_table[] = {
1.37 nicm 559: /* No INPUT_STATE_ANYWHERE */
560:
561: { 0x00, 0x1a, input_input, NULL },
562: { 0x1b, 0x1b, NULL, &input_state_dcs_escape },
563: { 0x1c, 0xff, input_input, NULL },
564:
565: { -1, -1, NULL, NULL }
566: };
567:
568: /* dcs_escape state table. */
569: const struct input_transition input_state_dcs_escape_table[] = {
570: /* No INPUT_STATE_ANYWHERE */
1.28 nicm 571:
1.37 nicm 572: { 0x00, 0x5b, input_input, &input_state_dcs_handler },
573: { 0x5c, 0x5c, input_dcs_dispatch, &input_state_ground },
574: { 0x5d, 0xff, input_input, &input_state_dcs_handler },
1.1 nicm 575:
1.28 nicm 576: { -1, -1, NULL, NULL }
577: };
1.1 nicm 578:
1.40 nicm 579: /* dcs_ignore state table. */
1.28 nicm 580: const struct input_transition input_state_dcs_ignore_table[] = {
581: INPUT_STATE_ANYWHERE,
582:
583: { 0x00, 0x17, NULL, NULL },
584: { 0x19, 0x19, NULL, NULL },
585: { 0x1c, 0x1f, NULL, NULL },
586: { 0x20, 0xff, NULL, NULL },
1.1 nicm 587:
1.28 nicm 588: { -1, -1, NULL, NULL }
589: };
1.1 nicm 590:
1.28 nicm 591: /* osc_string state table. */
592: const struct input_transition input_state_osc_string_table[] = {
593: INPUT_STATE_ANYWHERE,
594:
595: { 0x00, 0x06, NULL, NULL },
596: { 0x07, 0x07, NULL, &input_state_ground },
597: { 0x08, 0x17, NULL, NULL },
598: { 0x19, 0x19, NULL, NULL },
599: { 0x1c, 0x1f, NULL, NULL },
600: { 0x20, 0xff, input_input, NULL },
1.1 nicm 601:
1.28 nicm 602: { -1, -1, NULL, NULL }
603: };
1.1 nicm 604:
1.28 nicm 605: /* apc_string state table. */
606: const struct input_transition input_state_apc_string_table[] = {
607: INPUT_STATE_ANYWHERE,
608:
609: { 0x00, 0x17, NULL, NULL },
610: { 0x19, 0x19, NULL, NULL },
611: { 0x1c, 0x1f, NULL, NULL },
612: { 0x20, 0xff, input_input, NULL },
1.1 nicm 613:
1.28 nicm 614: { -1, -1, NULL, NULL }
615: };
1.1 nicm 616:
1.28 nicm 617: /* rename_string state table. */
618: const struct input_transition input_state_rename_string_table[] = {
619: INPUT_STATE_ANYWHERE,
620:
621: { 0x00, 0x17, NULL, NULL },
622: { 0x19, 0x19, NULL, NULL },
623: { 0x1c, 0x1f, NULL, NULL },
624: { 0x20, 0xff, input_input, NULL },
1.1 nicm 625:
1.28 nicm 626: { -1, -1, NULL, NULL }
627: };
1.1 nicm 628:
1.28 nicm 629: /* consume_st state table. */
630: const struct input_transition input_state_consume_st_table[] = {
631: INPUT_STATE_ANYWHERE,
632:
633: { 0x00, 0x17, NULL, NULL },
634: { 0x19, 0x19, NULL, NULL },
635: { 0x1c, 0x1f, NULL, NULL },
636: { 0x20, 0xff, NULL, NULL },
1.6 nicm 637:
1.28 nicm 638: { -1, -1, NULL, NULL }
639: };
1.6 nicm 640:
1.28 nicm 641: /* utf8_three state table. */
642: const struct input_transition input_state_utf8_three_table[] = {
643: /* No INPUT_STATE_ANYWHERE */
644:
645: { 0x00, 0x7f, NULL, &input_state_ground },
646: { 0x80, 0xbf, input_utf8_add, &input_state_utf8_two },
647: { 0xc0, 0xff, NULL, &input_state_ground },
1.4 nicm 648:
1.28 nicm 649: { -1, -1, NULL, NULL }
650: };
1.1 nicm 651:
1.28 nicm 652: /* utf8_two state table. */
653: const struct input_transition input_state_utf8_two_table[] = {
654: /* No INPUT_STATE_ANYWHERE */
655:
656: { 0x00, 0x7f, NULL, &input_state_ground },
657: { 0x80, 0xbf, input_utf8_add, &input_state_utf8_one },
658: { 0xc0, 0xff, NULL, &input_state_ground },
1.1 nicm 659:
1.28 nicm 660: { -1, -1, NULL, NULL }
661: };
1.1 nicm 662:
1.28 nicm 663: /* utf8_one state table. */
664: const struct input_transition input_state_utf8_one_table[] = {
665: /* No INPUT_STATE_ANYWHERE */
666:
667: { 0x00, 0x7f, NULL, &input_state_ground },
668: { 0x80, 0xbf, input_utf8_close, &input_state_ground },
669: { 0xc0, 0xff, NULL, &input_state_ground },
1.1 nicm 670:
1.28 nicm 671: { -1, -1, NULL, NULL }
672: };
1.1 nicm 673:
1.28 nicm 674: /* Input table compare. */
675: int
676: input_table_compare(const void *key, const void *value)
1.1 nicm 677: {
1.28 nicm 678: const struct input_ctx *ictx = key;
679: const struct input_table_entry *entry = value;
1.1 nicm 680:
1.28 nicm 681: if (ictx->ch != entry->ch)
682: return (ictx->ch - entry->ch);
683: return (strcmp(ictx->interm_buf, entry->interm));
1.1 nicm 684: }
685:
1.28 nicm 686: /* Initialise input parser. */
1.1 nicm 687: void
1.28 nicm 688: input_init(struct window_pane *wp)
1.1 nicm 689: {
1.28 nicm 690: struct input_ctx *ictx = &wp->ictx;
1.1 nicm 691:
1.28 nicm 692: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1.1 nicm 693:
1.28 nicm 694: memcpy(&ictx->old_cell, &grid_default_cell, sizeof ictx->old_cell);
695: ictx->old_cx = 0;
696: ictx->old_cy = 0;
1.1 nicm 697:
1.28 nicm 698: *ictx->interm_buf = '\0';
699: ictx->interm_len = 0;
1.1 nicm 700:
1.28 nicm 701: *ictx->param_buf = '\0';
702: ictx->param_len = 0;
1.1 nicm 703:
1.28 nicm 704: ictx->state = &input_state_ground;
705: ictx->flags = 0;
1.52 nicm 706:
707: ictx->since_ground = evbuffer_new();
1.1 nicm 708: }
709:
1.28 nicm 710: /* Destroy input parser. */
1.1 nicm 711: void
1.52 nicm 712: input_free(struct window_pane *wp)
1.1 nicm 713: {
1.52 nicm 714: if (wp != NULL)
715: evbuffer_free(wp->ictx.since_ground);
716: }
717:
718: /* Change input state. */
719: void
720: input_set_state(struct window_pane *wp, const struct input_transition *itr)
721: {
722: struct input_ctx *ictx = &wp->ictx;
723: struct evbuffer *ground_evb = ictx->since_ground;
724:
725: if (ictx->state->exit != NULL)
726: ictx->state->exit(ictx);
727:
728: if (itr->state == &input_state_ground)
729: evbuffer_drain(ground_evb, EVBUFFER_LENGTH(ground_evb));
730:
731: ictx->state = itr->state;
732: if (ictx->state->enter != NULL)
733: ictx->state->enter(ictx);
1.1 nicm 734: }
735:
1.28 nicm 736: /* Parse input. */
1.1 nicm 737: void
1.28 nicm 738: input_parse(struct window_pane *wp)
1.1 nicm 739: {
1.28 nicm 740: struct input_ctx *ictx = &wp->ictx;
741: const struct input_transition *itr;
742: struct evbuffer *evb = wp->event->input;
743: u_char *buf;
744: size_t len, off;
1.1 nicm 745:
1.28 nicm 746: if (EVBUFFER_LENGTH(evb) == 0)
747: return;
1.30 nicm 748:
1.28 nicm 749: wp->window->flags |= WINDOW_ACTIVITY;
1.30 nicm 750: wp->window->flags &= ~WINDOW_SILENCE;
1.1 nicm 751:
1.28 nicm 752: /*
753: * Open the screen. Use NULL wp if there is a mode set as don't want to
754: * update the tty.
755: */
756: if (wp->mode == NULL)
757: screen_write_start(&ictx->ctx, wp, &wp->base);
758: else
759: screen_write_start(&ictx->ctx, NULL, &wp->base);
760: ictx->wp = wp;
1.7 nicm 761:
1.28 nicm 762: buf = EVBUFFER_DATA(evb);
763: len = EVBUFFER_LENGTH(evb);
1.54 nicm 764: notify_input(wp, evb);
1.28 nicm 765: off = 0;
766:
767: /* Parse the input. */
768: while (off < len) {
769: ictx->ch = buf[off++];
770: log_debug("%s: '%c' %s", __func__, ictx->ch, ictx->state->name);
771:
772: /* Find the transition. */
773: itr = ictx->state->transitions;
774: while (itr->first != -1 && itr->last != -1) {
775: if (ictx->ch >= itr->first && ictx->ch <= itr->last)
1.7 nicm 776: break;
1.28 nicm 777: itr++;
1.1 nicm 778: }
1.28 nicm 779: if (itr->first == -1 || itr->last == -1) {
780: /* No transition? Eh? */
781: fatalx("No transition from state!");
1.3 nicm 782: }
1.1 nicm 783:
784: /*
1.28 nicm 785: * Execute the handler, if any. Don't switch state if it
786: * returns non-zero.
1.1 nicm 787: */
1.31 nicm 788: if (itr->handler != NULL && itr->handler(ictx) != 0)
1.28 nicm 789: continue;
790:
791: /* And switch state, if necessary. */
1.52 nicm 792: if (itr->state != NULL)
793: input_set_state(wp, itr);
794:
795: /* If not in ground state, save input. */
796: if (ictx->state != &input_state_ground)
797: evbuffer_add(ictx->since_ground, &ictx->ch, 1);
1.1 nicm 798: }
799:
1.28 nicm 800: /* Close the screen. */
801: screen_write_stop(&ictx->ctx);
1.1 nicm 802:
1.28 nicm 803: evbuffer_drain(evb, len);
1.1 nicm 804: }
805:
1.28 nicm 806: /* Split the parameter list (if any). */
807: int
808: input_split(struct input_ctx *ictx)
1.1 nicm 809:
810: {
1.28 nicm 811: const char *errstr;
812: char *ptr, *out;
813: int n;
1.1 nicm 814:
1.28 nicm 815: ictx->param_list_len = 0;
816: if (ictx->param_len == 0)
817: return (0);
1.1 nicm 818:
1.28 nicm 819: ptr = ictx->param_buf;
820: while ((out = strsep(&ptr, ";")) != NULL) {
821: if (*out == '\0')
822: n = -1;
823: else {
824: n = strtonum(out, 0, INT_MAX, &errstr);
825: if (errstr != NULL)
826: return (-1);
827: }
1.1 nicm 828:
1.28 nicm 829: ictx->param_list[ictx->param_list_len++] = n;
830: if (ictx->param_list_len == nitems(ictx->param_list))
831: return (-1);
832: }
1.1 nicm 833:
1.28 nicm 834: return (0);
1.1 nicm 835: }
836:
1.40 nicm 837: /* Get an argument or return default value. */
1.28 nicm 838: int
839: input_get(struct input_ctx *ictx, u_int validx, int minval, int defval)
1.1 nicm 840: {
1.28 nicm 841: int retval;
1.1 nicm 842:
1.28 nicm 843: if (validx >= ictx->param_list_len)
844: return (defval);
1.1 nicm 845:
1.28 nicm 846: retval = ictx->param_list[validx];
847: if (retval == -1)
848: return (defval);
849: if (retval < minval)
850: return (minval);
851: return (retval);
1.1 nicm 852: }
853:
1.28 nicm 854: /* Reply to terminal query. */
1.1 nicm 855: void
1.28 nicm 856: input_reply(struct input_ctx *ictx, const char *fmt, ...)
1.1 nicm 857: {
1.28 nicm 858: va_list ap;
859: char *reply;
1.1 nicm 860:
1.28 nicm 861: va_start(ap, fmt);
862: vasprintf(&reply, fmt, ap);
863: va_end(ap);
1.1 nicm 864:
1.28 nicm 865: bufferevent_write(ictx->wp->event, reply, strlen(reply));
1.53 nicm 866: free(reply);
1.8 nicm 867: }
868:
1.28 nicm 869: /* Clear saved state. */
1.8 nicm 870: void
1.28 nicm 871: input_clear(struct input_ctx *ictx)
1.8 nicm 872: {
1.28 nicm 873: *ictx->interm_buf = '\0';
874: ictx->interm_len = 0;
1.8 nicm 875:
1.28 nicm 876: *ictx->param_buf = '\0';
877: ictx->param_len = 0;
1.8 nicm 878:
1.35 nicm 879: *ictx->input_buf = '\0';
880: ictx->input_len = 0;
881:
1.28 nicm 882: ictx->flags &= ~INPUT_DISCARD;
1.14 nicm 883: }
884:
1.28 nicm 885: /* Output this character to the screen. */
886: int
887: input_print(struct input_ctx *ictx)
1.14 nicm 888: {
1.58 nicm 889: grid_cell_one(&ictx->cell, ictx->ch);
890: screen_write_cell(&ictx->ctx, &ictx->cell);
1.14 nicm 891:
1.28 nicm 892: return (0);
1.1 nicm 893: }
894:
1.28 nicm 895: /* Collect intermediate string. */
896: int
897: input_intermediate(struct input_ctx *ictx)
1.1 nicm 898: {
1.28 nicm 899: if (ictx->interm_len == (sizeof ictx->interm_buf) - 1)
900: ictx->flags |= INPUT_DISCARD;
901: else {
902: ictx->interm_buf[ictx->interm_len++] = ictx->ch;
903: ictx->interm_buf[ictx->interm_len] = '\0';
904: }
1.1 nicm 905:
1.28 nicm 906: return (0);
1.1 nicm 907: }
908:
1.28 nicm 909: /* Collect parameter string. */
910: int
911: input_parameter(struct input_ctx *ictx)
1.1 nicm 912: {
1.28 nicm 913: if (ictx->param_len == (sizeof ictx->param_buf) - 1)
914: ictx->flags |= INPUT_DISCARD;
915: else {
916: ictx->param_buf[ictx->param_len++] = ictx->ch;
917: ictx->param_buf[ictx->param_len] = '\0';
918: }
1.1 nicm 919:
1.28 nicm 920: return (0);
1.1 nicm 921: }
922:
1.28 nicm 923: /* Collect input string. */
924: int
925: input_input(struct input_ctx *ictx)
1.1 nicm 926: {
1.28 nicm 927: if (ictx->input_len == (sizeof ictx->input_buf) - 1)
928: ictx->flags |= INPUT_DISCARD;
929: else {
930: ictx->input_buf[ictx->input_len++] = ictx->ch;
931: ictx->input_buf[ictx->input_len] = '\0';
932: }
1.1 nicm 933:
1.28 nicm 934: return (0);
1.1 nicm 935: }
936:
1.28 nicm 937: /* Execute C0 control sequence. */
938: int
939: input_c0_dispatch(struct input_ctx *ictx)
1.1 nicm 940: {
1.28 nicm 941: struct screen_write_ctx *sctx = &ictx->ctx;
942: struct window_pane *wp = ictx->wp;
943: struct screen *s = sctx->s;
1.51 nicm 944: u_int trigger;
1.1 nicm 945:
1.28 nicm 946: log_debug("%s: '%c", __func__, ictx->ch);
1.1 nicm 947:
1.28 nicm 948: switch (ictx->ch) {
949: case '\000': /* NUL */
950: break;
951: case '\007': /* BEL */
952: wp->window->flags |= WINDOW_BELL;
953: break;
954: case '\010': /* BS */
955: screen_write_backspace(sctx);
1.51 nicm 956: goto count_c0;
1.28 nicm 957: case '\011': /* HT */
958: /* Don't tab beyond the end of the line. */
959: if (s->cx >= screen_size_x(s) - 1)
960: break;
1.1 nicm 961:
1.28 nicm 962: /* Find the next tab point, or use the last column if none. */
963: do {
964: s->cx++;
965: if (bit_test(s->tabs, s->cx))
966: break;
967: } while (s->cx < screen_size_x(s) - 1);
968: break;
969: case '\012': /* LF */
970: case '\013': /* VT */
971: case '\014': /* FF */
972: screen_write_linefeed(sctx, 0);
1.51 nicm 973: goto count_c0;
1.28 nicm 974: case '\015': /* CR */
975: screen_write_carriagereturn(sctx);
1.51 nicm 976: goto count_c0;
1.28 nicm 977: case '\016': /* SO */
978: ictx->cell.attr |= GRID_ATTR_CHARSET;
979: break;
980: case '\017': /* SI */
981: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
982: break;
983: default:
984: log_debug("%s: unknown '%c'", __func__, ictx->ch);
985: break;
1.51 nicm 986: }
987:
988: return (0);
989:
990: count_c0:
991: trigger = options_get_number(&wp->window->options, "c0-change-trigger");
992: if (++wp->changes == trigger) {
993: wp->flags |= PANE_DROP;
994: window_pane_timer_start(wp);
1.28 nicm 995: }
1.1 nicm 996:
1.28 nicm 997: return (0);
1.7 nicm 998: }
999:
1.28 nicm 1000: /* Execute escape sequence. */
1001: int
1002: input_esc_dispatch(struct input_ctx *ictx)
1.7 nicm 1003: {
1.31 nicm 1004: struct screen_write_ctx *sctx = &ictx->ctx;
1005: struct screen *s = sctx->s;
1006: struct input_table_entry *entry;
1.7 nicm 1007:
1.28 nicm 1008: if (ictx->flags & INPUT_DISCARD)
1009: return (0);
1010: log_debug("%s: '%c', %s", __func__, ictx->ch, ictx->interm_buf);
1.7 nicm 1011:
1.28 nicm 1012: entry = bsearch(ictx, input_esc_table, nitems(input_esc_table),
1013: sizeof input_esc_table[0], input_table_compare);
1014: if (entry == NULL) {
1015: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1016: return (0);
1017: }
1.7 nicm 1018:
1.28 nicm 1019: switch (entry->type) {
1020: case INPUT_ESC_RIS:
1021: memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
1022: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1023: ictx->old_cx = 0;
1024: ictx->old_cy = 0;
1.1 nicm 1025:
1.46 nicm 1026: screen_write_reset(sctx);
1.28 nicm 1027: break;
1028: case INPUT_ESC_IND:
1029: screen_write_linefeed(sctx, 0);
1030: break;
1031: case INPUT_ESC_NEL:
1032: screen_write_carriagereturn(sctx);
1033: screen_write_linefeed(sctx, 0);
1034: break;
1035: case INPUT_ESC_HTS:
1036: if (s->cx < screen_size_x(s))
1037: bit_set(s->tabs, s->cx);
1038: break;
1039: case INPUT_ESC_RI:
1040: screen_write_reverseindex(sctx);
1041: break;
1042: case INPUT_ESC_DECKPAM:
1.59 nicm 1043: screen_write_mode_set(sctx, MODE_KKEYPAD);
1.28 nicm 1044: break;
1045: case INPUT_ESC_DECKPNM:
1.59 nicm 1046: screen_write_mode_clear(sctx, MODE_KKEYPAD);
1.1 nicm 1047: break;
1.28 nicm 1048: case INPUT_ESC_DECSC:
1049: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1050: ictx->old_cx = s->cx;
1051: ictx->old_cy = s->cy;
1052: break;
1053: case INPUT_ESC_DECRC:
1054: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1055: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1056: break;
1057: case INPUT_ESC_DECALN:
1058: screen_write_alignmenttest(sctx);
1059: break;
1060: case INPUT_ESC_SCSON_G0:
1061: /*
1062: * Not really supported, but fake it up enough for those that
1063: * use it to switch character sets (by redefining G0 to
1064: * graphics set, rather than switching to G1).
1065: */
1066: ictx->cell.attr &= ~GRID_ATTR_CHARSET;
1.1 nicm 1067: break;
1.28 nicm 1068: case INPUT_ESC_SCSOFF_G0:
1069: ictx->cell.attr |= GRID_ATTR_CHARSET;
1.1 nicm 1070: break;
1071: }
1.28 nicm 1072:
1073: return (0);
1.1 nicm 1074: }
1075:
1.28 nicm 1076: /* Execute control sequence. */
1077: int
1078: input_csi_dispatch(struct input_ctx *ictx)
1.1 nicm 1079: {
1.28 nicm 1080: struct screen_write_ctx *sctx = &ictx->ctx;
1081: struct screen *s = sctx->s;
1082: struct input_table_entry *entry;
1.65 nicm 1083: int n, m;
1.1 nicm 1084:
1.28 nicm 1085: if (ictx->flags & INPUT_DISCARD)
1086: return (0);
1087: if (input_split(ictx) != 0)
1088: return (0);
1089: log_debug("%s: '%c' \"%s\" \"%s\"",
1090: __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
1.1 nicm 1091:
1.28 nicm 1092: entry = bsearch(ictx, input_csi_table, nitems(input_csi_table),
1093: sizeof input_csi_table[0], input_table_compare);
1094: if (entry == NULL) {
1095: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1096: return (0);
1097: }
1.1 nicm 1098:
1.28 nicm 1099: switch (entry->type) {
1100: case INPUT_CSI_CBT:
1101: /* Find the previous tab point, n times. */
1102: n = input_get(ictx, 0, 1, 1);
1103: while (s->cx > 0 && n-- > 0) {
1104: do
1105: s->cx--;
1106: while (s->cx > 0 && !bit_test(s->tabs, s->cx));
1107: }
1108: break;
1109: case INPUT_CSI_CUB:
1110: screen_write_cursorleft(sctx, input_get(ictx, 0, 1, 1));
1111: break;
1112: case INPUT_CSI_CUD:
1113: screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1114: break;
1115: case INPUT_CSI_CUF:
1116: screen_write_cursorright(sctx, input_get(ictx, 0, 1, 1));
1117: break;
1118: case INPUT_CSI_CUP:
1119: n = input_get(ictx, 0, 1, 1);
1120: m = input_get(ictx, 1, 1, 1);
1121: screen_write_cursormove(sctx, m - 1, n - 1);
1122: break;
1.65 nicm 1123: case INPUT_CSI_WINOPS:
1124: input_csi_dispatch_winops(ictx);
1125: break;
1.28 nicm 1126: case INPUT_CSI_CUU:
1.43 nicm 1127: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1128: break;
1129: case INPUT_CSI_CNL:
1130: screen_write_carriagereturn(sctx);
1131: screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
1132: break;
1133: case INPUT_CSI_CPL:
1134: screen_write_carriagereturn(sctx);
1.28 nicm 1135: screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
1136: break;
1137: case INPUT_CSI_DA:
1138: switch (input_get(ictx, 0, 0, 0)) {
1139: case 0:
1140: input_reply(ictx, "\033[?1;2c");
1.50 nicm 1141: break;
1142: default:
1143: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1144: break;
1145: }
1146: break;
1147: case INPUT_CSI_DA_TWO:
1148: switch (input_get(ictx, 0, 0, 0)) {
1149: case 0:
1.66 ! nicm 1150: input_reply(ictx, "\033[>84;0;0c");
1.28 nicm 1151: break;
1152: default:
1153: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1154: break;
1155: }
1.56 nicm 1156: break;
1157: case INPUT_CSI_ECH:
1158: screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1));
1.28 nicm 1159: break;
1160: case INPUT_CSI_DCH:
1161: screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1));
1162: break;
1163: case INPUT_CSI_DECSTBM:
1164: n = input_get(ictx, 0, 1, 1);
1165: m = input_get(ictx, 1, 1, screen_size_y(s));
1166: screen_write_scrollregion(sctx, n - 1, m - 1);
1.1 nicm 1167: break;
1.28 nicm 1168: case INPUT_CSI_DL:
1169: screen_write_deleteline(sctx, input_get(ictx, 0, 1, 1));
1.1 nicm 1170: break;
1.28 nicm 1171: case INPUT_CSI_DSR:
1172: switch (input_get(ictx, 0, 0, 0)) {
1173: case 5:
1174: input_reply(ictx, "\033[0n");
1175: break;
1176: case 6:
1177: input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
1178: break;
1179: default:
1180: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1181: break;
1182: }
1183: break;
1184: case INPUT_CSI_ED:
1185: switch (input_get(ictx, 0, 0, 0)) {
1186: case 0:
1187: screen_write_clearendofscreen(sctx);
1188: break;
1189: case 1:
1190: screen_write_clearstartofscreen(sctx);
1191: break;
1192: case 2:
1193: screen_write_clearscreen(sctx);
1.41 nicm 1194: break;
1195: case 3:
1196: switch (input_get(ictx, 1, 0, 0)) {
1197: case 0:
1198: /*
1199: * Linux console extension to clear history
1200: * (for example before locking the screen).
1201: */
1202: screen_write_clearhistory(sctx);
1203: break;
1204: }
1.28 nicm 1205: break;
1206: default:
1207: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1208: break;
1209: }
1210: break;
1211: case INPUT_CSI_EL:
1212: switch (input_get(ictx, 0, 0, 0)) {
1213: case 0:
1214: screen_write_clearendofline(sctx);
1215: break;
1216: case 1:
1217: screen_write_clearstartofline(sctx);
1218: break;
1219: case 2:
1220: screen_write_clearline(sctx);
1221: break;
1222: default:
1223: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1224: break;
1225: }
1226: break;
1227: case INPUT_CSI_HPA:
1228: n = input_get(ictx, 0, 1, 1);
1229: screen_write_cursormove(sctx, n - 1, s->cy);
1230: break;
1231: case INPUT_CSI_ICH:
1232: screen_write_insertcharacter(sctx, input_get(ictx, 0, 1, 1));
1233: break;
1234: case INPUT_CSI_IL:
1235: screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
1236: break;
1.42 nicm 1237: case INPUT_CSI_RCP:
1238: memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
1239: screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
1240: break;
1.28 nicm 1241: case INPUT_CSI_RM:
1.64 nicm 1242: input_csi_dispatch_rm(ictx);
1243: break;
1244: case INPUT_CSI_RM_PRIVATE:
1245: input_csi_dispatch_rm_private(ictx);
1246: break;
1247: case INPUT_CSI_SCP:
1248: memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
1249: ictx->old_cx = s->cx;
1250: ictx->old_cy = s->cy;
1251: break;
1252: case INPUT_CSI_SGR:
1253: input_csi_dispatch_sgr(ictx);
1254: break;
1255: case INPUT_CSI_SM:
1256: input_csi_dispatch_sm(ictx);
1257: break;
1258: case INPUT_CSI_SM_PRIVATE:
1259: input_csi_dispatch_sm_private(ictx);
1260: break;
1261: case INPUT_CSI_TBC:
1262: switch (input_get(ictx, 0, 0, 0)) {
1263: case 0:
1264: if (s->cx < screen_size_x(s))
1265: bit_clear(s->tabs, s->cx);
1266: break;
1267: case 3:
1268: bit_nclear(s->tabs, 0, screen_size_x(s) - 1);
1269: break;
1270: default:
1271: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1272: break;
1273: }
1274: break;
1275: case INPUT_CSI_VPA:
1276: n = input_get(ictx, 0, 1, 1);
1277: screen_write_cursormove(sctx, s->cx, n - 1);
1278: break;
1279: case INPUT_CSI_DECSCUSR:
1280: n = input_get(ictx, 0, 0, 0);
1281: screen_set_cursor_style(s, n);
1282: break;
1283: }
1284:
1285: return (0);
1286: }
1287:
1288: /* Handle CSI RM. */
1289: void
1290: input_csi_dispatch_rm(struct input_ctx *ictx)
1291: {
1292: u_int i;
1293:
1294: for (i = 0; i < ictx->param_list_len; i++) {
1295: switch (input_get(ictx, i, 0, -1)) {
1.28 nicm 1296: case 4: /* IRM */
1.59 nicm 1297: screen_write_mode_clear(&ictx->ctx, MODE_INSERT);
1.28 nicm 1298: break;
1299: default:
1300: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1301: break;
1302: }
1.64 nicm 1303: }
1304: }
1305:
1306: /* Handle CSI private RM. */
1307: void
1308: input_csi_dispatch_rm_private(struct input_ctx *ictx)
1309: {
1310: u_int i;
1311:
1312: for (i = 0; i < ictx->param_list_len; i++) {
1313: switch (input_get(ictx, i, 0, -1)) {
1314: case 1: /* DECCKM */
1.59 nicm 1315: screen_write_mode_clear(&ictx->ctx, MODE_KCURSOR);
1.1 nicm 1316: break;
1.17 nicm 1317: case 3: /* DECCOLM */
1.24 nicm 1318: screen_write_cursormove(&ictx->ctx, 0, 0);
1.17 nicm 1319: screen_write_clearscreen(&ictx->ctx);
1320: break;
1.61 nicm 1321: case 7: /* DECAWM */
1322: screen_write_mode_clear(&ictx->ctx, MODE_WRAP);
1323: break;
1.1 nicm 1324: case 25: /* TCEM */
1.59 nicm 1325: screen_write_mode_clear(&ictx->ctx, MODE_CURSOR);
1.1 nicm 1326: break;
1327: case 1000:
1.32 nicm 1328: case 1001:
1329: case 1002:
1330: case 1003:
1.59 nicm 1331: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1.1 nicm 1332: break;
1.62 nicm 1333: case 1004:
1334: screen_write_mode_clear(&ictx->ctx, MODE_FOCUSON);
1335: break;
1.33 nicm 1336: case 1005:
1.59 nicm 1337: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_UTF8);
1.33 nicm 1338: break;
1.60 nicm 1339: case 1006:
1340: screen_write_mode_clear(&ictx->ctx, MODE_MOUSE_SGR);
1341: break;
1.55 nicm 1342: case 47:
1343: case 1047:
1.64 nicm 1344: window_pane_alternate_off(ictx->wp, &ictx->cell, 0);
1.55 nicm 1345: break;
1.9 nicm 1346: case 1049:
1.64 nicm 1347: window_pane_alternate_off(ictx->wp, &ictx->cell, 1);
1.9 nicm 1348: break;
1.49 nicm 1349: case 2004:
1.59 nicm 1350: screen_write_mode_clear(&ictx->ctx, MODE_BRACKETPASTE);
1.49 nicm 1351: break;
1.1 nicm 1352: default:
1.28 nicm 1353: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1354: break;
1355: }
1.64 nicm 1356: }
1357: }
1358:
1359: /* Handle CSI SM. */
1360: void
1361: input_csi_dispatch_sm(struct input_ctx *ictx)
1362: {
1363: u_int i;
1364:
1365: for (i = 0; i < ictx->param_list_len; i++) {
1366: switch (input_get(ictx, i, 0, -1)) {
1.1 nicm 1367: case 4: /* IRM */
1.59 nicm 1368: screen_write_mode_set(&ictx->ctx, MODE_INSERT);
1.1 nicm 1369: break;
1370: default:
1.28 nicm 1371: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1372: break;
1373: }
1.64 nicm 1374: }
1375: }
1376:
1377: /* Handle CSI private SM. */
1378: void
1379: input_csi_dispatch_sm_private(struct input_ctx *ictx)
1380: {
1381: u_int i;
1382:
1383: for (i = 0; i < ictx->param_list_len; i++) {
1384: switch (input_get(ictx, i, 0, -1)) {
1385: case 1: /* DECCKM */
1.59 nicm 1386: screen_write_mode_set(&ictx->ctx, MODE_KCURSOR);
1.17 nicm 1387: break;
1388: case 3: /* DECCOLM */
1.24 nicm 1389: screen_write_cursormove(&ictx->ctx, 0, 0);
1.17 nicm 1390: screen_write_clearscreen(&ictx->ctx);
1.61 nicm 1391: break;
1392: case 7: /* DECAWM */
1393: screen_write_mode_set(&ictx->ctx, MODE_WRAP);
1.1 nicm 1394: break;
1395: case 25: /* TCEM */
1.59 nicm 1396: screen_write_mode_set(&ictx->ctx, MODE_CURSOR);
1.1 nicm 1397: break;
1398: case 1000:
1.59 nicm 1399: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1400: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_STANDARD);
1.32 nicm 1401: break;
1402: case 1002:
1.59 nicm 1403: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1404: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_BUTTON);
1.32 nicm 1405: break;
1406: case 1003:
1.59 nicm 1407: screen_write_mode_clear(&ictx->ctx, ALL_MOUSE_MODES);
1408: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_ANY);
1.62 nicm 1409: break;
1410: case 1004:
1.64 nicm 1411: if (ictx->ctx.s->mode & MODE_FOCUSON)
1.62 nicm 1412: break;
1413: screen_write_mode_set(&ictx->ctx, MODE_FOCUSON);
1.64 nicm 1414: ictx->wp->flags |= PANE_FOCUSPUSH; /* force update */
1.33 nicm 1415: break;
1416: case 1005:
1.59 nicm 1417: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_UTF8);
1.60 nicm 1418: break;
1419: case 1006:
1420: screen_write_mode_set(&ictx->ctx, MODE_MOUSE_SGR);
1.9 nicm 1421: break;
1.55 nicm 1422: case 47:
1423: case 1047:
1.64 nicm 1424: window_pane_alternate_on(ictx->wp, &ictx->cell, 0);
1.55 nicm 1425: break;
1.9 nicm 1426: case 1049:
1.64 nicm 1427: window_pane_alternate_on(ictx->wp, &ictx->cell, 1);
1.49 nicm 1428: break;
1429: case 2004:
1.59 nicm 1430: screen_write_mode_set(&ictx->ctx, MODE_BRACKETPASTE);
1.1 nicm 1431: break;
1432: default:
1.28 nicm 1433: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1.1 nicm 1434: break;
1435: }
1.65 nicm 1436: }
1437: }
1438:
1439: /* Handle CSI window operations. */
1440: void
1441: input_csi_dispatch_winops(struct input_ctx *ictx)
1442: {
1443: struct window_pane *wp = ictx->wp;
1444: int n, m;
1445:
1446: m = 0;
1447: while ((n = input_get(ictx, m, 0, -1)) != -1) {
1448: switch (n) {
1449: case 1:
1450: case 2:
1451: case 5:
1452: case 6:
1453: case 7:
1454: case 11:
1455: case 13:
1456: case 14:
1457: case 19:
1458: case 20:
1459: case 21:
1460: case 24:
1461: break;
1462: case 3:
1463: case 4:
1464: case 8:
1465: m++;
1466: if (input_get(ictx, m, 0, -1) == -1)
1467: return;
1468: /* FALLTHROUGH */
1469: case 9:
1470: case 10:
1471: case 22:
1472: case 23:
1473: m++;
1474: if (input_get(ictx, m, 0, -1) == -1)
1475: return;
1476: break;
1477: case 18:
1478: input_reply(ictx, "\033[8;%u;%u", wp->sy, wp->sx);
1479: break;
1480: default:
1481: log_debug("%s: unknown '%c'", __func__, ictx->ch);
1482: break;
1483: }
1484: m++;
1.1 nicm 1485: }
1486: }
1487:
1.28 nicm 1488: /* Handle CSI SGR. */
1.1 nicm 1489: void
1.28 nicm 1490: input_csi_dispatch_sgr(struct input_ctx *ictx)
1.1 nicm 1491: {
1.28 nicm 1492: struct grid_cell *gc = &ictx->cell;
1493: u_int i;
1494: int n, m;
1495: u_char attr;
1.1 nicm 1496:
1.28 nicm 1497: if (ictx->param_list_len == 0) {
1.1 nicm 1498: attr = gc->attr;
1499: memcpy(gc, &grid_default_cell, sizeof *gc);
1.24 nicm 1500: gc->attr |= (attr & GRID_ATTR_CHARSET);
1.1 nicm 1501: return;
1502: }
1503:
1.28 nicm 1504: for (i = 0; i < ictx->param_list_len; i++) {
1505: n = input_get(ictx, i, 0, 0);
1.1 nicm 1506:
1.28 nicm 1507: if (n == 38 || n == 48) {
1.1 nicm 1508: i++;
1.28 nicm 1509: if (input_get(ictx, i, 0, -1) != 5)
1.1 nicm 1510: continue;
1511:
1512: i++;
1.28 nicm 1513: m = input_get(ictx, i, 0, -1);
1514: if (m == -1) {
1515: if (n == 38) {
1516: gc->flags &= ~GRID_FLAG_FG256;
1517: gc->fg = 8;
1518: } else if (n == 48) {
1519: gc->flags &= ~GRID_FLAG_BG256;
1.36 nicm 1520: gc->bg = 8;
1.28 nicm 1521: }
1522:
1523: } else {
1524: if (n == 38) {
1525: gc->flags |= GRID_FLAG_FG256;
1526: gc->fg = m;
1527: } else if (n == 48) {
1528: gc->flags |= GRID_FLAG_BG256;
1529: gc->bg = m;
1530: }
1.1 nicm 1531: }
1532: continue;
1533: }
1534:
1.28 nicm 1535: switch (n) {
1.1 nicm 1536: case 0:
1537: case 10:
1538: attr = gc->attr;
1539: memcpy(gc, &grid_default_cell, sizeof *gc);
1540: gc->attr |= (attr & GRID_ATTR_CHARSET);
1541: break;
1542: case 1:
1543: gc->attr |= GRID_ATTR_BRIGHT;
1544: break;
1545: case 2:
1546: gc->attr |= GRID_ATTR_DIM;
1547: break;
1548: case 3:
1549: gc->attr |= GRID_ATTR_ITALICS;
1550: break;
1551: case 4:
1552: gc->attr |= GRID_ATTR_UNDERSCORE;
1553: break;
1554: case 5:
1555: gc->attr |= GRID_ATTR_BLINK;
1556: break;
1557: case 7:
1558: gc->attr |= GRID_ATTR_REVERSE;
1559: break;
1560: case 8:
1561: gc->attr |= GRID_ATTR_HIDDEN;
1562: break;
1563: case 22:
1564: gc->attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_DIM);
1565: break;
1566: case 23:
1567: gc->attr &= ~GRID_ATTR_ITALICS;
1568: break;
1569: case 24:
1570: gc->attr &= ~GRID_ATTR_UNDERSCORE;
1571: break;
1572: case 25:
1573: gc->attr &= ~GRID_ATTR_BLINK;
1574: break;
1575: case 27:
1576: gc->attr &= ~GRID_ATTR_REVERSE;
1577: break;
1578: case 30:
1579: case 31:
1580: case 32:
1581: case 33:
1582: case 34:
1583: case 35:
1584: case 36:
1585: case 37:
1586: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1587: gc->fg = n - 30;
1.1 nicm 1588: break;
1589: case 39:
1590: gc->flags &= ~GRID_FLAG_FG256;
1591: gc->fg = 8;
1592: break;
1593: case 40:
1594: case 41:
1595: case 42:
1596: case 43:
1597: case 44:
1598: case 45:
1599: case 46:
1600: case 47:
1601: gc->flags &= ~GRID_FLAG_BG256;
1.28 nicm 1602: gc->bg = n - 40;
1.1 nicm 1603: break;
1604: case 49:
1605: gc->flags &= ~GRID_FLAG_BG256;
1606: gc->bg = 8;
1.20 nicm 1607: break;
1608: case 90:
1609: case 91:
1610: case 92:
1611: case 93:
1612: case 94:
1613: case 95:
1614: case 96:
1615: case 97:
1.26 nicm 1616: gc->flags &= ~GRID_FLAG_FG256;
1.28 nicm 1617: gc->fg = n;
1.20 nicm 1618: break;
1619: case 100:
1620: case 101:
1621: case 102:
1622: case 103:
1623: case 104:
1624: case 105:
1625: case 106:
1626: case 107:
1.26 nicm 1627: gc->flags &= ~GRID_FLAG_BG256;
1.47 nicm 1628: gc->bg = n - 10;
1.1 nicm 1629: break;
1630: }
1631: }
1.28 nicm 1632: }
1633:
1.37 nicm 1634: /* DCS terminator (ST) received. */
1635: int
1636: input_dcs_dispatch(struct input_ctx *ictx)
1.28 nicm 1637: {
1.37 nicm 1638: const char prefix[] = "tmux;";
1639: const u_int prefix_len = (sizeof prefix) - 1;
1640:
1641: if (ictx->flags & INPUT_DISCARD)
1642: return (0);
1643:
1644: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1.28 nicm 1645:
1.37 nicm 1646: /* Check for tmux prefix. */
1647: if (ictx->input_len >= prefix_len &&
1648: strncmp(ictx->input_buf, prefix, prefix_len) == 0) {
1649: screen_write_rawstring(&ictx->ctx,
1650: ictx->input_buf + prefix_len, ictx->input_len - prefix_len);
1651: }
1.28 nicm 1652:
1.37 nicm 1653: return (0);
1.28 nicm 1654: }
1655:
1656: /* OSC string started. */
1657: void
1658: input_enter_osc(struct input_ctx *ictx)
1659: {
1660: log_debug("%s", __func__);
1661:
1.35 nicm 1662: input_clear(ictx);
1.28 nicm 1663: }
1664:
1665: /* OSC terminator (ST) received. */
1666: void
1667: input_exit_osc(struct input_ctx *ictx)
1668: {
1.38 nicm 1669: u_char *p = ictx->input_buf;
1670: int option;
1671:
1.28 nicm 1672: if (ictx->flags & INPUT_DISCARD)
1673: return;
1.38 nicm 1674: if (ictx->input_len < 1 || *p < '0' || *p > '9')
1675: return;
1.28 nicm 1676:
1.38 nicm 1677: log_debug("%s: \"%s\"", __func__, p);
1.28 nicm 1678:
1.38 nicm 1679: option = 0;
1680: while (*p >= '0' && *p <= '9')
1681: option = option * 10 + *p++ - '0';
1682: if (*p == ';')
1683: p++;
1684:
1685: switch (option) {
1686: case 0:
1687: case 2:
1688: screen_set_title(ictx->ctx.s, p);
1689: server_status_window(ictx->wp->window);
1690: break;
1691: case 12:
1.57 nicm 1692: if (*p != '?') /* ? is colour request */
1693: screen_set_cursor_colour(ictx->ctx.s, p);
1.38 nicm 1694: break;
1695: case 112:
1.57 nicm 1696: if (*p == '\0') /* no arguments allowed */
1.38 nicm 1697: screen_set_cursor_colour(ictx->ctx.s, "");
1698: break;
1699: default:
1700: log_debug("%s: unknown '%u'", __func__, option);
1701: break;
1702: }
1.28 nicm 1703: }
1704:
1705: /* APC string started. */
1706: void
1707: input_enter_apc(struct input_ctx *ictx)
1708: {
1709: log_debug("%s", __func__);
1710:
1.35 nicm 1711: input_clear(ictx);
1.28 nicm 1712: }
1713:
1714: /* APC terminator (ST) received. */
1715: void
1716: input_exit_apc(struct input_ctx *ictx)
1717: {
1718: if (ictx->flags & INPUT_DISCARD)
1719: return;
1720: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1721:
1722: screen_set_title(ictx->ctx.s, ictx->input_buf);
1723: server_status_window(ictx->wp->window);
1724: }
1725:
1726: /* Rename string started. */
1727: void
1728: input_enter_rename(struct input_ctx *ictx)
1729: {
1730: log_debug("%s", __func__);
1731:
1.35 nicm 1732: input_clear(ictx);
1.28 nicm 1733: }
1734:
1735: /* Rename terminator (ST) received. */
1736: void
1737: input_exit_rename(struct input_ctx *ictx)
1738: {
1739: if (ictx->flags & INPUT_DISCARD)
1.44 nicm 1740: return;
1741: if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
1.28 nicm 1742: return;
1743: log_debug("%s: \"%s\"", __func__, ictx->input_buf);
1744:
1.48 nicm 1745: window_set_name(ictx->wp->window, ictx->input_buf);
1.28 nicm 1746: options_set_number(&ictx->wp->window->options, "automatic-rename", 0);
1747:
1748: server_status_window(ictx->wp->window);
1749: }
1750:
1751: /* Open UTF-8 character. */
1752: int
1753: input_utf8_open(struct input_ctx *ictx)
1754: {
1755: if (!options_get_number(&ictx->wp->window->options, "utf8")) {
1756: /* Print, and do not switch state. */
1757: input_print(ictx);
1758: return (-1);
1759: }
1760: log_debug("%s", __func__);
1761:
1762: utf8_open(&ictx->utf8data, ictx->ch);
1763: return (0);
1764: }
1765:
1766: /* Append to UTF-8 character. */
1767: int
1768: input_utf8_add(struct input_ctx *ictx)
1769: {
1770: log_debug("%s", __func__);
1771:
1772: utf8_append(&ictx->utf8data, ictx->ch);
1773: return (0);
1774: }
1775:
1776: /* Close UTF-8 string. */
1777: int
1778: input_utf8_close(struct input_ctx *ictx)
1779: {
1780: log_debug("%s", __func__);
1781:
1782: utf8_append(&ictx->utf8data, ictx->ch);
1783:
1.58 nicm 1784: grid_cell_set(&ictx->cell, &ictx->utf8data);
1785: screen_write_cell(&ictx->ctx, &ictx->cell);
1.28 nicm 1786:
1787: return (0);
1.1 nicm 1788: }