comparison src/term.c @ 20774:10535993e913 v8.2.0939

patch 8.2.0939: checking for term escape sequences is long and confusing Commit: https://github.com/vim/vim/commit/218cb0fb62d29fba552281c2e8ffeb4046d540c4 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jun 9 21:26:36 2020 +0200 patch 8.2.0939: checking for term escape sequences is long and confusing Problem: checking for term escape sequences is long and confusing Solution: Refactor code into separate functions.
author Bram Moolenaar <Bram@vim.org>
date Tue, 09 Jun 2020 21:30:03 +0200
parents 1e2e81dbb958
children 7728e309e013
comparison
equal deleted inserted replaced
20773:764cb6c1e56c 20774:10535993e913
4382 } 4382 }
4383 } 4383 }
4384 return new_slen; 4384 return new_slen;
4385 } 4385 }
4386 4386
4387 static void
4388 handle_u7_response(int *arg, char_u *tp, int csi_len)
4389 {
4390 if (arg[0] == 2 && arg[1] >= 2)
4391 {
4392 char *aw = NULL;
4393
4394 LOG_TR(("Received U7 status: %s", tp));
4395 u7_status.tr_progress = STATUS_GOT;
4396 did_cursorhold = TRUE;
4397 if (arg[1] == 2)
4398 aw = "single";
4399 else if (arg[1] == 3)
4400 aw = "double";
4401 if (aw != NULL && STRCMP(aw, p_ambw) != 0)
4402 {
4403 // Setting the option causes a screen redraw. Do
4404 // that right away if possible, keeping any
4405 // messages.
4406 set_option_value((char_u *)"ambw", 0L,
4407 (char_u *)aw, 0);
4408 # ifdef DEBUG_TERMRESPONSE
4409 {
4410 int r = redraw_asap(CLEAR);
4411
4412 log_tr("set 'ambiwidth', redraw_asap(): %d", r);
4413 }
4414 # else
4415 redraw_asap(CLEAR);
4416 # endif
4417 # ifdef FEAT_EVAL
4418 set_vim_var_string(VV_TERMU7RESP, tp, csi_len);
4419 # endif
4420 }
4421 }
4422 else if (arg[0] == 3)
4423 {
4424 LOG_TR(("Received compatibility test result: %s", tp));
4425 // Third row: xterm compatibility test.
4426 // If the cursor is not on the first column then the
4427 // terminal is not xterm compatible.
4428 if (arg[1] != 1)
4429 xcc_test_failed = TRUE;
4430 xcc_status.tr_progress = STATUS_GOT;
4431 }
4432 }
4433
4434 /*
4435 * Handle a response to T_CRV.
4436 */
4437 static void
4438 handle_version_response(int first, int *arg, int argc, char_u *tp)
4439 {
4440 int version = arg[1];
4441
4442 LOG_TR(("Received CRV response: %s", tp));
4443 crv_status.tr_progress = STATUS_GOT;
4444 did_cursorhold = TRUE;
4445
4446 // If this code starts with CSI, you can bet that the
4447 // terminal uses 8-bit codes.
4448 if (tp[0] == CSI)
4449 switch_to_8bit();
4450
4451 // Screen sends 40500.
4452 // rxvt sends its version number: "20703" is 2.7.3.
4453 // Ignore it for when the user has set 'term' to xterm,
4454 // even though it's an rxvt.
4455 if (version > 20000)
4456 version = 0;
4457
4458 if (first == '>' && argc == 3)
4459 {
4460 int need_flush = FALSE;
4461 int is_iterm2 = FALSE;
4462 int is_mintty = FALSE;
4463 int is_screen = FALSE;
4464
4465 // mintty 2.9.5 sends 77;20905;0c.
4466 // (77 is ASCII 'M' for mintty.)
4467 if (arg[0] == 77)
4468 is_mintty = TRUE;
4469
4470 // if xterm version >= 141 try to get termcap codes
4471 if (version >= 141)
4472 {
4473 LOG_TR(("Enable checking for XT codes"));
4474 check_for_codes = TRUE;
4475 need_gather = TRUE;
4476 req_codes_from_term();
4477 }
4478
4479 // libvterm sends 0;100;0
4480 if (version == 100 && arg[0] == 0 && arg[2] == 0)
4481 {
4482 // If run from Vim $COLORS is set to the number of
4483 // colors the terminal supports. Otherwise assume
4484 // 256, libvterm supports even more.
4485 if (mch_getenv((char_u *)"COLORS") == NULL)
4486 may_adjust_color_count(256);
4487 // Libvterm can handle SGR mouse reporting.
4488 if (!option_was_set((char_u *)"ttym"))
4489 set_option_value((char_u *)"ttym", 0L,
4490 (char_u *)"sgr", 0);
4491 }
4492
4493 if (version == 95)
4494 {
4495 // Mac Terminal.app sends 1;95;0
4496 if (arg[0] == 1 && arg[2] == 0)
4497 {
4498 is_not_xterm = TRUE;
4499 is_mac_terminal = TRUE;
4500 }
4501 // iTerm2 sends 0;95;0
4502 else if (arg[0] == 0 && arg[2] == 0)
4503 is_iterm2 = TRUE;
4504 // old iTerm2 sends 0;95;
4505 else if (arg[0] == 0 && arg[2] == -1)
4506 is_not_xterm = TRUE;
4507 }
4508
4509 // screen sends 83;40500;0 83 is 'S' in ASCII.
4510 if (arg[0] == 83)
4511 is_screen = TRUE;
4512
4513 // Only set 'ttymouse' automatically if it was not set
4514 // by the user already.
4515 if (!option_was_set((char_u *)"ttym"))
4516 {
4517 // Xterm version 277 supports SGR. Also support
4518 // Terminal.app, iTerm2, mintty, and screen 4.7+.
4519 if ((!is_screen && version >= 277)
4520 || is_iterm2
4521 || is_mac_terminal
4522 || is_mintty
4523 || (is_screen && arg[1] >= 40700))
4524 set_option_value((char_u *)"ttym", 0L,
4525 (char_u *)"sgr", 0);
4526 // For xterm version >= 95 mouse dragging works.
4527 else if (version >= 95)
4528 set_option_value((char_u *)"ttym", 0L,
4529 (char_u *)"xterm2", 0);
4530 }
4531
4532 // Detect terminals that set $TERM to something like
4533 // "xterm-256color" but are not fully xterm compatible.
4534
4535 // Gnome terminal sends 1;3801;0, 1;4402;0 or 1;2501;0.
4536 // xfce4-terminal sends 1;2802;0.
4537 // screen sends 83;40500;0
4538 // Assuming any version number over 2500 is not an
4539 // xterm (without the limit for rxvt and screen).
4540 if (arg[1] >= 2500)
4541 is_not_xterm = TRUE;
4542
4543 // PuTTY sends 0;136;0
4544 // vandyke SecureCRT sends 1;136;0
4545 else if (version == 136 && arg[2] == 0)
4546 {
4547 is_not_xterm = TRUE;
4548
4549 // PuTTY supports sgr-like mouse reporting, but
4550 // only set 'ttymouse' if it was not set by the
4551 // user already.
4552 if (arg[0] == 0
4553 && !option_was_set((char_u *)"ttym"))
4554 set_option_value((char_u *)"ttym", 0L,
4555 (char_u *)"sgr", 0);
4556 }
4557
4558 // Konsole sends 0;115;0
4559 else if (version == 115 && arg[0] == 0 && arg[2] == 0)
4560 is_not_xterm = TRUE;
4561
4562 // GNU screen sends 83;30600;0, 83;40500;0, etc.
4563 // 30600/40500 is a version number of GNU screen. DA2
4564 // support is added on 3.6. DCS string has a special
4565 // meaning to GNU screen, but xterm compatibility
4566 // checking does not detect GNU screen.
4567 if (version >= 30600 && arg[0] == 83)
4568 xcc_test_failed = TRUE;
4569
4570 // Xterm first responded to this request at patch level
4571 // 95, so assume anything below 95 is not xterm.
4572 if (version < 95)
4573 is_not_xterm = TRUE;
4574
4575 // With the real Xterm setting the underline RGB color
4576 // clears the background color, disable "t_8u".
4577 if (!is_not_xterm && *T_8U != NUL)
4578 T_8U = empty_option;
4579
4580 // Only request the cursor style if t_SH and t_RS are
4581 // set. Only supported properly by xterm since version
4582 // 279 (otherwise it returns 0x18).
4583 // Only when the xcc_status was set, the test finished,
4584 // and xcc_test_failed is FALSE;
4585 // Not for Terminal.app, it can't handle t_RS, it
4586 // echoes the characters to the screen.
4587 if (rcs_status.tr_progress == STATUS_GET
4588 && xcc_status.tr_progress == STATUS_GOT
4589 && !xcc_test_failed
4590 && version >= 279
4591 && *T_CSH != NUL
4592 && *T_CRS != NUL)
4593 {
4594 LOG_TR(("Sending cursor style request"));
4595 out_str(T_CRS);
4596 termrequest_sent(&rcs_status);
4597 need_flush = TRUE;
4598 }
4599
4600 // Only request the cursor blink mode if t_RC set. Not
4601 // for Gnome terminal, it can't handle t_RC, it
4602 // echoes the characters to the screen.
4603 // Only when the xcc_status was set, the test finished,
4604 // and xcc_test_failed is FALSE;
4605 if (rbm_status.tr_progress == STATUS_GET
4606 && xcc_status.tr_progress == STATUS_GOT
4607 && !xcc_test_failed
4608 && *T_CRC != NUL)
4609 {
4610 LOG_TR(("Sending cursor blink mode request"));
4611 out_str(T_CRC);
4612 termrequest_sent(&rbm_status);
4613 need_flush = TRUE;
4614 }
4615
4616 if (need_flush)
4617 out_flush();
4618 }
4619 }
4620
4621 /*
4622 * Handle a sequence with key and modifier, one of:
4623 * {lead}27;{modifier};{key}~
4624 * {lead}{key};{modifier}u
4625 * Returns the difference in length.
4626 */
4627 static int
4628 handle_key_with_modifier(
4629 int *arg,
4630 int trail,
4631 int csi_len,
4632 int offset,
4633 char_u *buf,
4634 int bufsize,
4635 int *buflen)
4636 {
4637 int key;
4638 int modifiers;
4639 int new_slen;
4640 char_u string[MAX_KEY_CODE_LEN + 1];
4641
4642 seenModifyOtherKeys = TRUE;
4643 if (trail == 'u')
4644 key = arg[0];
4645 else
4646 key = arg[2];
4647
4648 modifiers = decode_modifiers(arg[1]);
4649
4650 // Some keys already have Shift included, pass them as
4651 // normal keys. Not when Ctrl is also used, because <C-H>
4652 // and <C-S-H> are different.
4653 if (modifiers == MOD_MASK_SHIFT
4654 && ((key >= '@' && key <= 'Z')
4655 || key == '^' || key == '_'
4656 || (key >= '{' && key <= '~')))
4657 modifiers = 0;
4658
4659 // When used with Ctrl we always make a letter upper case,
4660 // so that mapping <C-H> and <C-h> are the same. Typing
4661 // <C-S-H> also uses "H" but modifier is different.
4662 if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
4663 key = TOUPPER_ASC(key);
4664
4665 // insert modifiers with KS_MODIFIER
4666 new_slen = modifiers2keycode(modifiers, &key, string);
4667
4668 if (has_mbyte)
4669 new_slen += (*mb_char2bytes)(key, string + new_slen);
4670 else
4671 string[new_slen++] = key;
4672
4673 if (put_string_in_typebuf(offset, csi_len, string, new_slen,
4674 buf, bufsize, buflen) == FAIL)
4675 return -1;
4676 return new_slen - csi_len + offset;
4677 }
4678
4679 /*
4680 * Handle a CSI escape sequence.
4681 * - Xterm version string: {lead}>{x};{vers};{y}c
4682 * Also eat other possible responses to t_RV, rxvt returns
4683 * "{lead}?1;2c".
4684 *
4685 * - Cursor position report: {lead}{row};{col}R
4686 * The final byte must be 'R'. It is used for checking the
4687 * ambiguous-width character state.
4688 *
4689 * - window position reply: {lead}3;{x};{y}t
4690 *
4691 * - key with modifiers when modifyOtherKeys is enabled:
4692 * {lead}27;{modifier};{key}~
4693 * {lead}{key};{modifier}u
4694 * Return 0 for no match, -1 for partial match, > 0 for full match.
4695 */
4696 static int
4697 handle_csi(
4698 char_u *tp,
4699 int len,
4700 char_u *argp,
4701 int offset,
4702 char_u *buf,
4703 int bufsize,
4704 int *buflen,
4705 char_u *key_name,
4706 int *slen)
4707 {
4708 int first = -1; // optional char right after {lead}
4709 int trail; // char that ends CSI sequence
4710 int arg[3] = {-1, -1, -1}; // argument numbers
4711 int argc; // number of arguments
4712 char_u *ap = argp;
4713 int csi_len;
4714
4715 // Check for non-digit after CSI.
4716 if (!VIM_ISDIGIT(*ap))
4717 first = *ap++;
4718
4719 // Find up to three argument numbers.
4720 for (argc = 0; argc < 3; )
4721 {
4722 if (ap >= tp + len)
4723 return -1;
4724 if (*ap == ';')
4725 arg[argc++] = -1; // omitted number
4726 else if (VIM_ISDIGIT(*ap))
4727 {
4728 arg[argc] = 0;
4729 for (;;)
4730 {
4731 if (ap >= tp + len)
4732 return -1;
4733 if (!VIM_ISDIGIT(*ap))
4734 break;
4735 arg[argc] = arg[argc] * 10 + (*ap - '0');
4736 ++ap;
4737 }
4738 ++argc;
4739 }
4740 if (*ap == ';')
4741 ++ap;
4742 else
4743 break;
4744 }
4745
4746 // mrxvt has been reported to have "+" in the version. Assume
4747 // the escape sequence ends with a letter or one of "{|}~".
4748 while (ap < tp + len
4749 && !(*ap >= '{' && *ap <= '~')
4750 && !ASCII_ISALPHA(*ap))
4751 ++ap;
4752 if (ap >= tp + len)
4753 return -1;
4754 trail = *ap;
4755 csi_len = (int)(ap - tp) + 1;
4756
4757 // Cursor position report: Eat it when there are 2 arguments
4758 // and it ends in 'R'. Also when u7_status is not "sent", it
4759 // may be from a previous Vim that just exited. But not for
4760 // <S-F3>, it sends something similar, check for row and column
4761 // to make sense.
4762 if (first == -1 && argc == 2 && trail == 'R')
4763 {
4764 handle_u7_response(arg, tp, csi_len);
4765
4766 key_name[0] = (int)KS_EXTRA;
4767 key_name[1] = (int)KE_IGNORE;
4768 *slen = csi_len;
4769 }
4770
4771 // Version string: Eat it when there is at least one digit and
4772 // it ends in 'c'
4773 else if (*T_CRV != NUL && ap > argp + 1 && trail == 'c')
4774 {
4775 handle_version_response(first, arg, argc, tp);
4776
4777 *slen = csi_len;
4778 # ifdef FEAT_EVAL
4779 set_vim_var_string(VV_TERMRESPONSE, tp, *slen);
4780 # endif
4781 apply_autocmds(EVENT_TERMRESPONSE,
4782 NULL, NULL, FALSE, curbuf);
4783 key_name[0] = (int)KS_EXTRA;
4784 key_name[1] = (int)KE_IGNORE;
4785 }
4786
4787 // Check blinking cursor from xterm:
4788 // {lead}?12;1$y set
4789 // {lead}?12;2$y not set
4790 //
4791 // {lead} can be <Esc>[ or CSI
4792 else if (rbm_status.tr_progress == STATUS_SENT
4793 && first == '?'
4794 && ap == argp + 6
4795 && arg[0] == 12
4796 && ap[-1] == '$'
4797 && trail == 'y')
4798 {
4799 initial_cursor_blink = (arg[1] == '1');
4800 rbm_status.tr_progress = STATUS_GOT;
4801 LOG_TR(("Received cursor blinking mode response: %s", tp));
4802 key_name[0] = (int)KS_EXTRA;
4803 key_name[1] = (int)KE_IGNORE;
4804 *slen = csi_len;
4805 # ifdef FEAT_EVAL
4806 set_vim_var_string(VV_TERMBLINKRESP, tp, *slen);
4807 # endif
4808 }
4809
4810 // Check for a window position response from the terminal:
4811 // {lead}3;{x};{y}t
4812 else if (did_request_winpos && argc == 3 && arg[0] == 3
4813 && trail == 't')
4814 {
4815 winpos_x = arg[1];
4816 winpos_y = arg[2];
4817 // got finished code: consume it
4818 key_name[0] = (int)KS_EXTRA;
4819 key_name[1] = (int)KE_IGNORE;
4820 *slen = csi_len;
4821
4822 if (--did_request_winpos <= 0)
4823 winpos_status.tr_progress = STATUS_GOT;
4824 }
4825
4826 // Key with modifier:
4827 // {lead}27;{modifier};{key}~
4828 // {lead}{key};{modifier}u
4829 else if ((arg[0] == 27 && argc == 3 && trail == '~')
4830 || (argc == 2 && trail == 'u'))
4831 {
4832 return len + handle_key_with_modifier(arg, trail,
4833 csi_len, offset, buf, bufsize, buflen);
4834 }
4835
4836 // else: Unknown CSI sequence. We could drop it, but then the
4837 // user can't create a map for it.
4838 return 0;
4839 }
4840
4841 /*
4842 * Handle an OSC sequence, fore/background color response from the terminal:
4843 *
4844 * {lead}{code};rgb:{rrrr}/{gggg}/{bbbb}{tail}
4845 * or {lead}{code};rgb:{rr}/{gg}/{bb}{tail}
4846 *
4847 * {code} is 10 for foreground, 11 for background
4848 * {lead} can be <Esc>] or OSC
4849 * {tail} can be '\007', <Esc>\ or STERM.
4850 *
4851 * Consume any code that starts with "{lead}11;", it's also
4852 * possible that "rgba" is following.
4853 */
4854 static int
4855 handle_osc(char_u *tp, char_u *argp, int len, char_u *key_name, int *slen)
4856 {
4857 int i, j;
4858
4859 j = 1 + (tp[0] == ESC);
4860 if (len >= j + 3 && (argp[0] != '1'
4861 || (argp[1] != '1' && argp[1] != '0')
4862 || argp[2] != ';'))
4863 i = 0; // no match
4864 else
4865 for (i = j; i < len; ++i)
4866 if (tp[i] == '\007' || (tp[0] == OSC ? tp[i] == STERM
4867 : (tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')))
4868 {
4869 int is_bg = argp[1] == '1';
4870 int is_4digit = i - j >= 21 && tp[j + 11] == '/'
4871 && tp[j + 16] == '/';
4872
4873 if (i - j >= 15 && STRNCMP(tp + j + 3, "rgb:", 4) == 0
4874 && (is_4digit
4875 || (tp[j + 9] == '/' && tp[i + 12 == '/'])))
4876 {
4877 char_u *tp_r = tp + j + 7;
4878 char_u *tp_g = tp + j + (is_4digit ? 12 : 10);
4879 char_u *tp_b = tp + j + (is_4digit ? 17 : 13);
4880 # ifdef FEAT_TERMINAL
4881 int rval, gval, bval;
4882
4883 rval = hexhex2nr(tp_r);
4884 gval = hexhex2nr(tp_b);
4885 bval = hexhex2nr(tp_g);
4886 # endif
4887 if (is_bg)
4888 {
4889 char *new_bg_val = (3 * '6' < *tp_r + *tp_g +
4890 *tp_b) ? "light" : "dark";
4891
4892 LOG_TR(("Received RBG response: %s", tp));
4893 rbg_status.tr_progress = STATUS_GOT;
4894 # ifdef FEAT_TERMINAL
4895 bg_r = rval;
4896 bg_g = gval;
4897 bg_b = bval;
4898 # endif
4899 if (!option_was_set((char_u *)"bg")
4900 && STRCMP(p_bg, new_bg_val) != 0)
4901 {
4902 // value differs, apply it
4903 set_option_value((char_u *)"bg", 0L,
4904 (char_u *)new_bg_val, 0);
4905 reset_option_was_set((char_u *)"bg");
4906 redraw_asap(CLEAR);
4907 }
4908 }
4909 # ifdef FEAT_TERMINAL
4910 else
4911 {
4912 LOG_TR(("Received RFG response: %s", tp));
4913 rfg_status.tr_progress = STATUS_GOT;
4914 fg_r = rval;
4915 fg_g = gval;
4916 fg_b = bval;
4917 }
4918 # endif
4919 }
4920
4921 // got finished code: consume it
4922 key_name[0] = (int)KS_EXTRA;
4923 key_name[1] = (int)KE_IGNORE;
4924 *slen = i + 1 + (tp[i] == ESC);
4925 # ifdef FEAT_EVAL
4926 set_vim_var_string(is_bg ? VV_TERMRBGRESP
4927 : VV_TERMRFGRESP, tp, *slen);
4928 # endif
4929 break;
4930 }
4931 if (i == len)
4932 {
4933 LOG_TR(("not enough characters for RB"));
4934 return FAIL;
4935 }
4936 return OK;
4937 }
4938
4939 /*
4940 * Check for key code response from xterm:
4941 * {lead}{flag}+r<hex bytes><{tail}
4942 *
4943 * {lead} can be <Esc>P or DCS
4944 * {flag} can be '0' or '1'
4945 * {tail} can be Esc>\ or STERM
4946 *
4947 * Check for cursor shape response from xterm:
4948 * {lead}1$r<digit> q{tail}
4949 *
4950 * {lead} can be <Esc>P or DCS
4951 * {tail} can be <Esc>\ or STERM
4952 *
4953 * Consume any code that starts with "{lead}.+r" or "{lead}.$r".
4954 */
4955 static int
4956 handle_dcs(char_u *tp, char_u *argp, int len, char_u *key_name, int *slen)
4957 {
4958 int i, j;
4959
4960 j = 1 + (tp[0] == ESC);
4961 if (len < j + 3)
4962 i = len; // need more chars
4963 else if ((argp[1] != '+' && argp[1] != '$') || argp[2] != 'r')
4964 i = 0; // no match
4965 else if (argp[1] == '+')
4966 // key code response
4967 for (i = j; i < len; ++i)
4968 {
4969 if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
4970 || tp[i] == STERM)
4971 {
4972 if (i - j >= 3)
4973 got_code_from_term(tp + j, i);
4974 key_name[0] = (int)KS_EXTRA;
4975 key_name[1] = (int)KE_IGNORE;
4976 *slen = i + 1 + (tp[i] == ESC);
4977 break;
4978 }
4979 }
4980 else
4981 {
4982 // Probably the cursor shape response. Make sure that "i"
4983 // is equal to "len" when there are not sufficient
4984 // characters.
4985 for (i = j + 3; i < len; ++i)
4986 {
4987 if (i - j == 3 && !isdigit(tp[i]))
4988 break;
4989 if (i - j == 4 && tp[i] != ' ')
4990 break;
4991 if (i - j == 5 && tp[i] != 'q')
4992 break;
4993 if (i - j == 6 && tp[i] != ESC && tp[i] != STERM)
4994 break;
4995 if ((i - j == 6 && tp[i] == STERM)
4996 || (i - j == 7 && tp[i] == '\\'))
4997 {
4998 int number = argp[3] - '0';
4999
5000 // 0, 1 = block blink, 2 = block
5001 // 3 = underline blink, 4 = underline
5002 // 5 = vertical bar blink, 6 = vertical bar
5003 number = number == 0 ? 1 : number;
5004 initial_cursor_shape = (number + 1) / 2;
5005 // The blink flag is actually inverted, compared to
5006 // the value set with T_SH.
5007 initial_cursor_shape_blink =
5008 (number & 1) ? FALSE : TRUE;
5009 rcs_status.tr_progress = STATUS_GOT;
5010 LOG_TR(("Received cursor shape response: %s", tp));
5011
5012 key_name[0] = (int)KS_EXTRA;
5013 key_name[1] = (int)KE_IGNORE;
5014 *slen = i + 1;
5015 # ifdef FEAT_EVAL
5016 set_vim_var_string(VV_TERMSTYLERESP, tp, *slen);
5017 # endif
5018 break;
5019 }
5020 }
5021 }
5022
5023 if (i == len)
5024 {
5025 // These codes arrive many together, each code can be
5026 // truncated at any point.
5027 LOG_TR(("not enough characters for XT"));
5028 return FAIL;
5029 }
5030 return OK;
5031 }
5032
4387 /* 5033 /*
4388 * Check if typebuf.tb_buf[] contains a terminal key code. 5034 * Check if typebuf.tb_buf[] contains a terminal key code.
4389 * Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off 5035 * Check from typebuf.tb_buf[typebuf.tb_off] to typebuf.tb_buf[typebuf.tb_off
4390 * + "max_offset"]. 5036 * + "max_offset"].
4391 * Return 0 for no match, -1 for partial match, > 0 for full match. 5037 * Return 0 for no match, -1 for partial match, > 0 for full match.
4635 */ 5281 */
4636 if (((tp[0] == ESC && len >= 3 && tp[1] == '[') 5282 if (((tp[0] == ESC && len >= 3 && tp[1] == '[')
4637 || (tp[0] == CSI && len >= 2)) 5283 || (tp[0] == CSI && len >= 2))
4638 && (VIM_ISDIGIT(*argp) || *argp == '>' || *argp == '?')) 5284 && (VIM_ISDIGIT(*argp) || *argp == '>' || *argp == '?'))
4639 { 5285 {
4640 int first = -1; // optional char right after {lead} 5286 int resp = handle_csi(tp, len, argp, offset, buf,
4641 int trail; // char that ends CSI sequence 5287 bufsize, buflen, key_name, &slen);
4642 int arg[3] = {-1, -1, -1}; // argument numbers 5288 if (resp != 0)
4643 int argc; // number of arguments
4644 char_u *ap = argp;
4645 int csi_len;
4646
4647 // Check for non-digit after CSI.
4648 if (!VIM_ISDIGIT(*ap))
4649 first = *ap++;
4650
4651 // Find up to three argument numbers.
4652 for (argc = 0; argc < 3; )
4653 { 5289 {
4654 if (ap >= tp + len) 5290 # ifdef DEBUG_TERMRESPONSE
4655 { 5291 if (resp == -1)
4656 not_enough:
4657 LOG_TR(("Not enough characters for CSI sequence")); 5292 LOG_TR(("Not enough characters for CSI sequence"));
4658 return -1; 5293 # endif
4659 } 5294 return resp;
4660 if (*ap == ';')
4661 arg[argc++] = -1; // omitted number
4662 else if (VIM_ISDIGIT(*ap))
4663 {
4664 arg[argc] = 0;
4665 for (;;)
4666 {
4667 if (ap >= tp + len)
4668 goto not_enough;
4669 if (!VIM_ISDIGIT(*ap))
4670 break;
4671 arg[argc] = arg[argc] * 10 + (*ap - '0');
4672 ++ap;
4673 }
4674 ++argc;
4675 }
4676 if (*ap == ';')
4677 ++ap;
4678 else
4679 break;
4680 } 5295 }
4681 // mrxvt has been reported to have "+" in the version. Assume
4682 // the escape sequence ends with a letter or one of "{|}~".
4683 while (ap < tp + len
4684 && !(*ap >= '{' && *ap <= '~')
4685 && !ASCII_ISALPHA(*ap))
4686 ++ap;
4687 if (ap >= tp + len)
4688 goto not_enough;
4689 trail = *ap;
4690 csi_len = (int)(ap - tp) + 1;
4691
4692 // Cursor position report: Eat it when there are 2 arguments
4693 // and it ends in 'R'. Also when u7_status is not "sent", it
4694 // may be from a previous Vim that just exited. But not for
4695 // <S-F3>, it sends something similar, check for row and column
4696 // to make sense.
4697 if (first == -1 && argc == 2 && trail == 'R')
4698 {
4699 if (arg[0] == 2 && arg[1] >= 2)
4700 {
4701 char *aw = NULL;
4702
4703 LOG_TR(("Received U7 status: %s", tp));
4704 u7_status.tr_progress = STATUS_GOT;
4705 did_cursorhold = TRUE;
4706 if (arg[1] == 2)
4707 aw = "single";
4708 else if (arg[1] == 3)
4709 aw = "double";
4710 if (aw != NULL && STRCMP(aw, p_ambw) != 0)
4711 {
4712 // Setting the option causes a screen redraw. Do
4713 // that right away if possible, keeping any
4714 // messages.
4715 set_option_value((char_u *)"ambw", 0L,
4716 (char_u *)aw, 0);
4717 # ifdef DEBUG_TERMRESPONSE
4718 {
4719 int r = redraw_asap(CLEAR);
4720
4721 log_tr("set 'ambiwidth', redraw_asap(): %d", r);
4722 }
4723 # else
4724 redraw_asap(CLEAR);
4725 # endif
4726 }
4727 }
4728 else if (arg[0] == 3)
4729 {
4730 // Third row: xterm compatibility test.
4731 // If the cursor is not on the first column then the
4732 // terminal is not xterm compatible.
4733 if (arg[1] != 1)
4734 xcc_test_failed = TRUE;
4735 xcc_status.tr_progress = STATUS_GOT;
4736 }
4737
4738 key_name[0] = (int)KS_EXTRA;
4739 key_name[1] = (int)KE_IGNORE;
4740 slen = csi_len;
4741 # ifdef FEAT_EVAL
4742 set_vim_var_string(VV_TERMU7RESP, tp, slen);
4743 # endif
4744 }
4745
4746 // Version string: Eat it when there is at least one digit and
4747 // it ends in 'c'
4748 else if (*T_CRV != NUL && ap > argp + 1 && trail == 'c')
4749 {
4750 int version = arg[1];
4751
4752 LOG_TR(("Received CRV response: %s", tp));
4753 crv_status.tr_progress = STATUS_GOT;
4754 did_cursorhold = TRUE;
4755
4756 // If this code starts with CSI, you can bet that the
4757 // terminal uses 8-bit codes.
4758 if (tp[0] == CSI)
4759 switch_to_8bit();
4760
4761 // Screen sends 40500.
4762 // rxvt sends its version number: "20703" is 2.7.3.
4763 // Ignore it for when the user has set 'term' to xterm,
4764 // even though it's an rxvt.
4765 if (version > 20000)
4766 version = 0;
4767
4768 if (first == '>' && argc == 3)
4769 {
4770 int need_flush = FALSE;
4771 int is_iterm2 = FALSE;
4772 int is_mintty = FALSE;
4773 int is_screen = FALSE;
4774
4775 // mintty 2.9.5 sends 77;20905;0c.
4776 // (77 is ASCII 'M' for mintty.)
4777 if (arg[0] == 77)
4778 is_mintty = TRUE;
4779
4780 // if xterm version >= 141 try to get termcap codes
4781 if (version >= 141)
4782 {
4783 LOG_TR(("Enable checking for XT codes"));
4784 check_for_codes = TRUE;
4785 need_gather = TRUE;
4786 req_codes_from_term();
4787 }
4788
4789 // libvterm sends 0;100;0
4790 if (version == 100 && arg[0] == 0 && arg[2] == 0)
4791 {
4792 // If run from Vim $COLORS is set to the number of
4793 // colors the terminal supports. Otherwise assume
4794 // 256, libvterm supports even more.
4795 if (mch_getenv((char_u *)"COLORS") == NULL)
4796 may_adjust_color_count(256);
4797 // Libvterm can handle SGR mouse reporting.
4798 if (!option_was_set((char_u *)"ttym"))
4799 set_option_value((char_u *)"ttym", 0L,
4800 (char_u *)"sgr", 0);
4801 }
4802
4803 if (version == 95)
4804 {
4805 // Mac Terminal.app sends 1;95;0
4806 if (arg[0] == 1 && arg[2] == 0)
4807 {
4808 is_not_xterm = TRUE;
4809 is_mac_terminal = TRUE;
4810 }
4811 // iTerm2 sends 0;95;0
4812 else if (arg[0] == 0 && arg[2] == 0)
4813 is_iterm2 = TRUE;
4814 // old iTerm2 sends 0;95;
4815 else if (arg[0] == 0 && arg[2] == -1)
4816 is_not_xterm = TRUE;
4817 }
4818
4819 // screen sends 83;40500;0 83 is 'S' in ASCII.
4820 if (arg[0] == 83)
4821 is_screen = TRUE;
4822
4823 // Only set 'ttymouse' automatically if it was not set
4824 // by the user already.
4825 if (!option_was_set((char_u *)"ttym"))
4826 {
4827 // Xterm version 277 supports SGR. Also support
4828 // Terminal.app, iTerm2, mintty, and screen 4.7+.
4829 if ((!is_screen && version >= 277)
4830 || is_iterm2
4831 || is_mac_terminal
4832 || is_mintty
4833 || (is_screen && arg[1] >= 40700))
4834 set_option_value((char_u *)"ttym", 0L,
4835 (char_u *)"sgr", 0);
4836 // For xterm version >= 95 mouse dragging works.
4837 else if (version >= 95)
4838 set_option_value((char_u *)"ttym", 0L,
4839 (char_u *)"xterm2", 0);
4840 }
4841
4842 // Detect terminals that set $TERM to something like
4843 // "xterm-256color" but are not fully xterm compatible.
4844
4845 // Gnome terminal sends 1;3801;0, 1;4402;0 or 1;2501;0.
4846 // xfce4-terminal sends 1;2802;0.
4847 // screen sends 83;40500;0
4848 // Assuming any version number over 2500 is not an
4849 // xterm (without the limit for rxvt and screen).
4850 if (arg[1] >= 2500)
4851 is_not_xterm = TRUE;
4852
4853 // PuTTY sends 0;136;0
4854 // vandyke SecureCRT sends 1;136;0
4855 else if (version == 136 && arg[2] == 0)
4856 {
4857 is_not_xterm = TRUE;
4858
4859 // PuTTY supports sgr-like mouse reporting, but
4860 // only set 'ttymouse' if it was not set by the
4861 // user already.
4862 if (arg[0] == 0
4863 && !option_was_set((char_u *)"ttym"))
4864 set_option_value((char_u *)"ttym", 0L,
4865 (char_u *)"sgr", 0);
4866 }
4867
4868 // Konsole sends 0;115;0
4869 else if (version == 115 && arg[0] == 0 && arg[2] == 0)
4870 is_not_xterm = TRUE;
4871
4872 // GNU screen sends 83;30600;0, 83;40500;0, etc.
4873 // 30600/40500 is a version number of GNU screen. DA2
4874 // support is added on 3.6. DCS string has a special
4875 // meaning to GNU screen, but xterm compatibility
4876 // checking does not detect GNU screen.
4877 if (version >= 30600 && arg[0] == 83)
4878 xcc_test_failed = TRUE;
4879
4880 // Xterm first responded to this request at patch level
4881 // 95, so assume anything below 95 is not xterm.
4882 if (version < 95)
4883 is_not_xterm = TRUE;
4884
4885 // With the real Xterm setting the underline RGB color
4886 // clears the background color, disable "t_8u".
4887 if (!is_not_xterm && *T_8U != NUL)
4888 T_8U = empty_option;
4889
4890 // Only request the cursor style if t_SH and t_RS are
4891 // set. Only supported properly by xterm since version
4892 // 279 (otherwise it returns 0x18).
4893 // Only when the xcc_status was set, the test finished,
4894 // and xcc_test_failed is FALSE;
4895 // Not for Terminal.app, it can't handle t_RS, it
4896 // echoes the characters to the screen.
4897 if (rcs_status.tr_progress == STATUS_GET
4898 && xcc_status.tr_progress == STATUS_GOT
4899 && !xcc_test_failed
4900 && version >= 279
4901 && *T_CSH != NUL
4902 && *T_CRS != NUL)
4903 {
4904 LOG_TR(("Sending cursor style request"));
4905 out_str(T_CRS);
4906 termrequest_sent(&rcs_status);
4907 need_flush = TRUE;
4908 }
4909
4910 // Only request the cursor blink mode if t_RC set. Not
4911 // for Gnome terminal, it can't handle t_RC, it
4912 // echoes the characters to the screen.
4913 // Only when the xcc_status was set, the test finished,
4914 // and xcc_test_failed is FALSE;
4915 if (rbm_status.tr_progress == STATUS_GET
4916 && xcc_status.tr_progress == STATUS_GOT
4917 && !xcc_test_failed
4918 && *T_CRC != NUL)
4919 {
4920 LOG_TR(("Sending cursor blink mode request"));
4921 out_str(T_CRC);
4922 termrequest_sent(&rbm_status);
4923 need_flush = TRUE;
4924 }
4925
4926 if (need_flush)
4927 out_flush();
4928 }
4929 slen = csi_len;
4930 # ifdef FEAT_EVAL
4931 set_vim_var_string(VV_TERMRESPONSE, tp, slen);
4932 # endif
4933 apply_autocmds(EVENT_TERMRESPONSE,
4934 NULL, NULL, FALSE, curbuf);
4935 key_name[0] = (int)KS_EXTRA;
4936 key_name[1] = (int)KE_IGNORE;
4937 }
4938
4939 // Check blinking cursor from xterm:
4940 // {lead}?12;1$y set
4941 // {lead}?12;2$y not set
4942 //
4943 // {lead} can be <Esc>[ or CSI
4944 else if (rbm_status.tr_progress == STATUS_SENT
4945 && first == '?'
4946 && ap == argp + 6
4947 && arg[0] == 12
4948 && ap[-1] == '$'
4949 && trail == 'y')
4950 {
4951 initial_cursor_blink = (arg[1] == '1');
4952 rbm_status.tr_progress = STATUS_GOT;
4953 LOG_TR(("Received cursor blinking mode response: %s", tp));
4954 key_name[0] = (int)KS_EXTRA;
4955 key_name[1] = (int)KE_IGNORE;
4956 slen = csi_len;
4957 # ifdef FEAT_EVAL
4958 set_vim_var_string(VV_TERMBLINKRESP, tp, slen);
4959 # endif
4960 }
4961
4962 // Check for a window position response from the terminal:
4963 // {lead}3;{x};{y}t
4964 else if (did_request_winpos && argc == 3 && arg[0] == 3
4965 && trail == 't')
4966 {
4967 winpos_x = arg[1];
4968 winpos_y = arg[2];
4969 // got finished code: consume it
4970 key_name[0] = (int)KS_EXTRA;
4971 key_name[1] = (int)KE_IGNORE;
4972 slen = csi_len;
4973
4974 if (--did_request_winpos <= 0)
4975 winpos_status.tr_progress = STATUS_GOT;
4976 }
4977
4978 // Key with modifier:
4979 // {lead}27;{modifier};{key}~
4980 // {lead}{key};{modifier}u
4981 else if ((arg[0] == 27 && argc == 3 && trail == '~')
4982 || (argc == 2 && trail == 'u'))
4983 {
4984 seenModifyOtherKeys = TRUE;
4985 if (trail == 'u')
4986 key = arg[0];
4987 else
4988 key = arg[2];
4989
4990 modifiers = decode_modifiers(arg[1]);
4991
4992 // Some keys already have Shift included, pass them as
4993 // normal keys. Not when Ctrl is also used, because <C-H>
4994 // and <C-S-H> are different.
4995 if (modifiers == MOD_MASK_SHIFT
4996 && ((key >= '@' && key <= 'Z')
4997 || key == '^' || key == '_'
4998 || (key >= '{' && key <= '~')))
4999 modifiers = 0;
5000
5001 // When used with Ctrl we always make a letter upper case,
5002 // so that mapping <C-H> and <C-h> are the same. Typing
5003 // <C-S-H> also uses "H" but modifier is different.
5004 if ((modifiers & MOD_MASK_CTRL) && ASCII_ISALPHA(key))
5005 key = TOUPPER_ASC(key);
5006
5007 // insert modifiers with KS_MODIFIER
5008 new_slen = modifiers2keycode(modifiers, &key, string);
5009 slen = csi_len;
5010
5011 if (has_mbyte)
5012 new_slen += (*mb_char2bytes)(key, string + new_slen);
5013 else
5014 string[new_slen++] = key;
5015
5016 if (put_string_in_typebuf(offset, slen, string, new_slen,
5017 buf, bufsize, buflen) == FAIL)
5018 return -1;
5019 return len + new_slen - slen + offset;
5020 }
5021
5022 // else: Unknown CSI sequence. We could drop it, but then the
5023 // user can't create a map for it.
5024 } 5296 }
5025 5297
5026 // Check for fore/background color response from the terminal: 5298 // Check for fore/background color response from the terminal,
5027 // 5299 // starting} with <Esc>] or OSC
5028 // {lead}{code};rgb:{rrrr}/{gggg}/{bbbb}{tail}
5029 // or {lead}{code};rgb:{rr}/{gg}/{bb}{tail}
5030 //
5031 // {code} is 10 for foreground, 11 for background
5032 // {lead} can be <Esc>] or OSC
5033 // {tail} can be '\007', <Esc>\ or STERM.
5034 //
5035 // Consume any code that starts with "{lead}11;", it's also
5036 // possible that "rgba" is following.
5037 else if ((*T_RBG != NUL || *T_RFG != NUL) 5300 else if ((*T_RBG != NUL || *T_RFG != NUL)
5038 && ((tp[0] == ESC && len >= 2 && tp[1] == ']') 5301 && ((tp[0] == ESC && len >= 2 && tp[1] == ']')
5039 || tp[0] == OSC)) 5302 || tp[0] == OSC))
5040 { 5303 {
5041 j = 1 + (tp[0] == ESC); 5304 if (handle_osc(tp, argp, len, key_name, &slen) == FAIL)
5042 if (len >= j + 3 && (argp[0] != '1'
5043 || (argp[1] != '1' && argp[1] != '0')
5044 || argp[2] != ';'))
5045 i = 0; // no match
5046 else
5047 for (i = j; i < len; ++i)
5048 if (tp[i] == '\007' || (tp[0] == OSC ? tp[i] == STERM
5049 : (tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')))
5050 {
5051 int is_bg = argp[1] == '1';
5052 int is_4digit = i - j >= 21 && tp[j + 11] == '/'
5053 && tp[j + 16] == '/';
5054
5055 if (i - j >= 15 && STRNCMP(tp + j + 3, "rgb:", 4) == 0
5056 && (is_4digit
5057 || (tp[j + 9] == '/' && tp[i + 12 == '/'])))
5058 {
5059 char_u *tp_r = tp + j + 7;
5060 char_u *tp_g = tp + j + (is_4digit ? 12 : 10);
5061 char_u *tp_b = tp + j + (is_4digit ? 17 : 13);
5062 # ifdef FEAT_TERMINAL
5063 int rval, gval, bval;
5064
5065 rval = hexhex2nr(tp_r);
5066 gval = hexhex2nr(tp_b);
5067 bval = hexhex2nr(tp_g);
5068 # endif
5069 if (is_bg)
5070 {
5071 char *new_bg_val = (3 * '6' < *tp_r + *tp_g +
5072 *tp_b) ? "light" : "dark";
5073
5074 LOG_TR(("Received RBG response: %s", tp));
5075 rbg_status.tr_progress = STATUS_GOT;
5076 # ifdef FEAT_TERMINAL
5077 bg_r = rval;
5078 bg_g = gval;
5079 bg_b = bval;
5080 # endif
5081 if (!option_was_set((char_u *)"bg")
5082 && STRCMP(p_bg, new_bg_val) != 0)
5083 {
5084 // value differs, apply it
5085 set_option_value((char_u *)"bg", 0L,
5086 (char_u *)new_bg_val, 0);
5087 reset_option_was_set((char_u *)"bg");
5088 redraw_asap(CLEAR);
5089 }
5090 }
5091 # ifdef FEAT_TERMINAL
5092 else
5093 {
5094 LOG_TR(("Received RFG response: %s", tp));
5095 rfg_status.tr_progress = STATUS_GOT;
5096 fg_r = rval;
5097 fg_g = gval;
5098 fg_b = bval;
5099 }
5100 # endif
5101 }
5102
5103 // got finished code: consume it
5104 key_name[0] = (int)KS_EXTRA;
5105 key_name[1] = (int)KE_IGNORE;
5106 slen = i + 1 + (tp[i] == ESC);
5107 # ifdef FEAT_EVAL
5108 set_vim_var_string(is_bg ? VV_TERMRBGRESP
5109 : VV_TERMRFGRESP, tp, slen);
5110 # endif
5111 break;
5112 }
5113 if (i == len)
5114 {
5115 LOG_TR(("not enough characters for RB"));
5116 return -1; 5305 return -1;
5117 }
5118 } 5306 }
5119 5307
5120 // Check for key code response from xterm: 5308 // Check for key code response from xterm,
5121 // {lead}{flag}+r<hex bytes><{tail} 5309 // starting with <Esc>P or DCS
5122 //
5123 // {lead} can be <Esc>P or DCS
5124 // {flag} can be '0' or '1'
5125 // {tail} can be Esc>\ or STERM
5126 //
5127 // Check for cursor shape response from xterm:
5128 // {lead}1$r<digit> q{tail}
5129 //
5130 // {lead} can be <Esc>P or DCS
5131 // {tail} can be <Esc>\ or STERM
5132 //
5133 // Consume any code that starts with "{lead}.+r" or "{lead}.$r".
5134 else if ((check_for_codes || rcs_status.tr_progress == STATUS_SENT) 5310 else if ((check_for_codes || rcs_status.tr_progress == STATUS_SENT)
5135 && ((tp[0] == ESC && len >= 2 && tp[1] == 'P') 5311 && ((tp[0] == ESC && len >= 2 && tp[1] == 'P')
5136 || tp[0] == DCS)) 5312 || tp[0] == DCS))
5137 { 5313 {
5138 j = 1 + (tp[0] == ESC); 5314 if (handle_dcs(tp, argp, len, key_name, &slen) == FAIL)
5139 if (len < j + 3)
5140 i = len; // need more chars
5141 else if ((argp[1] != '+' && argp[1] != '$') || argp[2] != 'r')
5142 i = 0; // no match
5143 else if (argp[1] == '+')
5144 // key code response
5145 for (i = j; i < len; ++i)
5146 {
5147 if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
5148 || tp[i] == STERM)
5149 {
5150 if (i - j >= 3)
5151 got_code_from_term(tp + j, i);
5152 key_name[0] = (int)KS_EXTRA;
5153 key_name[1] = (int)KE_IGNORE;
5154 slen = i + 1 + (tp[i] == ESC);
5155 break;
5156 }
5157 }
5158 else
5159 {
5160 // Probably the cursor shape response. Make sure that "i"
5161 // is equal to "len" when there are not sufficient
5162 // characters.
5163 for (i = j + 3; i < len; ++i)
5164 {
5165 if (i - j == 3 && !isdigit(tp[i]))
5166 break;
5167 if (i - j == 4 && tp[i] != ' ')
5168 break;
5169 if (i - j == 5 && tp[i] != 'q')
5170 break;
5171 if (i - j == 6 && tp[i] != ESC && tp[i] != STERM)
5172 break;
5173 if ((i - j == 6 && tp[i] == STERM)
5174 || (i - j == 7 && tp[i] == '\\'))
5175 {
5176 int number = argp[3] - '0';
5177
5178 // 0, 1 = block blink, 2 = block
5179 // 3 = underline blink, 4 = underline
5180 // 5 = vertical bar blink, 6 = vertical bar
5181 number = number == 0 ? 1 : number;
5182 initial_cursor_shape = (number + 1) / 2;
5183 // The blink flag is actually inverted, compared to
5184 // the value set with T_SH.
5185 initial_cursor_shape_blink =
5186 (number & 1) ? FALSE : TRUE;
5187 rcs_status.tr_progress = STATUS_GOT;
5188 LOG_TR(("Received cursor shape response: %s", tp));
5189
5190 key_name[0] = (int)KS_EXTRA;
5191 key_name[1] = (int)KE_IGNORE;
5192 slen = i + 1;
5193 # ifdef FEAT_EVAL
5194 set_vim_var_string(VV_TERMSTYLERESP, tp, slen);
5195 # endif
5196 break;
5197 }
5198 }
5199 }
5200
5201 if (i == len)
5202 {
5203 // These codes arrive many together, each code can be
5204 // truncated at any point.
5205 LOG_TR(("not enough characters for XT"));
5206 return -1; 5315 return -1;
5207 }
5208 } 5316 }
5209 } 5317 }
5210 #endif 5318 #endif
5211 5319
5212 if (key_name[0] == NUL) 5320 if (key_name[0] == NUL)