comparison src/term.c @ 20768:1e2e81dbb958 v8.2.0936

patch 8.2.0936: some terminals misinterpret the code for getting cursor style Commit: https://github.com/vim/vim/commit/a45551a53557dba98973fdb3ff737dea2fffcda3 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jun 9 15:57:37 2020 +0200 patch 8.2.0936: some terminals misinterpret the code for getting cursor style Problem: Some terminals misinterpret the code for getting cursor style. Solution: Send a sequence to the terminal and check the result. (IWAMOTO Kouichi, closes #2126) Merged with current code.
author Bram Moolenaar <Bram@vim.org>
date Tue, 09 Jun 2020 16:00:05 +0200
parents 5ffe112b1afd
children 10535993e913
comparison
equal deleted inserted replaced
20767:c7edd278df99 20768:1e2e81dbb958
124 static termrequest_T crv_status = TERMREQUEST_INIT; 124 static termrequest_T crv_status = TERMREQUEST_INIT;
125 125
126 // Request Cursor position report: 126 // Request Cursor position report:
127 static termrequest_T u7_status = TERMREQUEST_INIT; 127 static termrequest_T u7_status = TERMREQUEST_INIT;
128 128
129 // Request xterm compatibility check:
130 static termrequest_T xcc_status = TERMREQUEST_INIT;
131
129 # ifdef FEAT_TERMINAL 132 # ifdef FEAT_TERMINAL
130 // Request foreground color report: 133 // Request foreground color report:
131 static termrequest_T rfg_status = TERMREQUEST_INIT; 134 static termrequest_T rfg_status = TERMREQUEST_INIT;
132 static int fg_r = 0; 135 static int fg_r = 0;
133 static int fg_g = 0; 136 static int fg_g = 0;
150 static termrequest_T winpos_status = TERMREQUEST_INIT; 153 static termrequest_T winpos_status = TERMREQUEST_INIT;
151 154
152 static termrequest_T *all_termrequests[] = { 155 static termrequest_T *all_termrequests[] = {
153 &crv_status, 156 &crv_status,
154 &u7_status, 157 &u7_status,
158 &xcc_status,
155 # ifdef FEAT_TERMINAL 159 # ifdef FEAT_TERMINAL
156 &rfg_status, 160 &rfg_status,
157 # endif 161 # endif
158 &rbg_status, 162 &rbg_status,
159 &rbm_status, 163 &rbm_status,
1426 static int need_gather = FALSE; // need to fill termleader[] 1430 static int need_gather = FALSE; // need to fill termleader[]
1427 static char_u termleader[256 + 1]; // for check_termcode() 1431 static char_u termleader[256 + 1]; // for check_termcode()
1428 #ifdef FEAT_TERMRESPONSE 1432 #ifdef FEAT_TERMRESPONSE
1429 static int check_for_codes = FALSE; // check for key code response 1433 static int check_for_codes = FALSE; // check for key code response
1430 static int is_not_xterm = FALSE; // recognized not-really-xterm 1434 static int is_not_xterm = FALSE; // recognized not-really-xterm
1435 static int xcc_test_failed = FALSE; // xcc_status check failed
1431 #endif 1436 #endif
1432 1437
1433 static struct builtin_term * 1438 static struct builtin_term *
1434 find_builtin_term(char_u *term) 1439 find_builtin_term(char_u *term)
1435 { 1440 {
3603 (void)vpeekc_nomap(); 3608 (void)vpeekc_nomap();
3604 } 3609 }
3605 } 3610 }
3606 3611
3607 /* 3612 /*
3608 * Check how the terminal treats ambiguous character width (UAX #11). 3613 * Send sequences to the terminal and check with t_u7 how the cursor moves, to
3609 * First, we move the cursor to (1, 0) and print a test ambiguous character 3614 * find out properties of the terminal.
3610 * \u25bd (WHITE DOWN-POINTING TRIANGLE) and query current cursor position.
3611 * If the terminal treats \u25bd as single width, the position is (1, 1),
3612 * or if it is treated as double width, that will be (1, 2).
3613 * This function has the side effect that changes cursor position, so
3614 * it must be called immediately after entering termcap mode.
3615 */ 3615 */
3616 void 3616 void
3617 may_req_ambiguous_char_width(void) 3617 check_terminal_behavior(void)
3618 { 3618 {
3619 int did_send = FALSE;
3620
3621 if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL)
3622 return;
3623
3619 if (u7_status.tr_progress == STATUS_GET 3624 if (u7_status.tr_progress == STATUS_GET
3620 && can_get_termresponse()
3621 && starting == 0
3622 && *T_U7 != NUL
3623 && !option_was_set((char_u *)"ambiwidth")) 3625 && !option_was_set((char_u *)"ambiwidth"))
3624 { 3626 {
3625 char_u buf[16]; 3627 char_u buf[16];
3626 3628
3627 LOG_TR(("Sending U7 request")); 3629 // Ambiguous width check.
3630 // Check how the terminal treats ambiguous character width (UAX #11).
3631 // First, we move the cursor to (1, 0) and print a test ambiguous
3632 // character \u25bd (WHITE DOWN-POINTING TRIANGLE) and then query
3633 // the current cursor position. If the terminal treats \u25bd as
3634 // single width, the position is (1, 1), or if it is treated as double
3635 // width, that will be (1, 2). This function has the side effect that
3636 // changes cursor position, so it must be called immediately after
3637 // entering termcap mode.
3638 LOG_TR(("Sending request for ambiwidth check"));
3628 // Do this in the second row. In the first row the returned sequence 3639 // Do this in the second row. In the first row the returned sequence
3629 // may be CSI 1;2R, which is the same as <S-F3>. 3640 // may be CSI 1;2R, which is the same as <S-F3>.
3630 term_windgoto(1, 0); 3641 term_windgoto(1, 0);
3631 buf[mb_char2bytes(0x25bd, buf)] = 0; 3642 buf[mb_char2bytes(0x25bd, buf)] = NUL;
3632 out_str(buf); 3643 out_str(buf);
3633 out_str(T_U7); 3644 out_str(T_U7);
3634 termrequest_sent(&u7_status); 3645 termrequest_sent(&u7_status);
3635 out_flush(); 3646 out_flush();
3647 did_send = TRUE;
3636 3648
3637 // This overwrites a few characters on the screen, a redraw is needed 3649 // This overwrites a few characters on the screen, a redraw is needed
3638 // after this. Clear them out for now. 3650 // after this. Clear them out for now.
3639 screen_stop_highlight(); 3651 screen_stop_highlight();
3640 term_windgoto(1, 0); 3652 term_windgoto(1, 0);
3641 out_str((char_u *)" "); 3653 out_str((char_u *)" ");
3654 }
3655
3656 if (xcc_status.tr_progress == STATUS_GET)
3657 {
3658 // 2. Check compatibility with xterm.
3659 // We move the cursor to (2, 0), print a test sequence and then query
3660 // the current cursor position. If the terminal properly handles
3661 // unknown DCS string and CSI sequence with intermediate byte, the test
3662 // sequence is ignored and the cursor does not move. If the terminal
3663 // handles test sequence incorrectly, a garbage string is displayed and
3664 // the cursor does move.
3665 LOG_TR(("Sending xterm compatibility test sequence."));
3666 // Do this in the third row. Second row is used by ambiguous
3667 // chararacter width check.
3668 term_windgoto(2, 0);
3669 // send the test DCS string.
3670 out_str((char_u *)"\033Pzz\033\\");
3671 // send the test CSI sequence with intermediate byte.
3672 out_str((char_u *)"\033[0%m");
3673 out_str(T_U7);
3674 termrequest_sent(&xcc_status);
3675 out_flush();
3676 did_send = TRUE;
3677
3678 // If the terminal handles test sequence incorrectly, garbage text is
3679 // displayed. Clear them out for now.
3680 screen_stop_highlight();
3681 term_windgoto(2, 0);
3682 out_str((char_u *)" ");
3683 }
3684
3685 if (did_send)
3686 {
3642 term_windgoto(0, 0); 3687 term_windgoto(0, 0);
3643 3688
3644 // Need to reset the known cursor position. 3689 // Need to reset the known cursor position.
3645 screen_start(); 3690 screen_start();
3646 3691
4678 # else 4723 # else
4679 redraw_asap(CLEAR); 4724 redraw_asap(CLEAR);
4680 # endif 4725 # endif
4681 } 4726 }
4682 } 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
4683 key_name[0] = (int)KS_EXTRA; 4738 key_name[0] = (int)KS_EXTRA;
4684 key_name[1] = (int)KE_IGNORE; 4739 key_name[1] = (int)KE_IGNORE;
4685 slen = csi_len; 4740 slen = csi_len;
4686 # ifdef FEAT_EVAL 4741 # ifdef FEAT_EVAL
4687 set_vim_var_string(VV_TERMU7RESP, tp, slen); 4742 set_vim_var_string(VV_TERMU7RESP, tp, slen);
4812 4867
4813 // Konsole sends 0;115;0 4868 // Konsole sends 0;115;0
4814 else if (version == 115 && arg[0] == 0 && arg[2] == 0) 4869 else if (version == 115 && arg[0] == 0 && arg[2] == 0)
4815 is_not_xterm = TRUE; 4870 is_not_xterm = TRUE;
4816 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
4817 // Xterm first responded to this request at patch level 4880 // Xterm first responded to this request at patch level
4818 // 95, so assume anything below 95 is not xterm. 4881 // 95, so assume anything below 95 is not xterm.
4819 if (version < 95) 4882 if (version < 95)
4820 is_not_xterm = TRUE; 4883 is_not_xterm = TRUE;
4821 4884
4825 T_8U = empty_option; 4888 T_8U = empty_option;
4826 4889
4827 // Only request the cursor style if t_SH and t_RS are 4890 // Only request the cursor style if t_SH and t_RS are
4828 // set. Only supported properly by xterm since version 4891 // set. Only supported properly by xterm since version
4829 // 279 (otherwise it returns 0x18). 4892 // 279 (otherwise it returns 0x18).
4893 // Only when the xcc_status was set, the test finished,
4894 // and xcc_test_failed is FALSE;
4830 // Not for Terminal.app, it can't handle t_RS, it 4895 // Not for Terminal.app, it can't handle t_RS, it
4831 // echoes the characters to the screen. 4896 // echoes the characters to the screen.
4832 if (rcs_status.tr_progress == STATUS_GET 4897 if (rcs_status.tr_progress == STATUS_GET
4898 && xcc_status.tr_progress == STATUS_GOT
4899 && !xcc_test_failed
4833 && version >= 279 4900 && version >= 279
4834 && !is_not_xterm
4835 && *T_CSH != NUL 4901 && *T_CSH != NUL
4836 && *T_CRS != NUL) 4902 && *T_CRS != NUL)
4837 { 4903 {
4838 LOG_TR(("Sending cursor style request")); 4904 LOG_TR(("Sending cursor style request"));
4839 out_str(T_CRS); 4905 out_str(T_CRS);
4842 } 4908 }
4843 4909
4844 // Only request the cursor blink mode if t_RC set. Not 4910 // Only request the cursor blink mode if t_RC set. Not
4845 // for Gnome terminal, it can't handle t_RC, it 4911 // for Gnome terminal, it can't handle t_RC, it
4846 // echoes the characters to the screen. 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;
4847 if (rbm_status.tr_progress == STATUS_GET 4915 if (rbm_status.tr_progress == STATUS_GET
4848 && !is_not_xterm 4916 && xcc_status.tr_progress == STATUS_GOT
4917 && !xcc_test_failed
4849 && *T_CRC != NUL) 4918 && *T_CRC != NUL)
4850 { 4919 {
4851 LOG_TR(("Sending cursor blink mode request")); 4920 LOG_TR(("Sending cursor blink mode request"));
4852 out_str(T_CRC); 4921 out_str(T_CRC);
4853 termrequest_sent(&rbm_status); 4922 termrequest_sent(&rbm_status);