To: vim_dev@googlegroups.com Subject: Patch 8.2.0936 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0936 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. Files: src/main.c, src/term.c, src/proto/term.pro, src/testdir/term_util.vim, src/testdir/test_quickfix.vim, src/testdir/test_terminal.vim, src/testdir/test_startup_utf8.vim, src/testdir/dumps/Test_balloon_eval_term_01.dump, src/testdir/dumps/Test_balloon_eval_term_01a.dump, src/testdir/dumps/Test_balloon_eval_term_02.dump, src/testdir/dumps/Test_terminal_all_ansi_colors.dump *** ../vim-8.2.0935/src/main.c 2020-06-06 15:57:59.083088326 +0200 --- src/main.c 2020-06-08 21:20:33.758644053 +0200 *************** *** 793,799 **** #if defined(FEAT_TERMRESPONSE) // Must be done before redrawing, puts a few characters on the screen. ! may_req_ambiguous_char_width(); #endif RedrawingDisabled = 0; --- 793,799 ---- #if defined(FEAT_TERMRESPONSE) // Must be done before redrawing, puts a few characters on the screen. ! check_terminal_behavior(); #endif RedrawingDisabled = 0; *** ../vim-8.2.0935/src/term.c 2020-06-06 22:36:20.464116743 +0200 --- src/term.c 2020-06-09 15:51:23.453869117 +0200 *************** *** 126,131 **** --- 126,134 ---- // Request Cursor position report: static termrequest_T u7_status = TERMREQUEST_INIT; + // Request xterm compatibility check: + static termrequest_T xcc_status = TERMREQUEST_INIT; + # ifdef FEAT_TERMINAL // Request foreground color report: static termrequest_T rfg_status = TERMREQUEST_INIT; *************** *** 152,157 **** --- 155,161 ---- static termrequest_T *all_termrequests[] = { &crv_status, &u7_status, + &xcc_status, # ifdef FEAT_TERMINAL &rfg_status, # endif *************** *** 1428,1433 **** --- 1432,1438 ---- #ifdef FEAT_TERMRESPONSE static int check_for_codes = FALSE; // check for key code response static int is_not_xterm = FALSE; // recognized not-really-xterm + static int xcc_test_failed = FALSE; // xcc_status check failed #endif static struct builtin_term * *************** *** 3605,3644 **** } /* ! * Check how the terminal treats ambiguous character width (UAX #11). ! * First, we move the cursor to (1, 0) and print a test ambiguous character ! * \u25bd (WHITE DOWN-POINTING TRIANGLE) and query current cursor position. ! * If the terminal treats \u25bd as single width, the position is (1, 1), ! * or if it is treated as double width, that will be (1, 2). ! * This function has the side effect that changes cursor position, so ! * it must be called immediately after entering termcap mode. */ void ! may_req_ambiguous_char_width(void) { if (u7_status.tr_progress == STATUS_GET - && can_get_termresponse() - && starting == 0 - && *T_U7 != NUL && !option_was_set((char_u *)"ambiwidth")) { char_u buf[16]; ! LOG_TR(("Sending U7 request")); // Do this in the second row. In the first row the returned sequence // may be CSI 1;2R, which is the same as . term_windgoto(1, 0); ! buf[mb_char2bytes(0x25bd, buf)] = 0; out_str(buf); out_str(T_U7); termrequest_sent(&u7_status); out_flush(); // This overwrites a few characters on the screen, a redraw is needed // after this. Clear them out for now. screen_stop_highlight(); term_windgoto(1, 0); out_str((char_u *)" "); term_windgoto(0, 0); // Need to reset the known cursor position. --- 3610,3689 ---- } /* ! * Send sequences to the terminal and check with t_u7 how the cursor moves, to ! * find out properties of the terminal. */ void ! check_terminal_behavior(void) { + int did_send = FALSE; + + if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL) + return; + if (u7_status.tr_progress == STATUS_GET && !option_was_set((char_u *)"ambiwidth")) { char_u buf[16]; ! // Ambiguous width check. ! // Check how the terminal treats ambiguous character width (UAX #11). ! // First, we move the cursor to (1, 0) and print a test ambiguous ! // character \u25bd (WHITE DOWN-POINTING TRIANGLE) and then query ! // the current cursor position. If the terminal treats \u25bd as ! // single width, the position is (1, 1), or if it is treated as double ! // width, that will be (1, 2). This function has the side effect that ! // changes cursor position, so it must be called immediately after ! // entering termcap mode. ! LOG_TR(("Sending request for ambiwidth check")); // Do this in the second row. In the first row the returned sequence // may be CSI 1;2R, which is the same as . term_windgoto(1, 0); ! buf[mb_char2bytes(0x25bd, buf)] = NUL; out_str(buf); out_str(T_U7); termrequest_sent(&u7_status); out_flush(); + did_send = TRUE; // This overwrites a few characters on the screen, a redraw is needed // after this. Clear them out for now. screen_stop_highlight(); term_windgoto(1, 0); out_str((char_u *)" "); + } + + if (xcc_status.tr_progress == STATUS_GET) + { + // 2. Check compatibility with xterm. + // We move the cursor to (2, 0), print a test sequence and then query + // the current cursor position. If the terminal properly handles + // unknown DCS string and CSI sequence with intermediate byte, the test + // sequence is ignored and the cursor does not move. If the terminal + // handles test sequence incorrectly, a garbage string is displayed and + // the cursor does move. + LOG_TR(("Sending xterm compatibility test sequence.")); + // Do this in the third row. Second row is used by ambiguous + // chararacter width check. + term_windgoto(2, 0); + // send the test DCS string. + out_str((char_u *)"\033Pzz\033\\"); + // send the test CSI sequence with intermediate byte. + out_str((char_u *)"\033[0%m"); + out_str(T_U7); + termrequest_sent(&xcc_status); + out_flush(); + did_send = TRUE; + + // If the terminal handles test sequence incorrectly, garbage text is + // displayed. Clear them out for now. + screen_stop_highlight(); + term_windgoto(2, 0); + out_str((char_u *)" "); + } + + if (did_send) + { term_windgoto(0, 0); // Need to reset the known cursor position. *************** *** 4680,4685 **** --- 4725,4740 ---- # endif } } + else if (arg[0] == 3) + { + // Third row: xterm compatibility test. + // If the cursor is not on the first column then the + // terminal is not xterm compatible. + if (arg[1] != 1) + xcc_test_failed = TRUE; + xcc_status.tr_progress = STATUS_GOT; + } + key_name[0] = (int)KS_EXTRA; key_name[1] = (int)KE_IGNORE; slen = csi_len; *************** *** 4814,4819 **** --- 4869,4882 ---- else if (version == 115 && arg[0] == 0 && arg[2] == 0) is_not_xterm = TRUE; + // GNU screen sends 83;30600;0, 83;40500;0, etc. + // 30600/40500 is a version number of GNU screen. DA2 + // support is added on 3.6. DCS string has a special + // meaning to GNU screen, but xterm compatibility + // checking does not detect GNU screen. + if (version >= 30600 && arg[0] == 83) + xcc_test_failed = TRUE; + // Xterm first responded to this request at patch level // 95, so assume anything below 95 is not xterm. if (version < 95) *************** *** 4827,4837 **** // Only request the cursor style if t_SH and t_RS are // set. Only supported properly by xterm since version // 279 (otherwise it returns 0x18). // Not for Terminal.app, it can't handle t_RS, it // echoes the characters to the screen. if (rcs_status.tr_progress == STATUS_GET && version >= 279 - && !is_not_xterm && *T_CSH != NUL && *T_CRS != NUL) { --- 4890,4903 ---- // Only request the cursor style if t_SH and t_RS are // set. Only supported properly by xterm since version // 279 (otherwise it returns 0x18). + // Only when the xcc_status was set, the test finished, + // and xcc_test_failed is FALSE; // Not for Terminal.app, it can't handle t_RS, it // echoes the characters to the screen. if (rcs_status.tr_progress == STATUS_GET + && xcc_status.tr_progress == STATUS_GOT + && !xcc_test_failed && version >= 279 && *T_CSH != NUL && *T_CRS != NUL) { *************** *** 4844,4851 **** // Only request the cursor blink mode if t_RC set. Not // for Gnome terminal, it can't handle t_RC, it // echoes the characters to the screen. if (rbm_status.tr_progress == STATUS_GET ! && !is_not_xterm && *T_CRC != NUL) { LOG_TR(("Sending cursor blink mode request")); --- 4910,4920 ---- // Only request the cursor blink mode if t_RC set. Not // for Gnome terminal, it can't handle t_RC, it // echoes the characters to the screen. + // Only when the xcc_status was set, the test finished, + // and xcc_test_failed is FALSE; if (rbm_status.tr_progress == STATUS_GET ! && xcc_status.tr_progress == STATUS_GOT ! && !xcc_test_failed && *T_CRC != NUL) { LOG_TR(("Sending cursor blink mode request")); *** ../vim-8.2.0935/src/proto/term.pro 2020-06-06 22:36:20.464116743 +0200 --- src/proto/term.pro 2020-06-08 21:41:51.650251418 +0200 *************** *** 47,53 **** void starttermcap(void); void stoptermcap(void); void may_req_termresponse(void); ! void may_req_ambiguous_char_width(void); void may_req_bg_color(void); int swapping_screen(void); void scroll_start(void); --- 47,53 ---- void starttermcap(void); void stoptermcap(void); void may_req_termresponse(void); ! void check_terminal_behavior(void); void may_req_bg_color(void); int swapping_screen(void); void scroll_start(void); *** ../vim-8.2.0935/src/testdir/term_util.vim 2020-05-11 22:04:46.928845435 +0200 --- src/testdir/term_util.vim 2020-06-08 22:26:59.581244739 +0200 *************** *** 44,49 **** --- 44,51 ---- " Returns the buffer number of the terminal. " " Options is a dictionary, these items are recognized: + " "keep_t_u7" - when 1 do not make t_u7 empty (resetting t_u7 avoids clearing + " parts of line 2 and 3 on the display) " "rows" - height of the terminal window (max. 20) " "cols" - width of the terminal window (max. 78) " "statusoff" - number of lines the status is offset from default *************** *** 74,80 **** let cols = get(a:options, 'cols', 75) let statusoff = get(a:options, 'statusoff', 1) ! let cmd = GetVimCommandCleanTerm() .. a:arguments let options = { \ 'curwin': 1, --- 76,88 ---- let cols = get(a:options, 'cols', 75) let statusoff = get(a:options, 'statusoff', 1) ! if get(a:options, 'keep_t_u7', 0) ! let reset_u7 = '' ! else ! let reset_u7 = ' --cmd "set t_u7=" ' ! endif ! ! let cmd = GetVimCommandCleanTerm() .. reset_u7 .. a:arguments let options = { \ 'curwin': 1, *** ../vim-8.2.0935/src/testdir/test_quickfix.vim 2020-06-08 19:35:55.781319897 +0200 --- src/testdir/test_quickfix.vim 2020-06-08 22:14:06.555443544 +0200 *************** *** 2710,2716 **** CheckScreendump let lines =<< trim END - set t_u7= call setline(1, ['some', 'text', 'with', 'matches']) write XCwindow vimgrep e XCwindow --- 2710,2715 ---- *** ../vim-8.2.0935/src/testdir/test_terminal.vim 2020-05-31 16:04:38.558053522 +0200 --- src/testdir/test_terminal.vim 2020-06-08 22:14:48.979337826 +0200 *************** *** 2465,2471 **** call writefile(text, 'Xtext') let cmd = GetVimCommandCleanTerm() let lines = [ - \ 'set t_u7=', \ 'call setline(1, range(20))', \ 'hi PopTerm ctermbg=grey', \ 'func OpenTerm(setColor)', --- 2465,2470 ---- *************** *** 2545,2551 **** END call writefile(text, 'Xtext') let lines = [ - \ 'set t_u7=', \ 'call setline(1, range(20))', \ 'func OpenTerm()', \ " let s:buf = term_start('cat Xtext', #{hidden: 1})", --- 2544,2549 ---- *************** *** 2575,2581 **** CheckUnix let lines = [ - \ 'set t_u7=', \ 'call setline(1, range(20))', \ 'func OpenTerm()', \ " let s:buf = term_start('cat', #{hidden: 1, " --- 2573,2578 ---- *** ../vim-8.2.0935/src/testdir/test_startup_utf8.vim 2020-05-31 21:27:58.335221898 +0200 --- src/testdir/test_startup_utf8.vim 2020-06-08 22:29:44.224733553 +0200 *************** *** 1,5 **** --- 1,6 ---- " Tests for startup using utf-8. + source check.vim source shared.vim source screendump.vim *************** *** 71,77 **** \ 'call test_option_not_set("ambiwidth")', \ 'redraw', \ ], 'Xscript') ! let buf = RunVimInTerminal('-S Xscript', {}) call TermWait(buf) call term_sendkeys(buf, "S\=&ambiwidth\\") call WaitForAssert({-> assert_match('single', term_getline(buf, 1))}) --- 72,78 ---- \ 'call test_option_not_set("ambiwidth")', \ 'redraw', \ ], 'Xscript') ! let buf = RunVimInTerminal('-S Xscript', #{keep_t_u7: 1}) call TermWait(buf) call term_sendkeys(buf, "S\=&ambiwidth\\") call WaitForAssert({-> assert_match('single', term_getline(buf, 1))}) *** ../vim-8.2.0935/src/testdir/dumps/Test_balloon_eval_term_01.dump 2019-11-09 16:45:21.000000000 +0100 --- src/testdir/dumps/Test_balloon_eval_term_01.dump 2020-06-08 22:05:16.197071495 +0200 *************** *** 1,5 **** |o+0&#ffffff0|n>e| |o|n|e| |o|n|e| @38 ! @2|o| |t|X|o| |t|w|o| @38 |t|h|r|e| +0#0000001#ffd7ff255@17| +0#0000000#ffffff0@27 |~+0#4040ff13&| @2| +0#0000001#ffd7ff255|l|i|n|e| |2| |c|o|l|u|m|n| |6|:| | +0#4040ff13#ffffff0@27 |~| @2| +0#0000001#ffd7ff255|t|X|o| @13| +0#4040ff13#ffffff0@27 --- 1,5 ---- |o+0&#ffffff0|n>e| |o|n|e| |o|n|e| @38 ! |t|w|o| |t|X|o| |t|w|o| @38 |t|h|r|e| +0#0000001#ffd7ff255@17| +0#0000000#ffffff0@27 |~+0#4040ff13&| @2| +0#0000001#ffd7ff255|l|i|n|e| |2| |c|o|l|u|m|n| |6|:| | +0#4040ff13#ffffff0@27 |~| @2| +0#0000001#ffd7ff255|t|X|o| @13| +0#4040ff13#ffffff0@27 *** ../vim-8.2.0935/src/testdir/dumps/Test_balloon_eval_term_01a.dump 2019-11-09 16:46:23.000000000 +0100 --- src/testdir/dumps/Test_balloon_eval_term_01a.dump 2020-06-08 22:09:19.352235966 +0200 *************** *** 1,5 **** |o+0&#ffffff0|n>e| |o|n|e| |o|n|e| @38 ! @2|o| |t|X|o| |t|w|o| @38 |t|h|r|e| +0#0000001#ffd7ff255@17| +0#0000000#ffffff0@27 |~+0#4040ff13&| @2| +0#0000001#ffd7ff255|l|i|n|e| |2| |c|o|l|u|m|n| |6|:| | +0#4040ff13#ffffff0@27 |~| @2| +0#0000001#ffd7ff255|t|X|o| @13| +0#4040ff13#ffffff0@27 --- 1,5 ---- |o+0&#ffffff0|n>e| |o|n|e| |o|n|e| @38 ! |t|w|o| |t|X|o| |t|w|o| @38 |t|h|r|e| +0#0000001#ffd7ff255@17| +0#0000000#ffffff0@27 |~+0#4040ff13&| @2| +0#0000001#ffd7ff255|l|i|n|e| |2| |c|o|l|u|m|n| |6|:| | +0#4040ff13#ffffff0@27 |~| @2| +0#0000001#ffd7ff255|t|X|o| @13| +0#4040ff13#ffffff0@27 *** ../vim-8.2.0935/src/testdir/dumps/Test_balloon_eval_term_02.dump 2019-11-09 16:45:27.000000000 +0100 --- src/testdir/dumps/Test_balloon_eval_term_02.dump 2020-06-08 22:09:23.844220571 +0200 *************** *** 1,5 **** |o+0&#ffffff0|n|e| |o|n|e| |o|n|e| @38 ! @2|o| |t|X|o| |t|w|o| @38 |t|h|r|e|e+0&#e0e0e08| |t|h>r+0&#ffffff0|e@1| |t|h|r|e@1| @32 |~+0#4040ff13&| @2| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@27 |~| @2| +0#0000001#ffd7ff255|l|i|n|e| |3| |c|o|l|u|m|n| |5|:| | +0#4040ff13#ffffff0@27 --- 1,5 ---- |o+0&#ffffff0|n|e| |o|n|e| |o|n|e| @38 ! |t|w|o| |t|X|o| |t|w|o| @38 |t|h|r|e|e+0&#e0e0e08| |t|h>r+0&#ffffff0|e@1| |t|h|r|e@1| @32 |~+0#4040ff13&| @2| +0#0000001#ffd7ff255@17| +0#4040ff13#ffffff0@27 |~| @2| +0#0000001#ffd7ff255|l|i|n|e| |3| |c|o|l|u|m|n| |5|:| | +0#4040ff13#ffffff0@27 *** ../vim-8.2.0935/src/testdir/dumps/Test_terminal_all_ansi_colors.dump 2019-05-13 20:22:27.000000000 +0200 --- src/testdir/dumps/Test_terminal_all_ansi_colors.dump 2020-06-08 22:11:43.519777958 +0200 *************** *** 1,5 **** >A+0#0000001#8080809@1|B+0#e000002#ff404010@1|C+0#00e0003#40ff4011@1|D+0#e0e0004#ffff4012@1|E+0#0000e05#4040ff13@1|F+0#e000e06#ff40ff14@1|G+0#00e0e07#40ffff15@1|H+0#e0e0e08#ffffff16@1|I+0#8080809#0000001@1|J+0#ff404010#e000002@1|K+0#40ff4011#00e0003@1|L+0#ffff4012#e0e0004@1|M+0#4040ff13#0000e05@1|N+0#ff40ff14#e000e06@1|O+0#40ffff15#00e0e07@1|P+0#ffffff16#e0e0e08@1| +0#0000000#ffffff0|X+2#e000002&@1|Y+2#40ff4011&@1|Z+2#ff40ff14#e000e06@1| +0#0000000#ffffff0@35 ! @2| +0#4040ff13&@72 |~| @73 |~| @73 |~| @73 --- 1,5 ---- >A+0#0000001#8080809@1|B+0#e000002#ff404010@1|C+0#00e0003#40ff4011@1|D+0#e0e0004#ffff4012@1|E+0#0000e05#4040ff13@1|F+0#e000e06#ff40ff14@1|G+0#00e0e07#40ffff15@1|H+0#e0e0e08#ffffff16@1|I+0#8080809#0000001@1|J+0#ff404010#e000002@1|K+0#40ff4011#00e0003@1|L+0#ffff4012#e0e0004@1|M+0#4040ff13#0000e05@1|N+0#ff40ff14#e000e06@1|O+0#40ffff15#00e0e07@1|P+0#ffffff16#e0e0e08@1| +0#0000000#ffffff0|X+2#e000002&@1|Y+2#40ff4011&@1|Z+2#ff40ff14#e000e06@1| +0#0000000#ffffff0@35 ! |~+0#4040ff13&| @73 |~| @73 |~| @73 |~| @73 *** ../vim-8.2.0935/src/version.c 2020-06-08 20:50:23.432250668 +0200 --- src/version.c 2020-06-08 21:49:44.056381283 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 936, /**/ -- Not too long ago, unzipping in public was illegal... /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///