comparison src/term.c @ 20778:6d5e233bac9c v8.2.0941

patch 8.2.0941: detecting terminal properties is unstructured Commit: https://github.com/vim/vim/commit/517f00f78893087d2f9d45768a5ba4dc48cb6856 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jun 10 12:15:51 2020 +0200 patch 8.2.0941: detecting terminal properties is unstructured Problem: Detecting terminal properties is unstructured. Solution: Add a table with terminal properties. Set properties when a terminal is detected.
author Bram Moolenaar <Bram@vim.org>
date Wed, 10 Jun 2020 12:30:04 +0200
parents 7728e309e013
children 9064044fd4f6
comparison
equal deleted inserted replaced
20777:9e7672e41fba 20778:6d5e233bac9c
1429 1429
1430 static int need_gather = FALSE; // need to fill termleader[] 1430 static int need_gather = FALSE; // need to fill termleader[]
1431 static char_u termleader[256 + 1]; // for check_termcode() 1431 static char_u termleader[256 + 1]; // for check_termcode()
1432 #ifdef FEAT_TERMRESPONSE 1432 #ifdef FEAT_TERMRESPONSE
1433 static int check_for_codes = FALSE; // check for key code response 1433 static int check_for_codes = FALSE; // check for key code response
1434 static int is_not_xterm = FALSE; // recognized not-really-xterm 1434
1435 static int xcc_test_failed = FALSE; // xcc_status check failed 1435 /*
1436 * Structure and table to store terminal features that can be detected by
1437 * querying the terminal. Either by inspecting the termresponse or a more
1438 * specific request. Besides this there are:
1439 * t_colors - number of colors supported
1440 */
1441 typedef struct {
1442 char *tpr_name;
1443 int tpr_set_by_termresponse;
1444 int tpr_status;
1445 } termprop_T;
1446
1447 // Values for tpr_status.
1448 #define TPR_UNKNOWN 'u'
1449 #define TPR_YES 'y'
1450 #define TPR_NO 'n'
1451 #define TPR_MOUSE_XTERM 'x' // use "xterm" for 'ttymouse'
1452 #define TPR_MOUSE_XTERM2 '2' // use "xterm2" for 'ttymouse'
1453 #define TPR_MOUSE_SGR 's' // use "sgr" for 'ttymouse'
1454
1455 // can request the cursor style without messing up the display
1456 #define TPR_CURSOR_STYLE 0
1457 // can request the cursor blink mode without messing up the display
1458 #define TPR_CURSOR_BLINK 1
1459 // can set the underline color with t_8u without resetting other colors
1460 #define TPR_UNDERLINE_RGB 2
1461 // mouse support - TPR_MOUSE_XTERM, TPR_MOUSE_XTERM2 or TPR_MOUSE_SGR
1462 #define TPR_MOUSE 3
1463 // table size
1464 #define TPR_COUNT 4
1465
1466 static termprop_T term_props[TPR_COUNT];
1467
1468 /*
1469 * Initialize the term_props table.
1470 * When "all" is FALSE only set those that are detected from the version
1471 * response.
1472 */
1473 static void
1474 init_term_props(int all)
1475 {
1476 int i;
1477
1478 term_props[TPR_CURSOR_STYLE].tpr_name = "cursor_style";
1479 term_props[TPR_CURSOR_STYLE].tpr_set_by_termresponse = FALSE;
1480 term_props[TPR_CURSOR_BLINK].tpr_name = "cursor_blink_mode";
1481 term_props[TPR_CURSOR_BLINK].tpr_set_by_termresponse = FALSE;
1482 term_props[TPR_UNDERLINE_RGB].tpr_name = "underline_rgb";
1483 term_props[TPR_UNDERLINE_RGB].tpr_set_by_termresponse = TRUE;
1484 term_props[TPR_MOUSE].tpr_name = "mouse";
1485 term_props[TPR_MOUSE].tpr_set_by_termresponse = TRUE;
1486
1487 for (i = 0; i < TPR_COUNT; ++i)
1488 if (all || term_props[i].tpr_set_by_termresponse)
1489 term_props[i].tpr_status = TPR_UNKNOWN;
1490 }
1436 #endif 1491 #endif
1437 1492
1438 static struct builtin_term * 1493 static struct builtin_term *
1439 find_builtin_term(char_u *term) 1494 find_builtin_term(char_u *term)
1440 { 1495 {
1956 2011
1957 #if defined(UNIX) || defined(VMS) 2012 #if defined(UNIX) || defined(VMS)
1958 term_is_xterm = vim_is_xterm(term); 2013 term_is_xterm = vim_is_xterm(term);
1959 #endif 2014 #endif
1960 #ifdef FEAT_TERMRESPONSE 2015 #ifdef FEAT_TERMRESPONSE
1961 is_not_xterm = FALSE; 2016 // Reset terminal properties that are set based on the termresponse, which
1962 is_mac_terminal = FALSE; 2017 // will be sent out soon.
2018 init_term_props(FALSE);
1963 #endif 2019 #endif
1964 2020
1965 #if defined(UNIX) || defined(VMS) 2021 #if defined(UNIX) || defined(VMS)
1966 /* 2022 /*
1967 * For Unix, set the 'ttymouse' option to the type of mouse to be used. 2023 * For Unix, set the 'ttymouse' option to the type of mouse to be used.
3610 } 3666 }
3611 3667
3612 /* 3668 /*
3613 * Send sequences to the terminal and check with t_u7 how the cursor moves, to 3669 * Send sequences to the terminal and check with t_u7 how the cursor moves, to
3614 * find out properties of the terminal. 3670 * find out properties of the terminal.
3671 * Note that this goes out before T_CRV, so that the result can be used when
3672 * the termresponse arrives.
3615 */ 3673 */
3616 void 3674 void
3617 check_terminal_behavior(void) 3675 check_terminal_behavior(void)
3618 { 3676 {
3619 int did_send = FALSE; 3677 int did_send = FALSE;
3678
3679 init_term_props(TRUE);
3620 3680
3621 if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL) 3681 if (!can_get_termresponse() || starting != 0 || *T_U7 == NUL)
3622 return; 3682 return;
3623 3683
3624 if (u7_status.tr_progress == STATUS_GET 3684 if (u7_status.tr_progress == STATUS_GET
4422 # endif 4482 # endif
4423 } 4483 }
4424 } 4484 }
4425 else if (arg[0] == 3) 4485 else if (arg[0] == 3)
4426 { 4486 {
4487 int value;
4488
4427 LOG_TR(("Received compatibility test result: %s", tp)); 4489 LOG_TR(("Received compatibility test result: %s", tp));
4490 xcc_status.tr_progress = STATUS_GOT;
4491
4428 // Third row: xterm compatibility test. 4492 // Third row: xterm compatibility test.
4429 // If the cursor is not on the first column then the 4493 // If the cursor is on the first column then the terminal can handle
4430 // terminal is not xterm compatible. 4494 // the request for cursor style and blinking.
4431 if (arg[1] != 1) 4495 value = arg[1] == 1 ? TPR_YES : TPR_NO;
4432 xcc_test_failed = TRUE; 4496 term_props[TPR_CURSOR_STYLE].tpr_status = value;
4433 xcc_status.tr_progress = STATUS_GOT; 4497 term_props[TPR_CURSOR_BLINK].tpr_status = value;
4434 } 4498 }
4435 } 4499 }
4436 4500
4437 /* 4501 /*
4438 * Handle a response to T_CRV. 4502 * Handle a response to T_CRV: {lead}{first}{x};{vers};{y}c
4503 * Xterm and alikes use '>' for {first}.
4504 * Rxvt sends "{lead}?1;2c".
4439 */ 4505 */
4440 static void 4506 static void
4441 handle_version_response(int first, int *arg, int argc, char_u *tp) 4507 handle_version_response(int first, int *arg, int argc, char_u *tp)
4442 { 4508 {
4509 // The xterm version. It is set to zero when it can't be an actual xterm
4510 // version.
4443 int version = arg[1]; 4511 int version = arg[1];
4444 4512
4445 LOG_TR(("Received CRV response: %s", tp)); 4513 LOG_TR(("Received CRV response: %s", tp));
4446 crv_status.tr_progress = STATUS_GOT; 4514 crv_status.tr_progress = STATUS_GOT;
4447 did_cursorhold = TRUE; 4515 did_cursorhold = TRUE;
4516
4517 // Reset terminal properties that are set based on the termresponse.
4518 // Mainly useful for tests that send the termresponse multiple times.
4519 init_term_props(FALSE);
4448 4520
4449 // If this code starts with CSI, you can bet that the 4521 // If this code starts with CSI, you can bet that the
4450 // terminal uses 8-bit codes. 4522 // terminal uses 8-bit codes.
4451 if (tp[0] == CSI) 4523 if (tp[0] == CSI)
4452 switch_to_8bit(); 4524 switch_to_8bit();
4456 // Ignore it for when the user has set 'term' to xterm, 4528 // Ignore it for when the user has set 'term' to xterm,
4457 // even though it's an rxvt. 4529 // even though it's an rxvt.
4458 if (version > 20000) 4530 if (version > 20000)
4459 version = 0; 4531 version = 0;
4460 4532
4533 // Figure out more if the reeponse is CSI > 99 ; 99 ; 99 c
4461 if (first == '>' && argc == 3) 4534 if (first == '>' && argc == 3)
4462 { 4535 {
4463 int need_flush = FALSE; 4536 int need_flush = FALSE;
4464 int is_iterm2 = FALSE;
4465 int is_mintty = FALSE;
4466 int is_screen = FALSE;
4467 4537
4468 // mintty 2.9.5 sends 77;20905;0c. 4538 // mintty 2.9.5 sends 77;20905;0c.
4469 // (77 is ASCII 'M' for mintty.) 4539 // (77 is ASCII 'M' for mintty.)
4470 if (arg[0] == 77) 4540 if (arg[0] == 77)
4471 is_mintty = TRUE; 4541 {
4472 4542 // mintty can do SGR mouse reporting
4473 // if xterm version >= 141 try to get termcap codes 4543 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4544 }
4545
4546 // If xterm version >= 141 try to get termcap codes. For other
4547 // terminals the request should be ignored.
4474 if (version >= 141) 4548 if (version >= 141)
4475 { 4549 {
4476 LOG_TR(("Enable checking for XT codes")); 4550 LOG_TR(("Enable checking for XT codes"));
4477 check_for_codes = TRUE; 4551 check_for_codes = TRUE;
4478 need_gather = TRUE; 4552 need_gather = TRUE;
4486 // colors the terminal supports. Otherwise assume 4560 // colors the terminal supports. Otherwise assume
4487 // 256, libvterm supports even more. 4561 // 256, libvterm supports even more.
4488 if (mch_getenv((char_u *)"COLORS") == NULL) 4562 if (mch_getenv((char_u *)"COLORS") == NULL)
4489 may_adjust_color_count(256); 4563 may_adjust_color_count(256);
4490 // Libvterm can handle SGR mouse reporting. 4564 // Libvterm can handle SGR mouse reporting.
4491 if (!option_was_set((char_u *)"ttym")) 4565 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4492 set_option_value((char_u *)"ttym", 0L,
4493 (char_u *)"sgr", 0);
4494 } 4566 }
4495 4567
4496 if (version == 95) 4568 if (version == 95)
4497 { 4569 {
4498 // Mac Terminal.app sends 1;95;0 4570 // Mac Terminal.app sends 1;95;0
4499 if (arg[0] == 1 && arg[2] == 0) 4571 if (arg[0] == 1 && arg[2] == 0)
4500 { 4572 {
4501 is_not_xterm = TRUE; 4573 term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
4502 is_mac_terminal = TRUE; 4574 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4503 } 4575 }
4504 // iTerm2 sends 0;95;0 4576 // iTerm2 sends 0;95;0
4505 else if (arg[0] == 0 && arg[2] == 0) 4577 else if (arg[0] == 0 && arg[2] == 0)
4506 is_iterm2 = TRUE; 4578 {
4579 // iTerm2 can do SGR mouse reporting
4580 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4581 }
4507 // old iTerm2 sends 0;95; 4582 // old iTerm2 sends 0;95;
4508 else if (arg[0] == 0 && arg[2] == -1) 4583 else if (arg[0] == 0 && arg[2] == -1)
4509 is_not_xterm = TRUE; 4584 term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
4510 } 4585 }
4511 4586
4512 // screen sends 83;40500;0 83 is 'S' in ASCII. 4587 // screen sends 83;40500;0 83 is 'S' in ASCII.
4513 if (arg[0] == 83) 4588 if (arg[0] == 83)
4514 is_screen = TRUE; 4589 {
4515 4590 // screen supports SGR mouse codes since 4.7.0
4516 // Only set 'ttymouse' automatically if it was not set 4591 if (arg[1] >= 40700)
4517 // by the user already. 4592 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4518 if (!option_was_set((char_u *)"ttym")) 4593 else
4519 { 4594 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_XTERM;
4520 // Xterm version 277 supports SGR. Also support 4595 }
4521 // Terminal.app, iTerm2, mintty, and screen 4.7+. 4596
4522 if ((!is_screen && version >= 277) 4597 // If no recognized terminal has set mouse behavior, assume xterm.
4523 || is_iterm2 4598 if (term_props[TPR_MOUSE].tpr_status == TPR_UNKNOWN)
4524 || is_mac_terminal 4599 {
4525 || is_mintty 4600 // Xterm version 277 supports SGR.
4526 || (is_screen && arg[1] >= 40700)) 4601 // Xterm version >= 95 supports mouse dragging.
4527 set_option_value((char_u *)"ttym", 0L, 4602 if (version >= 277)
4528 (char_u *)"sgr", 0); 4603 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4529 // For xterm version >= 95 mouse dragging works.
4530 else if (version >= 95) 4604 else if (version >= 95)
4531 set_option_value((char_u *)"ttym", 0L, 4605 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_XTERM2;
4532 (char_u *)"xterm2", 0);
4533 } 4606 }
4534 4607
4535 // Detect terminals that set $TERM to something like 4608 // Detect terminals that set $TERM to something like
4536 // "xterm-256color" but are not fully xterm compatible. 4609 // "xterm-256color" but are not fully xterm compatible.
4537 4610 //
4538 // Gnome terminal sends 1;3801;0, 1;4402;0 or 1;2501;0. 4611 // Gnome terminal sends 1;3801;0, 1;4402;0 or 1;2501;0.
4539 // xfce4-terminal sends 1;2802;0. 4612 // xfce4-terminal sends 1;2802;0.
4540 // screen sends 83;40500;0 4613 // screen sends 83;40500;0
4541 // Assuming any version number over 2500 is not an 4614 // Assuming any version number over 2500 is not an
4542 // xterm (without the limit for rxvt and screen). 4615 // xterm (without the limit for rxvt and screen).
4543 if (arg[1] >= 2500) 4616 if (arg[1] >= 2500)
4544 is_not_xterm = TRUE; 4617 term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
4545 4618
4546 // PuTTY sends 0;136;0
4547 // vandyke SecureCRT sends 1;136;0
4548 else if (version == 136 && arg[2] == 0) 4619 else if (version == 136 && arg[2] == 0)
4549 { 4620 {
4550 is_not_xterm = TRUE; 4621 term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
4551 4622
4552 // PuTTY supports sgr-like mouse reporting, but 4623 // PuTTY sends 0;136;0
4553 // only set 'ttymouse' if it was not set by the 4624 if (arg[0] == 0)
4554 // user already. 4625 {
4555 if (arg[0] == 0 4626 // supports sgr-like mouse reporting.
4556 && !option_was_set((char_u *)"ttym")) 4627 term_props[TPR_MOUSE].tpr_status = TPR_MOUSE_SGR;
4557 set_option_value((char_u *)"ttym", 0L, 4628 }
4558 (char_u *)"sgr", 0); 4629 // vandyke SecureCRT sends 1;136;0
4559 } 4630 }
4560 4631
4561 // Konsole sends 0;115;0 4632 // Konsole sends 0;115;0
4562 else if (version == 115 && arg[0] == 0 && arg[2] == 0) 4633 else if (version == 115 && arg[0] == 0 && arg[2] == 0)
4563 is_not_xterm = TRUE; 4634 term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
4564 4635
4565 // GNU screen sends 83;30600;0, 83;40500;0, etc. 4636 // GNU screen sends 83;30600;0, 83;40500;0, etc.
4566 // 30600/40500 is a version number of GNU screen. DA2 4637 // 30600/40500 is a version number of GNU screen. DA2 support is added
4567 // support is added on 3.6. DCS string has a special 4638 // on 3.6. DCS string has a special meaning to GNU screen, but xterm
4568 // meaning to GNU screen, but xterm compatibility 4639 // compatibility checking does not detect GNU screen.
4569 // checking does not detect GNU screen. 4640 if (arg[0] == 83 && arg[1] >= 30600)
4570 if (version >= 30600 && arg[0] == 83) 4641 {
4571 xcc_test_failed = TRUE; 4642 term_props[TPR_CURSOR_STYLE].tpr_status = TPR_NO;
4643 term_props[TPR_CURSOR_BLINK].tpr_status = TPR_NO;
4644 }
4572 4645
4573 // Xterm first responded to this request at patch level 4646 // Xterm first responded to this request at patch level
4574 // 95, so assume anything below 95 is not xterm. 4647 // 95, so assume anything below 95 is not xterm and hopefully supports
4648 // the underline RGB color sequence.
4575 if (version < 95) 4649 if (version < 95)
4576 is_not_xterm = TRUE; 4650 term_props[TPR_UNDERLINE_RGB].tpr_status = TPR_YES;
4577 4651
4578 // With the real Xterm setting the underline RGB color 4652 // Getting the cursor style is only supported properly by xterm since
4579 // clears the background color, disable "t_8u". 4653 // version 279 (otherwise it returns 0x18).
4580 if (!is_not_xterm && *T_8U != NUL) 4654 if (version < 279)
4655 term_props[TPR_CURSOR_STYLE].tpr_status = TPR_NO;
4656
4657 /*
4658 * Take action on the detected properties.
4659 */
4660
4661 // Unless the underline RGB color is expected to work, disable "t_8u".
4662 // It does not work for the real Xterm, it resets the background color.
4663 if (term_props[TPR_UNDERLINE_RGB].tpr_status == TPR_YES && *T_8U != NUL)
4581 T_8U = empty_option; 4664 T_8U = empty_option;
4665
4666 // Only set 'ttymouse' automatically if it was not set
4667 // by the user already.
4668 if (!option_was_set((char_u *)"ttym")
4669 && (term_props[TPR_MOUSE].tpr_status == TPR_MOUSE_XTERM2
4670 || term_props[TPR_MOUSE].tpr_status == TPR_MOUSE_SGR))
4671 {
4672 set_option_value((char_u *)"ttym", 0L,
4673 term_props[TPR_MOUSE].tpr_status == TPR_MOUSE_SGR
4674 ? (char_u *)"sgr" : (char_u *)"xterm2", 0);
4675 }
4582 4676
4583 // Only request the cursor style if t_SH and t_RS are 4677 // Only request the cursor style if t_SH and t_RS are
4584 // set. Only supported properly by xterm since version 4678 // set. Only supported properly by xterm since version
4585 // 279 (otherwise it returns 0x18). 4679 // 279 (otherwise it returns 0x18).
4586 // Only when the xcc_status was set, the test finished, 4680 // Only when getting the cursor style was detected to work.
4587 // and xcc_test_failed is FALSE;
4588 // Not for Terminal.app, it can't handle t_RS, it 4681 // Not for Terminal.app, it can't handle t_RS, it
4589 // echoes the characters to the screen. 4682 // echoes the characters to the screen.
4590 if (rcs_status.tr_progress == STATUS_GET 4683 if (rcs_status.tr_progress == STATUS_GET
4591 && xcc_status.tr_progress == STATUS_GOT 4684 && term_props[TPR_CURSOR_STYLE].tpr_status == TPR_YES
4592 && !xcc_test_failed
4593 && version >= 279
4594 && *T_CSH != NUL 4685 && *T_CSH != NUL
4595 && *T_CRS != NUL) 4686 && *T_CRS != NUL)
4596 { 4687 {
4597 LOG_TR(("Sending cursor style request")); 4688 LOG_TR(("Sending cursor style request"));
4598 out_str(T_CRS); 4689 out_str(T_CRS);
4601 } 4692 }
4602 4693
4603 // Only request the cursor blink mode if t_RC set. Not 4694 // Only request the cursor blink mode if t_RC set. Not
4604 // for Gnome terminal, it can't handle t_RC, it 4695 // for Gnome terminal, it can't handle t_RC, it
4605 // echoes the characters to the screen. 4696 // echoes the characters to the screen.
4606 // Only when the xcc_status was set, the test finished, 4697 // Only when getting the cursor style was detected to work.
4607 // and xcc_test_failed is FALSE;
4608 if (rbm_status.tr_progress == STATUS_GET 4698 if (rbm_status.tr_progress == STATUS_GET
4609 && xcc_status.tr_progress == STATUS_GOT 4699 && term_props[TPR_CURSOR_BLINK].tpr_status == TPR_YES
4610 && !xcc_test_failed
4611 && *T_CRC != NUL) 4700 && *T_CRC != NUL)
4612 { 4701 {
4613 LOG_TR(("Sending cursor blink mode request")); 4702 LOG_TR(("Sending cursor blink mode request"));
4614 out_str(T_CRC); 4703 out_str(T_CRC);
4615 termrequest_sent(&rbm_status); 4704 termrequest_sent(&rbm_status);
4679 return new_slen - csi_len + offset; 4768 return new_slen - csi_len + offset;
4680 } 4769 }
4681 4770
4682 /* 4771 /*
4683 * Handle a CSI escape sequence. 4772 * Handle a CSI escape sequence.
4684 * - Xterm version string: {lead}>{x};{vers};{y}c 4773 * - Xterm version string.
4685 * Also eat other possible responses to t_RV, rxvt returns
4686 * "{lead}?1;2c".
4687 * 4774 *
4688 * - Cursor position report: {lead}{row};{col}R 4775 * - Cursor position report: {lead}{row};{col}R
4689 * The final byte must be 'R'. It is used for checking the 4776 * The final byte must be 'R'. It is used for checking the
4690 * ambiguous-width character state. 4777 * ambiguous-width character state.
4691 * 4778 *