@@ -115,7 +115,7 @@ struct terminal_S {
115115 int tl_tty_fd ;
116116 char_u * tl_tty_name ;
117117
118- int tl_terminal_mode ;
118+ int tl_terminal_mode ; /* 0, TMODE_ONCE or TMODE_LOOP */
119119 int tl_channel_closed ;
120120
121121#ifdef WIN3264
@@ -144,6 +144,9 @@ struct terminal_S {
144144 int tl_cursor_visible ;
145145};
146146
147+ #define TMODE_ONCE 1 /* CTRL-\ CTRL-N used */
148+ #define TMODE_LOOP 2 /* CTRL-W N used */
149+
147150/*
148151 * List of all active terminals.
149152 */
@@ -459,7 +462,7 @@ term_write_job_output(term_T *term, char_u *msg, size_t len)
459462 static void
460463update_cursor (term_T * term , int redraw )
461464{
462- if (term -> tl_terminal_mode )
465+ if (term -> tl_terminal_mode != 0 )
463466 return ;
464467 setcursor ();
465468 if (redraw && term -> tl_buffer == curbuf )
@@ -492,7 +495,7 @@ write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
492495 ch_log (channel , "writing %d bytes to terminal" , (int )len );
493496 term_write_job_output (term , msg , len );
494497
495- if (! term -> tl_terminal_mode )
498+ if (term -> tl_terminal_mode == 0 )
496499 {
497500 /* TODO: only update once in a while. */
498501 update_screen (0 );
@@ -805,9 +808,9 @@ move_terminal_to_buffer(term_T *term)
805808}
806809
807810 static void
808- set_terminal_mode (term_T * term , int on )
811+ set_terminal_mode (term_T * term , int mode )
809812{
810- term -> tl_terminal_mode = on ;
813+ term -> tl_terminal_mode = mode ;
811814 vim_free (term -> tl_status_text );
812815 term -> tl_status_text = NULL ;
813816 if (term -> tl_buffer == curbuf )
@@ -823,22 +826,35 @@ cleanup_vterm(term_T *term)
823826{
824827 move_terminal_to_buffer (term );
825828 term_free_vterm (term );
826- set_terminal_mode (term , FALSE );
829+ set_terminal_mode (term , 0 );
827830}
828831
829832/*
830- * Switch from sending keys to the job to Terminal-Normal mode.
833+ * Switch from Terminal-Job mode to Terminal-Normal mode.
831834 * Suspends updating the terminal window.
832835 */
833836 static void
834- term_enter_terminal_mode ()
837+ term_enter_terminal_mode (int mode )
835838{
836839 term_T * term = curbuf -> b_term ;
837840
838841 /* Append the current terminal contents to the buffer. */
839842 move_terminal_to_buffer (term );
840843
841- set_terminal_mode (term , TRUE);
844+ set_terminal_mode (term , mode );
845+
846+ if (mode == TMODE_ONCE )
847+ {
848+ /* Move the window cursor to the position of the cursor in the
849+ * terminal. */
850+ curwin -> w_cursor .lnum = term -> tl_scrollback_scrolled
851+ + term -> tl_cursor_pos .row + 1 ;
852+ check_cursor ();
853+ coladvance (term -> tl_cursor_pos .col );
854+
855+ /* Display the same lines as in the terminal. */
856+ curwin -> w_topline = term -> tl_scrollback_scrolled + 1 ;
857+ }
842858}
843859
844860/*
@@ -850,11 +866,11 @@ term_in_terminal_mode()
850866{
851867 term_T * term = curbuf -> b_term ;
852868
853- return term != NULL && term -> tl_terminal_mode ;
869+ return term != NULL && term -> tl_terminal_mode != 0 ;
854870}
855871
856872/*
857- * Switch from Terminal-Normal mode to sending keys to the job .
873+ * Switch from Terminal-Normal mode to Terminal-Job mode .
858874 * Restores updating the terminal window.
859875 */
860876 void
@@ -877,7 +893,7 @@ term_leave_terminal_mode()
877893 }
878894 check_cursor ();
879895
880- set_terminal_mode (term , FALSE );
896+ set_terminal_mode (term , 0 );
881897
882898 if (term -> tl_channel_closed )
883899 cleanup_vterm (term );
@@ -1037,12 +1053,13 @@ term_paste_register(int prev_c UNUSED)
10371053 * keys to the job.
10381054 */
10391055 int
1040- term_use_loop ()
1056+ term_use_loop (int once )
10411057{
10421058 term_T * term = curbuf -> b_term ;
10431059
10441060 return term != NULL
1045- && !term -> tl_terminal_mode
1061+ && (once ? term -> tl_terminal_mode != TMODE_LOOP
1062+ : term -> tl_terminal_mode == 0 )
10461063 && term -> tl_vterm != NULL
10471064 && term_job_running (term );
10481065}
@@ -1060,6 +1077,13 @@ terminal_loop(void)
10601077 int c ;
10611078 int termkey = 0 ;
10621079
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+
10631087 if (* curwin -> w_p_tk != NUL )
10641088 termkey = string_to_key (curwin -> w_p_tk , TRUE);
10651089 position_cursor (curwin , & curbuf -> b_term -> tl_cursor_pos );
@@ -1073,7 +1097,7 @@ terminal_loop(void)
10731097 update_cursor (curbuf -> b_term , FALSE);
10741098
10751099 c = term_vgetc ();
1076- if (!term_use_loop ())
1100+ if (!term_use_loop (FALSE ))
10771101 /* job finished while waiting for a character */
10781102 break ;
10791103
@@ -1100,15 +1124,18 @@ terminal_loop(void)
11001124#ifdef FEAT_CMDL_INFO
11011125 clear_showcmd ();
11021126#endif
1103- if (!term_use_loop ())
1127+ if (!term_use_loop (FALSE ))
11041128 /* job finished while waiting for a character */
11051129 break ;
11061130
11071131 if (prev_c == Ctrl_BSL )
11081132 {
11091133 if (c == Ctrl_N )
1134+ {
11101135 /* CTRL-\ CTRL-N : execute one Normal mode command. */
1136+ term_enter_terminal_mode (TMODE_ONCE );
11111137 return OK ;
1138+ }
11121139 /* Send both keys to the terminal. */
11131140 send_keys_to_term (curbuf -> b_term , prev_c , TRUE);
11141141 }
@@ -1119,7 +1146,7 @@ terminal_loop(void)
11191146 }
11201147 else if (c == 'N' )
11211148 {
1122- term_enter_terminal_mode ();
1149+ term_enter_terminal_mode (TMODE_LOOP );
11231150 return FAIL ;
11241151 }
11251152 else if (c == '"' )
@@ -1222,7 +1249,7 @@ handle_movecursor(
12221249 if (wp -> w_buffer == term -> tl_buffer )
12231250 position_cursor (wp , & pos );
12241251 }
1225- if (term -> tl_buffer == curbuf && ! term -> tl_terminal_mode )
1252+ if (term -> tl_buffer == curbuf && term -> tl_terminal_mode == 0 )
12261253 {
12271254 may_toggle_cursor (term );
12281255 update_cursor (term , term -> tl_cursor_visible );
@@ -1358,7 +1385,7 @@ term_channel_closed(channel_T *ch)
13581385 term -> tl_status_text = NULL ;
13591386
13601387 /* Unless in Terminal-Normal mode: clear the vterm. */
1361- if (! term -> tl_terminal_mode )
1388+ if (term -> tl_terminal_mode == 0 )
13621389 cleanup_vterm (term );
13631390
13641391 redraw_buf_and_status_later (term -> tl_buffer , NOT_VALID );
@@ -1558,7 +1585,7 @@ term_update_window(win_T *wp)
15581585 VTermState * state ;
15591586 VTermPos pos ;
15601587
1561- if (term == NULL || term -> tl_vterm == NULL || term -> tl_terminal_mode )
1588+ if (term == NULL || term -> tl_vterm == NULL || term -> tl_terminal_mode != 0 )
15621589 return FAIL ;
15631590
15641591 vterm = term -> tl_vterm ;
@@ -1687,7 +1714,8 @@ term_show_buffer(buf_T *buf)
16871714{
16881715 term_T * term = buf -> b_term ;
16891716
1690- return term != NULL && (term -> tl_vterm == NULL || term -> tl_terminal_mode );
1717+ return term != NULL
1718+ && (term -> tl_vterm == NULL || term -> tl_terminal_mode != 0 );
16911719}
16921720
16931721/*
@@ -1770,7 +1798,7 @@ term_get_status_text(term_T *term)
17701798 char_u * txt ;
17711799 size_t len ;
17721800
1773- if (term -> tl_terminal_mode )
1801+ if (term -> tl_terminal_mode != 0 )
17741802 {
17751803 if (term_job_running (term ))
17761804 txt = (char_u * )_ ("Terminal" );
@@ -1997,7 +2025,7 @@ f_term_getstatus(typval_T *argvars, typval_T *rettv)
19972025 STRCPY (val , "running" );
19982026 else
19992027 STRCPY (val , "finished" );
2000- if (term -> tl_terminal_mode )
2028+ if (term -> tl_terminal_mode != 0 )
20012029 STRCAT (val , ",terminal" );
20022030 rettv -> vval .v_string = vim_strsave (val );
20032031}
@@ -2159,7 +2187,7 @@ f_term_sendkeys(typval_T *argvars, typval_T *rettv)
21592187 msg += MB_PTR2LEN (msg );
21602188 }
21612189
2162- if (! term -> tl_terminal_mode )
2190+ if (term -> tl_terminal_mode == 0 )
21632191 {
21642192 /* TODO: only update once in a while. */
21652193 update_screen (0 );
0 commit comments