comparison src/terminal.c @ 13878:a590029f16a0 v8.0.1810

patch 8.0.1810: buffer of a terminal only updated in Terminal-Normal mode commit https://github.com/vim/vim/commit/56bc8e299cdae1b4606897749ef54a0161381a4a Author: Bram Moolenaar <Bram@vim.org> Date: Thu May 10 18:05:56 2018 +0200 patch 8.0.1810: buffer of a terminal only updated in Terminal-Normal mode Problem: Buffer of a terminal only updated in Terminal-Normal mode. Solution: Copy the terminal window content to the buffer when in Terminal-Job mode.
author Christian Brabandt <cb@256bit.org>
date Thu, 10 May 2018 18:15:06 +0200
parents de8455bd2d05
children bbf5bdba4a80
comparison
equal deleted inserted replaced
13877:aee4384c0938 13878:a590029f16a0
41 * - Win32: Redirecting input does not work, half of Test_terminal_redir_file() 41 * - Win32: Redirecting input does not work, half of Test_terminal_redir_file()
42 * is disabled. 42 * is disabled.
43 * - Win32: Redirecting output works but includes escape sequences. 43 * - Win32: Redirecting output works but includes escape sequences.
44 * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for 44 * - Win32: Make terminal used for :!cmd in the GUI work better. Allow for
45 * redirection. 45 * redirection.
46 * - Copy text in the vterm to the Vim buffer once in a while, so that
47 * completion works.
48 * - When the job only outputs lines, we could handle resizing the terminal 46 * - When the job only outputs lines, we could handle resizing the terminal
49 * better: store lines separated by line breaks, instead of screen lines, 47 * better: store lines separated by line breaks, instead of screen lines,
50 * then when the window is resized redraw those lines. 48 * then when the window is resized redraw those lines.
51 * - Redrawing is slow with Athena and Motif. (Ramel Eshed) 49 * - Redrawing is slow with Athena and Motif. (Ramel Eshed)
52 * - For the GUI fill termios with default values, perhaps like pangoterm: 50 * - For the GUI fill termios with default values, perhaps like pangoterm:
129 char_u *tl_status_text; /* NULL or allocated */ 127 char_u *tl_status_text; /* NULL or allocated */
130 128
131 /* Range of screen rows to update. Zero based. */ 129 /* Range of screen rows to update. Zero based. */
132 int tl_dirty_row_start; /* MAX_ROW if nothing dirty */ 130 int tl_dirty_row_start; /* MAX_ROW if nothing dirty */
133 int tl_dirty_row_end; /* row below last one to update */ 131 int tl_dirty_row_end; /* row below last one to update */
134 132 int tl_dirty_snapshot; /* text updated after making snapshot */
133 #ifdef FEAT_TIMERS
134 int tl_timer_set;
135 proftime_T tl_timer_due;
136 #endif
135 int tl_postponed_scroll; /* to be scrolled up */ 137 int tl_postponed_scroll; /* to be scrolled up */
136 138
137 garray_T tl_scrollback; 139 garray_T tl_scrollback;
138 int tl_scrollback_scrolled; 140 int tl_scrollback_scrolled;
139 cellattr_T tl_default_color; 141 cellattr_T tl_default_color;
1440 } 1442 }
1441 return FALSE; 1443 return FALSE;
1442 } 1444 }
1443 1445
1444 /* 1446 /*
1447 * Remove the terminal contents from the scrollback and the buffer.
1448 * Used before adding a new scrollback line or updating the buffer for lines
1449 * displayed in the terminal.
1450 */
1451 static void
1452 cleanup_scrollback(term_T *term)
1453 {
1454 sb_line_T *line;
1455 garray_T *gap;
1456
1457 gap = &term->tl_scrollback;
1458 while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled
1459 && gap->ga_len > 0)
1460 {
1461 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
1462 line = (sb_line_T *)gap->ga_data + gap->ga_len - 1;
1463 vim_free(line->sb_cells);
1464 --gap->ga_len;
1465 }
1466 check_cursor();
1467 }
1468
1469 /*
1445 * Add the current lines of the terminal to scrollback and to the buffer. 1470 * Add the current lines of the terminal to scrollback and to the buffer.
1446 * Called after the job has ended and when switching to Terminal-Normal mode. 1471 * Called after the job has ended and when switching to Terminal-Normal mode.
1447 */ 1472 */
1448 static void 1473 static void
1449 move_terminal_to_buffer(term_T *term) 1474 move_terminal_to_buffer(term_T *term)
1457 cellattr_T *p; 1482 cellattr_T *p;
1458 VTermScreen *screen; 1483 VTermScreen *screen;
1459 1484
1460 if (term->tl_vterm == NULL) 1485 if (term->tl_vterm == NULL)
1461 return; 1486 return;
1487
1488 /* Nothing to do if the buffer already has the lines and nothing was
1489 * changed. */
1490 if (!term->tl_dirty_snapshot
1491 && curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled)
1492 return;
1493
1494 ch_log(term->tl_job == NULL ? NULL : term->tl_job->jv_channel,
1495 "Adding terminal window snapshot to buffer");
1496
1497 /* First remove the lines that were appended before, they might be
1498 * outdated. */
1499 cleanup_scrollback(term);
1500
1462 screen = vterm_obtain_screen(term->tl_vterm); 1501 screen = vterm_obtain_screen(term->tl_vterm);
1463 fill_attr = new_fill_attr = term->tl_default_color; 1502 fill_attr = new_fill_attr = term->tl_default_color;
1464
1465 for (pos.row = 0; pos.row < term->tl_rows; ++pos.row) 1503 for (pos.row = 0; pos.row < term->tl_rows; ++pos.row)
1466 { 1504 {
1467 len = 0; 1505 len = 0;
1468 for (pos.col = 0; pos.col < term->tl_cols; ++pos.col) 1506 for (pos.col = 0; pos.col < term->tl_cols; ++pos.col)
1469 if (vterm_screen_get_cell(screen, pos, &cell) != 0 1507 if (vterm_screen_get_cell(screen, pos, &cell) != 0
1546 else 1584 else
1547 vim_free(p); 1585 vim_free(p);
1548 } 1586 }
1549 } 1587 }
1550 1588
1589 term->tl_dirty_snapshot = FALSE;
1590 #ifdef FEAT_TIMERS
1591 term->tl_timer_set = FALSE;
1592 #endif
1593
1551 /* Obtain the current background color. */ 1594 /* Obtain the current background color. */
1552 vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm), 1595 vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
1553 &term->tl_default_color.fg, &term->tl_default_color.bg); 1596 &term->tl_default_color.fg, &term->tl_default_color.bg);
1554 1597
1555 FOR_ALL_WINDOWS(wp) 1598 FOR_ALL_WINDOWS(wp)
1569 redraw_win_later(wp, NOT_VALID); 1612 redraw_win_later(wp, NOT_VALID);
1570 } 1613 }
1571 } 1614 }
1572 } 1615 }
1573 1616
1617 #if defined(FEAT_TIMERS) || defined(PROTO)
1618 /*
1619 * Check if any terminal timer expired. If so, copy text from the terminal to
1620 * the buffer.
1621 * Return the time until the next timer will expire.
1622 */
1623 int
1624 term_check_timers(int next_due_arg, proftime_T *now)
1625 {
1626 term_T *term;
1627 int next_due = next_due_arg;
1628
1629 for (term = first_term; term != NULL; term = term->tl_next)
1630 {
1631 if (term->tl_timer_set && !term->tl_normal_mode)
1632 {
1633 long this_due = proftime_time_left(&term->tl_timer_due, now);
1634
1635 if (this_due <= 1)
1636 {
1637 term->tl_timer_set = FALSE;
1638 move_terminal_to_buffer(term);
1639 }
1640 else if (next_due == -1 || next_due > this_due)
1641 next_due = this_due;
1642 }
1643 }
1644
1645 return next_due;
1646 }
1647 #endif
1648
1574 static void 1649 static void
1575 set_terminal_mode(term_T *term, int normal_mode) 1650 set_terminal_mode(term_T *term, int normal_mode)
1576 { 1651 {
1577 term->tl_normal_mode = normal_mode; 1652 term->tl_normal_mode = normal_mode;
1578 VIM_CLEAR(term->tl_status_text); 1653 VIM_CLEAR(term->tl_status_text);
1636 */ 1711 */
1637 void 1712 void
1638 term_enter_job_mode() 1713 term_enter_job_mode()
1639 { 1714 {
1640 term_T *term = curbuf->b_term; 1715 term_T *term = curbuf->b_term;
1641 sb_line_T *line;
1642 garray_T *gap;
1643
1644 /* Remove the terminal contents from the scrollback and the buffer. */
1645 gap = &term->tl_scrollback;
1646 while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled
1647 && gap->ga_len > 0)
1648 {
1649 ml_delete(curbuf->b_ml.ml_line_count, FALSE);
1650 line = (sb_line_T *)gap->ga_data + gap->ga_len - 1;
1651 vim_free(line->sb_cells);
1652 --gap->ga_len;
1653 }
1654 check_cursor();
1655 1716
1656 set_terminal_mode(term, FALSE); 1717 set_terminal_mode(term, FALSE);
1657 1718
1658 if (term->tl_channel_closed) 1719 if (term->tl_channel_closed)
1659 cleanup_vterm(term); 1720 cleanup_vterm(term);
2172 2233
2173 theend: 2234 theend:
2174 in_terminal_loop = NULL; 2235 in_terminal_loop = NULL;
2175 if (restore_cursor) 2236 if (restore_cursor)
2176 prepare_restore_cursor_props(); 2237 prepare_restore_cursor_props();
2238
2239 /* Move a snapshot of the screen contents to the buffer, so that completion
2240 * works in other buffers. */
2241 if (curbuf->b_term != NULL)
2242 move_terminal_to_buffer(curbuf->b_term);
2243
2177 return ret; 2244 return ret;
2178 } 2245 }
2179 2246
2180 /* 2247 /*
2181 * Called when a job has finished. 2248 * Called when a job has finished.
2388 return get_cterm_attr_idx(attr, fg, bg); 2455 return get_cterm_attr_idx(attr, fg, bg);
2389 } 2456 }
2390 return 0; 2457 return 0;
2391 } 2458 }
2392 2459
2460 static void
2461 set_dirty_snapshot(term_T *term)
2462 {
2463 term->tl_dirty_snapshot = TRUE;
2464 #ifdef FEAT_TIMERS
2465 if (!term->tl_normal_mode)
2466 {
2467 /* Update the snapshot after 100 msec of not getting updates. */
2468 profile_setlimit(100L, &term->tl_timer_due);
2469 term->tl_timer_set = TRUE;
2470 }
2471 #endif
2472 }
2473
2393 static int 2474 static int
2394 handle_damage(VTermRect rect, void *user) 2475 handle_damage(VTermRect rect, void *user)
2395 { 2476 {
2396 term_T *term = (term_T *)user; 2477 term_T *term = (term_T *)user;
2397 2478
2398 term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row); 2479 term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, rect.start_row);
2399 term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row); 2480 term->tl_dirty_row_end = MAX(term->tl_dirty_row_end, rect.end_row);
2481 set_dirty_snapshot(term);
2400 redraw_buf_later(term->tl_buffer, SOME_VALID); 2482 redraw_buf_later(term->tl_buffer, SOME_VALID);
2401 return 1; 2483 return 1;
2402 } 2484 }
2403 2485
2404 static void 2486 static void
2441 term_scroll_up(term, dest.start_row, count); 2523 term_scroll_up(term, dest.start_row, count);
2442 } 2524 }
2443 2525
2444 term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, dest.start_row); 2526 term->tl_dirty_row_start = MIN(term->tl_dirty_row_start, dest.start_row);
2445 term->tl_dirty_row_end = MIN(term->tl_dirty_row_end, dest.end_row); 2527 term->tl_dirty_row_end = MIN(term->tl_dirty_row_end, dest.end_row);
2528 set_dirty_snapshot(term);
2446 2529
2447 /* Note sure if the scrolling will work correctly, let's do a complete 2530 /* Note sure if the scrolling will work correctly, let's do a complete
2448 * redraw later. */ 2531 * redraw later. */
2449 redraw_buf_later(term->tl_buffer, NOT_VALID); 2532 redraw_buf_later(term->tl_buffer, NOT_VALID);
2450 return 1; 2533 return 1;
2591 */ 2674 */
2592 static int 2675 static int
2593 handle_pushline(int cols, const VTermScreenCell *cells, void *user) 2676 handle_pushline(int cols, const VTermScreenCell *cells, void *user)
2594 { 2677 {
2595 term_T *term = (term_T *)user; 2678 term_T *term = (term_T *)user;
2679
2680 /* First remove the lines that were appended before, the pushed line goes
2681 * above it. */
2682 cleanup_scrollback(term);
2596 2683
2597 /* If the number of lines that are stored goes over 'termscrollback' then 2684 /* If the number of lines that are stored goes over 'termscrollback' then
2598 * delete the first 10%. */ 2685 * delete the first 10%. */
2599 if (term->tl_scrollback.ga_len >= term->tl_buffer->b_p_twsl) 2686 if (term->tl_scrollback.ga_len >= term->tl_buffer->b_p_twsl)
2600 { 2687 {