comparison src/terminal.c @ 11993:92a86fe8adc0 v8.0.0877

patch 8.0.0877: using CTRL- CTRL-N in terminal is inconsistent commit https://github.com/vim/vim/commit/6d8197485dc84532e37aced2c39292bff374200d Author: Bram Moolenaar <Bram@vim.org> Date: Sun Aug 6 14:57:49 2017 +0200 patch 8.0.0877: using CTRL-\ CTRL-N in terminal is inconsistent Problem: Using CTRL-\ CTRL-N in terminal is inconsistent. Solution: Stay in Normal mode.
author Christian Brabandt <cb@256bit.org>
date Sun, 06 Aug 2017 15:00:04 +0200
parents d036c1c8537d
children 64b822c4f7ae
comparison
equal deleted inserted replaced
11992:e5c731391a9f 11993:92a86fe8adc0
34 * 34 *
35 * When the job ends the text is put in a buffer. Redrawing then happens from 35 * When the job ends the text is put in a buffer. Redrawing then happens from
36 * that buffer, attributes come from the scrollback buffer tl_scrollback. 36 * that buffer, attributes come from the scrollback buffer tl_scrollback.
37 * 37 *
38 * TODO: 38 * TODO:
39 * - MS-Windows: no redraw for 'updatetime' #1915 39 * - Add argument to term_wait() for waiting time.
40 * - add argument to term_wait() for waiting time.
41 * - For the scrollback buffer store lines in the buffer, only attributes in 40 * - For the scrollback buffer store lines in the buffer, only attributes in
42 * tl_scrollback. 41 * tl_scrollback.
43 * - When the job ends: 42 * - When the job ends:
44 * - Need an option or argument to drop the window+buffer right away, to be 43 * - Need an option or argument to drop the window+buffer right away, to be
45 * used for a shell or Vim. 'termfinish'; "close", "open" (open window when 44 * used for a shell or Vim. 'termfinish'; "close", "open" (open window when
46 * job finishes). 45 * job finishes).
47 * - add option values to the command: 46 * - add option values to the command:
48 * :term <24x80> <close> vim notes.txt 47 * :term <24x80> <close> vim notes.txt
49 * - support different cursor shapes, colors and attributes 48 * - support different cursor shapes, colors and attributes
49 * - MS-Windows: no redraw for 'updatetime' #1915
50 * - make term_getcursor() return type (none/block/bar/underline) and 50 * - make term_getcursor() return type (none/block/bar/underline) and
51 * attributes (color, blink, etc.) 51 * attributes (color, blink, etc.)
52 * - To set BS correctly, check get_stty(); Pass the fd of the pty. 52 * - To set BS correctly, check get_stty(); Pass the fd of the pty.
53 * For the GUI fill termios with default values, perhaps like pangoterm: 53 * For the GUI fill termios with default values, perhaps like pangoterm:
54 * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134 54 * http://bazaar.launchpad.net/~leonerd/pangoterm/trunk/view/head:/main.c#L134
113 113
114 /* used when tl_job is NULL and only a pty was created */ 114 /* used when tl_job is NULL and only a pty was created */
115 int tl_tty_fd; 115 int tl_tty_fd;
116 char_u *tl_tty_name; 116 char_u *tl_tty_name;
117 117
118 int tl_terminal_mode; /* 0, TMODE_ONCE or TMODE_LOOP */ 118 int tl_normal_mode; /* TRUE: Terminal-Normal mode */
119 int tl_channel_closed; 119 int tl_channel_closed;
120 120
121 #ifdef WIN3264 121 #ifdef WIN3264
122 void *tl_winpty_config; 122 void *tl_winpty_config;
123 void *tl_winpty; 123 void *tl_winpty;
460 } 460 }
461 461
462 static void 462 static void
463 update_cursor(term_T *term, int redraw) 463 update_cursor(term_T *term, int redraw)
464 { 464 {
465 if (term->tl_terminal_mode != 0) 465 if (term->tl_normal_mode)
466 return; 466 return;
467 setcursor(); 467 setcursor();
468 if (redraw && term->tl_buffer == curbuf) 468 if (redraw && term->tl_buffer == curbuf)
469 { 469 {
470 if (term->tl_cursor_visible) 470 if (term->tl_cursor_visible)
493 return; 493 return;
494 } 494 }
495 ch_log(channel, "writing %d bytes to terminal", (int)len); 495 ch_log(channel, "writing %d bytes to terminal", (int)len);
496 term_write_job_output(term, msg, len); 496 term_write_job_output(term, msg, len);
497 497
498 if (term->tl_terminal_mode == 0) 498 if (!term->tl_normal_mode)
499 { 499 {
500 /* TODO: only update once in a while. */ 500 /* TODO: only update once in a while. */
501 update_screen(0); 501 update_screen(0);
502 update_cursor(term, TRUE); 502 update_cursor(term, TRUE);
503 } 503 }
806 } 806 }
807 } 807 }
808 } 808 }
809 809
810 static void 810 static void
811 set_terminal_mode(term_T *term, int mode) 811 set_terminal_mode(term_T *term, int normal_mode)
812 { 812 {
813 term->tl_terminal_mode = mode; 813 term->tl_normal_mode = normal_mode;
814 vim_free(term->tl_status_text); 814 vim_free(term->tl_status_text);
815 term->tl_status_text = NULL; 815 term->tl_status_text = NULL;
816 if (term->tl_buffer == curbuf) 816 if (term->tl_buffer == curbuf)
817 maketitle(); 817 maketitle();
818 } 818 }
824 static void 824 static void
825 cleanup_vterm(term_T *term) 825 cleanup_vterm(term_T *term)
826 { 826 {
827 move_terminal_to_buffer(term); 827 move_terminal_to_buffer(term);
828 term_free_vterm(term); 828 term_free_vterm(term);
829 set_terminal_mode(term, 0); 829 set_terminal_mode(term, FALSE);
830 } 830 }
831 831
832 /* 832 /*
833 * Switch from Terminal-Job mode to Terminal-Normal mode. 833 * Switch from Terminal-Job mode to Terminal-Normal mode.
834 * Suspends updating the terminal window. 834 * Suspends updating the terminal window.
835 */ 835 */
836 static void 836 static void
837 term_enter_terminal_mode(int mode) 837 term_enter_normal_mode(void)
838 { 838 {
839 term_T *term = curbuf->b_term; 839 term_T *term = curbuf->b_term;
840 840
841 /* Append the current terminal contents to the buffer. */ 841 /* Append the current terminal contents to the buffer. */
842 move_terminal_to_buffer(term); 842 move_terminal_to_buffer(term);
843 843
844 set_terminal_mode(term, mode); 844 set_terminal_mode(term, TRUE);
845 845
846 if (mode == TMODE_ONCE) 846 /* Move the window cursor to the position of the cursor in the
847 { 847 * terminal. */
848 /* Move the window cursor to the position of the cursor in the 848 curwin->w_cursor.lnum = term->tl_scrollback_scrolled
849 * terminal. */ 849 + term->tl_cursor_pos.row + 1;
850 curwin->w_cursor.lnum = term->tl_scrollback_scrolled 850 check_cursor();
851 + term->tl_cursor_pos.row + 1; 851 coladvance(term->tl_cursor_pos.col);
852 check_cursor(); 852
853 coladvance(term->tl_cursor_pos.col); 853 /* Display the same lines as in the terminal. */
854 854 curwin->w_topline = term->tl_scrollback_scrolled + 1;
855 /* Display the same lines as in the terminal. */
856 curwin->w_topline = term->tl_scrollback_scrolled + 1;
857 }
858 } 855 }
859 856
860 /* 857 /*
861 * Returns TRUE if the current window contains a terminal and we are in 858 * Returns TRUE if the current window contains a terminal and we are in
862 * Terminal-Normal mode. 859 * Terminal-Normal mode.
863 */ 860 */
864 int 861 int
865 term_in_terminal_mode() 862 term_in_normal_mode(void)
866 { 863 {
867 term_T *term = curbuf->b_term; 864 term_T *term = curbuf->b_term;
868 865
869 return term != NULL && term->tl_terminal_mode != 0; 866 return term != NULL && term->tl_normal_mode;
870 } 867 }
871 868
872 /* 869 /*
873 * Switch from Terminal-Normal mode to Terminal-Job mode. 870 * Switch from Terminal-Normal mode to Terminal-Job mode.
874 * Restores updating the terminal window. 871 * Restores updating the terminal window.
875 */ 872 */
876 void 873 void
877 term_leave_terminal_mode() 874 term_enter_job_mode()
878 { 875 {
879 term_T *term = curbuf->b_term; 876 term_T *term = curbuf->b_term;
880 sb_line_T *line; 877 sb_line_T *line;
881 garray_T *gap; 878 garray_T *gap;
882 879
891 if (gap->ga_len == 0) 888 if (gap->ga_len == 0)
892 break; 889 break;
893 } 890 }
894 check_cursor(); 891 check_cursor();
895 892
896 set_terminal_mode(term, 0); 893 set_terminal_mode(term, FALSE);
897 894
898 if (term->tl_channel_closed) 895 if (term->tl_channel_closed)
899 cleanup_vterm(term); 896 cleanup_vterm(term);
900 redraw_buf_and_status_later(curbuf, NOT_VALID); 897 redraw_buf_and_status_later(curbuf, NOT_VALID);
901 } 898 }
1051 /* 1048 /*
1052 * Returns TRUE if the current window contains a terminal and we are sending 1049 * Returns TRUE if the current window contains a terminal and we are sending
1053 * keys to the job. 1050 * keys to the job.
1054 */ 1051 */
1055 int 1052 int
1056 term_use_loop(int once) 1053 term_use_loop(void)
1057 { 1054 {
1058 term_T *term = curbuf->b_term; 1055 term_T *term = curbuf->b_term;
1059 1056
1060 return term != NULL 1057 return term != NULL
1061 && (once ? term->tl_terminal_mode != TMODE_LOOP 1058 && !term->tl_normal_mode
1062 : term->tl_terminal_mode == 0)
1063 && term->tl_vterm != NULL 1059 && term->tl_vterm != NULL
1064 && term_job_running(term); 1060 && term_job_running(term);
1065 } 1061 }
1066 1062
1067 /* 1063 /*
1075 terminal_loop(void) 1071 terminal_loop(void)
1076 { 1072 {
1077 int c; 1073 int c;
1078 int termkey = 0; 1074 int termkey = 0;
1079 1075
1080 if (curbuf->b_term->tl_terminal_mode != 0)
1081 {
1082 /* Got back from TMODE_ONCE, enter Terminal-Job mode. */
1083 term_leave_terminal_mode();
1084 update_cursor(curbuf->b_term, TRUE);
1085 }
1086
1087 if (*curwin->w_p_tk != NUL) 1076 if (*curwin->w_p_tk != NUL)
1088 termkey = string_to_key(curwin->w_p_tk, TRUE); 1077 termkey = string_to_key(curwin->w_p_tk, TRUE);
1089 position_cursor(curwin, &curbuf->b_term->tl_cursor_pos); 1078 position_cursor(curwin, &curbuf->b_term->tl_cursor_pos);
1090 1079
1091 for (;;) 1080 for (;;)
1095 while (curwin->w_redr_type != 0) 1084 while (curwin->w_redr_type != 0)
1096 update_screen(0); 1085 update_screen(0);
1097 update_cursor(curbuf->b_term, FALSE); 1086 update_cursor(curbuf->b_term, FALSE);
1098 1087
1099 c = term_vgetc(); 1088 c = term_vgetc();
1100 if (!term_use_loop(FALSE)) 1089 if (!term_use_loop())
1101 /* job finished while waiting for a character */ 1090 /* job finished while waiting for a character */
1102 break; 1091 break;
1103 1092
1104 #ifdef UNIX 1093 #ifdef UNIX
1105 may_send_sigint(c, curbuf->b_term->tl_job->jv_pid, 0); 1094 may_send_sigint(c, curbuf->b_term->tl_job->jv_pid, 0);
1122 #endif 1111 #endif
1123 c = term_vgetc(); 1112 c = term_vgetc();
1124 #ifdef FEAT_CMDL_INFO 1113 #ifdef FEAT_CMDL_INFO
1125 clear_showcmd(); 1114 clear_showcmd();
1126 #endif 1115 #endif
1127 if (!term_use_loop(FALSE)) 1116 if (!term_use_loop())
1128 /* job finished while waiting for a character */ 1117 /* job finished while waiting for a character */
1129 break; 1118 break;
1130 1119
1131 if (prev_c == Ctrl_BSL) 1120 if (prev_c == Ctrl_BSL)
1132 { 1121 {
1133 if (c == Ctrl_N) 1122 if (c == Ctrl_N)
1134 { 1123 {
1135 /* CTRL-\ CTRL-N : execute one Normal mode command. */ 1124 /* CTRL-\ CTRL-N : go to Terminal-Normal mode. */
1136 term_enter_terminal_mode(TMODE_ONCE); 1125 term_enter_normal_mode();
1137 return OK; 1126 return FAIL;
1138 } 1127 }
1139 /* Send both keys to the terminal. */ 1128 /* Send both keys to the terminal. */
1140 send_keys_to_term(curbuf->b_term, prev_c, TRUE); 1129 send_keys_to_term(curbuf->b_term, prev_c, TRUE);
1141 } 1130 }
1142 else if (termkey == 0 && c == '.') 1131 else if (termkey == 0 && c == '.')
1144 /* "CTRL-W .": send CTRL-W to the job */ 1133 /* "CTRL-W .": send CTRL-W to the job */
1145 c = Ctrl_W; 1134 c = Ctrl_W;
1146 } 1135 }
1147 else if (c == 'N') 1136 else if (c == 'N')
1148 { 1137 {
1149 term_enter_terminal_mode(TMODE_LOOP); 1138 /* CTRL-W N : go to Terminal-Normal mode. */
1139 term_enter_normal_mode();
1150 return FAIL; 1140 return FAIL;
1151 } 1141 }
1152 else if (c == '"') 1142 else if (c == '"')
1153 { 1143 {
1154 term_paste_register(prev_c); 1144 term_paste_register(prev_c);
1247 FOR_ALL_WINDOWS(wp) 1237 FOR_ALL_WINDOWS(wp)
1248 { 1238 {
1249 if (wp->w_buffer == term->tl_buffer) 1239 if (wp->w_buffer == term->tl_buffer)
1250 position_cursor(wp, &pos); 1240 position_cursor(wp, &pos);
1251 } 1241 }
1252 if (term->tl_buffer == curbuf && term->tl_terminal_mode == 0) 1242 if (term->tl_buffer == curbuf && !term->tl_normal_mode)
1253 { 1243 {
1254 may_toggle_cursor(term); 1244 may_toggle_cursor(term);
1255 update_cursor(term, term->tl_cursor_visible); 1245 update_cursor(term, term->tl_cursor_visible);
1256 } 1246 }
1257 1247
1383 term->tl_title = NULL; 1373 term->tl_title = NULL;
1384 vim_free(term->tl_status_text); 1374 vim_free(term->tl_status_text);
1385 term->tl_status_text = NULL; 1375 term->tl_status_text = NULL;
1386 1376
1387 /* Unless in Terminal-Normal mode: clear the vterm. */ 1377 /* Unless in Terminal-Normal mode: clear the vterm. */
1388 if (term->tl_terminal_mode == 0) 1378 if (!term->tl_normal_mode)
1389 cleanup_vterm(term); 1379 cleanup_vterm(term);
1390 1380
1391 redraw_buf_and_status_later(term->tl_buffer, NOT_VALID); 1381 redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
1392 did_one = TRUE; 1382 did_one = TRUE;
1393 } 1383 }
1571 } 1561 }
1572 return 0; 1562 return 0;
1573 } 1563 }
1574 1564
1575 /* 1565 /*
1576 * Called to update the window that contains a terminal. 1566 * Called to update a window that contains an active terminal.
1577 * Returns FAIL when there is no terminal running in this window. 1567 * Returns FAIL when there is no terminal running in this window or in
1568 * Terminal-Normal mode.
1578 */ 1569 */
1579 int 1570 int
1580 term_update_window(win_T *wp) 1571 term_update_window(win_T *wp)
1581 { 1572 {
1582 term_T *term = wp->w_buffer->b_term; 1573 term_T *term = wp->w_buffer->b_term;
1583 VTerm *vterm; 1574 VTerm *vterm;
1584 VTermScreen *screen; 1575 VTermScreen *screen;
1585 VTermState *state; 1576 VTermState *state;
1586 VTermPos pos; 1577 VTermPos pos;
1587 1578
1588 if (term == NULL || term->tl_vterm == NULL || term->tl_terminal_mode != 0) 1579 if (term == NULL || term->tl_vterm == NULL || term->tl_normal_mode)
1589 return FAIL; 1580 return FAIL;
1590 1581
1591 vterm = term->tl_vterm; 1582 vterm = term->tl_vterm;
1592 screen = vterm_obtain_screen(vterm); 1583 screen = vterm_obtain_screen(vterm);
1593 state = vterm_obtain_state(vterm); 1584 state = vterm_obtain_state(vterm);
1705 return buf->b_term != NULL && buf->b_term->tl_vterm == NULL; 1696 return buf->b_term != NULL && buf->b_term->tl_vterm == NULL;
1706 } 1697 }
1707 1698
1708 /* 1699 /*
1709 * Return TRUE if "wp" is a terminal window where the job has finished or we 1700 * Return TRUE if "wp" is a terminal window where the job has finished or we
1710 * are in Terminal-Normal mode. 1701 * are in Terminal-Normal mode, thus we show the buffer contents.
1711 */ 1702 */
1712 int 1703 int
1713 term_show_buffer(buf_T *buf) 1704 term_show_buffer(buf_T *buf)
1714 { 1705 {
1715 term_T *term = buf->b_term; 1706 term_T *term = buf->b_term;
1716 1707
1717 return term != NULL 1708 return term != NULL && (term->tl_vterm == NULL || term->tl_normal_mode);
1718 && (term->tl_vterm == NULL || term->tl_terminal_mode != 0);
1719 } 1709 }
1720 1710
1721 /* 1711 /*
1722 * The current buffer is going to be changed. If there is terminal 1712 * The current buffer is going to be changed. If there is terminal
1723 * highlighting remove it now. 1713 * highlighting remove it now.
1796 if (term->tl_status_text == NULL) 1786 if (term->tl_status_text == NULL)
1797 { 1787 {
1798 char_u *txt; 1788 char_u *txt;
1799 size_t len; 1789 size_t len;
1800 1790
1801 if (term->tl_terminal_mode != 0) 1791 if (term->tl_normal_mode)
1802 { 1792 {
1803 if (term_job_running(term)) 1793 if (term_job_running(term))
1804 txt = (char_u *)_("Terminal"); 1794 txt = (char_u *)_("Terminal");
1805 else 1795 else
1806 txt = (char_u *)_("Terminal-finished"); 1796 txt = (char_u *)_("Terminal-finished");
2023 2013
2024 if (term_job_running(term)) 2014 if (term_job_running(term))
2025 STRCPY(val, "running"); 2015 STRCPY(val, "running");
2026 else 2016 else
2027 STRCPY(val, "finished"); 2017 STRCPY(val, "finished");
2028 if (term->tl_terminal_mode != 0) 2018 if (term->tl_normal_mode)
2029 STRCAT(val, ",terminal"); 2019 STRCAT(val, ",normal");
2030 rettv->vval.v_string = vim_strsave(val); 2020 rettv->vval.v_string = vim_strsave(val);
2031 } 2021 }
2032 2022
2033 /* 2023 /*
2034 * "term_gettitle(buf)" function 2024 * "term_gettitle(buf)" function
2185 { 2175 {
2186 send_keys_to_term(term, PTR2CHAR(msg), FALSE); 2176 send_keys_to_term(term, PTR2CHAR(msg), FALSE);
2187 msg += MB_PTR2LEN(msg); 2177 msg += MB_PTR2LEN(msg);
2188 } 2178 }
2189 2179
2190 if (term->tl_terminal_mode == 0) 2180 if (!term->tl_normal_mode)
2191 { 2181 {
2192 /* TODO: only update once in a while. */ 2182 /* TODO: only update once in a while. */
2193 update_screen(0); 2183 update_screen(0);
2194 if (buf == curbuf) 2184 if (buf == curbuf)
2195 update_cursor(term, TRUE); 2185 update_cursor(term, TRUE);