Skip to content

Commit 423802d

Browse files
committed
patch 8.0.0813: cannot use a terminal window while the job is running
Problem: Cannot use Vim commands in a terminal window while the job is running. Solution: Implement Terminal Normal mode.
1 parent 68c4bdd commit 423802d

8 files changed

Lines changed: 351 additions & 137 deletions

File tree

runtime/doc/terminal.txt

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*terminal.txt* For Vim version 8.0. Last change: 2017 Jul 28
1+
*terminal.txt* For Vim version 8.0. Last change: 2017 Jul 30
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -33,24 +33,39 @@ Or to run a debugger: >
3333
The job runs asynchronously from Vim, the window will be updated to show
3434
output from the job, also while editing in any other window.
3535

36+
3637
Typing ~
3738

3839
When the keyboard focus is in the terminal window, typed keys will be send to
3940
the job. This uses a pty when possible. You can click outside of the
4041
terminal window to move keyboard focus elsewhere.
4142

42-
Navigate between windows with CTRL-W commands. E.g. CTRL-W CTRL-W moves focus
43-
to the next window. Use "CTRL-W :" to edit an Ex command. Use "CTRL-W ." to
44-
send a CTRL-W to the job in the terminal.
43+
CTRL-W can be used to navigate between windows and other CTRL-W commands, e.g.:
44+
CTRL-W CTRL-W move focus to the next window
45+
CTRL-W : enter an Ex command
46+
See |CTRL-W| for more commands.
47+
48+
Special in the terminal window: *CTRL-W_.* *CTRL-W_N*
49+
CTRL-W . send a CTRL-W to the job in the terminal
50+
CTRL-W N go to Terminal Normal mode, see |Terminal-mode|
51+
52+
See option 'termkey' for specifying another key instead of CTRL-W that
53+
will work like CTRL-W. However, typing 'termkey' twice sends 'termkey' to
54+
the job. For example:
55+
'termkey' CTRL-W move focus to the next window
56+
'termkey' : enter an Ex command
57+
'termkey' 'termkey' send 'termkey' to the job in the terminal
58+
'termkey' . send a CTRL-W to the job in the terminal
59+
'termkey' N go to terminal Normal mode, see below
60+
'termkey' CTRL-N same as CTRL-W N
4561

46-
See option 'termkey' for specifying another key that precedes a Vim command.
47-
Typing 'termkey' twice sends 'termkey' to the job.
4862

4963
Size ~
5064

5165
See option 'termsize' for controlling the size of the terminal window.
5266
(TODO: scrolling when the terminal is larger than the window)
5367

68+
5469
Syntax ~
5570

5671
:ter[minal] [command] *:ter* *:terminal*
@@ -99,6 +114,25 @@ terminal. |term_setsize()| can be used only when in the first or second mode,
99114
not when 'termsize' is "rowsXcols".
100115

101116

117+
Terminal Normal mode ~
118+
*Terminal-mode*
119+
When the job is running the contents of the terminal is under control of the
120+
job. That includes the cursor position. The terminal contents can change at
121+
any time.
122+
123+
Use CTRL-W N (or 'termkey' N) to go to Terminal Normal mode. Now the contents
124+
of the terminal window is under control of Vim, the job output is suspended.
125+
*E946*
126+
In this mode you can move the cursor around with the usual Vim commands,
127+
Visually mark text, yank text, etc. But you cannot change the contents of the
128+
buffer. The commands that would start insert mode, such as 'i' and 'a',
129+
return control of the window to the job. Any pending output will now be
130+
displayed.
131+
132+
In Terminal mode the statusline and window title show "(Terminal)". If the
133+
job ends while in Terminal mode this changes to "(Terminal-finished)".
134+
135+
102136
Unix ~
103137

104138
On Unix a pty is used to make it possible to run all kinds of commands. You

src/main.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1356,11 +1356,17 @@ main_loop(
13561356
else
13571357
{
13581358
#ifdef FEAT_TERMINAL
1359-
if (curbuf->b_term != NULL && oa.op_type == OP_NOP
1360-
&& oa.regname == NUL)
1361-
terminal_loop();
1359+
if (term_use_loop() && oa.op_type == OP_NOP && oa.regname == NUL)
1360+
{
1361+
/* If terminal_loop() returns OK we got a key that is handled
1362+
* in Normal model. With FAIL the terminal was closed and the
1363+
* screen needs to be redrawn. */
1364+
if (terminal_loop() == OK)
1365+
normal_cmd(&oa, TRUE);
1366+
}
1367+
else
13621368
#endif
1363-
normal_cmd(&oa, TRUE);
1369+
normal_cmd(&oa, TRUE);
13641370
}
13651371
}
13661372
}

src/normal.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9037,6 +9037,14 @@ nv_esc(cmdarg_T *cap)
90379037
static void
90389038
nv_edit(cmdarg_T *cap)
90399039
{
9040+
#ifdef FEAT_TERMINAL
9041+
if (term_in_terminal_mode())
9042+
{
9043+
term_leave_terminal_mode();
9044+
return;
9045+
}
9046+
#endif
9047+
90409048
/* <Insert> is equal to "i" */
90419049
if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS)
90429050
cap->cmdchar = 'i';

src/option.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8222,12 +8222,22 @@ set_bool_option(
82228222
}
82238223
#endif
82248224

8225-
#ifdef FEAT_TITLE
82268225
/* when 'modifiable' is changed, redraw the window title */
82278226
else if ((int *)varp == &curbuf->b_p_ma)
82288227
{
8228+
# ifdef FEAT_TERMINAL
8229+
/* Cannot set 'modifiable' when in Terminal mode. */
8230+
if (term_in_terminal_mode())
8231+
{
8232+
curbuf->b_p_ma = FALSE;
8233+
return (char_u *)N_("E946: Cannot make a terminal with running job modifiable");
8234+
}
8235+
# endif
8236+
# ifdef FEAT_TITLE
82298237
redraw_titles();
8238+
# endif
82308239
}
8240+
#ifdef FEAT_TITLE
82318241
/* when 'endofline' is changed, redraw the window title */
82328242
else if ((int *)varp == &curbuf->b_p_eol)
82338243
{

src/proto/terminal.pro

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
void ex_terminal(exarg_T *eap);
33
void free_terminal(buf_T *buf);
44
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
5+
int term_in_terminal_mode(void);
6+
void term_leave_terminal_mode(void);
7+
int term_use_loop(void);
58
int terminal_loop(void);
69
void term_job_ended(job_T *job);
710
void term_channel_closed(channel_T *ch);
811
int term_update_window(win_T *wp);
912
int term_is_finished(buf_T *buf);
13+
int term_show_buffer(buf_T *buf);
1014
void term_change_in_curbuf(void);
1115
int term_get_attr(buf_T *buf, linenr_T lnum, int col);
1216
char_u *term_get_status_text(term_T *term);
@@ -16,8 +20,8 @@ void f_term_getjob(typval_T *argvars, typval_T *rettv);
1620
void f_term_getline(typval_T *argvars, typval_T *rettv);
1721
void f_term_getsize(typval_T *argvars, typval_T *rettv);
1822
void f_term_list(typval_T *argvars, typval_T *rettv);
19-
void f_term_start(typval_T *argvars, typval_T *rettv);
2023
void f_term_scrape(typval_T *argvars, typval_T *rettv);
2124
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
25+
void f_term_start(typval_T *argvars, typval_T *rettv);
2226
void f_term_wait(typval_T *argvars, typval_T *rettv);
2327
/* vim: set ft=c : */

src/screen.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3245,7 +3245,7 @@ win_line(
32453245
#endif
32463246

32473247
#ifdef FEAT_TERMINAL
3248-
if (term_is_finished(wp->w_buffer))
3248+
if (term_show_buffer(wp->w_buffer))
32493249
{
32503250
extra_check = TRUE;
32513251
get_term_attr = TRUE;

0 commit comments

Comments
 (0)