Patch 8.0.0813
Problem: Cannot use Vim commands in a terminal window while the job is
running.
Solution: Implement Terminal Normal mode.
Files: src/terminal.c, src/proto/terminal.pro, src/main.c, src/screen.c,
src/normal.c, src/option.c, runtime/doc/terminal.txt
*** ../vim-8.0.0812/src/terminal.c 2017-07-29 22:23:35.170665661 +0200
--- src/terminal.c 2017-07-30 16:49:16.171156264 +0200
***************
*** 36,48 ****
* that buffer, attributes come from the scrollback buffer tl_scrollback.
*
* TODO:
* - For the scrollback buffer store lines in the buffer, only attributes in
* tl_scrollback.
* - When the job ends:
* - Need an option or argument to drop the window+buffer right away, to be
! * used for a shell or Vim.
* - To set BS correctly, check get_stty(); Pass the fd of the pty.
! * - do not store terminal buffer in viminfo. Or prefix term:// ?
* - add a character in :ls output
* - when closing window and job has not ended, make terminal hidden?
* - when closing window and job has ended, make buffer hidden?
--- 36,58 ----
* that buffer, attributes come from the scrollback buffer tl_scrollback.
*
* TODO:
+ * - Problem with statusline (Zyx, Christian)
+ * - Make CTRL-W "" paste register content to the job?
+ * - in bash mouse clicks are inserting characters.
+ * - mouse scroll: when over other window, scroll that window.
* - For the scrollback buffer store lines in the buffer, only attributes in
* tl_scrollback.
+ * - Add term_status(): "" if not a terminal, "running" if job running,
+ * "finished" if finished, "running,vim" when job is running and in
+ * Terminal mode, "running,vim,pending" when job output is pending.
* - When the job ends:
* - Need an option or argument to drop the window+buffer right away, to be
! * used for a shell or Vim. 'termfinish'; "close", "open" (open window
when
! * job finishes).
! * - add option values to the command:
! * :term <24x80> <close> vim notes.txt
* - To set BS correctly, check get_stty(); Pass the fd of the pty.
! * - do not store terminal window in viminfo. Or prefix term:// ?
* - add a character in :ls output
* - when closing window and job has not ended, make terminal hidden?
* - when closing window and job has ended, make buffer hidden?
***************
*** 53,58 ****
--- 63,70 ----
* - support minimal size when 'termsize' is empty?
* - implement "term" for job_start(): more job options when starting a
* terminal.
+ * - if the job in the terminal does not support the mouse, we can use the
+ * mouse in the Terminal window for copy/paste.
* - when 'encoding' is not utf-8, or the job is using another encoding, setup
* conversions.
* - In the GUI use a terminal emulator for :!cmd.
***************
*** 78,90 ****
struct terminal_S {
term_T *tl_next;
#ifdef WIN3264
void *tl_winpty_config;
void *tl_winpty;
#endif
- VTerm *tl_vterm;
- job_T *tl_job;
- buf_T *tl_buffer;
/* last known vterm size */
int tl_rows;
--- 90,106 ----
struct terminal_S {
term_T *tl_next;
+ VTerm *tl_vterm;
+ job_T *tl_job;
+ buf_T *tl_buffer;
+
+ int tl_terminal_mode;
+ int tl_channel_closed;
+
#ifdef WIN3264
void *tl_winpty_config;
void *tl_winpty;
#endif
/* last known vterm size */
int tl_rows;
***************
*** 553,558 ****
--- 569,773 ----
}
/*
+ * Add the last line of the scrollback buffer to the buffer in the window.
+ */
+ static void
+ add_scrollback_line_to_buffer(term_T *term)
+ {
+ linenr_T lnum = term->tl_scrollback.ga_len - 1;
+ sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data + lnum;
+ garray_T ga;
+ int c;
+ int col;
+ int i;
+
+ ga_init2(&ga, 1, 100);
+ for (col = 0; col < line->sb_cols; col += line->sb_cells[col].width)
+ {
+ if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
+ goto failed;
+ for (i = 0; (c = line->sb_cells[col].chars[i]) > 0 || i == 0; ++i)
+ ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c,
+ (char_u *)ga.ga_data + ga.ga_len);
+ }
+ if (ga_grow(&ga, 1) == FAIL)
+ goto failed;
+ *((char_u *)ga.ga_data + ga.ga_len) = NUL;
+ ml_append_buf(term->tl_buffer, lnum, ga.ga_data, ga.ga_len + 1, FALSE);
+
+ if (lnum == 0)
+ {
+ /* Delete the empty line that was in the empty buffer. */
+ curbuf = term->tl_buffer;
+ ml_delete(2, FALSE);
+ curbuf = curwin->w_buffer;
+ }
+
+ failed:
+ ga_clear(&ga);
+ }
+
+ /*
+ * Add the current lines of the terminal to scrollback and to the buffer.
+ * Called after the job has ended and when switching to Terminal mode.
+ */
+ static void
+ move_terminal_to_buffer(term_T *term)
+ {
+ win_T *wp;
+ int len;
+ int lines_skipped = 0;
+ VTermPos pos;
+ VTermScreenCell cell;
+ VTermScreenCell *p;
+ VTermScreen *screen = vterm_obtain_screen(term->tl_vterm);
+
+ for (pos.row = 0; pos.row < term->tl_rows; ++pos.row)
+ {
+ len = 0;
+ for (pos.col = 0; pos.col < term->tl_cols; ++pos.col)
+ if (vterm_screen_get_cell(screen, pos, &cell) != 0
+ && cell.chars[0] != NUL)
+ len = pos.col + 1;
+
+ if (len == 0)
+ ++lines_skipped;
+ else
+ {
+ while (lines_skipped > 0)
+ {
+ /* Line was skipped, add an empty line. */
+ --lines_skipped;
+ if (ga_grow(&term->tl_scrollback, 1) == OK)
+ {
+ sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+ + term->tl_scrollback.ga_len;
+
+ line->sb_cols = 0;
+ line->sb_cells = NULL;
+ ++term->tl_scrollback.ga_len;
+
+ add_scrollback_line_to_buffer(term);
+ }
+ }
+
+ p = (VTermScreenCell *)alloc((int)sizeof(VTermScreenCell) * len);
+ if (p != NULL && ga_grow(&term->tl_scrollback, 1) == OK)
+ {
+ sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
+ + term->tl_scrollback.ga_len;
+
+ for (pos.col = 0; pos.col < len; ++pos.col)
+ {
+ if (vterm_screen_get_cell(screen, pos, &cell) == 0)
+ vim_memset(p + pos.col, 0, sizeof(cell));
+ else
+ p[pos.col] = cell;
+ }
+ line->sb_cols = len;
+ line->sb_cells = p;
+ ++term->tl_scrollback.ga_len;
+
+ add_scrollback_line_to_buffer(term);
+ }
+ else
+ vim_free(p);
+ }
+ }
+
+ FOR_ALL_WINDOWS(wp)
+ {
+ if (wp->w_buffer == term->tl_buffer)
+ {
+ wp->w_cursor.lnum = term->tl_buffer->b_ml.ml_line_count;
+ wp->w_cursor.col = 0;
+ wp->w_valid = 0;
+ redraw_win_later(wp, NOT_VALID);
+ }
+ }
+ }
+
+ static void
+ set_terminal_mode(term_T *term, int on)
+ {
+ term->tl_terminal_mode = on;
+ vim_free(term->tl_status_text);
+ term->tl_status_text = NULL;
+ if (term->tl_buffer == curbuf)
+ maketitle();
+ }
+
+ /*
+ * Called after the job if finished and Terminal mode is not active:
+ * Move the vterm contents into the scrollback buffer and free the vterm.
+ */
+ static void
+ cleanup_vterm(term_T *term)
+ {
+ move_terminal_to_buffer(term);
+ term_free_vterm(term);
+ set_terminal_mode(term, FALSE);
+ }
+
+ /*
+ * Switch from sending keys to the job to Terminal-Normal mode.
+ * Suspends updating the terminal window.
+ */
+ static void
+ term_enter_terminal_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);
+ }
+
+ /*
+ * Returns TRUE if the current window contains a terminal and we are in
+ * Terminal-Normal mode.
+ */
+ int
+ term_in_terminal_mode()
+ {
+ term_T *term = curbuf->b_term;
+
+ return term != NULL && term->tl_terminal_mode;
+ }
+
+ /*
+ * Switch from Terminal-Normal mode to sending keys to the job.
+ * Restores updating the terminal window.
+ */
+ void
+ term_leave_terminal_mode()
+ {
+ term_T *term = curbuf->b_term;
+ sb_line_T *line;
+ garray_T *gap;
+
+ /* Remove the terminal contents from the scrollback and the buffer. */
+ gap = &term->tl_scrollback;
+ while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled)
+ {
+ ml_delete(curbuf->b_ml.ml_line_count, FALSE);
+ line = (sb_line_T *)gap->ga_data + gap->ga_len - 1;
+ vim_free(line->sb_cells);
+ --gap->ga_len;
+ if (gap->ga_len == 0)
+ break;
+ }
+ check_cursor();
+
+ set_terminal_mode(term, FALSE);
+
+ if (term->tl_channel_closed)
+ cleanup_vterm(term);
+ redraw_buf_and_status_later(curbuf, NOT_VALID);
+ }
+
+ /*
* Get a key from the user without mapping.
* TODO: use terminal mode mappings.
*/
***************
*** 641,646 ****
--- 856,876 ----
}
/*
+ * Returns TRUE if the current window contains a terminal and we are sending
+ * keys to the job.
+ */
+ int
+ term_use_loop()
+ {
+ term_T *term = curbuf->b_term;
+
+ return term != NULL
+ && !term->tl_terminal_mode
+ && term->tl_vterm != NULL
+ && term_job_running(term);
+ }
+
+ /*
* Wait for input and send it to the job.
* Return when the start of a CTRL-W command is typed or anything else that
* should be handled as a Normal mode command.
***************
*** 653,662 ****
int c;
int termkey = 0;
- if (curbuf->b_term->tl_vterm == NULL || !term_job_running(curbuf->b_term))
- /* job finished */
- return OK;
-
if (*curwin->w_p_tk != NUL)
termkey = string_to_key(curwin->w_p_tk, TRUE);
--- 883,888 ----
***************
*** 665,670 ****
--- 891,897 ----
/* TODO: skip screen update when handling a sequence of keys. */
update_screen(0);
update_cursor(curbuf->b_term, FALSE);
+
c = term_vgetc();
if (curbuf->b_term->tl_vterm == NULL
|| !term_job_running(curbuf->b_term))
***************
*** 687,694 ****
--- 914,928 ----
break;
if (termkey == 0 && c == '.')
+ {
/* "CTRL-W .": send CTRL-W to the job */
c = Ctrl_W;
+ }
+ else if (termkey == 0 && c == 'N')
+ {
+ term_enter_terminal_mode();
+ return FAIL;
+ }
else if (termkey == 0 || c != termkey)
{
stuffcharReadbuff(Ctrl_W);
***************
*** 704,709 ****
--- 938,945 ----
/*
* Called when a job has finished.
+ * This updates the title and status, but does not close the vter, because
+ * there might still be pending output in the channel.
*/
void
term_job_ended(job_T *job)
***************
*** 891,1008 ****
line->sb_cells = p;
++term->tl_scrollback.ga_len;
++term->tl_scrollback_scrolled;
- }
- return 0; /* ignored */
- }
-
- /*
- * Fill the buffer with the scrollback lines and current lines of the
terminal.
- * Called after the job has ended.
- */
- static void
- move_scrollback_to_buffer(term_T *term)
- {
- linenr_T lnum;
- garray_T ga;
- int c;
- int col;
- int i;
- win_T *wp;
- int len;
- int lines_skipped = 0;
- VTermPos pos;
- VTermScreenCell cell;
- VTermScreenCell *p;
- VTermScreen *screen = vterm_obtain_screen(term->tl_vterm);
-
- /* Append the the visible lines to the scrollback. */
- for (pos.row = 0; pos.row < term->tl_rows; ++pos.row)
- {
- len = 0;
- for (pos.col = 0; pos.col < term->tl_cols; ++pos.col)
- if (vterm_screen_get_cell(screen, pos, &cell) != 0
- && cell.chars[0] != NUL)
- len = pos.col + 1;
-
- if (len == 0)
- ++lines_skipped;
- else
- {
- while (lines_skipped > 0)
- {
- /* Line was skipped, add an empty line. */
- --lines_skipped;
- if (ga_grow(&term->tl_scrollback, 1) == OK)
- {
- sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
- + term->tl_scrollback.ga_len;
-
- line->sb_cols = 0;
- line->sb_cells = NULL;
- ++term->tl_scrollback.ga_len;
- }
- }
-
- p = (VTermScreenCell *)alloc((int)sizeof(VTermScreenCell) * len);
- if (p != NULL && ga_grow(&term->tl_scrollback, 1) == OK)
- {
- sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data
- + term->tl_scrollback.ga_len;
-
- for (pos.col = 0; pos.col < len; ++pos.col)
- {
- if (vterm_screen_get_cell(screen, pos, &cell) == 0)
- vim_memset(p + pos.col, 0, sizeof(cell));
- else
- p[pos.col] = cell;
- }
- line->sb_cols = len;
- line->sb_cells = p;
- ++term->tl_scrollback.ga_len;
- }
- else
- vim_free(p);
- }
- }
-
- /* Add the text to the buffer. */
- ga_init2(&ga, 1, 100);
- for (lnum = 0; lnum < term->tl_scrollback.ga_len; ++lnum)
- {
- sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data + lnum;
-
- ga.ga_len = 0;
- for (col = 0; col < line->sb_cols; ++col)
- {
- if (ga_grow(&ga, MB_MAXBYTES) == FAIL)
- goto failed;
- for (i = 0; (c = line->sb_cells[col].chars[i]) > 0 || i == 0; ++i)
- ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c,
- (char_u *)ga.ga_data + ga.ga_len);
- }
- if (ga_grow(&ga, 1) == FAIL)
- goto failed;
- *((char_u *)ga.ga_data + ga.ga_len) = NUL;
- ml_append_buf(term->tl_buffer, lnum, ga.ga_data, ga.ga_len + 1, FALSE);
- }
-
- /* Delete the empty line that was in the empty buffer. */
- curbuf = term->tl_buffer;
- ml_delete(lnum + 1, FALSE);
- curbuf = curwin->w_buffer;
-
- failed:
- ga_clear(&ga);
! FOR_ALL_WINDOWS(wp)
! {
! if (wp->w_buffer == term->tl_buffer)
! {
! wp->w_cursor.lnum = term->tl_buffer->b_ml.ml_line_count;
! wp->w_cursor.col = 0;
! wp->w_valid = 0;
! }
}
}
static VTermScreenCallbacks screen_callbacks = {
--- 1127,1136 ----
line->sb_cells = p;
++term->tl_scrollback.ga_len;
++term->tl_scrollback_scrolled;
! add_scrollback_line_to_buffer(term);
}
+ return 0; /* ignored */
}
static VTermScreenCallbacks screen_callbacks = {
***************
*** 1029,1042 ****
for (term = first_term; term != NULL; term = term->tl_next)
if (term->tl_job == ch->ch_job)
{
vim_free(term->tl_title);
term->tl_title = NULL;
vim_free(term->tl_status_text);
term->tl_status_text = NULL;
! /* move the lines into the buffer and free the vterm */
! move_scrollback_to_buffer(term);
! term_free_vterm(term);
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
did_one = TRUE;
--- 1157,1172 ----
for (term = first_term; term != NULL; term = term->tl_next)
if (term->tl_job == ch->ch_job)
{
+ term->tl_channel_closed = TRUE;
+
vim_free(term->tl_title);
term->tl_title = NULL;
vim_free(term->tl_status_text);
term->tl_status_text = NULL;
! /* Unless in Terminal-Normal mode: clear the vterm. */
! if (!term->tl_terminal_mode)
! cleanup_vterm(term);
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
did_one = TRUE;
***************
*** 1227,1234 ****
VTermState *state;
VTermPos pos;
! if (term == NULL || term->tl_vterm == NULL)
return FAIL;
vterm = term->tl_vterm;
screen = vterm_obtain_screen(vterm);
state = vterm_obtain_state(vterm);
--- 1357,1365 ----
VTermState *state;
VTermPos pos;
! if (term == NULL || term->tl_vterm == NULL || term->tl_terminal_mode)
return FAIL;
+
vterm = term->tl_vterm;
screen = vterm_obtain_screen(vterm);
state = vterm_obtain_state(vterm);
***************
*** 1347,1352 ****
--- 1478,1495 ----
}
/*
+ * Return TRUE if "wp" is a terminal window where the job has finished or we
+ * are in Terminal-Normal mode.
+ */
+ int
+ term_show_buffer(buf_T *buf)
+ {
+ term_T *term = buf->b_term;
+
+ return term != NULL && (term->tl_vterm == NULL || term->tl_terminal_mode);
+ }
+
+ /*
* The current buffer is going to be changed. If there is terminal
* highlighting remove it now.
*/
***************
*** 1450,1456 ****
char_u *txt;
size_t len;
! if (term->tl_title != NULL)
txt = term->tl_title;
else if (term_job_running(term))
txt = (char_u *)_("running");
--- 1593,1606 ----
char_u *txt;
size_t len;
! if (term->tl_terminal_mode)
! {
! if (term_job_running(term))
! txt = (char_u *)_("Terminal");
! else
! txt = (char_u *)_("Terminal-finished");
! }
! else if (term->tl_title != NULL)
txt = term->tl_title;
else if (term_job_running(term))
txt = (char_u *)_("running");
*** ../vim-8.0.0812/src/proto/terminal.pro 2017-07-29 20:07:00.764940487
+0200
--- src/proto/terminal.pro 2017-07-30 15:59:29.864818283 +0200
***************
*** 2,12 ****
--- 2,16 ----
void ex_terminal(exarg_T *eap);
void free_terminal(buf_T *buf);
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
+ int term_in_terminal_mode(void);
+ void term_leave_terminal_mode(void);
+ int term_use_loop(void);
int terminal_loop(void);
void term_job_ended(job_T *job);
void term_channel_closed(channel_T *ch);
int term_update_window(win_T *wp);
int term_is_finished(buf_T *buf);
+ int term_show_buffer(buf_T *buf);
void term_change_in_curbuf(void);
int term_get_attr(buf_T *buf, linenr_T lnum, int col);
char_u *term_get_status_text(term_T *term);
***************
*** 16,23 ****
void f_term_getline(typval_T *argvars, typval_T *rettv);
void f_term_getsize(typval_T *argvars, typval_T *rettv);
void f_term_list(typval_T *argvars, typval_T *rettv);
- void f_term_start(typval_T *argvars, typval_T *rettv);
void f_term_scrape(typval_T *argvars, typval_T *rettv);
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
void f_term_wait(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
--- 20,27 ----
void f_term_getline(typval_T *argvars, typval_T *rettv);
void f_term_getsize(typval_T *argvars, typval_T *rettv);
void f_term_list(typval_T *argvars, typval_T *rettv);
void f_term_scrape(typval_T *argvars, typval_T *rettv);
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
+ void f_term_start(typval_T *argvars, typval_T *rettv);
void f_term_wait(typval_T *argvars, typval_T *rettv);
/* vim: set ft=c : */
*** ../vim-8.0.0812/src/main.c 2017-07-16 20:13:22.265843572 +0200
--- src/main.c 2017-07-30 15:47:01.714210944 +0200
***************
*** 1356,1366 ****
else
{
#ifdef FEAT_TERMINAL
! if (curbuf->b_term != NULL && oa.op_type == OP_NOP
! && oa.regname == NUL)
! terminal_loop();
#endif
! normal_cmd(&oa, TRUE);
}
}
}
--- 1356,1372 ----
else
{
#ifdef FEAT_TERMINAL
! if (term_use_loop() && oa.op_type == OP_NOP && oa.regname == NUL)
! {
! /* If terminal_loop() returns OK we got a key that is handled
! * in Normal model. With FAIL the terminal was closed and the
! * screen needs to be redrawn. */
! if (terminal_loop() == OK)
! normal_cmd(&oa, TRUE);
! }
! else
#endif
! normal_cmd(&oa, TRUE);
}
}
}
*** ../vim-8.0.0812/src/screen.c 2017-07-30 13:57:37.616783276 +0200
--- src/screen.c 2017-07-30 15:43:01.783920068 +0200
***************
*** 3245,3251 ****
#endif
#ifdef FEAT_TERMINAL
! if (term_is_finished(wp->w_buffer))
{
extra_check = TRUE;
get_term_attr = TRUE;
--- 3245,3251 ----
#endif
#ifdef FEAT_TERMINAL
! if (term_show_buffer(wp->w_buffer))
{
extra_check = TRUE;
get_term_attr = TRUE;
*** ../vim-8.0.0812/src/normal.c 2017-07-16 20:13:22.269843541 +0200
--- src/normal.c 2017-07-30 15:59:33.516791950 +0200
***************
*** 9037,9042 ****
--- 9037,9050 ----
static void
nv_edit(cmdarg_T *cap)
{
+ #ifdef FEAT_TERMINAL
+ if (term_in_terminal_mode())
+ {
+ term_leave_terminal_mode();
+ return;
+ }
+ #endif
+
/* <Insert> is equal to "i" */
if (cap->cmdchar == K_INS || cap->cmdchar == K_KINS)
cap->cmdchar = 'i';
*** ../vim-8.0.0812/src/option.c 2017-07-28 13:48:15.398855045 +0200
--- src/option.c 2017-07-30 15:57:41.817597536 +0200
***************
*** 8222,8233 ****
}
#endif
- #ifdef FEAT_TITLE
/* when 'modifiable' is changed, redraw the window title */
else if ((int *)varp == &curbuf->b_p_ma)
{
redraw_titles();
}
/* when 'endofline' is changed, redraw the window title */
else if ((int *)varp == &curbuf->b_p_eol)
{
--- 8222,8243 ----
}
#endif
/* when 'modifiable' is changed, redraw the window title */
else if ((int *)varp == &curbuf->b_p_ma)
{
+ # ifdef FEAT_TERMINAL
+ /* Cannot set 'modifiable' when in Terminal mode. */
+ if (term_in_terminal_mode())
+ {
+ curbuf->b_p_ma = FALSE;
+ return (char_u *)N_("E946: Cannot make a terminal with running job
modifiable");
+ }
+ # endif
+ # ifdef FEAT_TITLE
redraw_titles();
+ # endif
}
+ #ifdef FEAT_TITLE
/* when 'endofline' is changed, redraw the window title */
else if ((int *)varp == &curbuf->b_p_eol)
{
*** ../vim-8.0.0812/runtime/doc/terminal.txt 2017-07-28 13:48:15.398855045
+0200
--- runtime/doc/terminal.txt 2017-07-30 16:45:34.584766890 +0200
***************
*** 1,4 ****
! *terminal.txt* For Vim version 8.0. Last change: 2017 Jul 28
VIM REFERENCE MANUAL by Bram Moolenaar
--- 1,4 ----
! *terminal.txt* For Vim version 8.0. Last change: 2017 Jul 30
VIM REFERENCE MANUAL by Bram Moolenaar
***************
*** 33,56 ****
The job runs asynchronously from Vim, the window will be updated to show
output from the job, also while editing in any other window.
Typing ~
When the keyboard focus is in the terminal window, typed keys will be send to
the job. This uses a pty when possible. You can click outside of the
terminal window to move keyboard focus elsewhere.
! Navigate between windows with CTRL-W commands. E.g. CTRL-W CTRL-W moves focus
! to the next window. Use "CTRL-W :" to edit an Ex command. Use "CTRL-W ." to
! send a CTRL-W to the job in the terminal.
- See option 'termkey' for specifying another key that precedes a Vim command.
- Typing 'termkey' twice sends 'termkey' to the job.
Size ~
See option 'termsize' for controlling the size of the terminal window.
(TODO: scrolling when the terminal is larger than the window)
Syntax ~
:ter[minal] [command] *:ter* *:terminal*
--- 33,71 ----
The job runs asynchronously from Vim, the window will be updated to show
output from the job, also while editing in any other window.
+
Typing ~
When the keyboard focus is in the terminal window, typed keys will be send to
the job. This uses a pty when possible. You can click outside of the
terminal window to move keyboard focus elsewhere.
! CTRL-W can be used to navigate between windows and other CTRL-W commands,
e.g.:
! CTRL-W CTRL-W move focus to the next window
! CTRL-W : enter an Ex command
! See |CTRL-W| for more commands.
!
! Special in the terminal window: *CTRL-W_.* *CTRL-W_N*
! CTRL-W . send a CTRL-W to the job in the terminal
! CTRL-W N go to Terminal Normal mode, see |Terminal-mode|
!
! See option 'termkey' for specifying another key instead of CTRL-W that
! will work like CTRL-W. However, typing 'termkey' twice sends 'termkey' to
! the job. For example:
! 'termkey' CTRL-W move focus to the next window
! 'termkey' : enter an Ex command
! 'termkey' 'termkey' send 'termkey' to the job in the terminal
! 'termkey' . send a CTRL-W to the job in the terminal
! 'termkey' N go to terminal Normal mode, see below
! 'termkey' CTRL-N same as CTRL-W N
Size ~
See option 'termsize' for controlling the size of the terminal window.
(TODO: scrolling when the terminal is larger than the window)
+
Syntax ~
:ter[minal] [command] *:ter* *:terminal*
***************
*** 99,104 ****
--- 114,138 ----
not when 'termsize' is "rowsXcols".
+ Terminal Normal mode ~
+ *Terminal-mode*
+ When the job is running the contents of the terminal is under control of the
+ job. That includes the cursor position. The terminal contents can change at
+ any time.
+
+ Use CTRL-W N (or 'termkey' N) to go to Terminal Normal mode. Now the contents
+ of the terminal window is under control of Vim, the job output is suspended.
+ *E946*
+ In this mode you can move the cursor around with the usual Vim commands,
+ Visually mark text, yank text, etc. But you cannot change the contents of the
+ buffer. The commands that would start insert mode, such as 'i' and 'a',
+ return control of the window to the job. Any pending output will now be
+ displayed.
+
+ In Terminal mode the statusline and window title show "(Terminal)". If the
+ job ends while in Terminal mode this changes to "(Terminal-finished)".
+
+
Unix ~
On Unix a pty is used to make it possible to run all kinds of commands. You
*** ../vim-8.0.0812/src/version.c 2017-07-30 13:57:37.616783276 +0200
--- src/version.c 2017-07-30 16:43:17.709763223 +0200
***************
*** 771,772 ****
--- 771,774 ----
{ /* Add new patch number below this line */
+ /**/
+ 813,
/**/
--
TALL KNIGHT: We shall say Ni! again to you if you do not appease us.
ARTHUR: All right! What do you want?
TALL KNIGHT: We want ... a shrubbery!
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- [email protected] -- 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 ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.