@@ -601,14 +601,14 @@ void terminal_close(Terminal **termpp, int status)
601601 // If this was called by close_buffer() (status is -1), or if exiting, we
602602 // must inform the buffer the terminal no longer exists so that
603603 // close_buffer() won't call this again.
604- // If inside Terminal mode K_EVENT handling, setting buf_handle to 0 also
604+ // If inside Terminal mode event handling, setting buf_handle to 0 also
605605 // informs terminal_enter() to call the close callback before returning.
606606 term -> buf_handle = 0 ;
607607 if (buf ) {
608608 buf -> terminal = NULL ;
609609 }
610610 if (!term -> refcount ) {
611- // Not inside Terminal mode K_EVENT handling.
611+ // Not inside Terminal mode event handling.
612612 // We should not wait for the user to press a key.
613613 term -> destroy = true;
614614 term -> opts .close_cb (term -> opts .data );
@@ -772,12 +772,13 @@ bool terminal_enter(void)
772772 adjust_topline (s -> term , buf , 0 ); // scroll to end
773773 showmode ();
774774 ui_cursor_shape ();
775- apply_autocmds (EVENT_TERMENTER , NULL , NULL , false, curbuf );
776- may_trigger_modechanged ();
777775
778776 // Tell the terminal it has focus
779777 terminal_focus (s -> term , true);
780778
779+ apply_autocmds (EVENT_TERMENTER , NULL , NULL , false, curbuf );
780+ may_trigger_modechanged ();
781+
781782 s -> state .execute = terminal_execute ;
782783 s -> state .check = terminal_check ;
783784 state_enter (& s -> state );
@@ -792,8 +793,6 @@ bool terminal_enter(void)
792793 ui_busy_stop ();
793794 }
794795
795- apply_autocmds (EVENT_TERMLEAVE , NULL , NULL , false, curbuf );
796-
797796 // Restore the terminal cursor to what is set in 'guicursor'
798797 (void )parse_shape_opt (SHAPE_CURSOR );
799798
@@ -811,12 +810,19 @@ bool terminal_enter(void)
811810 unshowmode (true);
812811 }
813812 ui_cursor_shape ();
813+
814+ // If we're to close the terminal, don't let TermLeave autocommands free it first!
815+ if (s -> close ) {
816+ s -> term -> refcount ++ ;
817+ }
818+ apply_autocmds (EVENT_TERMLEAVE , NULL , NULL , false, curbuf );
814819 if (s -> close ) {
815- bool wipe = s -> term -> buf_handle != 0 ;
820+ s -> term -> refcount -- ;
821+ const handle_T buf_handle = s -> term -> buf_handle ; // Callback may free s->term.
816822 s -> term -> destroy = true;
817823 s -> term -> opts .close_cb (s -> term -> opts .data );
818- if (wipe ) {
819- do_cmdline_cmd ( "bwipeout!" );
824+ if (buf_handle != 0 ) {
825+ do_buffer ( DOBUF_WIPE , DOBUF_FIRST , FORWARD , buf_handle , true );
820826 }
821827 }
822828
@@ -840,24 +846,68 @@ static void terminal_check_cursor(void)
840846 coladvance (curwin , MAX (0 , term -> cursor .col + off ));
841847}
842848
843- // Function executed before each iteration of terminal mode.
844- // Return:
845- // 1 if the iteration should continue normally
846- // 0 if the main loop must exit
849+ static bool terminal_check_focus (TerminalState * const s )
850+ FUNC_ATTR_NONNULL_ALL
851+ {
852+ if (curbuf -> terminal == NULL ) {
853+ return false;
854+ }
855+
856+ if (s -> save_curwin_handle != curwin -> handle ) {
857+ // Terminal window changed, update window options.
858+ unset_terminal_winopts (s );
859+ set_terminal_winopts (s );
860+ }
861+ if (s -> term != curbuf -> terminal ) {
862+ // Active terminal buffer changed, flush terminal's cursor state to the UI.
863+ terminal_focus (s -> term , false);
864+
865+ s -> term = curbuf -> terminal ;
866+ s -> term -> pending .cursor = true;
867+ invalidate_terminal (s -> term , -1 , -1 );
868+ terminal_focus (s -> term , true);
869+ }
870+ return true;
871+ }
872+
873+ /// Function executed before each iteration of terminal mode.
874+ ///
875+ /// @return:
876+ /// 1 if the iteration should continue normally
877+ /// 0 if the main loop must exit
847878static int terminal_check (VimState * state )
848879{
849880 TerminalState * const s = (TerminalState * )state ;
850881
851- if (stop_insert_mode ) {
882+ if (stop_insert_mode || ! terminal_check_focus ( s ) ) {
852883 return 0 ;
853884 }
854885
855- assert (s -> term == curbuf -> terminal );
886+ // Validate topline and cursor position for autocommands. Especially important for WinScrolled.
887+ terminal_check_cursor ();
888+ validate_cursor (curwin );
889+
890+ // Don't let autocommands free the terminal from under our fingers.
891+ s -> term -> refcount ++ ;
892+ if (must_redraw ) {
893+ // TODO(seandewar): above changes will maybe change the behaviour of this more; untrollify this
894+ apply_autocmds (EVENT_TEXTCHANGEDT , NULL , NULL , false, curbuf );
895+ }
896+ may_trigger_win_scrolled_resized ();
897+ s -> term -> refcount -- ;
898+ if (s -> term -> buf_handle == 0 ) {
899+ s -> close = true;
900+ return 0 ;
901+ }
902+
903+ // Autocommands above may have changed focus, scrolled, or moved the cursor.
904+ if (!terminal_check_focus (s )) {
905+ return 0 ;
906+ }
856907 terminal_check_cursor ();
857908 validate_cursor (curwin );
858- const bool text_changed = must_redraw != 0 ;
859- show_cursor_info_later (false);
860909
910+ show_cursor_info_later (false);
861911 if (must_redraw ) {
862912 update_screen ();
863913 } else {
@@ -866,21 +916,6 @@ static int terminal_check(VimState *state)
866916 showmode (); // clear cmdline and show mode
867917 }
868918 }
869- if (text_changed ) {
870- // Make sure an invoked autocmd doesn't delete the buffer (and the
871- // terminal) under our fingers.
872- curbuf -> b_locked ++ ;
873-
874- // save and restore curwin and curbuf, in case the autocmd changes them
875- aco_save_T aco ;
876- aucmd_prepbuf (& aco , curbuf );
877- apply_autocmds (EVENT_TEXTCHANGEDT , NULL , NULL , false, curbuf );
878- aucmd_restbuf (& aco );
879-
880- curbuf -> b_locked -- ;
881- }
882-
883- may_trigger_win_scrolled_resized ();
884919
885920 setcursor ();
886921 refresh_cursor (s -> term , & s -> cursor_visible );
@@ -981,23 +1016,6 @@ static int terminal_execute(VimState *state, int key)
9811016 terminal_send_key (s -> term , key );
9821017 }
9831018
984- if (curbuf -> terminal == NULL ) {
985- return 0 ;
986- }
987- if (s -> save_curwin_handle != curwin -> handle ) {
988- // Terminal window changed, update window options.
989- unset_terminal_winopts (s );
990- set_terminal_winopts (s );
991- }
992- if (s -> term != curbuf -> terminal ) {
993- // Active terminal buffer changed, flush terminal's cursor state to the UI
994- terminal_focus (s -> term , false);
995-
996- s -> term = curbuf -> terminal ;
997- s -> term -> pending .cursor = true;
998- invalidate_terminal (s -> term , -1 , -1 );
999- terminal_focus (s -> term , true);
1000- }
10011019 return 1 ;
10021020}
10031021
0 commit comments