4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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.
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.
19 #include <sys/types.h>
27 * Based on the description by Paul Williams at:
29 * http://vt100.net/emu/dec_ansi_parser
31 * With the following changes:
35 * - Support for UTF-8.
37 * - OSC (but not APC) may be terminated by \007 as well as ST.
39 * - A state for APC similar to OSC. Some terminals appear to use this to set
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.
45 * - Special handling for ESC inside a DCS to allow arbitrary byte sequences to
46 * be passed to the underlying teminal(s).
49 /* Helper functions. */
50 int input_split(struct input_ctx
*);
51 int input_get(struct input_ctx
*, u_int
, int, int);
52 void input_reply(struct input_ctx
*, const char *, ...);
54 /* Transition entry/exit handlers. */
55 void input_clear(struct input_ctx
*);
56 void input_enter_osc(struct input_ctx
*);
57 void input_exit_osc(struct input_ctx
*);
58 void input_enter_apc(struct input_ctx
*);
59 void input_exit_apc(struct input_ctx
*);
60 void input_enter_rename(struct input_ctx
*);
61 void input_exit_rename(struct input_ctx
*);
63 /* Input state handlers. */
64 int input_print(struct input_ctx
*);
65 int input_intermediate(struct input_ctx
*);
66 int input_parameter(struct input_ctx
*);
67 int input_input(struct input_ctx
*);
68 int input_c0_dispatch(struct input_ctx
*);
69 int input_esc_dispatch(struct input_ctx
*);
70 int input_csi_dispatch(struct input_ctx
*);
71 void input_csi_dispatch_sgr(struct input_ctx
*);
72 int input_dcs_dispatch(struct input_ctx
*);
73 int input_utf8_open(struct input_ctx
*);
74 int input_utf8_add(struct input_ctx
*);
75 int input_utf8_close(struct input_ctx
*);
77 /* Command table comparison function. */
78 int input_table_compare(const void *, const void *);
80 /* Command table entry. */
81 struct input_table_entry
{
87 /* Escape commands. */
103 /* Escape command table. */
104 const struct input_table_entry input_esc_table
[] = {
105 { '0', "(", INPUT_ESC_SCSOFF_G0
},
106 { '7', "", INPUT_ESC_DECSC
},
107 { '8', "", INPUT_ESC_DECRC
},
108 { '8', "#", INPUT_ESC_DECALN
},
109 { '=', "", INPUT_ESC_DECKPAM
},
110 { '>', "", INPUT_ESC_DECKPNM
},
111 { 'B', "(", INPUT_ESC_SCSON_G0
},
112 { 'D', "", INPUT_ESC_IND
},
113 { 'E', "", INPUT_ESC_NEL
},
114 { 'H', "", INPUT_ESC_HTS
},
115 { 'M', "", INPUT_ESC_RI
},
116 { 'c', "", INPUT_ESC_RIS
},
119 /* Control (CSI) commands. */
120 enum input_csi_type
{
138 INPUT_CSI_RM_PRIVATE
,
141 INPUT_CSI_SM_PRIVATE
,
146 /* Control (CSI) command table. */
147 const struct input_table_entry input_csi_table
[] = {
148 { '@', "", INPUT_CSI_ICH
},
149 { 'A', "", INPUT_CSI_CUU
},
150 { 'B', "", INPUT_CSI_CUD
},
151 { 'C', "", INPUT_CSI_CUF
},
152 { 'D', "", INPUT_CSI_CUB
},
153 { 'G', "", INPUT_CSI_HPA
},
154 { 'H', "", INPUT_CSI_CUP
},
155 { 'J', "", INPUT_CSI_ED
},
156 { 'K', "", INPUT_CSI_EL
},
157 { 'L', "", INPUT_CSI_IL
},
158 { 'M', "", INPUT_CSI_DL
},
159 { 'P', "", INPUT_CSI_DCH
},
160 { 'Z', "", INPUT_CSI_CBT
},
161 { 'c', "", INPUT_CSI_DA
},
162 { 'd', "", INPUT_CSI_VPA
},
163 { 'f', "", INPUT_CSI_CUP
},
164 { 'g', "", INPUT_CSI_TBC
},
165 { 'h', "", INPUT_CSI_SM
},
166 { 'h', "?", INPUT_CSI_SM_PRIVATE
},
167 { 'l', "", INPUT_CSI_RM
},
168 { 'l', "?", INPUT_CSI_RM_PRIVATE
},
169 { 'm', "", INPUT_CSI_SGR
},
170 { 'n', "", INPUT_CSI_DSR
},
171 { 'r', "", INPUT_CSI_DECSTBM
},
174 /* Input transition. */
175 struct input_transition
{
179 int (*handler
)(struct input_ctx
*);
180 const struct input_state
*state
;
186 void (*enter
)(struct input_ctx
*);
187 void (*exit
)(struct input_ctx
*);
188 const struct input_transition
*transitions
;
191 /* State transitions available from all states. */
192 #define INPUT_STATE_ANYWHERE \
193 { 0x18, 0x18, input_c0_dispatch, &input_state_ground }, \
194 { 0x1a, 0x1a, input_c0_dispatch, &input_state_ground }, \
195 { 0x1b, 0x1b, NULL, &input_state_esc_enter }
197 /* Forward declarations of state tables. */
198 const struct input_transition input_state_ground_table
[];
199 const struct input_transition input_state_esc_enter_table
[];
200 const struct input_transition input_state_esc_intermediate_table
[];
201 const struct input_transition input_state_csi_enter_table
[];
202 const struct input_transition input_state_csi_parameter_table
[];
203 const struct input_transition input_state_csi_intermediate_table
[];
204 const struct input_transition input_state_csi_ignore_table
[];
205 const struct input_transition input_state_dcs_enter_table
[];
206 const struct input_transition input_state_dcs_parameter_table
[];
207 const struct input_transition input_state_dcs_intermediate_table
[];
208 const struct input_transition input_state_dcs_handler_table
[];
209 const struct input_transition input_state_dcs_escape_table
[];
210 const struct input_transition input_state_dcs_ignore_table
[];
211 const struct input_transition input_state_osc_string_table
[];
212 const struct input_transition input_state_apc_string_table
[];
213 const struct input_transition input_state_rename_string_table
[];
214 const struct input_transition input_state_consume_st_table
[];
215 const struct input_transition input_state_utf8_three_table
[];
216 const struct input_transition input_state_utf8_two_table
[];
217 const struct input_transition input_state_utf8_one_table
[];
219 /* ground state definition. */
220 const struct input_state input_state_ground
= {
223 input_state_ground_table
226 /* esc_enter state definition. */
227 const struct input_state input_state_esc_enter
= {
230 input_state_esc_enter_table
233 /* esc_intermediate state definition. */
234 const struct input_state input_state_esc_intermediate
= {
237 input_state_esc_intermediate_table
240 /* csi_enter state definition. */
241 const struct input_state input_state_csi_enter
= {
244 input_state_csi_enter_table
247 /* csi_parameter state definition. */
248 const struct input_state input_state_csi_parameter
= {
251 input_state_csi_parameter_table
254 /* csi_intermediate state definition. */
255 const struct input_state input_state_csi_intermediate
= {
258 input_state_csi_intermediate_table
261 /* csi_ignore state definition. */
262 const struct input_state input_state_csi_ignore
= {
265 input_state_csi_ignore_table
268 /* dcs_enter state definition. */
269 const struct input_state input_state_dcs_enter
= {
272 input_state_dcs_enter_table
275 /* dcs_parameter state definition. */
276 const struct input_state input_state_dcs_parameter
= {
279 input_state_dcs_parameter_table
282 /* dcs_intermediate state definition. */
283 const struct input_state input_state_dcs_intermediate
= {
286 input_state_dcs_intermediate_table
289 /* dcs_handler state definition. */
290 const struct input_state input_state_dcs_handler
= {
293 input_state_dcs_handler_table
296 /* dcs_escape state definition. */
297 const struct input_state input_state_dcs_escape
= {
300 input_state_dcs_escape_table
303 /* dcs_ignore state definition. */
304 const struct input_state input_state_dcs_ignore
= {
307 input_state_dcs_ignore_table
310 /* osc_string state definition. */
311 const struct input_state input_state_osc_string
= {
313 input_enter_osc
, input_exit_osc
,
314 input_state_osc_string_table
317 /* apc_string state definition. */
318 const struct input_state input_state_apc_string
= {
320 input_enter_apc
, input_exit_apc
,
321 input_state_apc_string_table
324 /* rename_string state definition. */
325 const struct input_state input_state_rename_string
= {
327 input_enter_rename
, input_exit_rename
,
328 input_state_rename_string_table
331 /* consume_st state definition. */
332 const struct input_state input_state_consume_st
= {
335 input_state_consume_st_table
338 /* utf8_three state definition. */
339 const struct input_state input_state_utf8_three
= {
342 input_state_utf8_three_table
345 /* utf8_two state definition. */
346 const struct input_state input_state_utf8_two
= {
349 input_state_utf8_two_table
352 /* utf8_one state definition. */
353 const struct input_state input_state_utf8_one
= {
356 input_state_utf8_one_table
359 /* ground state table. */
360 const struct input_transition input_state_ground_table
[] = {
361 INPUT_STATE_ANYWHERE
,
363 { 0x00, 0x17, input_c0_dispatch
, NULL
},
364 { 0x19, 0x19, input_c0_dispatch
, NULL
},
365 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
366 { 0x20, 0x7e, input_print
, NULL
},
367 { 0x7f, 0x7f, NULL
, NULL
},
368 { 0x80, 0xc1, input_print
, NULL
},
369 { 0xc2, 0xdf, input_utf8_open
, &input_state_utf8_one
},
370 { 0xe0, 0xef, input_utf8_open
, &input_state_utf8_two
},
371 { 0xf0, 0xf4, input_utf8_open
, &input_state_utf8_three
},
372 { 0xf5, 0xff, input_print
, NULL
},
374 { -1, -1, NULL
, NULL
}
377 /* esc_enter state table. */
378 const struct input_transition input_state_esc_enter_table
[] = {
379 INPUT_STATE_ANYWHERE
,
381 { 0x00, 0x17, input_c0_dispatch
, NULL
},
382 { 0x19, 0x19, input_c0_dispatch
, NULL
},
383 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
384 { 0x20, 0x2f, input_intermediate
, &input_state_esc_intermediate
},
385 { 0x30, 0x4f, input_esc_dispatch
, &input_state_ground
},
386 { 0x50, 0x50, NULL
, &input_state_dcs_enter
},
387 { 0x51, 0x57, input_esc_dispatch
, &input_state_ground
},
388 { 0x58, 0x58, NULL
, &input_state_consume_st
},
389 { 0x59, 0x59, input_esc_dispatch
, &input_state_ground
},
390 { 0x5a, 0x5a, input_esc_dispatch
, &input_state_ground
},
391 { 0x5b, 0x5b, NULL
, &input_state_csi_enter
},
392 { 0x5c, 0x5c, input_esc_dispatch
, &input_state_ground
},
393 { 0x5d, 0x5d, NULL
, &input_state_osc_string
},
394 { 0x5e, 0x5e, NULL
, &input_state_consume_st
},
395 { 0x5f, 0x5f, NULL
, &input_state_apc_string
},
396 { 0x60, 0x6a, input_esc_dispatch
, &input_state_ground
},
397 { 0x6b, 0x6b, NULL
, &input_state_rename_string
},
398 { 0x6c, 0x7e, input_esc_dispatch
, &input_state_ground
},
399 { 0x7f, 0xff, NULL
, NULL
},
401 { -1, -1, NULL
, NULL
}
404 /* esc_interm state table. */
405 const struct input_transition input_state_esc_intermediate_table
[] = {
406 INPUT_STATE_ANYWHERE
,
408 { 0x00, 0x17, input_c0_dispatch
, NULL
},
409 { 0x19, 0x19, input_c0_dispatch
, NULL
},
410 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
411 { 0x20, 0x2f, input_intermediate
, NULL
},
412 { 0x30, 0x7e, input_esc_dispatch
, &input_state_ground
},
413 { 0x7f, 0xff, NULL
, NULL
},
415 { -1, -1, NULL
, NULL
}
418 /* csi_enter state table. */
419 const struct input_transition input_state_csi_enter_table
[] = {
420 INPUT_STATE_ANYWHERE
,
422 { 0x00, 0x17, input_c0_dispatch
, NULL
},
423 { 0x19, 0x19, input_c0_dispatch
, NULL
},
424 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
425 { 0x20, 0x2f, input_intermediate
, &input_state_csi_intermediate
},
426 { 0x30, 0x39, input_parameter
, &input_state_csi_parameter
},
427 { 0x3a, 0x3a, NULL
, &input_state_csi_ignore
},
428 { 0x3b, 0x3b, input_parameter
, &input_state_csi_parameter
},
429 { 0x3c, 0x3f, input_intermediate
, &input_state_csi_parameter
},
430 { 0x40, 0x7e, input_csi_dispatch
, &input_state_ground
},
431 { 0x7f, 0xff, NULL
, NULL
},
433 { -1, -1, NULL
, NULL
}
436 /* csi_parameter state table. */
437 const struct input_transition input_state_csi_parameter_table
[] = {
438 INPUT_STATE_ANYWHERE
,
440 { 0x00, 0x17, input_c0_dispatch
, NULL
},
441 { 0x19, 0x19, input_c0_dispatch
, NULL
},
442 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
443 { 0x20, 0x2f, input_intermediate
, &input_state_csi_intermediate
},
444 { 0x30, 0x39, input_parameter
, NULL
},
445 { 0x3a, 0x3a, NULL
, &input_state_csi_ignore
},
446 { 0x3b, 0x3b, input_parameter
, NULL
},
447 { 0x3c, 0x3f, NULL
, &input_state_csi_ignore
},
448 { 0x40, 0x7e, input_csi_dispatch
, &input_state_ground
},
449 { 0x7f, 0xff, NULL
, NULL
},
451 { -1, -1, NULL
, NULL
}
454 /* csi_intermediate state table. */
455 const struct input_transition input_state_csi_intermediate_table
[] = {
456 INPUT_STATE_ANYWHERE
,
458 { 0x00, 0x17, input_c0_dispatch
, NULL
},
459 { 0x19, 0x19, input_c0_dispatch
, NULL
},
460 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
461 { 0x20, 0x2f, input_intermediate
, NULL
},
462 { 0x30, 0x3f, NULL
, &input_state_csi_ignore
},
463 { 0x40, 0x7e, input_csi_dispatch
, &input_state_ground
},
464 { 0x7f, 0xff, NULL
, NULL
},
466 { -1, -1, NULL
, NULL
}
469 /* csi_ignore state table. */
470 const struct input_transition input_state_csi_ignore_table
[] = {
471 INPUT_STATE_ANYWHERE
,
473 { 0x00, 0x17, input_c0_dispatch
, NULL
},
474 { 0x19, 0x19, input_c0_dispatch
, NULL
},
475 { 0x1c, 0x1f, input_c0_dispatch
, NULL
},
476 { 0x20, 0x3f, NULL
, NULL
},
477 { 0x40, 0x7e, NULL
, &input_state_ground
},
478 { 0x7f, 0xff, NULL
, NULL
},
480 { -1, -1, NULL
, NULL
}
483 /* dcs_enter state table. */
484 const struct input_transition input_state_dcs_enter_table
[] = {
485 INPUT_STATE_ANYWHERE
,
487 { 0x00, 0x17, NULL
, NULL
},
488 { 0x19, 0x19, NULL
, NULL
},
489 { 0x1c, 0x1f, NULL
, NULL
},
490 { 0x20, 0x2f, input_intermediate
, &input_state_dcs_intermediate
},
491 { 0x30, 0x39, input_parameter
, &input_state_dcs_parameter
},
492 { 0x3a, 0x3a, NULL
, &input_state_dcs_ignore
},
493 { 0x3b, 0x3b, input_parameter
, &input_state_dcs_parameter
},
494 { 0x3c, 0x3f, input_intermediate
, &input_state_dcs_parameter
},
495 { 0x40, 0x7e, input_input
, &input_state_dcs_handler
},
496 { 0x7f, 0xff, NULL
, NULL
},
498 { -1, -1, NULL
, NULL
}
501 /* dcs_parameter state table. */
502 const struct input_transition input_state_dcs_parameter_table
[] = {
503 INPUT_STATE_ANYWHERE
,
505 { 0x00, 0x17, NULL
, NULL
},
506 { 0x19, 0x19, NULL
, NULL
},
507 { 0x1c, 0x1f, NULL
, NULL
},
508 { 0x20, 0x2f, input_intermediate
, &input_state_dcs_intermediate
},
509 { 0x30, 0x39, input_parameter
, NULL
},
510 { 0x3a, 0x3a, NULL
, &input_state_dcs_ignore
},
511 { 0x3b, 0x3b, input_parameter
, NULL
},
512 { 0x3c, 0x3f, NULL
, &input_state_dcs_ignore
},
513 { 0x40, 0x7e, input_input
, &input_state_dcs_handler
},
514 { 0x7f, 0xff, NULL
, NULL
},
516 { -1, -1, NULL
, NULL
}
519 /* dcs_interm state table. */
520 const struct input_transition input_state_dcs_intermediate_table
[] = {
521 INPUT_STATE_ANYWHERE
,
523 { 0x00, 0x17, NULL
, NULL
},
524 { 0x19, 0x19, NULL
, NULL
},
525 { 0x1c, 0x1f, NULL
, NULL
},
526 { 0x20, 0x2f, input_intermediate
, NULL
},
527 { 0x30, 0x3f, NULL
, &input_state_dcs_ignore
},
528 { 0x40, 0x7e, input_input
, &input_state_dcs_handler
},
529 { 0x7f, 0xff, NULL
, NULL
},
531 { -1, -1, NULL
, NULL
}
534 /* dcs_handler state table. */
535 const struct input_transition input_state_dcs_handler_table
[] = {
536 /* No INPUT_STATE_ANYWHERE */
538 { 0x00, 0x1a, input_input
, NULL
},
539 { 0x1b, 0x1b, NULL
, &input_state_dcs_escape
},
540 { 0x1c, 0xff, input_input
, NULL
},
542 { -1, -1, NULL
, NULL
}
545 /* dcs_escape state table. */
546 const struct input_transition input_state_dcs_escape_table
[] = {
547 /* No INPUT_STATE_ANYWHERE */
549 { 0x00, 0x5b, input_input
, &input_state_dcs_handler
},
550 { 0x5c, 0x5c, input_dcs_dispatch
, &input_state_ground
},
551 { 0x5d, 0xff, input_input
, &input_state_dcs_handler
},
553 { -1, -1, NULL
, NULL
}
556 /* device_ignore state table. */
557 const struct input_transition input_state_dcs_ignore_table
[] = {
558 INPUT_STATE_ANYWHERE
,
560 { 0x00, 0x17, NULL
, NULL
},
561 { 0x19, 0x19, NULL
, NULL
},
562 { 0x1c, 0x1f, NULL
, NULL
},
563 { 0x20, 0xff, NULL
, NULL
},
565 { -1, -1, NULL
, NULL
}
568 /* osc_string state table. */
569 const struct input_transition input_state_osc_string_table
[] = {
570 INPUT_STATE_ANYWHERE
,
572 { 0x00, 0x06, NULL
, NULL
},
573 { 0x07, 0x07, NULL
, &input_state_ground
},
574 { 0x08, 0x17, NULL
, NULL
},
575 { 0x19, 0x19, NULL
, NULL
},
576 { 0x1c, 0x1f, NULL
, NULL
},
577 { 0x20, 0xff, input_input
, NULL
},
579 { -1, -1, NULL
, NULL
}
582 /* apc_string state table. */
583 const struct input_transition input_state_apc_string_table
[] = {
584 INPUT_STATE_ANYWHERE
,
586 { 0x00, 0x17, NULL
, NULL
},
587 { 0x19, 0x19, NULL
, NULL
},
588 { 0x1c, 0x1f, NULL
, NULL
},
589 { 0x20, 0xff, input_input
, NULL
},
591 { -1, -1, NULL
, NULL
}
594 /* rename_string state table. */
595 const struct input_transition input_state_rename_string_table
[] = {
596 INPUT_STATE_ANYWHERE
,
598 { 0x00, 0x17, NULL
, NULL
},
599 { 0x19, 0x19, NULL
, NULL
},
600 { 0x1c, 0x1f, NULL
, NULL
},
601 { 0x20, 0xff, input_input
, NULL
},
603 { -1, -1, NULL
, NULL
}
606 /* consume_st state table. */
607 const struct input_transition input_state_consume_st_table
[] = {
608 INPUT_STATE_ANYWHERE
,
610 { 0x00, 0x17, NULL
, NULL
},
611 { 0x19, 0x19, NULL
, NULL
},
612 { 0x1c, 0x1f, NULL
, NULL
},
613 { 0x20, 0xff, NULL
, NULL
},
615 { -1, -1, NULL
, NULL
}
618 /* utf8_three state table. */
619 const struct input_transition input_state_utf8_three_table
[] = {
620 /* No INPUT_STATE_ANYWHERE */
622 { 0x00, 0x7f, NULL
, &input_state_ground
},
623 { 0x80, 0xbf, input_utf8_add
, &input_state_utf8_two
},
624 { 0xc0, 0xff, NULL
, &input_state_ground
},
626 { -1, -1, NULL
, NULL
}
629 /* utf8_two state table. */
630 const struct input_transition input_state_utf8_two_table
[] = {
631 /* No INPUT_STATE_ANYWHERE */
633 { 0x00, 0x7f, NULL
, &input_state_ground
},
634 { 0x80, 0xbf, input_utf8_add
, &input_state_utf8_one
},
635 { 0xc0, 0xff, NULL
, &input_state_ground
},
637 { -1, -1, NULL
, NULL
}
640 /* utf8_one state table. */
641 const struct input_transition input_state_utf8_one_table
[] = {
642 /* No INPUT_STATE_ANYWHERE */
644 { 0x00, 0x7f, NULL
, &input_state_ground
},
645 { 0x80, 0xbf, input_utf8_close
, &input_state_ground
},
646 { 0xc0, 0xff, NULL
, &input_state_ground
},
648 { -1, -1, NULL
, NULL
}
651 /* Input table compare. */
653 input_table_compare(const void *key
, const void *value
)
655 const struct input_ctx
*ictx
= key
;
656 const struct input_table_entry
*entry
= value
;
658 if (ictx
->ch
!= entry
->ch
)
659 return (ictx
->ch
- entry
->ch
);
660 return (strcmp(ictx
->interm_buf
, entry
->interm
));
663 /* Initialise input parser. */
665 input_init(struct window_pane
*wp
)
667 struct input_ctx
*ictx
= &wp
->ictx
;
669 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
671 memcpy(&ictx
->old_cell
, &grid_default_cell
, sizeof ictx
->old_cell
);
675 *ictx
->interm_buf
= '\0';
676 ictx
->interm_len
= 0;
678 *ictx
->param_buf
= '\0';
681 ictx
->state
= &input_state_ground
;
685 /* Destroy input parser. */
687 input_free(unused
struct window_pane
*wp
)
693 input_parse(struct window_pane
*wp
)
695 struct input_ctx
*ictx
= &wp
->ictx
;
696 const struct input_transition
*itr
;
697 struct evbuffer
*evb
= wp
->event
->input
;
701 if (EVBUFFER_LENGTH(evb
) == 0)
704 wp
->window
->flags
|= WINDOW_ACTIVITY
;
705 wp
->window
->flags
&= ~WINDOW_SILENCE
;
708 * Open the screen. Use NULL wp if there is a mode set as don't want to
711 if (wp
->mode
== NULL
)
712 screen_write_start(&ictx
->ctx
, wp
, &wp
->base
);
714 screen_write_start(&ictx
->ctx
, NULL
, &wp
->base
);
717 buf
= EVBUFFER_DATA(evb
);
718 len
= EVBUFFER_LENGTH(evb
);
721 /* Parse the input. */
723 ictx
->ch
= buf
[off
++];
724 log_debug("%s: '%c' %s", __func__
, ictx
->ch
, ictx
->state
->name
);
726 /* Find the transition. */
727 itr
= ictx
->state
->transitions
;
728 while (itr
->first
!= -1 && itr
->last
!= -1) {
729 if (ictx
->ch
>= itr
->first
&& ictx
->ch
<= itr
->last
)
733 if (itr
->first
== -1 || itr
->last
== -1) {
734 /* No transition? Eh? */
735 fatalx("No transition from state!");
739 * Execute the handler, if any. Don't switch state if it
742 if (itr
->handler
!= NULL
&& itr
->handler(ictx
) != 0)
745 /* And switch state, if necessary. */
746 if (itr
->state
!= NULL
) {
747 if (ictx
->state
->exit
!= NULL
)
748 ictx
->state
->exit(ictx
);
749 ictx
->state
= itr
->state
;
750 if (ictx
->state
->enter
!= NULL
)
751 ictx
->state
->enter(ictx
);
755 /* Close the screen. */
756 screen_write_stop(&ictx
->ctx
);
758 evbuffer_drain(evb
, len
);
761 /* Split the parameter list (if any). */
763 input_split(struct input_ctx
*ictx
)
770 ictx
->param_list_len
= 0;
771 if (ictx
->param_len
== 0)
774 ptr
= ictx
->param_buf
;
775 while ((out
= strsep(&ptr
, ";")) != NULL
) {
779 n
= strtonum(out
, 0, INT_MAX
, &errstr
);
784 ictx
->param_list
[ictx
->param_list_len
++] = n
;
785 if (ictx
->param_list_len
== nitems(ictx
->param_list
))
792 /* Get an argument or return default value..*/
794 input_get(struct input_ctx
*ictx
, u_int validx
, int minval
, int defval
)
798 if (validx
>= ictx
->param_list_len
)
801 retval
= ictx
->param_list
[validx
];
809 /* Reply to terminal query. */
811 input_reply(struct input_ctx
*ictx
, const char *fmt
, ...)
817 vasprintf(&reply
, fmt
, ap
);
820 bufferevent_write(ictx
->wp
->event
, reply
, strlen(reply
));
824 /* Clear saved state. */
826 input_clear(struct input_ctx
*ictx
)
828 *ictx
->interm_buf
= '\0';
829 ictx
->interm_len
= 0;
831 *ictx
->param_buf
= '\0';
834 *ictx
->input_buf
= '\0';
837 ictx
->flags
&= ~INPUT_DISCARD
;
840 /* Output this character to the screen. */
842 input_print(struct input_ctx
*ictx
)
844 ictx
->cell
.data
= ictx
->ch
;
845 screen_write_cell(&ictx
->ctx
, &ictx
->cell
, NULL
);
850 /* Collect intermediate string. */
852 input_intermediate(struct input_ctx
*ictx
)
854 if (ictx
->interm_len
== (sizeof ictx
->interm_buf
) - 1)
855 ictx
->flags
|= INPUT_DISCARD
;
857 ictx
->interm_buf
[ictx
->interm_len
++] = ictx
->ch
;
858 ictx
->interm_buf
[ictx
->interm_len
] = '\0';
864 /* Collect parameter string. */
866 input_parameter(struct input_ctx
*ictx
)
868 if (ictx
->param_len
== (sizeof ictx
->param_buf
) - 1)
869 ictx
->flags
|= INPUT_DISCARD
;
871 ictx
->param_buf
[ictx
->param_len
++] = ictx
->ch
;
872 ictx
->param_buf
[ictx
->param_len
] = '\0';
878 /* Collect input string. */
880 input_input(struct input_ctx
*ictx
)
882 if (ictx
->input_len
== (sizeof ictx
->input_buf
) - 1)
883 ictx
->flags
|= INPUT_DISCARD
;
885 ictx
->input_buf
[ictx
->input_len
++] = ictx
->ch
;
886 ictx
->input_buf
[ictx
->input_len
] = '\0';
892 /* Execute C0 control sequence. */
894 input_c0_dispatch(struct input_ctx
*ictx
)
896 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
897 struct window_pane
*wp
= ictx
->wp
;
898 struct screen
*s
= sctx
->s
;
900 log_debug("%s: '%c", __func__
, ictx
->ch
);
903 case '\000': /* NUL */
905 case '\007': /* BEL */
906 wp
->window
->flags
|= WINDOW_BELL
;
908 case '\010': /* BS */
909 screen_write_backspace(sctx
);
911 case '\011': /* HT */
912 /* Don't tab beyond the end of the line. */
913 if (s
->cx
>= screen_size_x(s
) - 1)
916 /* Find the next tab point, or use the last column if none. */
919 if (bit_test(s
->tabs
, s
->cx
))
921 } while (s
->cx
< screen_size_x(s
) - 1);
923 case '\012': /* LF */
924 case '\013': /* VT */
925 case '\014': /* FF */
926 screen_write_linefeed(sctx
, 0);
928 case '\015': /* CR */
929 screen_write_carriagereturn(sctx
);
931 case '\016': /* SO */
932 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
934 case '\017': /* SI */
935 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
938 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
945 /* Execute escape sequence. */
947 input_esc_dispatch(struct input_ctx
*ictx
)
949 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
950 struct screen
*s
= sctx
->s
;
951 struct input_table_entry
*entry
;
953 if (ictx
->flags
& INPUT_DISCARD
)
955 log_debug("%s: '%c', %s", __func__
, ictx
->ch
, ictx
->interm_buf
);
957 entry
= bsearch(ictx
, input_esc_table
, nitems(input_esc_table
),
958 sizeof input_esc_table
[0], input_table_compare
);
960 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
964 switch (entry
->type
) {
966 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
967 memcpy(&ictx
->old_cell
, &ictx
->cell
, sizeof ictx
->old_cell
);
971 screen_reset_tabs(sctx
->s
);
973 screen_write_scrollregion(sctx
, 0, screen_size_y(sctx
->s
) - 1);
975 screen_write_insertmode(sctx
, 0);
976 screen_write_kcursormode(sctx
, 0);
977 screen_write_kkeypadmode(sctx
, 0);
978 screen_write_mousemode_off(sctx
);
980 screen_write_clearscreen(sctx
);
981 screen_write_cursormove(sctx
, 0, 0);
984 screen_write_linefeed(sctx
, 0);
987 screen_write_carriagereturn(sctx
);
988 screen_write_linefeed(sctx
, 0);
991 if (s
->cx
< screen_size_x(s
))
992 bit_set(s
->tabs
, s
->cx
);
995 screen_write_reverseindex(sctx
);
997 case INPUT_ESC_DECKPAM
:
998 screen_write_kkeypadmode(sctx
, 1);
1000 case INPUT_ESC_DECKPNM
:
1001 screen_write_kkeypadmode(sctx
, 0);
1003 case INPUT_ESC_DECSC
:
1004 memcpy(&ictx
->old_cell
, &ictx
->cell
, sizeof ictx
->old_cell
);
1005 ictx
->old_cx
= s
->cx
;
1006 ictx
->old_cy
= s
->cy
;
1008 case INPUT_ESC_DECRC
:
1009 memcpy(&ictx
->cell
, &ictx
->old_cell
, sizeof ictx
->cell
);
1010 screen_write_cursormove(sctx
, ictx
->old_cx
, ictx
->old_cy
);
1012 case INPUT_ESC_DECALN
:
1013 screen_write_alignmenttest(sctx
);
1015 case INPUT_ESC_SCSON_G0
:
1017 * Not really supported, but fake it up enough for those that
1018 * use it to switch character sets (by redefining G0 to
1019 * graphics set, rather than switching to G1).
1021 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
1023 case INPUT_ESC_SCSOFF_G0
:
1024 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
1031 /* Execute control sequence. */
1033 input_csi_dispatch(struct input_ctx
*ictx
)
1035 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
1036 struct window_pane
*wp
= ictx
->wp
;
1037 struct screen
*s
= sctx
->s
;
1038 struct input_table_entry
*entry
;
1041 if (ictx
->flags
& INPUT_DISCARD
)
1043 if (input_split(ictx
) != 0)
1045 log_debug("%s: '%c' \"%s\" \"%s\"",
1046 __func__
, ictx
->ch
, ictx
->interm_buf
, ictx
->param_buf
);
1048 entry
= bsearch(ictx
, input_csi_table
, nitems(input_csi_table
),
1049 sizeof input_csi_table
[0], input_table_compare
);
1050 if (entry
== NULL
) {
1051 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1055 switch (entry
->type
) {
1057 /* Find the previous tab point, n times. */
1058 n
= input_get(ictx
, 0, 1, 1);
1059 while (s
->cx
> 0 && n
-- > 0) {
1062 while (s
->cx
> 0 && !bit_test(s
->tabs
, s
->cx
));
1066 screen_write_cursorleft(sctx
, input_get(ictx
, 0, 1, 1));
1069 screen_write_cursordown(sctx
, input_get(ictx
, 0, 1, 1));
1072 screen_write_cursorright(sctx
, input_get(ictx
, 0, 1, 1));
1075 n
= input_get(ictx
, 0, 1, 1);
1076 m
= input_get(ictx
, 1, 1, 1);
1077 screen_write_cursormove(sctx
, m
- 1, n
- 1);
1080 screen_write_cursorup(sctx
, input_get(ictx
, 0, 1, 1));
1083 switch (input_get(ictx
, 0, 0, 0)) {
1085 input_reply(ictx
, "\033[?1;2c");
1088 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1093 screen_write_deletecharacter(sctx
, input_get(ictx
, 0, 1, 1));
1095 case INPUT_CSI_DECSTBM
:
1096 n
= input_get(ictx
, 0, 1, 1);
1097 m
= input_get(ictx
, 1, 1, screen_size_y(s
));
1098 screen_write_scrollregion(sctx
, n
- 1, m
- 1);
1101 screen_write_deleteline(sctx
, input_get(ictx
, 0, 1, 1));
1104 switch (input_get(ictx
, 0, 0, 0)) {
1106 input_reply(ictx
, "\033[0n");
1109 input_reply(ictx
, "\033[%u;%uR", s
->cy
+ 1, s
->cx
+ 1);
1112 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1117 switch (input_get(ictx
, 0, 0, 0)) {
1119 screen_write_clearendofscreen(sctx
);
1122 screen_write_clearstartofscreen(sctx
);
1125 screen_write_clearscreen(sctx
);
1128 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1133 switch (input_get(ictx
, 0, 0, 0)) {
1135 screen_write_clearendofline(sctx
);
1138 screen_write_clearstartofline(sctx
);
1141 screen_write_clearline(sctx
);
1144 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1149 n
= input_get(ictx
, 0, 1, 1);
1150 screen_write_cursormove(sctx
, n
- 1, s
->cy
);
1153 screen_write_insertcharacter(sctx
, input_get(ictx
, 0, 1, 1));
1156 screen_write_insertline(sctx
, input_get(ictx
, 0, 1, 1));
1159 switch (input_get(ictx
, 0, 0, -1)) {
1161 screen_write_insertmode(&ictx
->ctx
, 0);
1164 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1168 case INPUT_CSI_RM_PRIVATE
:
1169 switch (input_get(ictx
, 0, 0, -1)) {
1171 screen_write_kcursormode(&ictx
->ctx
, 0);
1173 case 3: /* DECCOLM */
1174 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1175 screen_write_clearscreen(&ictx
->ctx
);
1178 screen_write_cursormode(&ictx
->ctx
, 0);
1184 screen_write_mousemode_off(&ictx
->ctx
);
1187 screen_write_utf8mousemode(&ictx
->ctx
, 0);
1190 window_pane_alternate_off(wp
, &ictx
->cell
);
1193 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1198 input_csi_dispatch_sgr(ictx
);
1201 switch (input_get(ictx
, 0, 0, -1)) {
1203 screen_write_insertmode(&ictx
->ctx
, 1);
1206 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1210 case INPUT_CSI_SM_PRIVATE
:
1211 switch (input_get(ictx
, 0, 0, -1)) {
1213 screen_write_kcursormode(&ictx
->ctx
, 1);
1215 case 3: /* DECCOLM */
1216 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1217 screen_write_clearscreen(&ictx
->ctx
);
1220 screen_write_cursormode(&ictx
->ctx
, 1);
1223 screen_write_mousemode_on(
1224 &ictx
->ctx
, MODE_MOUSE_STANDARD
);
1227 screen_write_mousemode_on(
1228 &ictx
->ctx
, MODE_MOUSE_BUTTON
);
1231 screen_write_mousemode_on(&ictx
->ctx
, MODE_MOUSE_ANY
);
1234 screen_write_utf8mousemode(&ictx
->ctx
, 1);
1237 window_pane_alternate_on(wp
, &ictx
->cell
);
1240 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1245 switch (input_get(ictx
, 0, 0, 0)) {
1247 if (s
->cx
< screen_size_x(s
))
1248 bit_clear(s
->tabs
, s
->cx
);
1251 bit_nclear(s
->tabs
, 0, screen_size_x(s
) - 1);
1254 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1259 n
= input_get(ictx
, 0, 1, 1);
1260 screen_write_cursormove(sctx
, s
->cx
, n
- 1);
1267 /* Handle CSI SGR. */
1269 input_csi_dispatch_sgr(struct input_ctx
*ictx
)
1271 struct grid_cell
*gc
= &ictx
->cell
;
1276 if (ictx
->param_list_len
== 0) {
1278 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1279 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1283 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1284 n
= input_get(ictx
, i
, 0, 0);
1286 if (n
== 38 || n
== 48) {
1288 if (input_get(ictx
, i
, 0, -1) != 5)
1292 m
= input_get(ictx
, i
, 0, -1);
1295 gc
->flags
&= ~GRID_FLAG_FG256
;
1297 } else if (n
== 48) {
1298 gc
->flags
&= ~GRID_FLAG_BG256
;
1304 gc
->flags
|= GRID_FLAG_FG256
;
1306 } else if (n
== 48) {
1307 gc
->flags
|= GRID_FLAG_BG256
;
1318 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1319 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1322 gc
->attr
|= GRID_ATTR_BRIGHT
;
1325 gc
->attr
|= GRID_ATTR_DIM
;
1328 gc
->attr
|= GRID_ATTR_ITALICS
;
1331 gc
->attr
|= GRID_ATTR_UNDERSCORE
;
1334 gc
->attr
|= GRID_ATTR_BLINK
;
1337 gc
->attr
|= GRID_ATTR_REVERSE
;
1340 gc
->attr
|= GRID_ATTR_HIDDEN
;
1343 gc
->attr
&= ~(GRID_ATTR_BRIGHT
|GRID_ATTR_DIM
);
1346 gc
->attr
&= ~GRID_ATTR_ITALICS
;
1349 gc
->attr
&= ~GRID_ATTR_UNDERSCORE
;
1352 gc
->attr
&= ~GRID_ATTR_BLINK
;
1355 gc
->attr
&= ~GRID_ATTR_REVERSE
;
1365 gc
->flags
&= ~GRID_FLAG_FG256
;
1369 gc
->flags
&= ~GRID_FLAG_FG256
;
1380 gc
->flags
&= ~GRID_FLAG_BG256
;
1384 gc
->flags
&= ~GRID_FLAG_BG256
;
1395 gc
->flags
&= ~GRID_FLAG_FG256
;
1406 gc
->flags
&= ~GRID_FLAG_BG256
;
1413 /* DCS terminator (ST) received. */
1415 input_dcs_dispatch(struct input_ctx
*ictx
)
1417 const char prefix
[] = "tmux;";
1418 const u_int prefix_len
= (sizeof prefix
) - 1;
1420 if (ictx
->flags
& INPUT_DISCARD
)
1423 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1425 /* Check for tmux prefix. */
1426 if (ictx
->input_len
>= prefix_len
&&
1427 strncmp(ictx
->input_buf
, prefix
, prefix_len
) == 0) {
1428 screen_write_rawstring(&ictx
->ctx
,
1429 ictx
->input_buf
+ prefix_len
, ictx
->input_len
- prefix_len
);
1435 /* OSC string started. */
1437 input_enter_osc(struct input_ctx
*ictx
)
1439 log_debug("%s", __func__
);
1444 /* OSC terminator (ST) received. */
1446 input_exit_osc(struct input_ctx
*ictx
)
1448 if (ictx
->flags
& INPUT_DISCARD
)
1450 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1452 if (ictx
->input_len
< 2 || ictx
->input_buf
[1] != ';')
1454 if (ictx
->input_buf
[0] != '0' && ictx
->input_buf
[0] != '2')
1457 screen_set_title(ictx
->ctx
.s
, ictx
->input_buf
+ 2);
1458 server_status_window(ictx
->wp
->window
);
1461 /* APC string started. */
1463 input_enter_apc(struct input_ctx
*ictx
)
1465 log_debug("%s", __func__
);
1470 /* APC terminator (ST) received. */
1472 input_exit_apc(struct input_ctx
*ictx
)
1474 if (ictx
->flags
& INPUT_DISCARD
)
1476 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1478 screen_set_title(ictx
->ctx
.s
, ictx
->input_buf
);
1479 server_status_window(ictx
->wp
->window
);
1482 /* Rename string started. */
1484 input_enter_rename(struct input_ctx
*ictx
)
1486 log_debug("%s", __func__
);
1491 /* Rename terminator (ST) received. */
1493 input_exit_rename(struct input_ctx
*ictx
)
1495 if (ictx
->flags
& INPUT_DISCARD
)
1497 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1499 xfree(ictx
->wp
->window
->name
);
1500 ictx
->wp
->window
->name
= xstrdup(ictx
->input_buf
);
1501 options_set_number(&ictx
->wp
->window
->options
, "automatic-rename", 0);
1503 server_status_window(ictx
->wp
->window
);
1506 /* Open UTF-8 character. */
1508 input_utf8_open(struct input_ctx
*ictx
)
1510 if (!options_get_number(&ictx
->wp
->window
->options
, "utf8")) {
1511 /* Print, and do not switch state. */
1515 log_debug("%s", __func__
);
1517 utf8_open(&ictx
->utf8data
, ictx
->ch
);
1521 /* Append to UTF-8 character. */
1523 input_utf8_add(struct input_ctx
*ictx
)
1525 log_debug("%s", __func__
);
1527 utf8_append(&ictx
->utf8data
, ictx
->ch
);
1531 /* Close UTF-8 string. */
1533 input_utf8_close(struct input_ctx
*ictx
)
1535 log_debug("%s", __func__
);
1537 utf8_append(&ictx
->utf8data
, ictx
->ch
);
1539 ictx
->cell
.flags
|= GRID_FLAG_UTF8
;
1540 screen_write_cell(&ictx
->ctx
, &ictx
->cell
, &ictx
->utf8data
);
1541 ictx
->cell
.flags
&= ~GRID_FLAG_UTF8
;