From 9ec7fa82a2c4f0283862ed704c2940959e6130ee Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 Oct 2016 13:06:41 +0200 Subject: [PATCH 1/3] patch 8.0.0043 Problem: When using Insert mode completion with 'completeopt' containing "noinsert" with CTRL-N the change is not saved for undo. (Tommy Allen) Solution: Call stop_arrow() before inserting for any key. --- src/edit.c | 19 ++++++++++++++----- src/testdir/test_popup.vim | 5 +++++ src/version.c | 2 ++ 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/edit.c b/src/edit.c index 776a420f27..3a0e18841c 100644 --- a/src/edit.c +++ b/src/edit.c @@ -4634,14 +4634,19 @@ ins_compl_get_exp(pos_T *ini) static void ins_compl_delete(void) { - int i; + int col; /* * In insert mode: Delete the typed part. * In replace mode: Put the old characters back, if any. */ - i = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0); - backspace_until_column(i); + col = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0); + if ((int)curwin->w_cursor.col > col) + { + if (stop_arrow() == FAIL) + return; + backspace_until_column(col); + } /* TODO: is this sufficient for redrawing? Redrawing everything causes * flicker, thus we can't do that. */ @@ -5059,8 +5064,11 @@ ins_complete(int c, int enable_pum) colnr_T curs_col; /* cursor column */ int n; int save_w_wrow; + int insert_match; compl_direction = ins_compl_key2dir(c); + insert_match = ins_compl_use_match(c); + if (!compl_started) { /* First time we hit ^N or ^P (in a row, I mean) */ @@ -5486,6 +5494,8 @@ ins_complete(int c, int enable_pum) edit_submode_extra = NULL; out_flush(); } + else if (insert_match && stop_arrow() == FAIL) + return FAIL; compl_shown_match = compl_curr_match; compl_shows_dir = compl_direction; @@ -5494,8 +5504,7 @@ ins_complete(int c, int enable_pum) * Find next match (and following matches). */ save_w_wrow = curwin->w_wrow; - n = ins_compl_next(TRUE, ins_compl_key2count(c), - ins_compl_use_match(c), FALSE); + n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE); /* may undisplay the popup menu */ ins_compl_upd_pum(); diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index d037b7abd9..cc93ff84fa 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -427,6 +427,11 @@ func Test_complete_no_undo() call feedkeys("u", 'xt') call assert_equal('bbb', getline(2)) + call feedkeys("A\\\", 'xt') + call assert_equal('January', getline(2)) + call feedkeys("u", 'xt') + call assert_equal('bbb', getline(2)) + iunmap set completeopt& q! diff --git a/src/version.c b/src/version.c index 3a2b1a5e04..e910845d1c 100644 --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 43, /**/ 42, /**/ From 025e3e0bafbc85cc4e365145af711edf99d0a90d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 Oct 2016 14:50:18 +0200 Subject: [PATCH 2/3] patch 8.0.0044 Problem: In diff mode the cursor may end up below the last line, resulting in an ml_get error. Solution: Check the line to be valid. --- src/diff.c | 62 ++++++++++++++++++----------------- src/move.c | 7 ++-- src/proto/diff.pro | 2 +- src/testdir/test_diffmode.vim | 17 ++++++++++ src/version.c | 2 ++ 5 files changed, 54 insertions(+), 36 deletions(-) diff --git a/src/diff.c b/src/diff.c index 9c12ea4e67..a4a2acb95f 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1100,10 +1100,7 @@ ex_diffsplit(exarg_T *eap) if (bufref_valid(&old_curbuf)) /* Move the cursor position to that of the old window. */ curwin->w_cursor.lnum = diff_get_corresponding_line( - old_curbuf.br_buf, - old_curwin->w_cursor.lnum, - curbuf, - curwin->w_cursor.lnum); + old_curbuf.br_buf, old_curwin->w_cursor.lnum); } /* Now that lines are folded scroll to show the cursor at the same * relative position. */ @@ -2524,21 +2521,22 @@ diff_move_to(int dir, long count) return OK; } - linenr_T -diff_get_corresponding_line( +/* + * Return the line number in the current window that is closest to "lnum1" in + * "buf1" in diff mode. + */ + static linenr_T +diff_get_corresponding_line_int( buf_T *buf1, - linenr_T lnum1, - buf_T *buf2, - linenr_T lnum3) + linenr_T lnum1) { int idx1; int idx2; diff_T *dp; int baseline = 0; - linenr_T lnum2; idx1 = diff_buf_idx(buf1); - idx2 = diff_buf_idx(buf2); + idx2 = diff_buf_idx(curbuf); if (idx1 == DB_COUNT || idx2 == DB_COUNT || curtab->tp_first_diff == NULL) return lnum1; @@ -2551,15 +2549,8 @@ diff_get_corresponding_line( for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next) { if (dp->df_lnum[idx1] > lnum1) - { - lnum2 = lnum1 - baseline; - /* don't end up past the end of the file */ - if (lnum2 > buf2->b_ml.ml_line_count) - lnum2 = buf2->b_ml.ml_line_count; - - return lnum2; - } - else if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1) + return lnum1 - baseline; + if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1) { /* Inside the diffblock */ baseline = lnum1 - dp->df_lnum[idx1]; @@ -2568,10 +2559,11 @@ diff_get_corresponding_line( return dp->df_lnum[idx2] + baseline; } - else if ( (dp->df_lnum[idx1] == lnum1) - && (dp->df_count[idx1] == 0) - && (dp->df_lnum[idx2] <= lnum3) - && ((dp->df_lnum[idx2] + dp->df_count[idx2]) > lnum3)) + if ( (dp->df_lnum[idx1] == lnum1) + && (dp->df_count[idx1] == 0) + && (dp->df_lnum[idx2] <= curwin->w_cursor.lnum) + && ((dp->df_lnum[idx2] + dp->df_count[idx2]) + > curwin->w_cursor.lnum)) /* * Special case: if the cursor is just after a zero-count * block (i.e. all filler) and the target cursor is already @@ -2579,18 +2571,28 @@ diff_get_corresponding_line( * unmoved. This makes repeated CTRL-W W operations work * as expected. */ - return lnum3; + return curwin->w_cursor.lnum; baseline = (dp->df_lnum[idx1] + dp->df_count[idx1]) - (dp->df_lnum[idx2] + dp->df_count[idx2]); } /* If we get here then the cursor is after the last diff */ - lnum2 = lnum1 - baseline; - /* don't end up past the end of the file */ - if (lnum2 > buf2->b_ml.ml_line_count) - lnum2 = buf2->b_ml.ml_line_count; + return lnum1 - baseline; +} - return lnum2; +/* + * Return the line number in the current window that is closest to "lnum1" in + * "buf1" in diff mode. Checks the line number to be valid. + */ + linenr_T +diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1) +{ + linenr_T lnum = diff_get_corresponding_line_int(buf1, lnum1); + + /* don't end up past the end of the file */ + if (lnum > curbuf->b_ml.ml_line_count) + return curbuf->b_ml.ml_line_count; + return lnum; } #if defined(FEAT_FOLDING) || defined(PROTO) diff --git a/src/move.c b/src/move.c index a4d5f82997..c7acdfa68b 100644 --- a/src/move.c +++ b/src/move.c @@ -2824,11 +2824,8 @@ do_check_cursorbind(void) { # ifdef FEAT_DIFF if (curwin->w_p_diff) - curwin->w_cursor.lnum - = diff_get_corresponding_line(old_curbuf, - line, - curbuf, - curwin->w_cursor.lnum); + curwin->w_cursor.lnum = + diff_get_corresponding_line(old_curbuf, line); else # endif curwin->w_cursor.lnum = line; diff --git a/src/proto/diff.pro b/src/proto/diff.pro index c7a7ebe579..718640152f 100644 --- a/src/proto/diff.pro +++ b/src/proto/diff.pro @@ -22,6 +22,6 @@ void nv_diffgetput(int put, long count); void ex_diffgetput(exarg_T *eap); int diff_mode_buf(buf_T *buf); int diff_move_to(int dir, long count); -linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1, buf_T *buf2, linenr_T lnum3); +linenr_T diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1); linenr_T diff_lnum_win(linenr_T lnum, win_T *wp); /* vim: set ft=c : */ diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index 5de394de8e..f40e06ff33 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -218,3 +218,20 @@ func Test_diffoff() bwipe! bwipe! endfunc + +func Test_setting_cursor() + new Xtest1 + put =range(1,90) + wq + new Xtest2 + put =range(1,100) + wq + + tabe Xtest2 + $ + diffsp Xtest1 + tabclose + + call delete('Xtest1') + call delete('Xtest2') +endfunc diff --git a/src/version.c b/src/version.c index e910845d1c..80a837a381 100644 --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 44, /**/ 43, /**/ From bb09ceb95477ecc271854b3fdd8d2776eca66adf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 18 Oct 2016 16:27:23 +0200 Subject: [PATCH 3/3] patch 8.0.0045 Problem: Calling job_stop() right after job_start() does not work. Solution: Block signals while fork is still busy. (Ozaki Kiichi, closes #1155) --- src/auto/configure | 2 +- src/config.h.in | 1 + src/configure.in | 2 +- src/os_unix.c | 56 +++++++++++++++++++++++++++++++++--- src/testdir/test_channel.vim | 15 ++++++++++ src/version.c | 2 ++ 6 files changed, 72 insertions(+), 6 deletions(-) diff --git a/src/auto/configure b/src/auto/configure index b42f601db2..27aea9c989 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -12004,7 +12004,7 @@ for ac_func in bcmp fchdir fchown fsync getcwd getpseudotty \ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ - sigvec strcasecmp strerror strftime stricmp strncasecmp \ + sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \ strnicmp strpbrk strtol tgetent towlower towupper iswupper \ usleep utime utimes do : diff --git a/src/config.h.in b/src/config.h.in index 9d35e48fa6..62427e28eb 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -190,6 +190,7 @@ #undef HAVE_SIGSET #undef HAVE_SIGSETJMP #undef HAVE_SIGSTACK +#undef HAVE_SIGPROCMASK #undef HAVE_SIGVEC #undef HAVE_SMACK #undef HAVE_STRCASECMP diff --git a/src/configure.in b/src/configure.in index c0a60b2277..43bf9ad170 100644 --- a/src/configure.in +++ b/src/configure.in @@ -3598,7 +3598,7 @@ AC_CHECK_FUNCS(bcmp fchdir fchown fsync getcwd getpseudotty \ getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \ memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \ setpgid setsid sigaltstack sigstack sigset sigsetjmp sigaction \ - sigvec strcasecmp strerror strftime stricmp strncasecmp \ + sigprocmask sigvec strcasecmp strerror strftime stricmp strncasecmp \ strnicmp strpbrk strtol tgetent towlower towupper iswupper \ usleep utime utimes) AC_FUNC_FSEEKO diff --git a/src/os_unix.c b/src/os_unix.c index bc9acd4f7b..0569184139 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -211,6 +211,15 @@ static RETSIGTYPE deathtrap SIGPROTOARG; static void catch_int_signal(void); static void set_signals(void); static void catch_signals(RETSIGTYPE (*func_deadly)(), RETSIGTYPE (*func_other)()); +#ifdef HAVE_SIGPROCMASK +# define SIGSET_DECL(set) sigset_t set; +# define BLOCK_SIGNALS(set) block_signals(set) +# define UNBLOCK_SIGNALS(set) unblock_signals(set) +#else +# define SIGSET_DECL(set) +# define BLOCK_SIGNALS(set) do { /**/ } while (0) +# define UNBLOCK_SIGNALS(set) do { /**/ } while (0) +#endif static int have_wildcard(int, char_u **); static int have_dollars(int, char_u **); @@ -1468,6 +1477,33 @@ catch_signals( signal(signal_info[i].sig, func_other); } +#ifdef HAVE_SIGPROCMASK + static void +block_signals(sigset_t *set) +{ + sigset_t newset; + int i; + + sigemptyset(&newset); + + for (i = 0; signal_info[i].sig != -1; i++) + sigaddset(&newset, signal_info[i].sig); + +# if defined(_REENTRANT) && defined(SIGCONT) + /* SIGCONT isn't in the list, because its default action is ignore */ + sigaddset(&newset, SIGCONT); +# endif + + sigprocmask(SIG_BLOCK, &newset, set); +} + + static void +unblock_signals(sigset_t *set) +{ + sigprocmask(SIG_SETMASK, set, NULL); +} +#endif + /* * Handling of SIGHUP, SIGQUIT and SIGTERM: * "when" == a signal: when busy, postpone and return FALSE, otherwise @@ -4283,12 +4319,18 @@ mch_call_shell( if (!pipe_error) /* pty or pipe opened or not used */ { + SIGSET_DECL(curset) + # ifdef __BEOS__ beos_cleanup_read_thread(); # endif - if ((pid = fork()) == -1) /* maybe we should use vfork() */ + BLOCK_SIGNALS(&curset); + pid = fork(); /* maybe we should use vfork() */ + if (pid == -1) { + UNBLOCK_SIGNALS(&curset); + MSG_PUTS(_("\nCannot fork\n")); if ((options & (SHELL_READ|SHELL_WRITE)) # ifdef FEAT_GUI @@ -4315,6 +4357,7 @@ mch_call_shell( else if (pid == 0) /* child */ { reset_signals(); /* handle signals normally */ + UNBLOCK_SIGNALS(&curset); if (!show_shell_mess || (options & SHELL_EXPAND)) { @@ -4458,6 +4501,7 @@ mch_call_shell( */ catch_signals(SIG_IGN, SIG_ERR); catch_int_signal(); + UNBLOCK_SIGNALS(&curset); /* * For the GUI we redirect stdin, stdout and stderr to our window. @@ -5069,6 +5113,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) int use_file_for_out = options->jo_io[PART_OUT] == JIO_FILE; int use_file_for_err = options->jo_io[PART_ERR] == JIO_FILE; int use_out_for_err = options->jo_io[PART_ERR] == JIO_OUT; + SIGSET_DECL(curset) if (use_out_for_err && use_null_for_out) use_null_for_err = TRUE; @@ -5140,13 +5185,14 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) goto failed; } + BLOCK_SIGNALS(&curset); pid = fork(); /* maybe we should use vfork() */ - if (pid == -1) + if (pid == -1) { /* failed to fork */ + UNBLOCK_SIGNALS(&curset); goto failed; } - if (pid == 0) { int null_fd = -1; @@ -5154,6 +5200,7 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) /* child */ reset_signals(); /* handle signals normally */ + UNBLOCK_SIGNALS(&curset); # ifdef HAVE_SETSID /* Create our own process group, so that the child and all its @@ -5234,6 +5281,8 @@ mch_start_job(char **argv, job_T *job, jobopt_T *options UNUSED) } /* parent */ + UNBLOCK_SIGNALS(&curset); + job->jv_pid = pid; job->jv_status = JOB_STARTED; job->jv_channel = channel; /* ch_refcount was set above */ @@ -5357,7 +5406,6 @@ mch_detect_ended_job(job_T *job_list) } } return NULL; - } int diff --git a/src/testdir/test_channel.vim b/src/testdir/test_channel.vim index e7ba667680..0a50ed47e4 100644 --- a/src/testdir/test_channel.vim +++ b/src/testdir/test_channel.vim @@ -1433,6 +1433,21 @@ func Test_job_start_invalid() call assert_fails('call job_start("")', 'E474:') endfunc +func Test_job_stop_immediately() + if !has('job') + return + endif + + let job = job_start([s:python, '-c', 'import time;time.sleep(10)']) + try + call job_stop(job) + call WaitFor('"dead" == job_status(job)') + call assert_equal('dead', job_status(job)) + finally + call job_stop(job, 'kill') + endtry +endfunc + " This was leaking memory. func Test_partial_in_channel_cycle() let d = {} diff --git a/src/version.c b/src/version.c index 80a837a381..b15752024a 100644 --- a/src/version.c +++ b/src/version.c @@ -764,6 +764,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 45, /**/ 44, /**/