mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +00:00 
			
		
		
		
	terminal: Follow output only if cursor is at end.
Closes #2257 Closes #2636 References #2683
This commit is contained in:
		@@ -370,8 +370,7 @@ void terminal_enter(void)
 | 
			
		||||
  State = TERM_FOCUS;
 | 
			
		||||
  mapped_ctrl_c |= TERM_FOCUS;  // Always map CTRL-C to avoid interrupt.
 | 
			
		||||
  RedrawingDisabled = false;
 | 
			
		||||
  // go to the bottom when the terminal is focused
 | 
			
		||||
  adjust_topline(s->term, buf, false);
 | 
			
		||||
  adjust_topline(s->term, buf, 0);  // scroll to end
 | 
			
		||||
  // erase the unfocused cursor
 | 
			
		||||
  invalidate_terminal(s->term, s->term->cursor.row, s->term->cursor.row + 1);
 | 
			
		||||
  showmode();
 | 
			
		||||
@@ -966,14 +965,15 @@ static void refresh_terminal(Terminal *term)
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  bool pending_resize = term->pending_resize;
 | 
			
		||||
  long ml_before = buf->b_ml.ml_line_count;
 | 
			
		||||
  WITH_BUFFER(buf, {
 | 
			
		||||
    refresh_size(term, buf);
 | 
			
		||||
    refresh_scrollback(term, buf);
 | 
			
		||||
    refresh_screen(term, buf);
 | 
			
		||||
    redraw_buf_later(buf, NOT_VALID);
 | 
			
		||||
  });
 | 
			
		||||
  adjust_topline(term, buf, pending_resize);
 | 
			
		||||
  long ml_added = buf->b_ml.ml_line_count - ml_before;
 | 
			
		||||
  adjust_topline(term, buf, ml_added);
 | 
			
		||||
}
 | 
			
		||||
// Calls refresh_terminal() on all invalidated_terminals.
 | 
			
		||||
static void refresh_timer_cb(TimeWatcher *watcher, void *data)
 | 
			
		||||
@@ -1153,21 +1153,21 @@ static void redraw(bool restore_cursor)
 | 
			
		||||
  ui_flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void adjust_topline(Terminal *term, buf_T *buf, bool force)
 | 
			
		||||
static void adjust_topline(Terminal *term, buf_T *buf, long added)
 | 
			
		||||
{
 | 
			
		||||
  int height, width;
 | 
			
		||||
  vterm_get_size(term->vt, &height, &width);
 | 
			
		||||
  FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
 | 
			
		||||
    if (wp->w_buffer == buf) {
 | 
			
		||||
      // for every window that displays a terminal, ensure the cursor is in a
 | 
			
		||||
      // valid line
 | 
			
		||||
      wp->w_cursor.lnum = MIN(wp->w_cursor.lnum, buf->b_ml.ml_line_count);
 | 
			
		||||
      if (force || curbuf != buf || is_focused(term)) {
 | 
			
		||||
        // if the terminal is not in the current window or if it's focused,
 | 
			
		||||
        // adjust topline/cursor so the window will "follow" the terminal
 | 
			
		||||
        // output
 | 
			
		||||
        wp->w_cursor.lnum = buf->b_ml.ml_line_count;
 | 
			
		||||
      linenr_T ml_end = buf->b_ml.ml_line_count;
 | 
			
		||||
      bool following = ml_end == wp->w_cursor.lnum + added;  // cursor at end?
 | 
			
		||||
      if (following || (wp == curwin && is_focused(term))) {
 | 
			
		||||
        // "Follow" the terminal output
 | 
			
		||||
        wp->w_cursor.lnum = ml_end;
 | 
			
		||||
        set_topline(wp, MAX(wp->w_cursor.lnum - height + 1, 1));
 | 
			
		||||
      } else {
 | 
			
		||||
        // Ensure valid cursor for each window displaying this terminal.
 | 
			
		||||
        wp->w_cursor.lnum = MIN(wp->w_cursor.lnum, ml_end);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,8 @@ describe(':edit term://*', function()
 | 
			
		||||
    meths.set_option('shellcmdflag', 'REP ' .. rep)
 | 
			
		||||
    local rep_size = rep:byte()  -- 'a' => 97
 | 
			
		||||
    local sb = 10
 | 
			
		||||
    command('autocmd TermOpen * :setlocal scrollback='..tostring(sb))
 | 
			
		||||
    command('autocmd TermOpen * :setlocal scrollback='..tostring(sb)
 | 
			
		||||
            ..'|call feedkeys("G", "n")')
 | 
			
		||||
    command('edit term://foobar')
 | 
			
		||||
 | 
			
		||||
    local bufcontents = {}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,18 @@ describe(':terminal', function()
 | 
			
		||||
    ]])
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
  it("in normal-mode :split does not move cursor", function()
 | 
			
		||||
    execute([[terminal while true; do echo foo; sleep .1; done]])
 | 
			
		||||
    helpers.feed([[<C-\><C-N>M]])  -- move cursor away from last line
 | 
			
		||||
    wait()
 | 
			
		||||
    eq(3, eval("line('$')"))  -- window height
 | 
			
		||||
    eq(2, eval("line('.')"))  -- cursor is in the middle
 | 
			
		||||
    execute('vsplit')
 | 
			
		||||
    eq(2, eval("line('.')"))  -- cursor stays where we put it
 | 
			
		||||
    execute('split')
 | 
			
		||||
    eq(2, eval("line('.')"))  -- cursor stays where we put it
 | 
			
		||||
  end)
 | 
			
		||||
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
describe(':terminal (with fake shell)', function()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user