Compare commits

...

11 Commits

Author SHA1 Message Date
Bram Moolenaar
73dd1bd54e patch 8.0.1824: Coverity warns for variable that may be uninitialized
Problem:    Coverity warns for variable that may be uninitialized.
Solution:   Initialize the variable.
2018-05-12 21:16:25 +02:00
Bram Moolenaar
54c6bafa16 patch 8.0.1823: test for terminal stdout redirection is flaky
Problem:    Test for terminal stdout redirection is flaky.
Solution:   Wait for the job to finish.
2018-05-12 21:12:12 +02:00
Bram Moolenaar
ee62f9fa74 patch 8.0.1822: make uninstall does not remove colors/tools
Problem:    Make uninstall does not remove colors/tools.
Solution:   Add a line to delete the tools directory. (Kazunobu Kuriyama)
2018-05-12 21:05:45 +02:00
Bram Moolenaar
2bc799579d patch 8.0.1821: cursor in terminal window moves when pressing CTRL-W
Problem:    Cursor in terminal window moves when pressing CTRL-W. (Dominique
            Pelle)
Solution:   Do not more the cursor or redraw when not in Terminal-Normal mode.
            (closes #2904)
2018-05-12 20:36:24 +02:00
Bram Moolenaar
cd8fb449d6 patch 8.0.1820: terminal window redirecting stdout does not show stderr
Problem:    Terminal window redirecting stdout does not show stderr. (Matéo
            Zanibelli)
Solution:   When stdout is not connected to pty_master_fd then use it for
            stderr. (closes #2903)
2018-05-12 17:42:42 +02:00
Bram Moolenaar
8c3169c58e patch 8.0.1819: swap file warning for file with non-existing directory
Problem:    Swap file warning for a file in a non-existing directory, if there
            is another with the same file name. (Juergen Weigert)
Solution:   When expanding the file name fails compare the file names.
2018-05-12 17:04:12 +02:00
Bram Moolenaar
3f1a53c434 patch 8.0.1818: lines remove from wrong buffer when using terminal window
Problem:    Lines remove from wrong buffer when using terminal window.
Solution:   Make sure to use tl_buffer.
2018-05-12 16:55:14 +02:00
Bram Moolenaar
b0f42ba60d patch 8.0.1817: a timer may change v:count unexpectedly
Problem:    A timer may change v:count unexpectedly.
Solution:   Save and restore v:count and similar variables when a timer
            callback is invoked. (closes #2897)
2018-05-12 15:38:26 +02:00
Bram Moolenaar
ff3be4fe1e patch 8.0.1816: no test for setcmdpos()
Problem:    No test for setcmdpos().
Solution:   Add a test. (Dominique Pelle, closes #2901)
2018-05-12 13:18:46 +02:00
Bram Moolenaar
0cb8ac71ae patch 8.0.1815: crash with terminal window and with 'lazyredraw' set
Problem:    Still a crash with terminal window and with 'lazyredraw' set.
            (Antoine)
Solution:   Do not wipe out the buffer when updating the screen.
2018-05-11 22:01:51 +02:00
Bram Moolenaar
a10ae5e323 patch 8.0.1814: crash with terminal window and with 'lazyredraw' set
Problem:    Crash with terminal window and with 'lazyredraw' set. (Antoine)
Solution:   Check the terminal still exists after update_screen().
2018-05-11 20:48:29 +02:00
17 changed files with 301 additions and 67 deletions

View File

@@ -2824,6 +2824,7 @@ uninstall_runtime:
-rm -f $(SYS_FTPLUGOF_FILE) $(SYS_FTPLUGIN_FILE)
-rm -f $(SYS_OPTWIN_FILE)
-rm -f $(DEST_COL)/*.vim $(DEST_COL)/README.txt
-rm -rf $(DEST_COL)/tools
-rm -f $(DEST_SYN)/*.vim $(DEST_SYN)/README.txt
-rm -f $(DEST_IND)/*.vim $(DEST_IND)/README.txt
-rm -rf $(DEST_MACRO)

View File

@@ -6461,6 +6461,29 @@ set_vcount(
vimvars[VV_COUNT1].vv_nr = count1;
}
/*
* Save variables that might be changed as a side effect. Used when executing
* a timer callback.
*/
void
save_vimvars(vimvars_save_T *vvsave)
{
vvsave->vv_prevcount = vimvars[VV_PREVCOUNT].vv_nr;
vvsave->vv_count = vimvars[VV_COUNT].vv_nr;
vvsave->vv_count1 = vimvars[VV_COUNT1].vv_nr;
}
/*
* Restore variables saved by save_vimvars().
*/
void
restore_vimvars(vimvars_save_T *vvsave)
{
vimvars[VV_PREVCOUNT].vv_nr = vvsave->vv_prevcount;
vimvars[VV_COUNT].vv_nr = vvsave->vv_count;
vimvars[VV_COUNT1].vv_nr = vvsave->vv_count1;
}
/*
* Set string v: variable to a copy of "val".
*/

View File

@@ -1336,6 +1336,8 @@ check_due_timer(void)
this_due = proftime_time_left(&timer->tr_due, &now);
if (this_due <= 1)
{
/* Save and restore a lot of flags, because the timer fires while
* waiting for a character, which might be halfway a command. */
int save_timer_busy = timer_busy;
int save_vgetc_busy = vgetc_busy;
int save_did_emsg = did_emsg;
@@ -1345,6 +1347,7 @@ check_due_timer(void)
int save_did_throw = did_throw;
int save_ex_pressedreturn = get_pressedreturn();
except_T *save_current_exception = current_exception;
vimvars_save_T vvsave;
/* Create a scope for running the timer callback, ignoring most of
* the current scope, such as being inside a try/catch. */
@@ -1357,6 +1360,7 @@ check_due_timer(void)
trylevel = 0;
did_throw = FALSE;
current_exception = NULL;
save_vimvars(&vvsave);
timer->tr_firing = TRUE;
timer_callback(timer);
@@ -1373,6 +1377,7 @@ check_due_timer(void)
trylevel = save_trylevel;
did_throw = save_did_throw;
current_exception = save_current_exception;
restore_vimvars(&vvsave);
if (must_redraw != 0)
need_update_screen = TRUE;
must_redraw = must_redraw > save_must_redraw

View File

@@ -4648,8 +4648,8 @@ b0_magic_wrong(ZERO_BL *b0p)
* == 0 == 0 OK FAIL TRUE
*
* current file doesn't exist, inode for swap unknown, both file names not
* available -> probably same file
* == 0 == 0 FAIL FAIL FALSE
* available -> compare file names
* == 0 == 0 FAIL FAIL fname_c != fname_s
*
* Note that when the ino_t is 64 bits, only the last 32 will be used. This
* can't be changed without making the block 0 incompatible with 32 bit
@@ -4693,14 +4693,15 @@ fnamecmp_ino(
retval_c = vim_FullName(fname_c, buf_c, MAXPATHL, TRUE);
retval_s = vim_FullName(fname_s, buf_s, MAXPATHL, TRUE);
if (retval_c == OK && retval_s == OK)
return (STRCMP(buf_c, buf_s) != 0);
return STRCMP(buf_c, buf_s) != 0;
/*
* Can't compare inodes or file names, guess that the files are different,
* unless both appear not to exist at all.
* unless both appear not to exist at all, then compare with the file name
* in the swap file.
*/
if (ino_s == 0 && ino_c == 0 && retval_c == FAIL && retval_s == FAIL)
return FALSE;
return STRCMP(fname_c, fname_s) != 0;
return TRUE;
}
#endif /* CHECK_INODE */

View File

@@ -5645,7 +5645,12 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
/* When using pty_master_fd only set it for stdout, do not duplicate it
* for stderr, it only needs to be read once. */
int err_fd = use_out_for_err || use_file_for_err || use_null_for_err
? INVALID_FD : fd_err[0] < 0 ? INVALID_FD : fd_err[0];
? INVALID_FD
: fd_err[0] >= 0
? fd_err[0]
: (out_fd == pty_master_fd
? INVALID_FD
: pty_master_fd);
channel_set_pipes(channel, in_fd, out_fd, err_fd);
channel_set_job(channel, job, options);

View File

@@ -67,6 +67,8 @@ list_T *get_vim_var_list(int idx);
dict_T *get_vim_var_dict(int idx);
void set_vim_var_char(int c);
void set_vcount(long count, long count1, int set_prevcount);
void save_vimvars(vimvars_save_T *vvsave);
void restore_vimvars(vimvars_save_T *vvsave);
void set_vim_var_string(int idx, char_u *val, int len);
void set_vim_var_list(int idx, list_T *val);
void set_vim_var_dict(int idx, dict_T *val);

View File

@@ -9,6 +9,7 @@ void redraw_buf_and_status_later(buf_T *buf, int type);
int redraw_asap(int type);
void redraw_after_callback(int call_update_screen);
void redrawWinline(linenr_T lnum, int invalid);
void reset_updating_screen(int may_resize_shell);
void update_curbuf(int type);
int update_screen(int type_arg);
int conceal_cursor_line(win_T *wp);

View File

@@ -20,6 +20,7 @@ void term_win_entered(void);
int terminal_loop(int blocking);
void term_job_ended(job_T *job);
void term_channel_closed(channel_T *ch);
void term_check_channel_closed_recently(void);
int term_do_update_window(win_T *wp);
void term_update_window(win_T *wp);
int term_is_finished(buf_T *buf);

View File

@@ -512,6 +512,19 @@ redrawWinline(
curwin->w_lines[i].wl_valid = FALSE;
}
#endif
}
void
reset_updating_screen(int may_resize_shell UNUSED)
{
updating_screen = FALSE;
#ifdef FEAT_GUI
if (may_resize_shell)
gui_may_resize_shell();
#endif
#ifdef FEAT_TERMINAL
term_check_channel_closed_recently();
#endif
}
/*
@@ -778,10 +791,7 @@ update_screen(int type_arg)
FOR_ALL_WINDOWS(wp)
wp->w_buffer->b_mod_set = FALSE;
updating_screen = FALSE;
#ifdef FEAT_GUI
gui_may_resize_shell();
#endif
reset_updating_screen(TRUE);
/* Clear or redraw the command line. Done last, because scrolling may
* mess up the command line. */
@@ -861,11 +871,9 @@ update_finish(void)
end_search_hl();
# endif
updating_screen = FALSE;
reset_updating_screen(TRUE);
# ifdef FEAT_GUI
gui_may_resize_shell();
/* Redraw the cursor and update the scrollbars when all screen updating is
* done. */
if (gui.in_use)

View File

@@ -3423,3 +3423,9 @@ typedef struct {
int save_opcount;
tasave_T tabuf;
} save_state_T;
typedef struct {
varnumber_T vv_prevcount;
varnumber_T vv_count;
varnumber_T vv_count1;
} vimvars_save_T;

View File

@@ -38,6 +38,9 @@
* in tl_scrollback are no longer used.
*
* TODO:
* - Win32: Termdebug doesn't work, because gdb does not support mi2. This
* plugin: https://github.com/cpiger/NeoDebug runs gdb as a job, redirecting
* input and output. Command I/O is in gdb window.
* - Win32: Redirecting input does not work, half of Test_terminal_redir_file()
* is disabled.
* - Win32: Redirecting output works but includes escape sequences.
@@ -100,6 +103,8 @@ struct terminal_S {
int tl_normal_mode; /* TRUE: Terminal-Normal mode */
int tl_channel_closed;
int tl_channel_recently_closed; // still need to handle tl_finish
int tl_finish;
#define TL_FINISH_UNSET NUL
#define TL_FINISH_CLOSE 'c' /* ++close or :terminal without argument */
@@ -971,7 +976,10 @@ write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
if (buffer == curbuf)
{
update_screen(0);
update_cursor(term, TRUE);
/* update_screen() can be slow, check the terminal wasn't closed
* already */
if (buffer == curbuf && curbuf->b_term != NULL)
update_cursor(curbuf->b_term, TRUE);
}
else
redraw_after_callback(TRUE);
@@ -1454,6 +1462,7 @@ cleanup_scrollback(term_T *term)
sb_line_T *line;
garray_T *gap;
curbuf = term->tl_buffer;
gap = &term->tl_scrollback;
while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled
&& gap->ga_len > 0)
@@ -1463,7 +1472,9 @@ cleanup_scrollback(term_T *term)
vim_free(line->sb_cells);
--gap->ga_len;
}
check_cursor();
curbuf = curwin->w_buffer;
if (curbuf == term->tl_buffer)
check_cursor();
}
/*
@@ -1487,8 +1498,8 @@ move_terminal_to_buffer(term_T *term)
/* Nothing to do if the buffer already has the lines and nothing was
* changed. */
if (!term->tl_dirty_snapshot
&& curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled)
if (!term->tl_dirty_snapshot && term->tl_buffer->b_ml.ml_line_count
> term->tl_scrollback_scrolled)
return;
ch_log(term->tl_job == NULL ? NULL : term->tl_job->jv_channel,
@@ -1595,23 +1606,24 @@ move_terminal_to_buffer(term_T *term)
vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
&term->tl_default_color.fg, &term->tl_default_color.bg);
FOR_ALL_WINDOWS(wp)
{
if (wp->w_buffer == term->tl_buffer)
if (term->tl_normal_mode)
FOR_ALL_WINDOWS(wp)
{
wp->w_cursor.lnum = term->tl_buffer->b_ml.ml_line_count;
wp->w_cursor.col = 0;
wp->w_valid = 0;
if (wp->w_cursor.lnum >= wp->w_height)
if (wp->w_buffer == term->tl_buffer)
{
linenr_T min_topline = wp->w_cursor.lnum - wp->w_height + 1;
wp->w_cursor.lnum = term->tl_buffer->b_ml.ml_line_count;
wp->w_cursor.col = 0;
wp->w_valid = 0;
if (wp->w_cursor.lnum >= wp->w_height)
{
linenr_T min_topline = wp->w_cursor.lnum - wp->w_height + 1;
if (wp->w_topline < min_topline)
wp->w_topline = min_topline;
if (wp->w_topline < min_topline)
wp->w_topline = min_topline;
}
redraw_win_later(wp, NOT_VALID);
}
redraw_win_later(wp, NOT_VALID);
}
}
}
#if defined(FEAT_TIMERS) || defined(PROTO)
@@ -1677,11 +1689,11 @@ term_enter_normal_mode(void)
{
term_T *term = curbuf->b_term;
set_terminal_mode(term, TRUE);
/* Append the current terminal contents to the buffer. */
move_terminal_to_buffer(term);
set_terminal_mode(term, TRUE);
/* Move the window cursor to the position of the cursor in the
* terminal. */
curwin->w_cursor.lnum = term->tl_scrollback_scrolled
@@ -2076,7 +2088,7 @@ terminal_loop(int blocking)
int tty_fd = curbuf->b_term->tl_job->jv_channel
->ch_part[get_tty_part(curbuf->b_term)].ch_fd;
#endif
int restore_cursor;
int restore_cursor = FALSE;
/* Remember the terminal we are sending keys to. However, the terminal
* might be closed while waiting for a character, e.g. typing "exit" in a
@@ -2100,6 +2112,10 @@ terminal_loop(int blocking)
while (must_redraw != 0)
if (update_screen(0) == FAIL)
break;
if (!term_use_loop_check(TRUE))
/* job finished while redrawing */
break;
update_cursor(curbuf->b_term, FALSE);
restore_cursor = TRUE;
@@ -2769,6 +2785,53 @@ static VTermScreenCallbacks screen_callbacks = {
NULL /* sb_popline */
};
/*
* Do the work after the channel of a terminal was closed.
* Must be called only when updating_screen is FALSE.
* Returns TRUE when a buffer was closed (list of terminals may have changed).
*/
static int
term_after_channel_closed(term_T *term)
{
/* Unless in Terminal-Normal mode: clear the vterm. */
if (!term->tl_normal_mode)
{
int fnum = term->tl_buffer->b_fnum;
cleanup_vterm(term);
if (term->tl_finish == TL_FINISH_CLOSE)
{
aco_save_T aco;
/* ++close or term_finish == "close" */
ch_log(NULL, "terminal job finished, closing window");
aucmd_prepbuf(&aco, term->tl_buffer);
do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
aucmd_restbuf(&aco);
return TRUE;
}
if (term->tl_finish == TL_FINISH_OPEN
&& term->tl_buffer->b_nwindows == 0)
{
char buf[50];
/* TODO: use term_opencmd */
ch_log(NULL, "terminal job finished, opening window");
vim_snprintf(buf, sizeof(buf),
term->tl_opencmd == NULL
? "botright sbuf %d"
: (char *)term->tl_opencmd, fnum);
do_cmdline_cmd((char_u *)buf);
}
else
ch_log(NULL, "terminal job finished");
}
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
return FALSE;
}
/*
* Called when a channel has been closed.
* If this was a channel for a terminal window then finish it up.
@@ -2777,9 +2840,12 @@ static VTermScreenCallbacks screen_callbacks = {
term_channel_closed(channel_T *ch)
{
term_T *term;
term_T *next_term;
int did_one = FALSE;
for (term = first_term; term != NULL; term = term->tl_next)
for (term = first_term; term != NULL; term = next_term)
{
next_term = term->tl_next;
if (term->tl_job == ch->ch_job)
{
term->tl_channel_closed = TRUE;
@@ -2795,43 +2861,19 @@ term_channel_closed(channel_T *ch)
}
#endif
/* Unless in Terminal-Normal mode: clear the vterm. */
if (!term->tl_normal_mode)
if (updating_screen)
{
int fnum = term->tl_buffer->b_fnum;
cleanup_vterm(term);
if (term->tl_finish == TL_FINISH_CLOSE)
{
aco_save_T aco;
/* ++close or term_finish == "close" */
ch_log(NULL, "terminal job finished, closing window");
aucmd_prepbuf(&aco, term->tl_buffer);
do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE);
aucmd_restbuf(&aco);
break;
}
if (term->tl_finish == TL_FINISH_OPEN
&& term->tl_buffer->b_nwindows == 0)
{
char buf[50];
/* TODO: use term_opencmd */
ch_log(NULL, "terminal job finished, opening window");
vim_snprintf(buf, sizeof(buf),
term->tl_opencmd == NULL
? "botright sbuf %d"
: (char *)term->tl_opencmd, fnum);
do_cmdline_cmd((char_u *)buf);
}
else
ch_log(NULL, "terminal job finished");
/* Cannot open or close windows now. Can happen when
* 'lazyredraw' is set. */
term->tl_channel_recently_closed = TRUE;
continue;
}
redraw_buf_and_status_later(term->tl_buffer, NOT_VALID);
if (term_after_channel_closed(term))
next_term = first_term;
}
}
if (did_one)
{
redraw_statuslines();
@@ -2850,6 +2892,29 @@ term_channel_closed(channel_T *ch)
}
}
/*
* To be called after resetting updating_screen: handle any terminal where the
* channel was closed.
*/
void
term_check_channel_closed_recently()
{
term_T *term;
term_T *next_term;
for (term = first_term; term != NULL; term = next_term)
{
next_term = term->tl_next;
if (term->tl_channel_recently_closed)
{
term->tl_channel_recently_closed = FALSE;
if (term_after_channel_closed(term))
// start over, the list may have changed
next_term = first_term;
}
}
}
/*
* Fill one screen line from a line of the terminal.
* Advances "pos" to past the last column.

View File

@@ -470,4 +470,25 @@ func Test_verbosefile()
call delete('Xlog')
endfunc
func Test_setcmdpos()
func InsertTextAtPos(text, pos)
call assert_equal(0, setcmdpos(a:pos))
return a:text
endfunc
" setcmdpos() with position in the middle of the command line.
call feedkeys(":\"12\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
call assert_equal('"1ab2', @:)
call feedkeys(":\"12\<C-R>\<C-R>=InsertTextAtPos('a', 3)\<CR>b\<CR>", 'xt')
call assert_equal('"1b2a', @:)
" setcmdpos() with position beyond the end of the command line.
call feedkeys(":\"12\<C-B>\<C-R>=InsertTextAtPos('a', 10)\<CR>b\<CR>", 'xt')
call assert_equal('"12ab', @:)
" setcmdpos() returns 1 when not editing the command line.
call assert_equal(1, setcmdpos(3))
endfunc
set cpo&

View File

@@ -82,3 +82,18 @@ func Test_swap_group()
call delete('Xtest')
endtry
endfunc
func Test_missing_dir()
call mkdir('Xswapdir')
exe 'set directory=' . getcwd() . '/Xswapdir'
call assert_equal('', glob('foo'))
call assert_equal('', glob('bar'))
edit foo/x.txt
" This should not give a warning for an existing swap file.
split bar/x.txt
only
set directory&
call delete('Xswapdir', 'rf')
endfunc

View File

@@ -1484,3 +1484,26 @@ func Test_terminal_termwinkey()
call feedkeys("\<C-L>\<C-C>", 'tx')
call WaitForAssert({-> assert_equal("dead", job_status(job))})
endfunc
func Test_terminal_out_err()
if !has('unix')
return
endif
call writefile([
\ '#!/bin/sh',
\ 'echo "this is standard error" >&2',
\ 'echo "this is standard out" >&1',
\ ], 'Xechoerrout.sh')
call setfperm('Xechoerrout.sh', 'rwxrwx---')
let outfile = 'Xtermstdout'
let buf = term_start(['./Xechoerrout.sh'], {'out_io': 'file', 'out_name': outfile})
call WaitForAssert({-> assert_inrange(1, 2, len(readfile(outfile)))})
call assert_equal("this is standard out", readfile(outfile)[0])
call assert_equal('this is standard error', term_getline(buf, 1))
call WaitForAssert({-> assert_equal('dead', job_status(term_getjob(buf)))})
exe buf . 'bwipe'
call delete('Xechoerrout.sh')
call delete(outfile)
endfunc

View File

@@ -5,6 +5,7 @@ if !has('timers')
endif
source shared.vim
source screendump.vim
func MyHandler(timer)
let g:val += 1
@@ -260,4 +261,35 @@ func Test_ex_mode()
call timer_stop(timer)
endfunc
func Test_restore_count()
if !CanRunVimInTerminal()
return
endif
" Check that v:count is saved and restored, not changed by a timer.
call writefile([
\ 'nnoremap <expr><silent> L v:count ? v:count . "l" : "l"',
\ 'func Doit(id)',
\ ' normal 3j',
\ 'endfunc',
\ 'call timer_start(100, "Doit")',
\ ], 'Xtrcscript')
call writefile([
\ '1-1234',
\ '2-1234',
\ '3-1234',
\ ], 'Xtrctext')
let buf = RunVimInTerminal('-S Xtrcscript Xtrctext', {})
" Wait for the timer to move the cursor to the third line.
call WaitForAssert({-> assert_equal(3, term_getcursor(buf)[0])})
call assert_equal(1, term_getcursor(buf)[1])
" Now check that v:count has not been set to 3
call term_sendkeys(buf, 'L')
call WaitForAssert({-> assert_equal(2, term_getcursor(buf)[1])})
call StopVimInTerminal(buf)
call delete('Xtrcscript')
call delete('Xtrctext')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -415,7 +415,10 @@ ui_breakcheck_force(int force)
#endif
mch_breakcheck(force);
updating_screen = save_us;
if (save_us)
updating_screen = save_us;
else
reset_updating_screen(FALSE);
}
/*****************************************************************************

View File

@@ -761,6 +761,28 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1824,
/**/
1823,
/**/
1822,
/**/
1821,
/**/
1820,
/**/
1819,
/**/
1818,
/**/
1817,
/**/
1816,
/**/
1815,
/**/
1814,
/**/
1813,
/**/