Mercurial > vim
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); |