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 struct input_transition
;
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 *, ...) __printflike(2, 3);
54 void input_set_state(struct window_pane
*, const struct input_transition
*);
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
*);
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
*);
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
*);
77 void input_csi_dispatch_winops(struct input_ctx
*);
78 void input_csi_dispatch_sgr(struct input_ctx
*);
79 int input_dcs_dispatch(struct input_ctx
*);
80 int input_utf8_open(struct input_ctx
*);
81 int input_utf8_add(struct input_ctx
*);
82 int input_utf8_close(struct input_ctx
*);
84 /* Command table comparison function. */
85 int input_table_compare(const void *, const void *);
87 /* Command table entry. */
88 struct input_table_entry
{
94 /* Escape commands. */
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
},
126 /* Control (CSI) commands. */
127 enum input_csi_type
{
151 INPUT_CSI_RM_PRIVATE
,
155 INPUT_CSI_SM_PRIVATE
,
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
},
168 { 'E', "", INPUT_CSI_CNL
},
169 { 'F', "", INPUT_CSI_CPL
},
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
},
177 { 'X', "", INPUT_CSI_ECH
},
178 { 'Z', "", INPUT_CSI_CBT
},
179 { 'c', "", INPUT_CSI_DA
},
180 { 'c', ">", INPUT_CSI_DA_TWO
},
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
},
190 { 'q', " ", INPUT_CSI_DECSCUSR
},
191 { 'r', "", INPUT_CSI_DECSTBM
},
192 { 's', "", INPUT_CSI_SCP
},
193 { 't', "", INPUT_CSI_WINOPS
},
194 { 'u', "", INPUT_CSI_RCP
},
197 /* Input transition. */
198 struct input_transition
{
202 int (*handler
)(struct input_ctx
*);
203 const struct input_state
*state
;
209 void (*enter
)(struct input_ctx
*);
210 void (*exit
)(struct input_ctx
*);
211 const struct input_transition
*transitions
;
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 }
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
[];
232 const struct input_transition input_state_dcs_escape_table
[];
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
[];
242 /* ground state definition. */
243 const struct input_state input_state_ground
= {
246 input_state_ground_table
249 /* esc_enter state definition. */
250 const struct input_state input_state_esc_enter
= {
253 input_state_esc_enter_table
256 /* esc_intermediate state definition. */
257 const struct input_state input_state_esc_intermediate
= {
260 input_state_esc_intermediate_table
263 /* csi_enter state definition. */
264 const struct input_state input_state_csi_enter
= {
267 input_state_csi_enter_table
270 /* csi_parameter state definition. */
271 const struct input_state input_state_csi_parameter
= {
274 input_state_csi_parameter_table
277 /* csi_intermediate state definition. */
278 const struct input_state input_state_csi_intermediate
= {
281 input_state_csi_intermediate_table
284 /* csi_ignore state definition. */
285 const struct input_state input_state_csi_ignore
= {
288 input_state_csi_ignore_table
291 /* dcs_enter state definition. */
292 const struct input_state input_state_dcs_enter
= {
295 input_state_dcs_enter_table
298 /* dcs_parameter state definition. */
299 const struct input_state input_state_dcs_parameter
= {
302 input_state_dcs_parameter_table
305 /* dcs_intermediate state definition. */
306 const struct input_state input_state_dcs_intermediate
= {
309 input_state_dcs_intermediate_table
312 /* dcs_handler state definition. */
313 const struct input_state input_state_dcs_handler
= {
316 input_state_dcs_handler_table
319 /* dcs_escape state definition. */
320 const struct input_state input_state_dcs_escape
= {
323 input_state_dcs_escape_table
326 /* dcs_ignore state definition. */
327 const struct input_state input_state_dcs_ignore
= {
330 input_state_dcs_ignore_table
333 /* osc_string state definition. */
334 const struct input_state input_state_osc_string
= {
336 input_enter_osc
, input_exit_osc
,
337 input_state_osc_string_table
340 /* apc_string state definition. */
341 const struct input_state input_state_apc_string
= {
343 input_enter_apc
, input_exit_apc
,
344 input_state_apc_string_table
347 /* rename_string state definition. */
348 const struct input_state input_state_rename_string
= {
350 input_enter_rename
, input_exit_rename
,
351 input_state_rename_string_table
354 /* consume_st state definition. */
355 const struct input_state input_state_consume_st
= {
358 input_state_consume_st_table
361 /* utf8_three state definition. */
362 const struct input_state input_state_utf8_three
= {
365 input_state_utf8_three_table
368 /* utf8_two state definition. */
369 const struct input_state input_state_utf8_two
= {
372 input_state_utf8_two_table
375 /* utf8_one state definition. */
376 const struct input_state input_state_utf8_one
= {
379 input_state_utf8_one_table
382 /* ground state table. */
383 const struct input_transition input_state_ground_table
[] = {
384 INPUT_STATE_ANYWHERE
,
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
},
397 { -1, -1, NULL
, NULL
}
400 /* esc_enter state table. */
401 const struct input_transition input_state_esc_enter_table
[] = {
402 INPUT_STATE_ANYWHERE
,
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
},
421 { 0x6c, 0x7e, input_esc_dispatch
, &input_state_ground
},
422 { 0x7f, 0xff, NULL
, NULL
},
424 { -1, -1, NULL
, NULL
}
427 /* esc_interm state table. */
428 const struct input_transition input_state_esc_intermediate_table
[] = {
429 INPUT_STATE_ANYWHERE
,
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
},
438 { -1, -1, NULL
, NULL
}
441 /* csi_enter state table. */
442 const struct input_transition input_state_csi_enter_table
[] = {
443 INPUT_STATE_ANYWHERE
,
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
},
456 { -1, -1, NULL
, NULL
}
459 /* csi_parameter state table. */
460 const struct input_transition input_state_csi_parameter_table
[] = {
461 INPUT_STATE_ANYWHERE
,
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
},
474 { -1, -1, NULL
, NULL
}
477 /* csi_intermediate state table. */
478 const struct input_transition input_state_csi_intermediate_table
[] = {
479 INPUT_STATE_ANYWHERE
,
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
},
489 { -1, -1, NULL
, NULL
}
492 /* csi_ignore state table. */
493 const struct input_transition input_state_csi_ignore_table
[] = {
494 INPUT_STATE_ANYWHERE
,
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
},
503 { -1, -1, NULL
, NULL
}
506 /* dcs_enter state table. */
507 const struct input_transition input_state_dcs_enter_table
[] = {
508 INPUT_STATE_ANYWHERE
,
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
},
518 { 0x40, 0x7e, input_input
, &input_state_dcs_handler
},
519 { 0x7f, 0xff, NULL
, NULL
},
521 { -1, -1, NULL
, NULL
}
524 /* dcs_parameter state table. */
525 const struct input_transition input_state_dcs_parameter_table
[] = {
526 INPUT_STATE_ANYWHERE
,
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
},
536 { 0x40, 0x7e, input_input
, &input_state_dcs_handler
},
537 { 0x7f, 0xff, NULL
, NULL
},
539 { -1, -1, NULL
, NULL
}
542 /* dcs_interm state table. */
543 const struct input_transition input_state_dcs_intermediate_table
[] = {
544 INPUT_STATE_ANYWHERE
,
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
},
551 { 0x40, 0x7e, input_input
, &input_state_dcs_handler
},
552 { 0x7f, 0xff, NULL
, NULL
},
554 { -1, -1, NULL
, NULL
}
557 /* dcs_handler state table. */
558 const struct input_transition input_state_dcs_handler_table
[] = {
559 /* No INPUT_STATE_ANYWHERE */
561 { 0x00, 0x1a, input_input
, NULL
},
562 { 0x1b, 0x1b, NULL
, &input_state_dcs_escape
},
563 { 0x1c, 0xff, input_input
, NULL
},
565 { -1, -1, NULL
, NULL
}
568 /* dcs_escape state table. */
569 const struct input_transition input_state_dcs_escape_table
[] = {
570 /* No INPUT_STATE_ANYWHERE */
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
},
576 { -1, -1, NULL
, NULL
}
579 /* dcs_ignore state table. */
580 const struct input_transition input_state_dcs_ignore_table
[] = {
581 INPUT_STATE_ANYWHERE
,
583 { 0x00, 0x17, NULL
, NULL
},
584 { 0x19, 0x19, NULL
, NULL
},
585 { 0x1c, 0x1f, NULL
, NULL
},
586 { 0x20, 0xff, NULL
, NULL
},
588 { -1, -1, NULL
, NULL
}
591 /* osc_string state table. */
592 const struct input_transition input_state_osc_string_table
[] = {
593 INPUT_STATE_ANYWHERE
,
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
},
602 { -1, -1, NULL
, NULL
}
605 /* apc_string state table. */
606 const struct input_transition input_state_apc_string_table
[] = {
607 INPUT_STATE_ANYWHERE
,
609 { 0x00, 0x17, NULL
, NULL
},
610 { 0x19, 0x19, NULL
, NULL
},
611 { 0x1c, 0x1f, NULL
, NULL
},
612 { 0x20, 0xff, input_input
, NULL
},
614 { -1, -1, NULL
, NULL
}
617 /* rename_string state table. */
618 const struct input_transition input_state_rename_string_table
[] = {
619 INPUT_STATE_ANYWHERE
,
621 { 0x00, 0x17, NULL
, NULL
},
622 { 0x19, 0x19, NULL
, NULL
},
623 { 0x1c, 0x1f, NULL
, NULL
},
624 { 0x20, 0xff, input_input
, NULL
},
626 { -1, -1, NULL
, NULL
}
629 /* consume_st state table. */
630 const struct input_transition input_state_consume_st_table
[] = {
631 INPUT_STATE_ANYWHERE
,
633 { 0x00, 0x17, NULL
, NULL
},
634 { 0x19, 0x19, NULL
, NULL
},
635 { 0x1c, 0x1f, NULL
, NULL
},
636 { 0x20, 0xff, NULL
, NULL
},
638 { -1, -1, NULL
, NULL
}
641 /* utf8_three state table. */
642 const struct input_transition input_state_utf8_three_table
[] = {
643 /* No INPUT_STATE_ANYWHERE */
645 { 0x00, 0x7f, NULL
, &input_state_ground
},
646 { 0x80, 0xbf, input_utf8_add
, &input_state_utf8_two
},
647 { 0xc0, 0xff, NULL
, &input_state_ground
},
649 { -1, -1, NULL
, NULL
}
652 /* utf8_two state table. */
653 const struct input_transition input_state_utf8_two_table
[] = {
654 /* No INPUT_STATE_ANYWHERE */
656 { 0x00, 0x7f, NULL
, &input_state_ground
},
657 { 0x80, 0xbf, input_utf8_add
, &input_state_utf8_one
},
658 { 0xc0, 0xff, NULL
, &input_state_ground
},
660 { -1, -1, NULL
, NULL
}
663 /* utf8_one state table. */
664 const struct input_transition input_state_utf8_one_table
[] = {
665 /* No INPUT_STATE_ANYWHERE */
667 { 0x00, 0x7f, NULL
, &input_state_ground
},
668 { 0x80, 0xbf, input_utf8_close
, &input_state_ground
},
669 { 0xc0, 0xff, NULL
, &input_state_ground
},
671 { -1, -1, NULL
, NULL
}
674 /* Input table compare. */
676 input_table_compare(const void *key
, const void *value
)
678 const struct input_ctx
*ictx
= key
;
679 const struct input_table_entry
*entry
= value
;
681 if (ictx
->ch
!= entry
->ch
)
682 return (ictx
->ch
- entry
->ch
);
683 return (strcmp((const char *)ictx
->interm_buf
, entry
->interm
));
686 /* Initialise input parser. */
688 input_init(struct window_pane
*wp
)
690 struct input_ctx
*ictx
= &wp
->ictx
;
692 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
694 memcpy(&ictx
->old_cell
, &grid_default_cell
, sizeof ictx
->old_cell
);
698 *ictx
->interm_buf
= '\0';
699 ictx
->interm_len
= 0;
701 *ictx
->param_buf
= '\0';
704 ictx
->state
= &input_state_ground
;
707 ictx
->since_ground
= evbuffer_new();
710 /* Destroy input parser. */
712 input_free(struct window_pane
*wp
)
715 evbuffer_free(wp
->ictx
.since_ground
);
718 /* Change input state. */
720 input_set_state(struct window_pane
*wp
, const struct input_transition
*itr
)
722 struct input_ctx
*ictx
= &wp
->ictx
;
723 struct evbuffer
*ground_evb
= ictx
->since_ground
;
725 if (ictx
->state
->exit
!= NULL
)
726 ictx
->state
->exit(ictx
);
728 if (itr
->state
== &input_state_ground
)
729 evbuffer_drain(ground_evb
, EVBUFFER_LENGTH(ground_evb
));
731 ictx
->state
= itr
->state
;
732 if (ictx
->state
->enter
!= NULL
)
733 ictx
->state
->enter(ictx
);
738 input_parse(struct window_pane
*wp
)
740 struct input_ctx
*ictx
= &wp
->ictx
;
741 const struct input_transition
*itr
;
742 struct evbuffer
*evb
= wp
->event
->input
;
746 if (EVBUFFER_LENGTH(evb
) == 0)
749 wp
->window
->flags
|= WINDOW_ACTIVITY
;
750 wp
->window
->flags
&= ~WINDOW_SILENCE
;
753 * Open the screen. Use NULL wp if there is a mode set as don't want to
756 if (wp
->mode
== NULL
)
757 screen_write_start(&ictx
->ctx
, wp
, &wp
->base
);
759 screen_write_start(&ictx
->ctx
, NULL
, &wp
->base
);
762 buf
= EVBUFFER_DATA(evb
);
763 len
= EVBUFFER_LENGTH(evb
);
764 notify_input(wp
, evb
);
767 /* Parse the input. */
769 ictx
->ch
= buf
[off
++];
770 log_debug("%s: '%c' %s", __func__
, ictx
->ch
, ictx
->state
->name
);
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
)
779 if (itr
->first
== -1 || itr
->last
== -1) {
780 /* No transition? Eh? */
781 fatalx("No transition from state!");
785 * Execute the handler, if any. Don't switch state if it
788 if (itr
->handler
!= NULL
&& itr
->handler(ictx
) != 0)
791 /* And switch state, if necessary. */
792 if (itr
->state
!= NULL
)
793 input_set_state(wp
, itr
);
795 /* If not in ground state, save input. */
796 if (ictx
->state
!= &input_state_ground
)
797 evbuffer_add(ictx
->since_ground
, &ictx
->ch
, 1);
800 /* Close the screen. */
801 screen_write_stop(&ictx
->ctx
);
803 evbuffer_drain(evb
, len
);
806 /* Split the parameter list (if any). */
808 input_split(struct input_ctx
*ictx
)
815 ictx
->param_list_len
= 0;
816 if (ictx
->param_len
== 0)
819 ptr
= (char *)ictx
->param_buf
;
820 while ((out
= strsep(&ptr
, ";")) != NULL
) {
824 n
= strtonum(out
, 0, INT_MAX
, &errstr
);
829 ictx
->param_list
[ictx
->param_list_len
++] = n
;
830 if (ictx
->param_list_len
== nitems(ictx
->param_list
))
837 /* Get an argument or return default value. */
839 input_get(struct input_ctx
*ictx
, u_int validx
, int minval
, int defval
)
843 if (validx
>= ictx
->param_list_len
)
846 retval
= ictx
->param_list
[validx
];
854 /* Reply to terminal query. */
856 input_reply(struct input_ctx
*ictx
, const char *fmt
, ...)
862 vasprintf(&reply
, fmt
, ap
);
865 bufferevent_write(ictx
->wp
->event
, reply
, strlen(reply
));
869 /* Clear saved state. */
871 input_clear(struct input_ctx
*ictx
)
873 *ictx
->interm_buf
= '\0';
874 ictx
->interm_len
= 0;
876 *ictx
->param_buf
= '\0';
879 *ictx
->input_buf
= '\0';
882 ictx
->flags
&= ~INPUT_DISCARD
;
885 /* Output this character to the screen. */
887 input_print(struct input_ctx
*ictx
)
889 grid_cell_one(&ictx
->cell
, ictx
->ch
);
890 screen_write_cell(&ictx
->ctx
, &ictx
->cell
);
895 /* Collect intermediate string. */
897 input_intermediate(struct input_ctx
*ictx
)
899 if (ictx
->interm_len
== (sizeof ictx
->interm_buf
) - 1)
900 ictx
->flags
|= INPUT_DISCARD
;
902 ictx
->interm_buf
[ictx
->interm_len
++] = ictx
->ch
;
903 ictx
->interm_buf
[ictx
->interm_len
] = '\0';
909 /* Collect parameter string. */
911 input_parameter(struct input_ctx
*ictx
)
913 if (ictx
->param_len
== (sizeof ictx
->param_buf
) - 1)
914 ictx
->flags
|= INPUT_DISCARD
;
916 ictx
->param_buf
[ictx
->param_len
++] = ictx
->ch
;
917 ictx
->param_buf
[ictx
->param_len
] = '\0';
923 /* Collect input string. */
925 input_input(struct input_ctx
*ictx
)
927 if (ictx
->input_len
== (sizeof ictx
->input_buf
) - 1)
928 ictx
->flags
|= INPUT_DISCARD
;
930 ictx
->input_buf
[ictx
->input_len
++] = ictx
->ch
;
931 ictx
->input_buf
[ictx
->input_len
] = '\0';
937 /* Execute C0 control sequence. */
939 input_c0_dispatch(struct input_ctx
*ictx
)
941 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
942 struct window_pane
*wp
= ictx
->wp
;
943 struct screen
*s
= sctx
->s
;
946 log_debug("%s: '%c", __func__
, ictx
->ch
);
949 case '\000': /* NUL */
951 case '\007': /* BEL */
952 wp
->window
->flags
|= WINDOW_BELL
;
954 case '\010': /* BS */
955 screen_write_backspace(sctx
);
957 case '\011': /* HT */
958 /* Don't tab beyond the end of the line. */
959 if (s
->cx
>= screen_size_x(s
) - 1)
962 /* Find the next tab point, or use the last column if none. */
965 if (bit_test(s
->tabs
, s
->cx
))
967 } while (s
->cx
< screen_size_x(s
) - 1);
969 case '\012': /* LF */
970 case '\013': /* VT */
971 case '\014': /* FF */
972 screen_write_linefeed(sctx
, 0);
974 case '\015': /* CR */
975 screen_write_carriagereturn(sctx
);
977 case '\016': /* SO */
978 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
980 case '\017': /* SI */
981 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
984 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
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
);
1000 /* Execute escape sequence. */
1002 input_esc_dispatch(struct input_ctx
*ictx
)
1004 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
1005 struct screen
*s
= sctx
->s
;
1006 struct input_table_entry
*entry
;
1008 if (ictx
->flags
& INPUT_DISCARD
)
1010 log_debug("%s: '%c', %s", __func__
, ictx
->ch
, ictx
->interm_buf
);
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
);
1019 switch (entry
->type
) {
1021 memcpy(&ictx
->cell
, &grid_default_cell
, sizeof ictx
->cell
);
1022 memcpy(&ictx
->old_cell
, &ictx
->cell
, sizeof ictx
->old_cell
);
1026 screen_write_reset(sctx
);
1029 screen_write_linefeed(sctx
, 0);
1032 screen_write_carriagereturn(sctx
);
1033 screen_write_linefeed(sctx
, 0);
1036 if (s
->cx
< screen_size_x(s
))
1037 bit_set(s
->tabs
, s
->cx
);
1040 screen_write_reverseindex(sctx
);
1042 case INPUT_ESC_DECKPAM
:
1043 screen_write_mode_set(sctx
, MODE_KKEYPAD
);
1045 case INPUT_ESC_DECKPNM
:
1046 screen_write_mode_clear(sctx
, MODE_KKEYPAD
);
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
;
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
);
1057 case INPUT_ESC_DECALN
:
1058 screen_write_alignmenttest(sctx
);
1060 case INPUT_ESC_SCSON_G0
:
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).
1066 ictx
->cell
.attr
&= ~GRID_ATTR_CHARSET
;
1068 case INPUT_ESC_SCSOFF_G0
:
1069 ictx
->cell
.attr
|= GRID_ATTR_CHARSET
;
1076 /* Execute control sequence. */
1078 input_csi_dispatch(struct input_ctx
*ictx
)
1080 struct screen_write_ctx
*sctx
= &ictx
->ctx
;
1081 struct screen
*s
= sctx
->s
;
1082 struct input_table_entry
*entry
;
1085 if (ictx
->flags
& INPUT_DISCARD
)
1087 if (input_split(ictx
) != 0)
1089 log_debug("%s: '%c' \"%s\" \"%s\"",
1090 __func__
, ictx
->ch
, ictx
->interm_buf
, ictx
->param_buf
);
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
);
1099 switch (entry
->type
) {
1101 /* Find the previous tab point, n times. */
1102 n
= input_get(ictx
, 0, 1, 1);
1103 while (s
->cx
> 0 && n
-- > 0) {
1106 while (s
->cx
> 0 && !bit_test(s
->tabs
, s
->cx
));
1110 screen_write_cursorleft(sctx
, input_get(ictx
, 0, 1, 1));
1113 screen_write_cursordown(sctx
, input_get(ictx
, 0, 1, 1));
1116 screen_write_cursorright(sctx
, input_get(ictx
, 0, 1, 1));
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);
1123 case INPUT_CSI_WINOPS
:
1124 input_csi_dispatch_winops(ictx
);
1127 screen_write_cursorup(sctx
, input_get(ictx
, 0, 1, 1));
1130 screen_write_carriagereturn(sctx
);
1131 screen_write_cursordown(sctx
, input_get(ictx
, 0, 1, 1));
1134 screen_write_carriagereturn(sctx
);
1135 screen_write_cursorup(sctx
, input_get(ictx
, 0, 1, 1));
1138 switch (input_get(ictx
, 0, 0, 0)) {
1140 input_reply(ictx
, "\033[?1;2c");
1143 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1147 case INPUT_CSI_DA_TWO
:
1148 switch (input_get(ictx
, 0, 0, 0)) {
1150 input_reply(ictx
, "\033[>0;95;0c");
1153 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1158 screen_write_clearcharacter(sctx
, input_get(ictx
, 0, 1, 1));
1161 screen_write_deletecharacter(sctx
, input_get(ictx
, 0, 1, 1));
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);
1169 screen_write_deleteline(sctx
, input_get(ictx
, 0, 1, 1));
1172 switch (input_get(ictx
, 0, 0, 0)) {
1174 input_reply(ictx
, "\033[0n");
1177 input_reply(ictx
, "\033[%u;%uR", s
->cy
+ 1, s
->cx
+ 1);
1180 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1185 switch (input_get(ictx
, 0, 0, 0)) {
1187 screen_write_clearendofscreen(sctx
);
1190 screen_write_clearstartofscreen(sctx
);
1193 screen_write_clearscreen(sctx
);
1196 switch (input_get(ictx
, 1, 0, 0)) {
1199 * Linux console extension to clear history
1200 * (for example before locking the screen).
1202 screen_write_clearhistory(sctx
);
1207 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1212 switch (input_get(ictx
, 0, 0, 0)) {
1214 screen_write_clearendofline(sctx
);
1217 screen_write_clearstartofline(sctx
);
1220 screen_write_clearline(sctx
);
1223 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1228 n
= input_get(ictx
, 0, 1, 1);
1229 screen_write_cursormove(sctx
, n
- 1, s
->cy
);
1232 screen_write_insertcharacter(sctx
, input_get(ictx
, 0, 1, 1));
1235 screen_write_insertline(sctx
, input_get(ictx
, 0, 1, 1));
1238 memcpy(&ictx
->cell
, &ictx
->old_cell
, sizeof ictx
->cell
);
1239 screen_write_cursormove(sctx
, ictx
->old_cx
, ictx
->old_cy
);
1242 input_csi_dispatch_rm(ictx
);
1244 case INPUT_CSI_RM_PRIVATE
:
1245 input_csi_dispatch_rm_private(ictx
);
1248 memcpy(&ictx
->old_cell
, &ictx
->cell
, sizeof ictx
->old_cell
);
1249 ictx
->old_cx
= s
->cx
;
1250 ictx
->old_cy
= s
->cy
;
1253 input_csi_dispatch_sgr(ictx
);
1256 input_csi_dispatch_sm(ictx
);
1258 case INPUT_CSI_SM_PRIVATE
:
1259 input_csi_dispatch_sm_private(ictx
);
1262 switch (input_get(ictx
, 0, 0, 0)) {
1264 if (s
->cx
< screen_size_x(s
))
1265 bit_clear(s
->tabs
, s
->cx
);
1268 bit_nclear(s
->tabs
, 0, screen_size_x(s
) - 1);
1271 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1276 n
= input_get(ictx
, 0, 1, 1);
1277 screen_write_cursormove(sctx
, s
->cx
, n
- 1);
1279 case INPUT_CSI_DECSCUSR
:
1280 n
= input_get(ictx
, 0, 0, 0);
1281 screen_set_cursor_style(s
, n
);
1288 /* Handle CSI RM. */
1290 input_csi_dispatch_rm(struct input_ctx
*ictx
)
1294 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1295 switch (input_get(ictx
, i
, 0, -1)) {
1297 screen_write_mode_clear(&ictx
->ctx
, MODE_INSERT
);
1300 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1306 /* Handle CSI private RM. */
1308 input_csi_dispatch_rm_private(struct input_ctx
*ictx
)
1312 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1313 switch (input_get(ictx
, i
, 0, -1)) {
1314 case 1: /* DECCKM */
1315 screen_write_mode_clear(&ictx
->ctx
, MODE_KCURSOR
);
1317 case 3: /* DECCOLM */
1318 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1319 screen_write_clearscreen(&ictx
->ctx
);
1321 case 7: /* DECAWM */
1322 screen_write_mode_clear(&ictx
->ctx
, MODE_WRAP
);
1325 screen_write_mode_clear(&ictx
->ctx
, MODE_CURSOR
);
1331 screen_write_mode_clear(&ictx
->ctx
, ALL_MOUSE_MODES
);
1334 screen_write_mode_clear(&ictx
->ctx
, MODE_FOCUSON
);
1337 screen_write_mode_clear(&ictx
->ctx
, MODE_MOUSE_UTF8
);
1340 screen_write_mode_clear(&ictx
->ctx
, MODE_MOUSE_SGR
);
1344 window_pane_alternate_off(ictx
->wp
, &ictx
->cell
, 0);
1347 window_pane_alternate_off(ictx
->wp
, &ictx
->cell
, 1);
1350 screen_write_mode_clear(&ictx
->ctx
, MODE_BRACKETPASTE
);
1353 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1359 /* Handle CSI SM. */
1361 input_csi_dispatch_sm(struct input_ctx
*ictx
)
1365 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1366 switch (input_get(ictx
, i
, 0, -1)) {
1368 screen_write_mode_set(&ictx
->ctx
, MODE_INSERT
);
1371 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1377 /* Handle CSI private SM. */
1379 input_csi_dispatch_sm_private(struct input_ctx
*ictx
)
1383 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1384 switch (input_get(ictx
, i
, 0, -1)) {
1385 case 1: /* DECCKM */
1386 screen_write_mode_set(&ictx
->ctx
, MODE_KCURSOR
);
1388 case 3: /* DECCOLM */
1389 screen_write_cursormove(&ictx
->ctx
, 0, 0);
1390 screen_write_clearscreen(&ictx
->ctx
);
1392 case 7: /* DECAWM */
1393 screen_write_mode_set(&ictx
->ctx
, MODE_WRAP
);
1396 screen_write_mode_set(&ictx
->ctx
, MODE_CURSOR
);
1399 screen_write_mode_clear(&ictx
->ctx
, ALL_MOUSE_MODES
);
1400 screen_write_mode_set(&ictx
->ctx
, MODE_MOUSE_STANDARD
);
1403 screen_write_mode_clear(&ictx
->ctx
, ALL_MOUSE_MODES
);
1404 screen_write_mode_set(&ictx
->ctx
, MODE_MOUSE_BUTTON
);
1407 screen_write_mode_clear(&ictx
->ctx
, ALL_MOUSE_MODES
);
1408 screen_write_mode_set(&ictx
->ctx
, MODE_MOUSE_ANY
);
1411 if (ictx
->ctx
.s
->mode
& MODE_FOCUSON
)
1413 screen_write_mode_set(&ictx
->ctx
, MODE_FOCUSON
);
1414 ictx
->wp
->flags
|= PANE_FOCUSPUSH
; /* force update */
1417 screen_write_mode_set(&ictx
->ctx
, MODE_MOUSE_UTF8
);
1420 screen_write_mode_set(&ictx
->ctx
, MODE_MOUSE_SGR
);
1424 window_pane_alternate_on(ictx
->wp
, &ictx
->cell
, 0);
1427 window_pane_alternate_on(ictx
->wp
, &ictx
->cell
, 1);
1430 screen_write_mode_set(&ictx
->ctx
, MODE_BRACKETPASTE
);
1433 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1439 /* Handle CSI window operations. */
1441 input_csi_dispatch_winops(struct input_ctx
*ictx
)
1443 struct window_pane
*wp
= ictx
->wp
;
1447 while ((n
= input_get(ictx
, m
, 0, -1)) != -1) {
1466 if (input_get(ictx
, m
, 0, -1) == -1)
1474 if (input_get(ictx
, m
, 0, -1) == -1)
1478 input_reply(ictx
, "\033[8;%u;%u", wp
->sy
, wp
->sx
);
1481 log_debug("%s: unknown '%c'", __func__
, ictx
->ch
);
1488 /* Handle CSI SGR. */
1490 input_csi_dispatch_sgr(struct input_ctx
*ictx
)
1492 struct grid_cell
*gc
= &ictx
->cell
;
1497 if (ictx
->param_list_len
== 0) {
1499 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1500 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1504 for (i
= 0; i
< ictx
->param_list_len
; i
++) {
1505 n
= input_get(ictx
, i
, 0, 0);
1507 if (n
== 38 || n
== 48) {
1509 if (input_get(ictx
, i
, 0, -1) != 5)
1513 m
= input_get(ictx
, i
, 0, -1);
1516 gc
->flags
&= ~GRID_FLAG_FG256
;
1518 } else if (n
== 48) {
1519 gc
->flags
&= ~GRID_FLAG_BG256
;
1525 gc
->flags
|= GRID_FLAG_FG256
;
1527 } else if (n
== 48) {
1528 gc
->flags
|= GRID_FLAG_BG256
;
1539 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
1540 gc
->attr
|= (attr
& GRID_ATTR_CHARSET
);
1543 gc
->attr
|= GRID_ATTR_BRIGHT
;
1546 gc
->attr
|= GRID_ATTR_DIM
;
1549 gc
->attr
|= GRID_ATTR_ITALICS
;
1552 gc
->attr
|= GRID_ATTR_UNDERSCORE
;
1555 gc
->attr
|= GRID_ATTR_BLINK
;
1558 gc
->attr
|= GRID_ATTR_REVERSE
;
1561 gc
->attr
|= GRID_ATTR_HIDDEN
;
1564 gc
->attr
&= ~(GRID_ATTR_BRIGHT
|GRID_ATTR_DIM
);
1567 gc
->attr
&= ~GRID_ATTR_ITALICS
;
1570 gc
->attr
&= ~GRID_ATTR_UNDERSCORE
;
1573 gc
->attr
&= ~GRID_ATTR_BLINK
;
1576 gc
->attr
&= ~GRID_ATTR_REVERSE
;
1586 gc
->flags
&= ~GRID_FLAG_FG256
;
1590 gc
->flags
&= ~GRID_FLAG_FG256
;
1601 gc
->flags
&= ~GRID_FLAG_BG256
;
1605 gc
->flags
&= ~GRID_FLAG_BG256
;
1616 gc
->flags
&= ~GRID_FLAG_FG256
;
1627 gc
->flags
&= ~GRID_FLAG_BG256
;
1634 /* DCS terminator (ST) received. */
1636 input_dcs_dispatch(struct input_ctx
*ictx
)
1638 const char prefix
[] = "tmux;";
1639 const u_int prefix_len
= (sizeof prefix
) - 1;
1641 if (ictx
->flags
& INPUT_DISCARD
)
1644 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1646 /* Check for tmux prefix. */
1647 if (ictx
->input_len
>= prefix_len
&&
1648 strncmp((const char *)ictx
->input_buf
, prefix
, prefix_len
) == 0) {
1649 screen_write_rawstring(&ictx
->ctx
,
1650 ictx
->input_buf
+ prefix_len
, ictx
->input_len
- prefix_len
);
1656 /* OSC string started. */
1658 input_enter_osc(struct input_ctx
*ictx
)
1660 log_debug("%s", __func__
);
1665 /* OSC terminator (ST) received. */
1667 input_exit_osc(struct input_ctx
*ictx
)
1669 u_char
*p
= ictx
->input_buf
;
1672 if (ictx
->flags
& INPUT_DISCARD
)
1674 if (ictx
->input_len
< 1 || *p
< '0' || *p
> '9')
1677 log_debug("%s: \"%s\"", __func__
, p
);
1680 while (*p
>= '0' && *p
<= '9')
1681 option
= option
* 10 + *p
++ - '0';
1688 screen_set_title(ictx
->ctx
.s
, (const char *)p
);
1689 server_status_window(ictx
->wp
->window
);
1692 if (*p
!= '?') /* ? is colour request */
1693 screen_set_cursor_colour(ictx
->ctx
.s
, (const char *)p
);
1696 if (*p
== '\0') /* no arguments allowed */
1697 screen_set_cursor_colour(ictx
->ctx
.s
, "");
1700 log_debug("%s: unknown '%u'", __func__
, option
);
1705 /* APC string started. */
1707 input_enter_apc(struct input_ctx
*ictx
)
1709 log_debug("%s", __func__
);
1714 /* APC terminator (ST) received. */
1716 input_exit_apc(struct input_ctx
*ictx
)
1718 if (ictx
->flags
& INPUT_DISCARD
)
1720 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1722 screen_set_title(ictx
->ctx
.s
, (const char *)ictx
->input_buf
);
1723 server_status_window(ictx
->wp
->window
);
1726 /* Rename string started. */
1728 input_enter_rename(struct input_ctx
*ictx
)
1730 log_debug("%s", __func__
);
1735 /* Rename terminator (ST) received. */
1737 input_exit_rename(struct input_ctx
*ictx
)
1739 if (ictx
->flags
& INPUT_DISCARD
)
1741 if (!options_get_number(&ictx
->wp
->window
->options
, "allow-rename"))
1743 log_debug("%s: \"%s\"", __func__
, ictx
->input_buf
);
1745 window_set_name(ictx
->wp
->window
, (const char *)ictx
->input_buf
);
1746 options_set_number(&ictx
->wp
->window
->options
, "automatic-rename", 0);
1748 server_status_window(ictx
->wp
->window
);
1751 /* Open UTF-8 character. */
1753 input_utf8_open(struct input_ctx
*ictx
)
1755 if (!options_get_number(&ictx
->wp
->window
->options
, "utf8")) {
1756 /* Print, and do not switch state. */
1760 log_debug("%s", __func__
);
1762 utf8_open(&ictx
->utf8data
, ictx
->ch
);
1766 /* Append to UTF-8 character. */
1768 input_utf8_add(struct input_ctx
*ictx
)
1770 log_debug("%s", __func__
);
1772 utf8_append(&ictx
->utf8data
, ictx
->ch
);
1776 /* Close UTF-8 string. */
1778 input_utf8_close(struct input_ctx
*ictx
)
1780 log_debug("%s", __func__
);
1782 utf8_append(&ictx
->utf8data
, ictx
->ch
);
1784 grid_cell_set(&ictx
->cell
, &ictx
->utf8data
);
1785 screen_write_cell(&ictx
->ctx
, &ictx
->cell
);