# HG changeset patch # User Christian Brabandt # Date 1501957803 -7200 # Node ID d036c1c8537dd643933f38f73f5c273a78f1cf5b # Parent 829a855d3204129e6f58cf55e06ef2abd62fb095 patch 8.0.0873: in terminal cannot use CTRL- CTRL-N to start Visual mode commit https://github.com/vim/vim/commit/aaa8a35fbd38d5e6cc57ae60a8477e787d695a20 Author: Bram Moolenaar Date: Sat Aug 5 20:17:00 2017 +0200 patch 8.0.0873: in terminal cannot use CTRL-\ CTRL-N to start Visual mode Problem: In a terminal window cannot use CTRL-\ CTRL-N to start Visual mode. Solution: After CTRL-\ CTRL-N enter Terminal-Normal mode for one command. diff --git a/src/main.c b/src/main.c --- a/src/main.c +++ b/src/main.c @@ -1356,7 +1356,9 @@ main_loop( else { #ifdef FEAT_TERMINAL - if (term_use_loop() && oa.op_type == OP_NOP && oa.regname == NUL) + if (term_use_loop(TRUE) + && oa.op_type == OP_NOP && oa.regname == NUL + && !VIsual_active) { /* If terminal_loop() returns OK we got a key that is handled * in Normal model. With FAIL the terminal was closed and the diff --git a/src/proto/terminal.pro b/src/proto/terminal.pro --- a/src/proto/terminal.pro +++ b/src/proto/terminal.pro @@ -6,7 +6,7 @@ int term_job_running(term_T *term); int term_in_terminal_mode(void); void term_leave_terminal_mode(void); int send_keys_to_term(term_T *term, int c, int typed); -int term_use_loop(void); +int term_use_loop(int once); int terminal_loop(void); void term_job_ended(job_T *job); void term_channel_closed(channel_T *ch); diff --git a/src/terminal.c b/src/terminal.c --- a/src/terminal.c +++ b/src/terminal.c @@ -115,7 +115,7 @@ struct terminal_S { int tl_tty_fd; char_u *tl_tty_name; - int tl_terminal_mode; + int tl_terminal_mode; /* 0, TMODE_ONCE or TMODE_LOOP */ int tl_channel_closed; #ifdef WIN3264 @@ -144,6 +144,9 @@ struct terminal_S { int tl_cursor_visible; }; +#define TMODE_ONCE 1 /* CTRL-\ CTRL-N used */ +#define TMODE_LOOP 2 /* CTRL-W N used */ + /* * List of all active terminals. */ @@ -459,7 +462,7 @@ term_write_job_output(term_T *term, char static void update_cursor(term_T *term, int redraw) { - if (term->tl_terminal_mode) + if (term->tl_terminal_mode != 0) return; setcursor(); if (redraw && term->tl_buffer == curbuf) @@ -492,7 +495,7 @@ write_to_term(buf_T *buffer, char_u *msg ch_log(channel, "writing %d bytes to terminal", (int)len); term_write_job_output(term, msg, len); - if (!term->tl_terminal_mode) + if (term->tl_terminal_mode == 0) { /* TODO: only update once in a while. */ update_screen(0); @@ -805,9 +808,9 @@ move_terminal_to_buffer(term_T *term) } static void -set_terminal_mode(term_T *term, int on) +set_terminal_mode(term_T *term, int mode) { - term->tl_terminal_mode = on; + term->tl_terminal_mode = mode; vim_free(term->tl_status_text); term->tl_status_text = NULL; if (term->tl_buffer == curbuf) @@ -823,22 +826,35 @@ cleanup_vterm(term_T *term) { move_terminal_to_buffer(term); term_free_vterm(term); - set_terminal_mode(term, FALSE); + set_terminal_mode(term, 0); } /* - * Switch from sending keys to the job to Terminal-Normal mode. + * Switch from Terminal-Job mode to Terminal-Normal mode. * Suspends updating the terminal window. */ static void -term_enter_terminal_mode() +term_enter_terminal_mode(int mode) { term_T *term = curbuf->b_term; /* Append the current terminal contents to the buffer. */ move_terminal_to_buffer(term); - set_terminal_mode(term, TRUE); + set_terminal_mode(term, mode); + + if (mode == TMODE_ONCE) + { + /* Move the window cursor to the position of the cursor in the + * terminal. */ + curwin->w_cursor.lnum = term->tl_scrollback_scrolled + + term->tl_cursor_pos.row + 1; + check_cursor(); + coladvance(term->tl_cursor_pos.col); + + /* Display the same lines as in the terminal. */ + curwin->w_topline = term->tl_scrollback_scrolled + 1; + } } /* @@ -850,11 +866,11 @@ term_in_terminal_mode() { term_T *term = curbuf->b_term; - return term != NULL && term->tl_terminal_mode; + return term != NULL && term->tl_terminal_mode != 0; } /* - * Switch from Terminal-Normal mode to sending keys to the job. + * Switch from Terminal-Normal mode to Terminal-Job mode. * Restores updating the terminal window. */ void @@ -877,7 +893,7 @@ term_leave_terminal_mode() } check_cursor(); - set_terminal_mode(term, FALSE); + set_terminal_mode(term, 0); if (term->tl_channel_closed) cleanup_vterm(term); @@ -1037,12 +1053,13 @@ term_paste_register(int prev_c UNUSED) * keys to the job. */ int -term_use_loop() +term_use_loop(int once) { term_T *term = curbuf->b_term; return term != NULL - && !term->tl_terminal_mode + && (once ? term->tl_terminal_mode != TMODE_LOOP + : term->tl_terminal_mode == 0) && term->tl_vterm != NULL && term_job_running(term); } @@ -1060,6 +1077,13 @@ terminal_loop(void) int c; int termkey = 0; + if (curbuf->b_term->tl_terminal_mode != 0) + { + /* Got back from TMODE_ONCE, enter Terminal-Job mode. */ + term_leave_terminal_mode(); + update_cursor(curbuf->b_term, TRUE); + } + if (*curwin->w_p_tk != NUL) termkey = string_to_key(curwin->w_p_tk, TRUE); position_cursor(curwin, &curbuf->b_term->tl_cursor_pos); @@ -1073,7 +1097,7 @@ terminal_loop(void) update_cursor(curbuf->b_term, FALSE); c = term_vgetc(); - if (!term_use_loop()) + if (!term_use_loop(FALSE)) /* job finished while waiting for a character */ break; @@ -1100,15 +1124,18 @@ terminal_loop(void) #ifdef FEAT_CMDL_INFO clear_showcmd(); #endif - if (!term_use_loop()) + if (!term_use_loop(FALSE)) /* job finished while waiting for a character */ break; if (prev_c == Ctrl_BSL) { if (c == Ctrl_N) + { /* CTRL-\ CTRL-N : execute one Normal mode command. */ + term_enter_terminal_mode(TMODE_ONCE); return OK; + } /* Send both keys to the terminal. */ send_keys_to_term(curbuf->b_term, prev_c, TRUE); } @@ -1119,7 +1146,7 @@ terminal_loop(void) } else if (c == 'N') { - term_enter_terminal_mode(); + term_enter_terminal_mode(TMODE_LOOP); return FAIL; } else if (c == '"') @@ -1222,7 +1249,7 @@ handle_movecursor( if (wp->w_buffer == term->tl_buffer) position_cursor(wp, &pos); } - if (term->tl_buffer == curbuf && !term->tl_terminal_mode) + if (term->tl_buffer == curbuf && term->tl_terminal_mode == 0) { may_toggle_cursor(term); update_cursor(term, term->tl_cursor_visible); @@ -1358,7 +1385,7 @@ term_channel_closed(channel_T *ch) term->tl_status_text = NULL; /* Unless in Terminal-Normal mode: clear the vterm. */ - if (!term->tl_terminal_mode) + if (term->tl_terminal_mode == 0) cleanup_vterm(term); redraw_buf_and_status_later(term->tl_buffer, NOT_VALID); @@ -1558,7 +1585,7 @@ term_update_window(win_T *wp) VTermState *state; VTermPos pos; - if (term == NULL || term->tl_vterm == NULL || term->tl_terminal_mode) + if (term == NULL || term->tl_vterm == NULL || term->tl_terminal_mode != 0) return FAIL; vterm = term->tl_vterm; @@ -1687,7 +1714,8 @@ term_show_buffer(buf_T *buf) { term_T *term = buf->b_term; - return term != NULL && (term->tl_vterm == NULL || term->tl_terminal_mode); + return term != NULL + && (term->tl_vterm == NULL || term->tl_terminal_mode != 0); } /* @@ -1770,7 +1798,7 @@ term_get_status_text(term_T *term) char_u *txt; size_t len; - if (term->tl_terminal_mode) + if (term->tl_terminal_mode != 0) { if (term_job_running(term)) txt = (char_u *)_("Terminal"); @@ -1997,7 +2025,7 @@ f_term_getstatus(typval_T *argvars, typv STRCPY(val, "running"); else STRCPY(val, "finished"); - if (term->tl_terminal_mode) + if (term->tl_terminal_mode != 0) STRCAT(val, ",terminal"); rettv->vval.v_string = vim_strsave(val); } @@ -2159,7 +2187,7 @@ f_term_sendkeys(typval_T *argvars, typva msg += MB_PTR2LEN(msg); } - if (!term->tl_terminal_mode) + if (term->tl_terminal_mode == 0) { /* TODO: only update once in a while. */ update_screen(0); diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -770,6 +770,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 873, +/**/ 872, /**/ 871,