From 7cc596547a582e7bc18d91312eb674906ebdc5c2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 13:14:46 +0200 Subject: [PATCH 01/24] patch 8.1.0241: effect of ":tabmove N" is not clear Problem: Effect of ":tabmove N" is not clear. Solution: Add a test that shows the behavior. (Christian Brabandt, closes #3288) --- src/testdir/test_tabpage.vim | 13 +++++++++++++ src/version.c | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/testdir/test_tabpage.vim b/src/testdir/test_tabpage.vim index f4fbf28d19..add9b3d7cf 100644 --- a/src/testdir/test_tabpage.vim +++ b/src/testdir/test_tabpage.vim @@ -105,6 +105,19 @@ function Test_tabpage() call assert_equal(4, tabpagenr()) 7tabmove 5 call assert_equal(5, tabpagenr()) + + " The following are a no-op + norm! 2gt + call assert_equal(2, tabpagenr()) + tabmove 2 + call assert_equal(2, tabpagenr()) + 2tabmove + call assert_equal(2, tabpagenr()) + tabmove 1 + call assert_equal(2, tabpagenr()) + 1tabmove + call assert_equal(2, tabpagenr()) + call assert_fails("99tabmove", 'E16:') call assert_fails("+99tabmove", 'E16:') call assert_fails("-99tabmove", 'E16:') diff --git a/src/version.c b/src/version.c index c3b7add519..6162752f20 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 241, /**/ 240, /**/ From 02ab97709d5c56fb7fe42e134bb9fc54f76a1f9f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 14:55:09 +0200 Subject: [PATCH 02/24] patch 8.1.0242: Insert mode completion may use an invalid buffer pointer Problem: Insert mode completion may use an invalid buffer pointer. Solution: Check for ins_buf to be valid. (closes #3290) --- src/edit.c | 7 ++++++- src/version.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/edit.c b/src/edit.c index daadc7b7b0..45176d79f4 100644 --- a/src/edit.c +++ b/src/edit.c @@ -4419,10 +4419,15 @@ ins_compl_get_exp(pos_T *ini) ? (char_u *)"." : curbuf->b_p_cpt; last_match_pos = first_match_pos = *ini; } + else if (ins_buf != curbuf && !buf_valid(ins_buf)) + ins_buf = curbuf; // In case the buffer was wiped out. compl_old_match = compl_curr_match; /* remember the last current match */ pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos; - /* For ^N/^P loop over all the flags/windows/buffers in 'complete' */ + + /* + * For ^N/^P loop over all the flags/windows/buffers in 'complete'. + */ for (;;) { found_new_match = FAIL; diff --git a/src/version.c b/src/version.c index 6162752f20..5a263a93e0 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 242, /**/ 241, /**/ From 5db7eec42337f0eecdc332f582eecf37278044e8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 16:33:18 +0200 Subject: [PATCH 03/24] patch 8.1.0243: using :term ++close ++hidden closes a window Problem: Using :term ++close ++hidden closes a window. (Marcin Szamotulski) Solution: Don't close the window if only using it temporarily for unloading the terminal buffer. (closes #3287) --- src/terminal.c | 8 +++++++- src/testdir/test_terminal.vim | 12 ++++++++++++ src/version.c | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/terminal.c b/src/terminal.c index 427e027c5b..66a73690fa 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -2818,11 +2818,17 @@ term_after_channel_closed(term_T *term) if (term->tl_finish == TL_FINISH_CLOSE) { aco_save_T aco; + int do_set_w_closing = term->tl_buffer->b_nwindows == 0; - /* ++close or term_finish == "close" */ + // ++close or term_finish == "close" ch_log(NULL, "terminal job finished, closing window"); aucmd_prepbuf(&aco, term->tl_buffer); + // Avoid closing the window if we temporarily use it. + if (do_set_w_closing) + curwin->w_closing = TRUE; do_bufdel(DOBUF_WIPE, (char_u *)"", 1, fnum, fnum, FALSE); + if (do_set_w_closing) + curwin->w_closing = FALSE; aucmd_restbuf(&aco); return TRUE; } diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 9126324707..b82dae13e3 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -1621,3 +1621,15 @@ func Test_terminal_hidden() call WaitForAssert({-> assert_equal('finished', term_getstatus(bnr))}) bwipe! endfunc + +func Test_terminal_hidden_and_close() + if !has('unix') + return + endif + call assert_equal(1, winnr('$')) + term ++hidden ++close ls + let bnr = bufnr('$') + call assert_equal('terminal', getbufvar(bnr, '&buftype')) + call WaitForAssert({-> assert_false(bufexists(bnr))}) + call assert_equal(1, winnr('$')) +endfunc diff --git a/src/version.c b/src/version.c index 5a263a93e0..46125c029d 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 243, /**/ 242, /**/ From 917e32bda5a93941fbbccab09ae3960114b67188 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 17:38:41 +0200 Subject: [PATCH 04/24] patch 8.1.0244: no redraw when using a STOP signal on Vim and then CONT Problem: No redraw when using a STOP signal on Vim and then a CONT signal. Solution: Catch the CONT signal and force a redraw. (closes #3285) --- src/os_unix.c | 68 +++++++++++++++++++++++++++++++++++++--------- src/proto/term.pro | 1 + src/term.c | 15 +++++++--- src/version.c | 2 ++ 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/src/os_unix.c b/src/os_unix.c index 3649276c49..94c3dc9a2e 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -1227,7 +1227,23 @@ deathtrap SIGDEFARG(sigarg) SIGRETURN; } -#if defined(_REENTRANT) && defined(SIGCONT) + static void +after_sigcont(void) +{ +# ifdef FEAT_TITLE + // Set oldtitle to NULL, so the current title is obtained again. + VIM_CLEAR(oldtitle); +# endif + settmode(TMODE_RAW); + need_check_timestamps = TRUE; + did_check_timestamps = FALSE; +} + +#if defined(SIGCONT) +static RETSIGTYPE sigcont_handler SIGPROTOARG; +static int in_mch_suspend = FALSE; + +# if defined(_REENTRANT) && defined(SIGCONT) /* * On Solaris with multi-threading, suspending might not work immediately. * Catch the SIGCONT signal, which will be used as an indication whether the @@ -1239,7 +1255,7 @@ deathtrap SIGDEFARG(sigarg) * volatile because it is used in signal handler sigcont_handler(). */ static volatile int sigcont_received; -static RETSIGTYPE sigcont_handler SIGPROTOARG; +# endif /* * signal handler for SIGCONT @@ -1247,7 +1263,38 @@ static RETSIGTYPE sigcont_handler SIGPROTOARG; static RETSIGTYPE sigcont_handler SIGDEFARG(sigarg) { - sigcont_received = TRUE; + if (in_mch_suspend) + { +# if defined(_REENTRANT) && defined(SIGCONT) + sigcont_received = TRUE; +# endif + } + else + { + // We didn't suspend ourselves, assume we were stopped by a SIGSTOP + // signal (which can't be intercepted) and get a SIGCONT. Need to get + // back to a sane mode and redraw. + after_sigcont(); + + update_screen(CLEAR); + if (State & CMDLINE) + redrawcmdline(); + else if (State == HITRETURN || State == SETWSIZE || State == ASKMORE + || State == EXTERNCMD || State == CONFIRM || exmode_active) + repeat_message(); + else if (redrawing()) + setcursor(); +#if defined(FEAT_INS_EXPAND) + if (pum_visible()) + { + redraw_later(NOT_VALID); + ins_compl_show_pum(); + } +#endif + cursor_on_force(); + out_flush(); + } + SIGRETURN; } #endif @@ -1330,6 +1377,8 @@ mch_suspend(void) { /* BeOS does have SIGTSTP, but it doesn't work. */ #if defined(SIGTSTP) && !defined(__BEOS__) + in_mch_suspend = TRUE; + out_flush(); /* needed to make cursor visible on some systems */ settmode(TMODE_COOK); out_flush(); /* needed to disable mouse on some systems */ @@ -1361,16 +1410,9 @@ mch_suspend(void) mch_delay(wait_time, FALSE); } # endif + in_mch_suspend = FALSE; -# ifdef FEAT_TITLE - /* - * Set oldtitle to NULL, so the current title is obtained again. - */ - VIM_CLEAR(oldtitle); -# endif - settmode(TMODE_RAW); - need_check_timestamps = TRUE; - did_check_timestamps = FALSE; + after_sigcont(); #else suspend_shell(); #endif @@ -1410,7 +1452,7 @@ set_signals(void) #ifdef SIGTSTP signal(SIGTSTP, restricted ? SIG_IGN : SIG_DFL); #endif -#if defined(_REENTRANT) && defined(SIGCONT) +#if defined(SIGCONT) signal(SIGCONT, sigcont_handler); #endif diff --git a/src/proto/term.pro b/src/proto/term.pro index 7eafdeffa9..9a9606baf0 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -50,6 +50,7 @@ void setmouse(void); int mouse_has(int c); int mouse_model_popup(void); void scroll_start(void); +void cursor_on_force(void); void cursor_on(void); void cursor_off(void); void term_cursor_mode(int forced); diff --git a/src/term.c b/src/term.c index 209a03f5c1..ace467f6df 100644 --- a/src/term.c +++ b/src/term.c @@ -3788,6 +3788,16 @@ scroll_start(void) static int cursor_is_off = FALSE; +/* + * Enable the cursor without checking if it's already enabled. + */ + void +cursor_on_force(void) +{ + out_str(T_VE); + cursor_is_off = FALSE; +} + /* * Enable the cursor. */ @@ -3795,10 +3805,7 @@ static int cursor_is_off = FALSE; cursor_on(void) { if (cursor_is_off) - { - out_str(T_VE); - cursor_is_off = FALSE; - } + cursor_on_force(); } /* diff --git a/src/version.c b/src/version.c index 46125c029d..08345408b4 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 244, /**/ 243, /**/ From 91d2e783b41ca900bc603b3cb5e083c8a4a33170 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 19:05:01 +0200 Subject: [PATCH 05/24] patch 8.1.0245: calling setline() in TextChangedI autocmd breaks undo Problem: Calling setline() in TextChangedI autocmd breaks undo. (Jason Felice) Solution: Don't save lines for undo when already saved. (closes #3291) --- src/edit.c | 8 ++++++++ src/testdir/test_autocmd.vim | 27 ++++++++++++++++++++++++++- src/version.c | 2 ++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/edit.c b/src/edit.c index 45176d79f4..b5c129f991 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1722,11 +1722,19 @@ ins_redraw( { aco_save_T aco; + // Sync undo when the autocommand calls setline() or append(), so that + // it can be undone separately. + u_sync_once = 2; + // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); aucmd_restbuf(&aco); curbuf->b_last_changedtick = CHANGEDTICK(curbuf); + + if (u_sync_once == 1) + ins_need_undo = TRUE; + u_sync_once = 0; } #ifdef FEAT_INS_EXPAND diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index 19c54d1567..b52493fcb4 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -587,7 +587,7 @@ func Test_OptionSet() " Cleanup au! OptionSet for opt in ['nu', 'ai', 'acd', 'ar', 'bs', 'backup', 'cul', 'cp'] - exe printf(":set %s&vi", opt) + exe printf(":set %s&vim", opt) endfor call test_override('starting', 0) delfunc! AutoCommandOptionSet @@ -1313,6 +1313,31 @@ func Test_ChangedP() bw! endfunc +let g:setline_handled = v:false +func! SetLineOne() + if !g:setline_handled + call setline(1, "(x)") + let g:setline_handled = v:true + endif +endfunc + +func Test_TextChangedI_with_setline() + new + call test_override('char_avail', 1) + autocmd TextChangedI call SetLineOne() + call feedkeys("i(\\", 'tx') + call assert_equal('(', getline(1)) + call assert_equal('x)', getline(2)) + undo + call assert_equal('(', getline(1)) + call assert_equal('', getline(2)) + undo + call assert_equal('', getline(1)) + + call test_override('starting', 0) + bwipe! +endfunc + func Test_Changed_FirstTime() if !has('terminal') || has('gui_running') return diff --git a/src/version.c b/src/version.c index 08345408b4..3b437c45ac 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 245, /**/ 244, /**/ From ee380ae376692529b6f1805185015cb4717c6940 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 19:32:52 +0200 Subject: [PATCH 06/24] patch 8.1.0246: build failure without the +eval feature Problem: Build failure without the +eval feature. Solution: Add #ifdef --- src/edit.c | 4 ++++ src/version.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/edit.c b/src/edit.c index b5c129f991..8ee4643570 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1722,9 +1722,11 @@ ins_redraw( { aco_save_T aco; +#ifdef FEAT_EVAL // Sync undo when the autocommand calls setline() or append(), so that // it can be undone separately. u_sync_once = 2; +#endif // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); @@ -1732,9 +1734,11 @@ ins_redraw( aucmd_restbuf(&aco); curbuf->b_last_changedtick = CHANGEDTICK(curbuf); +#ifdef FEAT_EVAL if (u_sync_once == 1) ins_need_undo = TRUE; u_sync_once = 0; +#endif } #ifdef FEAT_INS_EXPAND diff --git a/src/version.c b/src/version.c index 3b437c45ac..a3539f0c1e 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 246, /**/ 245, /**/ From 447bd5a346b5c4bf4d91280700bdb4b45e0aa667 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 19:45:27 +0200 Subject: [PATCH 07/24] patch 8.1.0247: Python: error message for failing import is incorrect Problem: Python: error message for failing import is incorrect. Solution: Adjust how modules are loaded. (Ozaki Kiichi, closes #3162) --- src/if_py_both.h | 89 +++++++++++++++++++++++++++++-------------- src/testdir/test86.ok | 2 +- src/testdir/test87.ok | 2 +- src/version.c | 2 + 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/if_py_both.h b/src/if_py_both.h index 459bc50cdd..cdd7460191 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -544,27 +544,57 @@ PythonIO_Init_io(void) } #if PY_VERSION_HEX < 0x030700f0 +static PyObject *call_load_module(char *name, int len, PyObject *find_module_result); + typedef struct { PyObject_HEAD - PyObject *module; + char *fullname; + PyObject *result; } LoaderObject; static PyTypeObject LoaderType; static void LoaderDestructor(LoaderObject *self) { - Py_DECREF(self->module); + vim_free(self->fullname); + Py_XDECREF(self->result); DESTRUCTOR_FINISH(self); } static PyObject * LoaderLoadModule(LoaderObject *self, PyObject *args UNUSED) { - PyObject *ret = self->module; + char *fullname = self->fullname; + PyObject *result = self->result; + PyObject *module; - Py_INCREF(ret); - return ret; + if (!fullname) + { + module = result ? result : Py_None; + Py_INCREF(module); + return module; + } + + module = call_load_module(fullname, (int)STRLEN(fullname), result); + + self->fullname = NULL; + self->result = module; + + vim_free(fullname); + Py_DECREF(result); + + if (!module) + { + if (PyErr_Occurred()) + return NULL; + + Py_INCREF(Py_None); + return Py_None; + } + + Py_INCREF(module); + return module; } static struct PyMethodDef LoaderMethods[] = { @@ -1252,7 +1282,11 @@ find_module(char *fullname, char *tail, PyObject *new_path) if (!(find_module_result = PyObject_CallFunction(py_find_module, "s#O", tail, partlen, new_path))) + { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_ImportError)) + PyErr_Clear(); return NULL; + } if (!(module = call_load_module( fullname, @@ -1273,30 +1307,23 @@ find_module(char *fullname, char *tail, PyObject *new_path) Py_DECREF(module); - module = find_module(fullname, dot + 1, newest_path); + find_module_result = find_module(fullname, dot + 1, newest_path); Py_DECREF(newest_path); - return module; + return find_module_result; } else { if (!(find_module_result = PyObject_CallFunction(py_find_module, "sO", tail, new_path))) - return NULL; - - if (!(module = call_load_module( - fullname, - (int)STRLEN(fullname), - find_module_result))) { - Py_DECREF(find_module_result); + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_ImportError)) + PyErr_Clear(); return NULL; } - Py_DECREF(find_module_result); - - return module; + return find_module_result; } } @@ -1304,7 +1331,7 @@ find_module(char *fullname, char *tail, PyObject *new_path) FinderFindModule(PyObject *self, PyObject *args) { char *fullname; - PyObject *module; + PyObject *result; PyObject *new_path; LoaderObject *loader; @@ -1314,31 +1341,35 @@ FinderFindModule(PyObject *self, PyObject *args) if (!(new_path = Vim_GetPaths(self))) return NULL; - module = find_module(fullname, fullname, new_path); + result = find_module(fullname, fullname, new_path); Py_DECREF(new_path); - if (!module) + if (!result) { if (PyErr_Occurred()) - { - if (PyErr_ExceptionMatches(PyExc_ImportError)) - PyErr_Clear(); - else - return NULL; - } + return NULL; Py_INCREF(Py_None); return Py_None; } - if (!(loader = PyObject_NEW(LoaderObject, &LoaderType))) + if (!(fullname = (char *)vim_strsave((char_u *)fullname))) { - Py_DECREF(module); + Py_DECREF(result); + PyErr_NoMemory(); return NULL; } - loader->module = module; + if (!(loader = PyObject_NEW(LoaderObject, &LoaderType))) + { + vim_free(fullname); + Py_DECREF(result); + return NULL; + } + + loader->fullname = fullname; + loader->result = result; return (PyObject *) loader; } diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok index f8d4ceb577..24d3fd4bde 100644 --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -701,7 +701,7 @@ vim.foreach_rtp(FailingCall()):NotImplementedError:('call',) vim.foreach_rtp(int, 2):TypeError:('foreach_rtp() takes exactly one argument (2 given)',) > import import xxx_no_such_module_xxx:ImportError:('No module named xxx_no_such_module_xxx',) -import failing_import:ImportError:('No module named failing_import',) +import failing_import:ImportError:() import failing:NotImplementedError:() > Options >> OptionsItem diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok index 9ca4b624cf..a7d4f64264 100644 --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -701,7 +701,7 @@ vim.foreach_rtp(FailingCall()):(, NotImplementedErr vim.foreach_rtp(int, 2):(, TypeError('foreach_rtp() takes exactly one argument (2 given)',)) > import import xxx_no_such_module_xxx:(, ImportError('No module named xxx_no_such_module_xxx',)) -import failing_import:(, ImportError('No module named failing_import',)) +import failing_import:(, ImportError()) import failing:(, NotImplementedError()) > Options >> OptionsItem diff --git a/src/version.c b/src/version.c index a3539f0c1e..95a2e5b432 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 247, /**/ 246, /**/ From 8d8a65e389cef318ae661ff0fe7b1b00fd7cb25f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 19:48:08 +0200 Subject: [PATCH 08/24] patch 8.1.0248: duplicated quickfix code Problem: duplicated quickfix code. Solution: Move the code to a function. --- src/quickfix.c | 40 ++++++++++++++++++++++------------------ src/version.c | 2 ++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index 97bfb37cab..6108b36be3 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -4125,6 +4125,20 @@ qf_id2nr(qf_info_T *qi, int_u qfid) return INVALID_QFIDX; } +/* + * Jump to the first entry if there is one. + */ + static void +qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit) +{ + // If autocommands changed the current list, then restore it + if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) + qi->qf_curlist = qf_id2nr(qi, save_qfid); + + if (qi->qf_lists[qi->qf_curlist].qf_count > 0) + qf_jump(qi, 0, 0, forceit); +} + /* * Return TRUE when using ":vimgrep" for ":grep". */ @@ -4247,12 +4261,8 @@ ex_make(exarg_T *eap) apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, TRUE, curbuf); if (res > 0 && !eap->forceit && qflist_valid(wp, save_qfid)) - { - // If autocommands changed the current list, then restore it - if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) - qi->qf_curlist = qf_id2nr(qi, save_qfid); - qf_jump(qi, 0, 0, FALSE); /* display first error */ - } + // display the first error + qf_jump_first(qi, save_qfid, FALSE); cleanup: mch_remove(fname); @@ -4650,10 +4660,8 @@ ex_cfile(exarg_T *eap) if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile) && qflist_valid(wp, save_qfid)) { - // If autocommands changed the current list, then restore it - if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) - qi->qf_curlist = qf_id2nr(qi, save_qfid); - qf_jump(qi, 0, 0, eap->forceit); /* display first error */ + // display the first error + qf_jump_first(qi, save_qfid, eap->forceit); } } @@ -6361,10 +6369,8 @@ ex_cbuffer(exarg_T *eap) eap->cmdidx == CMD_lbuffer) && qflist_valid(wp, save_qfid)) { - // If autocommands changed the current list, then restore it - if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) - qi->qf_curlist = qf_id2nr(qi, save_qfid); - qf_jump(qi, 0, 0, eap->forceit); /* display first error */ + // display the first error + qf_jump_first(qi, save_qfid, eap->forceit); } } } @@ -6443,10 +6449,8 @@ ex_cexpr(exarg_T *eap) || eap->cmdidx == CMD_lexpr) && qflist_valid(wp, save_qfid)) { - // If autocommands changed the current list, then restore it - if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) - qi->qf_curlist = qf_id2nr(qi, save_qfid); - qf_jump(qi, 0, 0, eap->forceit); + // display the first error + qf_jump_first(qi, save_qfid, eap->forceit); } } else diff --git a/src/version.c b/src/version.c index 95a2e5b432..cc1648ff84 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 248, /**/ 247, /**/ From 7ebf4e1c346783b25624258e5bcc599130fd18f9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 20:01:40 +0200 Subject: [PATCH 09/24] patch 8.1.0249: GTK: when screen DPI changes Vim does not handle it Problem: GTK: when screen DPI changes Vim does not handle it. Solution: Handle the gtk-xft-dpi signal. (Roel van de Kraats, closes #2357) --- src/gui_gtk_x11.c | 32 ++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 9c7e8d5648..7541d79072 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -788,6 +788,29 @@ property_event(GtkWidget *widget, } #endif /* defined(FEAT_CLIENTSERVER) */ +/* + * Handle changes to the "Xft/DPI" setting + */ + static void +gtk_settings_xft_dpi_changed_cb(GtkSettings *gtk_settings UNUSED, + GParamSpec *pspec UNUSED, + gpointer data UNUSED) +{ + // Create a new PangoContext for this screen, and initialize it + // with the current font if necessary. + if (gui.text_context != NULL) + g_object_unref(gui.text_context); + + gui.text_context = gtk_widget_create_pango_context(gui.mainwin); + pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR); + + if (gui.norm_font != NULL) + { + // force default font + gui_mch_init_font(*p_guifont == NUL ? NULL : p_guifont, FALSE); + gui_set_shellsize(TRUE, FALSE, RESIZE_BOTH); + } +} #if GTK_CHECK_VERSION(3,0,0) typedef gboolean timeout_cb_type; @@ -4383,6 +4406,15 @@ gui_mch_init(void) /* Pretend we don't have input focus, we will get an event if we do. */ gui.in_focus = FALSE; + // Handle changes to the "Xft/DPI" setting. + { + GtkSettings *gtk_settings = + gtk_settings_get_for_screen(gdk_screen_get_default()); + + g_signal_connect(gtk_settings, "notify::gtk-xft-dpi", + G_CALLBACK(gtk_settings_xft_dpi_changed_cb), NULL); + } + return OK; } diff --git a/src/version.c b/src/version.c index cc1648ff84..bb730f4e3f 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 249, /**/ 248, /**/ From b1cf16113f7ab67f42fb6822cecdef74a54fa950 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 20:47:16 +0200 Subject: [PATCH 10/24] patch 8.1.0250: MS-Windows using VTP: windows size change incorrect Problem: MS-Windows using VTP: windows size change incorrect. Solution: Call SetConsoleScreenBufferSize() first. (Nobuhiro Takasaki, closes #3164) --- src/os_win32.c | 74 +++++++++++++++++++++++++++++++++++--------------- src/version.c | 2 ++ 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/os_win32.c b/src/os_win32.c index f8884e4011..63572350b2 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -3966,6 +3966,48 @@ mch_get_shellsize(void) return OK; } +/* + * Resize console buffer to 'COORD' + */ + static void +ResizeConBuf( + HANDLE hConsole, + COORD coordScreen) +{ + if (!SetConsoleScreenBufferSize(hConsole, coordScreen)) + { +#ifdef MCH_WRITE_DUMP + if (fdDump) + { + fprintf(fdDump, "SetConsoleScreenBufferSize failed: %lx\n", + GetLastError()); + fflush(fdDump); + } +#endif + } +} + +/* + * Resize console window size to 'srWindowRect' + */ + static void +ResizeWindow( + HANDLE hConsole, + SMALL_RECT srWindowRect) +{ + if (!SetConsoleWindowInfo(hConsole, TRUE, &srWindowRect)) + { +#ifdef MCH_WRITE_DUMP + if (fdDump) + { + fprintf(fdDump, "SetConsoleWindowInfo failed: %lx\n", + GetLastError()); + fflush(fdDump); + } +#endif + } +} + /* * Set a console window to `xSize' * `ySize' */ @@ -4019,32 +4061,20 @@ ResizeConBufAndWindow( } } - if (!SetConsoleWindowInfo(g_hConOut, TRUE, &srWindowRect)) - { -#ifdef MCH_WRITE_DUMP - if (fdDump) - { - fprintf(fdDump, "SetConsoleWindowInfo failed: %lx\n", - GetLastError()); - fflush(fdDump); - } -#endif - } - - /* define the new console buffer size */ + // define the new console buffer size coordScreen.X = xSize; coordScreen.Y = ySize; - if (!SetConsoleScreenBufferSize(hConsole, coordScreen)) + // In the new console call API in reverse order + if (!vtp_working) { -#ifdef MCH_WRITE_DUMP - if (fdDump) - { - fprintf(fdDump, "SetConsoleScreenBufferSize failed: %lx\n", - GetLastError()); - fflush(fdDump); - } -#endif + ResizeWindow(hConsole, srWindowRect); + ResizeConBuf(hConsole, coordScreen); + } + else + { + ResizeConBuf(hConsole, coordScreen); + ResizeWindow(hConsole, srWindowRect); } } diff --git a/src/version.c b/src/version.c index bb730f4e3f..c9b0ec4dcb 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 250, /**/ 249, /**/ From b782ba475a3f8f2b0be99dda164ba4545347f60f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 21:39:28 +0200 Subject: [PATCH 11/24] patch 8.1.0251: using full path is not supported for 'backupdir' Problem: Using a full path is supported for 'directory' but not for 'backupdir'. (Mikolaj Machowski) Solution: Support 'backupdir' as well. (Christian Brabandt, closes #179) --- runtime/doc/options.txt | 22 ++++++++++---- src/Make_all.mak | 1 + src/fileio.c | 50 +++++++++++++++++++++++++------- src/memline.c | 15 ++++------ src/proto/memline.pro | 1 + src/testdir/test_alot.vim | 1 + src/testdir/test_backup.vim | 58 +++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 8 files changed, 124 insertions(+), 26 deletions(-) create mode 100644 src/testdir/test_backup.vim diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 8645c47333..eb455fc09b 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1054,6 +1054,14 @@ A jump table for the options with a short description can be found at |Q_op|. name, precede it with a backslash. - To include a comma in a directory name precede it with a backslash. - A directory name may end in an '/'. + - For Unix and Win32, if a directory ends in two path separators "//", + the swap file name will be built from the complete path to the file + with all path separators changed to percent '%' signs. This will + ensure file name uniqueness in the backup directory. + On Win32, it is also possible to end with "\\". However, When a + separating comma is following, you must use "//", since "\\" will + include the comma in the file name. Therefore it is recommended to + use '//', instead of '\\'. - Environment variables are expanded |:set_env|. - Careful with '\' characters, type one before a space, type two to get one in the option (see |option-backslash|), for example: > @@ -2680,12 +2688,14 @@ A jump table for the options with a short description can be found at |Q_op|. - A directory starting with "./" (or ".\" for MS-DOS et al.) means to put the swap file relative to where the edited file is. The leading "." is replaced with the path name of the edited file. - - For Unix and Win32, if a directory ends in two path separators "//" - or "\\", the swap file name will be built from the complete path to - the file with all path separators substituted to percent '%' signs. - This will ensure file name uniqueness in the preserve directory. - On Win32, when a separating comma is following, you must use "//", - since "\\" will include the comma in the file name. + - For Unix and Win32, if a directory ends in two path separators "//", + the swap file name will be built from the complete path to the file + with all path separators substituted to percent '%' signs. This will + ensure file name uniqueness in the preserve directory. + On Win32, it is also possible to end with "\\". However, When a + separating comma is following, you must use "//", since "\\" will + include the comma in the file name. Therefore it is recommended to + use '//', instead of '\\'. - Spaces after the comma are ignored, other spaces are considered part of the directory name. To have a space at the start of a directory name, precede it with a backslash. diff --git a/src/Make_all.mak b/src/Make_all.mak index 9831f7b044..49ad4f0af8 100644 --- a/src/Make_all.mak +++ b/src/Make_all.mak @@ -12,6 +12,7 @@ NEW_TESTS = \ test_autocmd \ test_autoload \ test_backspace_opt \ + test_backup \ test_blockedit \ test_breakindent \ test_bufline \ diff --git a/src/fileio.c b/src/fileio.c index 281191cfbf..42f388a11f 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3850,6 +3850,9 @@ buf_write( stat_T st_new; char_u *dirp; char_u *rootname; +#if defined(UNIX) || defined(WIN3264) + char_u *p; +#endif #if defined(UNIX) int did_set_shortname; mode_t umask_save; @@ -3887,6 +3890,17 @@ buf_write( * Isolate one directory name, using an entry in 'bdir'. */ (void)copy_option_part(&dirp, copybuf, BUFSIZE, ","); + +#if defined(UNIX) || defined(WIN3264) + p = copybuf + STRLEN(copybuf); + if (after_pathsep(copybuf, p) && p[-1] == p[-2]) + // Ends with '//', use full path + if ((p = make_percent_swname(copybuf, fname)) != NULL) + { + backup = modname(p, backup_ext, FALSE); + vim_free(p); + } +#endif rootname = get_file_in_dir(fname, copybuf); if (rootname == NULL) { @@ -3904,9 +3918,10 @@ buf_write( for (;;) { /* - * Make backup file name. + * Make the backup file name. */ - backup = buf_modname((buf->b_p_sn || buf->b_shortname), + if (backup == NULL) + backup = buf_modname((buf->b_p_sn || buf->b_shortname), rootname, backup_ext, FALSE); if (backup == NULL) { @@ -4108,14 +4123,29 @@ buf_write( * Isolate one directory name and make the backup file name. */ (void)copy_option_part(&dirp, IObuff, IOSIZE, ","); - rootname = get_file_in_dir(fname, IObuff); - if (rootname == NULL) - backup = NULL; - else + +#if defined(UNIX) || defined(WIN3264) + p = IObuff + STRLEN(IObuff); + if (after_pathsep(IObuff, p) && p[-1] == p[-2]) + // path ends with '//', use full path + if ((p = make_percent_swname(IObuff, fname)) != NULL) + { + backup = modname(p, backup_ext, FALSE); + vim_free(p); + } +#endif + if (backup == NULL) { - backup = buf_modname((buf->b_p_sn || buf->b_shortname), - rootname, backup_ext, FALSE); - vim_free(rootname); + rootname = get_file_in_dir(fname, IObuff); + if (rootname == NULL) + backup = NULL; + else + { + backup = buf_modname( + (buf->b_p_sn || buf->b_shortname), + rootname, backup_ext, FALSE); + vim_free(rootname); + } } if (backup != NULL) @@ -6252,7 +6282,7 @@ shorten_filenames(char_u **fnames, int count) #endif /* - * add extension to file name - change path/fo.o.h to path/fo.o.h.ext or + * Add extension to file name - change path/fo.o.h to path/fo.o.h.ext or * fo_o_h.ext for MSDOS or when shortname option set. * * Assumed that fname is a valid name found in the filesystem we assure that diff --git a/src/memline.c b/src/memline.c index be395fce6b..a2f0b4f626 100644 --- a/src/memline.c +++ b/src/memline.c @@ -262,9 +262,6 @@ static int fnamecmp_ino(char_u *, char_u *, long); #endif static void long_to_char(long, char_u *); static long char_to_long(char_u *); -#if defined(UNIX) || defined(WIN3264) -static char_u *make_percent_swname(char_u *dir, char_u *name); -#endif #ifdef FEAT_CRYPT static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading); #endif @@ -2007,18 +2004,18 @@ recover_names( return file_count; } -#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */ +#if defined(UNIX) || defined(WIN3264) || defined(PROTO) /* + * Need _very_ long file names. * Append the full path to name with path separators made into percent * signs, to dir. An unnamed buffer is handled as "" (/"") */ - static char_u * + char_u * make_percent_swname(char_u *dir, char_u *name) { - char_u *d, *s, *f; + char_u *d = NULL, *s, *f; - f = fix_fname(name != NULL ? name : (char_u *) ""); - d = NULL; + f = fix_fname(name != NULL ? name : (char_u *)""); if (f != NULL) { s = alloc((unsigned)(STRLEN(f) + 1)); @@ -4070,8 +4067,6 @@ attention_message( } #if defined(FEAT_EVAL) -static int do_swapexists(buf_T *buf, char_u *fname); - /* * Trigger the SwapExists autocommands. * Returns a value for equivalent to do_dialog() (see below): diff --git a/src/proto/memline.pro b/src/proto/memline.pro index bddb902f48..727b24cc30 100644 --- a/src/proto/memline.pro +++ b/src/proto/memline.pro @@ -34,4 +34,5 @@ char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned siz void ml_decrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size); long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp); void goto_byte(long cnt); +char_u *make_percent_swname (char_u *dir, char_u *name); /* vim: set ft=c : */ diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim index 1465a7abfc..16a3f7f8ac 100644 --- a/src/testdir/test_alot.vim +++ b/src/testdir/test_alot.vim @@ -2,6 +2,7 @@ " This makes testing go faster, since Vim doesn't need to restart. source test_assign.vim +source test_backup.vim source test_bufline.vim source test_cd.vim source test_changedtick.vim diff --git a/src/testdir/test_backup.vim b/src/testdir/test_backup.vim new file mode 100644 index 0000000000..3187b58878 --- /dev/null +++ b/src/testdir/test_backup.vim @@ -0,0 +1,58 @@ +" Tests for the backup function + +func Test_backup() + set backup backupdir=. + new + call setline(1, ['line1', 'line2']) + :f Xbackup.txt + :w! Xbackup.txt + " backup file is only created after + " writing a second time (before overwriting) + :w! Xbackup.txt + let l = readfile('Xbackup.txt~') + call assert_equal(['line1', 'line2'], l) + bw! + set backup&vim backupdir&vim + call delete('Xbackup.txt') + call delete('Xbackup.txt~') +endfunc + +func Test_backup2() + set backup backupdir=.// + new + call setline(1, ['line1', 'line2', 'line3']) + :f Xbackup.txt + :w! Xbackup.txt + " backup file is only created after + " writing a second time (before overwriting) + :w! Xbackup.txt + sp *Xbackup.txt~ + call assert_equal(['line1', 'line2', 'line3'], getline(1,'$')) + let f=expand('%') + call assert_match('src%testdir%Xbackup.txt\~', f) + bw! + bw! + call delete('Xbackup.txt') + call delete(f) + set backup&vim backupdir&vim +endfunc + +func Test_backup2_backupcopy() + set backup backupdir=.// backupcopy=yes + new + call setline(1, ['line1', 'line2', 'line3']) + :f Xbackup.txt + :w! Xbackup.txt + " backup file is only created after + " writing a second time (before overwriting) + :w! Xbackup.txt + sp *Xbackup.txt~ + call assert_equal(['line1', 'line2', 'line3'], getline(1,'$')) + let f=expand('%') + call assert_match('src%testdir%Xbackup.txt\~', f) + bw! + bw! + call delete('Xbackup.txt') + call delete(f) + set backup&vim backupdir&vim backupcopy&vim +endfunc diff --git a/src/version.c b/src/version.c index c9b0ec4dcb..432a7ab752 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 251, /**/ 250, /**/ From de3b3677f7eace66be454196db0fbf710cfc8c5e Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 21:54:41 +0200 Subject: [PATCH 12/24] patch 8.1.0252: quickfix functions are too long Problem: Quickfix functions are too long. Solution: Refactor. (Yegappan Lakshmanan, closes #2950) --- src/quickfix.c | 787 +++++++++++++++++++++++++++++++------------------ src/version.c | 2 + 2 files changed, 502 insertions(+), 287 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index 6108b36be3..d4aa5090da 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -201,106 +201,109 @@ static struct fmtpattern /* * Convert an errorformat pattern to a regular expression pattern. - * See fmt_pat definition above for the list of supported patterns. + * See fmt_pat definition above for the list of supported patterns. The + * pattern specifier is supplied in "efmpat". The converted pattern is stored + * in "regpat". Returns a pointer to the location after the pattern. */ static char_u * -fmtpat_to_regpat( - char_u *efmp, - efm_T *fmt_ptr, +efmpat_to_regpat( + char_u *efmpat, + char_u *regpat, + efm_T *efminfo, int idx, int round, - char_u *ptr, char_u *errmsg) { char_u *srcptr; - if (fmt_ptr->addr[idx]) + if (efminfo->addr[idx]) { /* Each errorformat pattern can occur only once */ sprintf((char *)errmsg, - _("E372: Too many %%%c in format string"), *efmp); + _("E372: Too many %%%c in format string"), *efmpat); EMSG(errmsg); return NULL; } if ((idx && idx < 6 - && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL) + && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL) || (idx == 6 - && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) + && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL)) { sprintf((char *)errmsg, - _("E373: Unexpected %%%c in format string"), *efmp); + _("E373: Unexpected %%%c in format string"), *efmpat); EMSG(errmsg); return NULL; } - fmt_ptr->addr[idx] = (char_u)++round; - *ptr++ = '\\'; - *ptr++ = '('; + efminfo->addr[idx] = (char_u)++round; + *regpat++ = '\\'; + *regpat++ = '('; #ifdef BACKSLASH_IN_FILENAME - if (*efmp == 'f') + if (*efmpat == 'f') { /* Also match "c:" in the file name, even when * checking for a colon next: "%f:". * "\%(\a:\)\=" */ - STRCPY(ptr, "\\%(\\a:\\)\\="); - ptr += 10; + STRCPY(regpat, "\\%(\\a:\\)\\="); + regpat += 10; } #endif - if (*efmp == 'f' && efmp[1] != NUL) + if (*efmpat == 'f' && efmpat[1] != NUL) { - if (efmp[1] != '\\' && efmp[1] != '%') + if (efmpat[1] != '\\' && efmpat[1] != '%') { /* A file name may contain spaces, but this isn't * in "\f". For "%f:%l:%m" there may be a ":" in * the file name. Use ".\{-1,}x" instead (x is * the next character), the requirement that :999: * follows should work. */ - STRCPY(ptr, ".\\{-1,}"); - ptr += 7; + STRCPY(regpat, ".\\{-1,}"); + regpat += 7; } else { /* File name followed by '\\' or '%': include as * many file name chars as possible. */ - STRCPY(ptr, "\\f\\+"); - ptr += 4; + STRCPY(regpat, "\\f\\+"); + regpat += 4; } } else { srcptr = (char_u *)fmt_pat[idx].pattern; - while ((*ptr = *srcptr++) != NUL) - ++ptr; + while ((*regpat = *srcptr++) != NUL) + ++regpat; } - *ptr++ = '\\'; - *ptr++ = ')'; + *regpat++ = '\\'; + *regpat++ = ')'; - return ptr; + return regpat; } /* * Convert a scanf like format in 'errorformat' to a regular expression. + * Returns a pointer to the location after the pattern. */ static char_u * scanf_fmt_to_regpat( + char_u **pefmp, char_u *efm, int len, - char_u **pefmp, - char_u *ptr, + char_u *regpat, char_u *errmsg) { char_u *efmp = *pefmp; - if (*++efmp == '[' || *efmp == '\\') + if (*efmp == '[' || *efmp == '\\') { - if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ + if ((*regpat++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ { if (efmp[1] == '^') - *ptr++ = *++efmp; + *regpat++ = *++efmp; if (efmp < efm + len) { - *ptr++ = *++efmp; /* could be ']' */ + *regpat++ = *++efmp; /* could be ']' */ while (efmp < efm + len - && (*ptr++ = *++efmp) != ']') + && (*regpat++ = *++efmp) != ']') /* skip */; if (efmp == efm + len) { @@ -310,9 +313,9 @@ scanf_fmt_to_regpat( } } else if (efmp < efm + len) /* %*\D, %*\s etc. */ - *ptr++ = *++efmp; - *ptr++ = '\\'; - *ptr++ = '+'; + *regpat++ = *++efmp; + *regpat++ = '\\'; + *regpat++ = '+'; } else { @@ -325,36 +328,35 @@ scanf_fmt_to_regpat( *pefmp = efmp; - return ptr; + return regpat; } /* * Analyze/parse an errorformat prefix. */ - static int -efm_analyze_prefix(char_u **pefmp, efm_T *fmt_ptr, char_u *errmsg) + static char_u * +efm_analyze_prefix(char_u *efmp, efm_T *efminfo, char_u *errmsg) { - char_u *efmp = *pefmp; - if (vim_strchr((char_u *)"+-", *efmp) != NULL) - fmt_ptr->flags = *efmp++; + efminfo->flags = *efmp++; if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) - fmt_ptr->prefix = *efmp; + efminfo->prefix = *efmp; else { sprintf((char *)errmsg, _("E376: Invalid %%%c in format string prefix"), *efmp); EMSG(errmsg); - return FAIL; + return NULL; } - *pefmp = efmp; - - return OK; + return efmp; } /* - * Converts a 'errorformat' string to regular expression pattern + * Converts a 'errorformat' string part in 'efm' to a regular expression + * pattern. The resulting regex pattern is returned in "regpat". Additional + * information about the 'erroformat' pattern is returned in "fmt_ptr". + * Returns OK or FAIL. */ static int efm_to_regpat( @@ -370,7 +372,7 @@ efm_to_regpat( int idx = 0; /* - * Build regexp pattern from current 'errorformat' option + * Build a regexp pattern for a 'errorformat' option part */ ptr = regpat; *ptr++ = '^'; @@ -385,17 +387,18 @@ efm_to_regpat( break; if (idx < FMT_PATTERNS) { - ptr = fmtpat_to_regpat(efmp, fmt_ptr, idx, round, ptr, + ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round, errmsg); if (ptr == NULL) - return -1; + return FAIL; round++; } else if (*efmp == '*') { - ptr = scanf_fmt_to_regpat(efm, len, &efmp, ptr, errmsg); + ++efmp; + ptr = scanf_fmt_to_regpat(&efmp, efm, len, ptr, errmsg); if (ptr == NULL) - return -1; + return FAIL; } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) *ptr++ = *efmp; /* regexp magic characters */ @@ -405,15 +408,20 @@ efm_to_regpat( fmt_ptr->conthere = TRUE; else if (efmp == efm + 1) /* analyse prefix */ { - if (efm_analyze_prefix(&efmp, fmt_ptr, errmsg) == FAIL) - return -1; + /* + * prefix is allowed only at the beginning of the errorformat + * option part + */ + efmp = efm_analyze_prefix(efmp, fmt_ptr, errmsg); + if (efmp == NULL) + return FAIL; } else { sprintf((char *)errmsg, _("E377: Invalid %%%c in format string"), *efmp); EMSG(errmsg); - return -1; + return FAIL; } } else /* copy normal character */ @@ -429,9 +437,12 @@ efm_to_regpat( *ptr++ = '$'; *ptr = NUL; - return 0; + return OK; } +/* + * Free the 'errorformat' information list + */ static void free_efm_list(efm_T **efm_first) { @@ -446,7 +457,48 @@ free_efm_list(efm_T **efm_first) fmt_start = NULL; } -/* Parse 'errorformat' option */ +/* + * Compute the size of the buffer used to convert a 'errorformat' pattern into + * a regular expression pattern. + */ + static int +efm_regpat_bufsz(char_u *efm) +{ + int sz; + int i; + + sz = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2); + for (i = FMT_PATTERNS; i > 0; ) + sz += (int)STRLEN(fmt_pat[--i].pattern); +#ifdef BACKSLASH_IN_FILENAME + sz += 12; /* "%f" can become twelve chars longer (see efm_to_regpat) */ +#else + sz += 2; /* "%f" can become two chars longer */ +#endif + + return sz; +} + +/* + * Return the length of a 'errorformat' option part (separated by ","). + */ + static int +efm_option_part_len(char_u *efm) +{ + int len; + + for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) + if (efm[len] == '\\' && efm[len + 1] != NUL) + ++len; + + return len; +} + +/* + * Parse the 'errorformat' option. Multiple parts in the 'errorformat' option + * are parsed and converted to regular expressions. Returns information about + * the parsed 'errorformat' option. + */ static efm_T * parse_efm_option(char_u *efm) { @@ -457,8 +509,7 @@ parse_efm_option(char_u *efm) efm_T *fmt_last = NULL; char_u *fmtstr = NULL; int len; - int i; - int round; + int sz; errmsglen = CMDBUFFSIZE + 1; errmsg = alloc_id(errmsglen, aid_qf_errmsg); @@ -473,15 +524,8 @@ parse_efm_option(char_u *efm) /* * Get some space to modify the format string into. */ - i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2); - for (round = FMT_PATTERNS; round > 0; ) - i += (int)STRLEN(fmt_pat[--round].pattern); -#ifdef BACKSLASH_IN_FILENAME - i += 12; /* "%f" can become twelve chars longer (see efm_to_regpat) */ -#else - i += 2; /* "%f" can become two chars longer */ -#endif - if ((fmtstr = alloc(i)) == NULL) + sz = efm_regpat_bufsz(efm); + if ((fmtstr = alloc(sz)) == NULL) goto parse_efm_error; while (efm[0] != NUL) @@ -501,11 +545,9 @@ parse_efm_option(char_u *efm) /* * Isolate one part in the 'errorformat' option */ - for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) - if (efm[len] == '\\' && efm[len + 1] != NUL) - ++len; + len = efm_option_part_len(efm); - if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == -1) + if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == FAIL) goto parse_efm_error; if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) goto parse_efm_error; @@ -539,6 +581,10 @@ enum { QF_MULTISCAN = 5, }; +/* + * State information used to parse lines and add entries to a quickfix/location + * list. + */ typedef struct { char_u *linebuf; int linelen; @@ -554,6 +600,9 @@ typedef struct { vimconv_T vc; } qfstate_T; +/* + * Allocate more memory for the line buffer used for parsing lines. + */ static char_u * qf_grow_linebuf(qfstate_T *state, int newsz) { @@ -861,10 +910,251 @@ typedef struct { } qffields_T; /* - * Parse the error format matches in 'regmatch' and set the values in 'fields'. - * fmt_ptr contains the 'efm' format specifiers/prefixes that have a match. - * Returns QF_OK if all the matches are successfully parsed. On failure, - * returns QF_FAIL or QF_NOMEM. + * Parse the match for filename ('%f') pattern in regmatch. + * Return the matched value in "fields->namebuf". + */ + static int +qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix) +{ + int c; + + if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) + return QF_FAIL; + + /* Expand ~/file and $HOME/file to full path. */ + c = *rmp->endp[midx]; + *rmp->endp[midx] = NUL; + expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE); + *rmp->endp[midx] = c; + + /* + * For separate filename patterns (%O, %P and %Q), the specified file + * should exist. + */ + if (vim_strchr((char_u *)"OPQ", prefix) != NULL + && mch_getperm(fields->namebuf) == -1) + return QF_FAIL; + + return QF_OK; +} + +/* + * Parse the match for error number ('%n') pattern in regmatch. + * Return the matched value in "fields->enr". + */ + static int +qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->enr = (int)atol((char *)rmp->startp[midx]); + return QF_OK; +} + +/* + * Parse the match for line number (%l') pattern in regmatch. + * Return the matched value in "fields->lnum". + */ + static int +qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->lnum = atol((char *)rmp->startp[midx]); + return QF_OK; +} + +/* + * Parse the match for column number ('%c') pattern in regmatch. + * Return the matched value in "fields->col". + */ + static int +qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->col = (int)atol((char *)rmp->startp[midx]); + return QF_OK; +} + +/* + * Parse the match for error type ('%t') pattern in regmatch. + * Return the matched value in "fields->type". + */ + static int +qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->type = *rmp->startp[midx]; + return QF_OK; +} + +/* + * Parse the match for '%+' format pattern. The whole matching line is included + * in the error string. Return the matched line in "fields->errmsg". + */ + static int +qf_parse_fmt_plus(char_u *linebuf, int linelen, qffields_T *fields) +{ + char_u *p; + + if (linelen >= fields->errmsglen) + { + /* linelen + null terminator */ + if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL) + return QF_NOMEM; + fields->errmsg = p; + fields->errmsglen = linelen + 1; + } + vim_strncpy(fields->errmsg, linebuf, linelen); + return QF_OK; +} + +/* + * Parse the match for error message ('%m') pattern in regmatch. + * Return the matched value in "fields->errmsg". + */ + static int +qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields) +{ + char_u *p; + int len; + + if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) + return QF_FAIL; + len = (int)(rmp->endp[midx] - rmp->startp[midx]); + if (len >= fields->errmsglen) + { + /* len + null terminator */ + if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL) + return QF_NOMEM; + fields->errmsg = p; + fields->errmsglen = len + 1; + } + vim_strncpy(fields->errmsg, rmp->startp[midx], len); + return QF_OK; +} + +/* + * Parse the match for rest of a single-line file message ('%r') pattern. + * Return the matched value in "tail". + */ + static int +qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + *tail = rmp->startp[midx]; + return QF_OK; +} + +/* + * Parse the match for the pointer line ('%p') pattern in regmatch. + * Return the matched value in "fields->col". + */ + static int +qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields) +{ + char_u *match_ptr; + + if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) + return QF_FAIL; + fields->col = 0; + for (match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx]; + ++match_ptr) + { + ++fields->col; + if (*match_ptr == TAB) + { + fields->col += 7; + fields->col -= fields->col % 8; + } + } + ++fields->col; + fields->use_viscol = TRUE; + return QF_OK; +} + +/* + * Parse the match for the virtual column number ('%v') pattern in regmatch. + * Return the matched value in "fields->col". + */ + static int +qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->col = (int)atol((char *)rmp->startp[midx]); + fields->use_viscol = TRUE; + return QF_OK; +} + +/* + * Parse the match for the search text ('%s') pattern in regmatch. + * Return the matched value in "fields->pattern". + */ + static int +qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields) +{ + int len; + + if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) + return QF_FAIL; + len = (int)(rmp->endp[midx] - rmp->startp[midx]); + if (len > CMDBUFFSIZE - 5) + len = CMDBUFFSIZE - 5; + STRCPY(fields->pattern, "^\\V"); + STRNCAT(fields->pattern, rmp->startp[midx], len); + fields->pattern[len + 3] = '\\'; + fields->pattern[len + 4] = '$'; + fields->pattern[len + 5] = NUL; + return QF_OK; +} + +/* + * Parse the match for the module ('%o') pattern in regmatch. + * Return the matched value in "fields->module". + */ + static int +qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields) +{ + int len; + + if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL) + return QF_FAIL; + len = (int)(rmp->endp[midx] - rmp->startp[midx]); + if (len > CMDBUFFSIZE) + len = CMDBUFFSIZE; + STRNCAT(fields->module, rmp->startp[midx], len); + return QF_OK; +} + +/* + * 'errorformat' format pattern parser functions. + * The '%f' and '%r' formats are parsed differently from other formats. + * See qf_parse_match() for details. + */ +static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = +{ + NULL, + qf_parse_fmt_n, + qf_parse_fmt_l, + qf_parse_fmt_c, + qf_parse_fmt_t, + qf_parse_fmt_m, + NULL, + qf_parse_fmt_p, + qf_parse_fmt_v, + qf_parse_fmt_s, + qf_parse_fmt_o +}; + +/* + * Parse the error format pattern matches in "regmatch" and set the values in + * "fields". fmt_ptr contains the 'efm' format specifiers/prefixes that have a + * match. Returns QF_OK if all the matches are successfully parsed. On + * failure, returns QF_FAIL or QF_NOMEM. */ static int qf_parse_match( @@ -877,10 +1167,10 @@ qf_parse_match( int qf_multiscan, char_u **tail) { - char_u *p; int idx = fmt_ptr->prefix; int i; - int len; + int midx; + int status; if ((idx == 'C' || idx == 'Z') && !qf_multiline) return QF_FAIL; @@ -893,128 +1183,26 @@ qf_parse_match( * We check for an actual submatch, because "\[" and "\]" in * the 'errorformat' may cause the wrong submatch to be used. */ - if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */ + for (i = 0; i < FMT_PATTERNS; i++) { - int c; - - if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) - return QF_FAIL; - - /* Expand ~/file and $HOME/file to full path. */ - c = *regmatch->endp[i]; - *regmatch->endp[i] = NUL; - expand_env(regmatch->startp[i], fields->namebuf, CMDBUFFSIZE); - *regmatch->endp[i] = c; - - if (vim_strchr((char_u *)"OPQ", idx) != NULL - && mch_getperm(fields->namebuf) == -1) - return QF_FAIL; - } - if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */ - { - if (regmatch->startp[i] == NULL) - return QF_FAIL; - fields->enr = (int)atol((char *)regmatch->startp[i]); - } - if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */ - { - if (regmatch->startp[i] == NULL) - return QF_FAIL; - fields->lnum = atol((char *)regmatch->startp[i]); - } - if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */ - { - if (regmatch->startp[i] == NULL) - return QF_FAIL; - fields->col = (int)atol((char *)regmatch->startp[i]); - } - if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */ - { - if (regmatch->startp[i] == NULL) - return QF_FAIL; - fields->type = *regmatch->startp[i]; - } - if (fmt_ptr->flags == '+' && !qf_multiscan) /* %+ */ - { - if (linelen >= fields->errmsglen) + status = QF_OK; + midx = (int)fmt_ptr->addr[i]; + if (i == 0 && midx > 0) /* %f */ + status = qf_parse_fmt_f(regmatch, midx, fields, idx); + else if (i == 5) { - /* linelen + null terminator */ - if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL) - return QF_NOMEM; - fields->errmsg = p; - fields->errmsglen = linelen + 1; + if (fmt_ptr->flags == '+' && !qf_multiscan) /* %+ */ + status = qf_parse_fmt_plus(linebuf, linelen, fields); + else if (midx > 0) /* %m */ + status = qf_parse_fmt_m(regmatch, midx, fields); } - vim_strncpy(fields->errmsg, linebuf, linelen); - } - else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ - { - if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) - return QF_FAIL; - len = (int)(regmatch->endp[i] - regmatch->startp[i]); - if (len >= fields->errmsglen) - { - /* len + null terminator */ - if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL) - return QF_NOMEM; - fields->errmsg = p; - fields->errmsglen = len + 1; - } - vim_strncpy(fields->errmsg, regmatch->startp[i], len); - } - if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */ - { - if (regmatch->startp[i] == NULL) - return QF_FAIL; - *tail = regmatch->startp[i]; - } - if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */ - { - char_u *match_ptr; + else if (i == 6 && midx > 0) /* %r */ + status = qf_parse_fmt_r(regmatch, midx, tail); + else if (midx > 0) /* others */ + status = (qf_parse_fmt[i])(regmatch, midx, fields); - if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) - return QF_FAIL; - fields->col = 0; - for (match_ptr = regmatch->startp[i]; - match_ptr != regmatch->endp[i]; ++match_ptr) - { - ++fields->col; - if (*match_ptr == TAB) - { - fields->col += 7; - fields->col -= fields->col % 8; - } - } - ++fields->col; - fields->use_viscol = TRUE; - } - if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */ - { - if (regmatch->startp[i] == NULL) - return QF_FAIL; - fields->col = (int)atol((char *)regmatch->startp[i]); - fields->use_viscol = TRUE; - } - if ((i = (int)fmt_ptr->addr[9]) > 0) /* %s */ - { - if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) - return QF_FAIL; - len = (int)(regmatch->endp[i] - regmatch->startp[i]); - if (len > CMDBUFFSIZE - 5) - len = CMDBUFFSIZE - 5; - STRCPY(fields->pattern, "^\\V"); - STRNCAT(fields->pattern, regmatch->startp[i], len); - fields->pattern[len + 3] = '\\'; - fields->pattern[len + 4] = '$'; - fields->pattern[len + 5] = NUL; - } - if ((i = (int)fmt_ptr->addr[10]) > 0) /* %o */ - { - if (regmatch->startp[i] == NULL || regmatch->endp[i] == NULL) - return QF_FAIL; - len = (int)(regmatch->endp[i] - regmatch->startp[i]); - if (len > CMDBUFFSIZE) - len = CMDBUFFSIZE; - STRNCAT(fields->module, regmatch->startp[i], len); + if (status != QF_OK) + return status; } return QF_OK; @@ -1307,6 +1495,18 @@ restofline: return QF_OK; } +/* + * Returns TRUE if the specified quickfix/location list is empty. + */ + static int +qf_list_empty(qf_info_T *qi, int qf_idx) +{ + if (qi == NULL || qf_idx < 0 || qf_idx >= LISTCOUNT) + return TRUE; + return qi->qf_lists[qf_idx].qf_count <= 0; +} + + /* * Allocate the fields used for parsing lines and populating a quickfix list. */ @@ -1450,7 +1650,7 @@ qf_init_ext( { /* Adding to existing list, use last entry. */ adding = TRUE; - if (qi->qf_lists[qf_idx].qf_count > 0) + if (!qf_list_empty(qi, qf_idx)) old_last = qi->qf_lists[qf_idx].qf_last; } @@ -1777,8 +1977,7 @@ qf_add_entry( qfp->qf_valid = valid; lastp = &qi->qf_lists[qf_idx].qf_last; - if (qi->qf_lists[qf_idx].qf_count == 0) - /* first element in the list */ + if (qf_list_empty(qi, qf_idx)) /* first element in the list */ { qi->qf_lists[qf_idx].qf_start = qfp; qi->qf_lists[qf_idx].qf_ptr = qfp; @@ -1875,7 +2074,7 @@ copy_loclist(win_T *from, win_T *to) to->w_llist->qf_listcount = qi->qf_listcount; /* Copy the location lists one at a time */ - for (idx = 0; idx < qi->qf_listcount; idx++) + for (idx = 0; idx < qi->qf_listcount; ++idx) { qf_list_T *from_qfl; qf_list_T *to_qfl; @@ -2907,7 +3106,7 @@ qf_jump(qf_info_T *qi, qi = &ql_info; if (qi->qf_curlist >= qi->qf_listcount - || qi->qf_lists[qi->qf_curlist].qf_count == 0) + || qf_list_empty(qi, qi->qf_curlist)) { EMSG(_(e_quickfix)); return; @@ -3032,6 +3231,93 @@ theend: } } +/* + * Highlight attributes used for displaying entries from the quickfix list. + */ +static int qfFileAttr; +static int qfSepAttr; +static int qfLineAttr; + +/* + * Display information about a single entry from the quickfix/location list. + * Used by ":clist/:llist" commands. + */ + static void +qf_list_entry(qf_info_T *qi, qfline_T *qfp, int qf_idx) +{ + char_u *fname; + buf_T *buf; + int filter_entry; + + fname = NULL; + if (qfp->qf_module != NULL && *qfp->qf_module != NUL) + vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx, + (char *)qfp->qf_module); + else { + if (qfp->qf_fnum != 0 + && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) + { + fname = buf->b_fname; + if (qfp->qf_type == 1) /* :helpgrep */ + fname = gettail(fname); + } + if (fname == NULL) + sprintf((char *)IObuff, "%2d", qf_idx); + else + vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", + qf_idx, (char *)fname); + } + + // Support for filtering entries using :filter /pat/ clist + // Match against the module name, file name, search pattern and + // text of the entry. + filter_entry = TRUE; + if (qfp->qf_module != NULL && *qfp->qf_module != NUL) + filter_entry &= message_filtered(qfp->qf_module); + if (filter_entry && fname != NULL) + filter_entry &= message_filtered(fname); + if (filter_entry && qfp->qf_pattern != NULL) + filter_entry &= message_filtered(qfp->qf_pattern); + if (filter_entry) + filter_entry &= message_filtered(qfp->qf_text); + if (filter_entry) + return; + + msg_putchar('\n'); + msg_outtrans_attr(IObuff, qf_idx == qi->qf_lists[qi->qf_curlist].qf_index + ? HL_ATTR(HLF_QFL) : qfFileAttr); + + if (qfp->qf_lnum != 0) + msg_puts_attr((char_u *)":", qfSepAttr); + if (qfp->qf_lnum == 0) + IObuff[0] = NUL; + else if (qfp->qf_col == 0) + sprintf((char *)IObuff, "%ld", qfp->qf_lnum); + else + sprintf((char *)IObuff, "%ld col %d", + qfp->qf_lnum, qfp->qf_col); + sprintf((char *)IObuff + STRLEN(IObuff), "%s", + (char *)qf_types(qfp->qf_type, qfp->qf_nr)); + msg_puts_attr(IObuff, qfLineAttr); + msg_puts_attr((char_u *)":", qfSepAttr); + if (qfp->qf_pattern != NULL) + { + qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); + msg_puts(IObuff); + msg_puts_attr((char_u *)":", qfSepAttr); + } + msg_puts((char_u *)" "); + + /* Remove newlines and leading whitespace from the text. For an + * unrecognized line keep the indent, the compiler may mark a word + * with ^^^^. */ + qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) + ? skipwhite(qfp->qf_text) : qfp->qf_text, + IObuff, IOSIZE); + msg_prt_line(IObuff, FALSE); + out_flush(); /* show one line at a time */ +} + /* * ":clist": list all errors * ":llist": list all locations @@ -3039,18 +3325,12 @@ theend: void qf_list(exarg_T *eap) { - buf_T *buf; - char_u *fname; qfline_T *qfp; int i; int idx1 = 1; int idx2 = -1; char_u *arg = eap->arg; int plus = FALSE; - int qfFileAttr; - int qfSepAttr; - int qfLineAttr; - int filter_entry; int all = eap->forceit; /* if not :cl!, only show recognised errors */ qf_info_T *qi = &ql_info; @@ -3066,7 +3346,7 @@ qf_list(exarg_T *eap) } if (qi->qf_curlist >= qi->qf_listcount - || qi->qf_lists[qi->qf_curlist].qf_count == 0) + || qf_list_empty(qi, qi->qf_curlist)) { EMSG(_(e_quickfix)); return; @@ -3123,75 +3403,9 @@ qf_list(exarg_T *eap) if (got_int) break; - fname = NULL; - if (qfp->qf_module != NULL && *qfp->qf_module != NUL) - vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)qfp->qf_module); - else { - if (qfp->qf_fnum != 0 - && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) - { - fname = buf->b_fname; - if (qfp->qf_type == 1) /* :helpgrep */ - fname = gettail(fname); - } - if (fname == NULL) - sprintf((char *)IObuff, "%2d", i); - else - vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", - i, (char *)fname); - } - - // Support for filtering entries using :filter /pat/ clist - // Match against the module name, file name, search pattern and - // text of the entry. - filter_entry = TRUE; - if (qfp->qf_module != NULL && *qfp->qf_module != NUL) - filter_entry &= message_filtered(qfp->qf_module); - if (filter_entry && fname != NULL) - filter_entry &= message_filtered(fname); - if (filter_entry && qfp->qf_pattern != NULL) - filter_entry &= message_filtered(qfp->qf_pattern); - if (filter_entry) - filter_entry &= message_filtered(qfp->qf_text); - if (filter_entry) - goto next_entry; - - msg_putchar('\n'); - msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index - ? HL_ATTR(HLF_QFL) : qfFileAttr); - - if (qfp->qf_lnum != 0) - msg_puts_attr((char_u *)":", qfSepAttr); - if (qfp->qf_lnum == 0) - IObuff[0] = NUL; - else if (qfp->qf_col == 0) - sprintf((char *)IObuff, "%ld", qfp->qf_lnum); - else - sprintf((char *)IObuff, "%ld col %d", - qfp->qf_lnum, qfp->qf_col); - sprintf((char *)IObuff + STRLEN(IObuff), "%s", - (char *)qf_types(qfp->qf_type, qfp->qf_nr)); - msg_puts_attr(IObuff, qfLineAttr); - msg_puts_attr((char_u *)":", qfSepAttr); - if (qfp->qf_pattern != NULL) - { - qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); - msg_puts(IObuff); - msg_puts_attr((char_u *)":", qfSepAttr); - } - msg_puts((char_u *)" "); - - /* Remove newlines and leading whitespace from the text. For an - * unrecognized line keep the indent, the compiler may mark a word - * with ^^^^. */ - qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) - ? skipwhite(qfp->qf_text) : qfp->qf_text, - IObuff, IOSIZE); - msg_prt_line(IObuff, FALSE); - out_flush(); /* show one line at a time */ + qf_list_entry(qi, qfp, i); } -next_entry: qfp = qfp->qf_next; if (qfp == NULL) break; @@ -3320,7 +3534,7 @@ qf_history(exarg_T *eap) if (eap->cmdidx == CMD_lhistory) qi = GET_LOC_LIST(curwin); if (qi == NULL || (qi->qf_listcount == 0 - && qi->qf_lists[qi->qf_curlist].qf_count == 0)) + && qf_list_empty(qi, qi->qf_curlist))) MSG(_("No entries")); else for (i = 0; i < qi->qf_listcount; ++i) @@ -3421,7 +3635,7 @@ qf_mark_adjust( } for (idx = 0; idx < qi->qf_listcount; ++idx) - if (qi->qf_lists[idx].qf_count) + if (!qf_list_empty(qi, idx)) for (i = 0, qfp = qi->qf_lists[idx].qf_start; i < qi->qf_lists[idx].qf_count && qfp != NULL; ++i, qfp = qfp->qf_next) @@ -3552,7 +3766,7 @@ ex_cwindow(exarg_T *eap) * it if we have errors; otherwise, leave it closed. */ if (qi->qf_lists[qi->qf_curlist].qf_nonevalid - || qi->qf_lists[qi->qf_curlist].qf_count == 0 + || qf_list_empty(qi, qi->qf_curlist) || qi->qf_curlist >= qi->qf_listcount) { if (win != NULL) @@ -5154,7 +5368,7 @@ ex_vimgrep(exarg_T *eap) qi->qf_curlist = qf_id2nr(qi, save_qfid); /* Jump to first match. */ - if (qi->qf_lists[qi->qf_curlist].qf_count > 0) + if (!qf_list_empty(qi, qi->qf_curlist)) { if ((flags & VGR_NOJUMP) == 0) vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, @@ -5387,8 +5601,7 @@ get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list) if (qf_idx == INVALID_QFIDX) qf_idx = qi->qf_curlist; - if (qf_idx >= qi->qf_listcount - || qi->qf_lists[qf_idx].qf_count == 0) + if (qf_idx >= qi->qf_listcount || qf_list_empty(qi, qf_idx)) return FAIL; qfp = qi->qf_lists[qf_idx].qf_start; @@ -5709,7 +5922,7 @@ qf_getprop_ctx(qf_info_T *qi, int qf_idx, dict_T *retdict) qf_getprop_idx(qf_info_T *qi, int qf_idx, dict_T *retdict) { int idx = qi->qf_lists[qf_idx].qf_index; - if (qi->qf_lists[qf_idx].qf_count == 0) + if (qf_list_empty(qi, qf_idx)) /* For empty lists, qf_index is set to 1 */ idx = 0; return dict_add_number(retdict, "idx", idx); @@ -5798,7 +6011,7 @@ qf_add_entries( qf_new_list(qi, title); qf_idx = qi->qf_curlist; } - else if (action == 'a' && qi->qf_lists[qf_idx].qf_count > 0) + else if (action == 'a' && !qf_list_empty(qi, qf_idx)) /* Adding to existing list, use last entry. */ old_last = qi->qf_lists[qf_idx].qf_last; else if (action == 'r') @@ -5887,7 +6100,7 @@ qf_add_entries( { qi->qf_lists[qf_idx].qf_ptr = qi->qf_lists[qf_idx].qf_start; - if (qi->qf_lists[qf_idx].qf_count > 0) + if (!qf_list_empty(qi, qf_idx)) qi->qf_lists[qf_idx].qf_index = 1; } @@ -6746,7 +6959,7 @@ ex_helpgrep(exarg_T *eap) } /* Jump to first match. */ - if (qi->qf_lists[qi->qf_curlist].qf_count > 0) + if (!qf_list_empty(qi, qi->qf_curlist)) qf_jump(qi, 0, 0, FALSE); else EMSG2(_(e_nomatch2), eap->arg); diff --git a/src/version.c b/src/version.c index 432a7ab752..4a4969c435 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 252, /**/ 251, /**/ From 40385dbcdfb44885f2e9b83e1e0285aeb8a0c2a8 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 22:31:44 +0200 Subject: [PATCH 13/24] patch 8.1.0253: saving and restoring window title does not always work Problem: Saving and restoring window title does not always work. Solution: Use the stack push and pop commands. (Kouichi Iwamoto, closes #3059) --- runtime/doc/term.txt | 4 ++++ src/buffer.c | 3 ++- src/ex_docmd.c | 2 +- src/main.c | 4 ++++ src/option.c | 10 +++++++--- src/os_amiga.c | 10 +++++----- src/os_mswin.c | 6 +++--- src/os_unix.c | 18 ++++++++++++------ src/os_win32.c | 2 +- src/proto/term.pro | 2 ++ src/term.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ src/term.h | 12 ++++++++++-- src/version.c | 2 ++ src/vim.h | 12 ++++++++++++ 14 files changed, 110 insertions(+), 22 deletions(-) diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 77cd933b42..4ade4a131c 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -352,6 +352,10 @@ Added by Vim (there are no standard codes for these): t_SH set cursor shape *t_SH* *'t_SH'* t_RC request terminal cursor blinking *t_RC* *'t_RC'* t_RS request terminal cursor style *t_RS* *'t_RS'* + t_ST save window title to stack *t_ST* *'t_ST'* + t_RT restore window title from stack *t_RT* *'t_RT'* + t_Si save icon text to stack *t_Si* *'t_Si'* + t_Ri restore icon text from stack *t_Ri* *'t_Ri'* Some codes have a start, middle and end part. The start and end are defined by the termcap option, the middle part is text. diff --git a/src/buffer.c b/src/buffer.c index 64ba5ab0e6..32d1eb4020 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -3798,7 +3798,8 @@ value_changed(char_u *str, char_u **last) if (str == NULL) { *last = NULL; - mch_restore_title(last == &lasttitle ? 1 : 2); + mch_restore_title( + last == &lasttitle ? SAVE_RESTORE_TITLE : SAVE_RESTORE_ICON); } else { diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 0539a5114b..294fbdbccc 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -7750,7 +7750,7 @@ ex_stop(exarg_T *eap) stoptermcap(); out_flush(); /* needed for SUN to restore xterm buffer */ #ifdef FEAT_TITLE - mch_restore_title(3); /* restore window titles */ + mch_restore_title(SAVE_RESTORE_BOTH); /* restore window titles */ #endif ui_suspend(); /* call machine specific function */ #ifdef FEAT_TITLE diff --git a/src/main.c b/src/main.c index f67706699c..b8390508d3 100644 --- a/src/main.c +++ b/src/main.c @@ -706,6 +706,10 @@ vim_main2(void) scroll_region_reset(); /* In case Rows changed */ scroll_start(); /* may scroll the screen to the right position */ +#ifdef FEAT_TITLE + term_push_title(SAVE_RESTORE_BOTH); +#endif + /* * Don't clear the screen when starting in Ex mode, unless using the GUI. */ diff --git a/src/option.c b/src/option.c index f86b1b19c3..a7a6ebbd92 100644 --- a/src/option.c +++ b/src/option.c @@ -3192,7 +3192,9 @@ static struct vimoption options[] = p_term("t_RB", T_RBG) p_term("t_RC", T_CRC) p_term("t_RI", T_CRI) + p_term("t_Ri", T_SRI) p_term("t_RS", T_CRS) + p_term("t_RT", T_CRT) p_term("t_RV", T_CRV) p_term("t_Sb", T_CSB) p_term("t_SC", T_CSC) @@ -3200,9 +3202,11 @@ static struct vimoption options[] = p_term("t_Sf", T_CSF) p_term("t_SH", T_CSH) p_term("t_SI", T_CSI) + p_term("t_Si", T_SSI) p_term("t_so", T_SO) p_term("t_SR", T_CSR) p_term("t_sr", T_SR) + p_term("t_ST", T_CST) p_term("t_Te", T_STE) p_term("t_te", T_TE) p_term("t_ti", T_TI) @@ -10414,7 +10418,7 @@ clear_termoptions(void) mch_setmouse(FALSE); /* switch mouse off */ #endif #ifdef FEAT_TITLE - mch_restore_title(3); /* restore window titles */ + mch_restore_title(SAVE_RESTORE_BOTH); /* restore window titles */ #endif #if defined(FEAT_XCLIPBOARD) && defined(FEAT_GUI) /* When starting the GUI close the display opened for the clipboard. @@ -11219,8 +11223,8 @@ buf_copy_options(buf_T *buf, int flags) buf->b_p_isk = NULL; } /* - * Always free the allocated strings. - * If not already initialized, set 'readonly' and copy 'fileformat'. + * Always free the allocated strings. If not already initialized, + * reset 'readonly' and copy 'fileformat'. */ if (!buf->b_p_initialized) { diff --git a/src/os_amiga.c b/src/os_amiga.c index 39fb222fdd..767cbfaf31 100644 --- a/src/os_amiga.c +++ b/src/os_amiga.c @@ -617,14 +617,14 @@ mch_settitle(char_u *title, char_u *icon) /* * Restore the window/icon title. * which is one of: - * 1 Just restore title - * 2 Just restore icon (which we don't have) - * 3 Restore title and icon (which we don't have) + * SAVE_RESTORE_TITLE Just restore title + * SAVE_RESTORE_ICON Just restore icon (which we don't have) + * SAVE_RESTORE_BOTH Restore title and icon (which we don't have) */ void mch_restore_title(int which) { - if (which & 1) + if (which & SAVE_RESTORE_TITLE) mch_settitle(oldwindowtitle, NULL); } @@ -907,7 +907,7 @@ mch_exit(int r) } #ifdef FEAT_TITLE - mch_restore_title(3); /* restore window title */ + mch_restore_title(SAVE_RESTORE_BOTH); /* restore window title */ #endif ml_close_all(TRUE); /* remove all memfiles */ diff --git a/src/os_mswin.c b/src/os_mswin.c index 5dbfd0ef0c..2112b0c2aa 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -304,9 +304,9 @@ mch_settitle( /* * Restore the window/icon title. * which is one of: - * 1: Just restore title - * 2: Just restore icon (which we don't have) - * 3: Restore title and icon (which we don't have) + * SAVE_RESTORE_TITLE: Just restore title + * SAVE_RESTORE_ICON: Just restore icon (which we don't have) + * SAVE_RESTORE_BOTH: Restore title and icon (which we don't have) */ void mch_restore_title(int which UNUSED) diff --git a/src/os_unix.c b/src/os_unix.c index 94c3dc9a2e..4b452b5ceb 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -2336,17 +2336,21 @@ mch_settitle(char_u *title, char_u *icon) /* * Restore the window/icon title. * "which" is one of: - * 1 only restore title - * 2 only restore icon - * 3 restore title and icon + * SAVE_RESTORE_TITLE only restore title + * SAVE_RESTORE_ICON only restore icon + * SAVE_RESTORE_BOTH restore title and icon */ void mch_restore_title(int which) { /* only restore the title or icon when it has been set */ - mch_settitle(((which & 1) && did_set_title) ? + mch_settitle(((which & SAVE_RESTORE_TITLE) && did_set_title) ? (oldtitle ? oldtitle : p_titleold) : NULL, - ((which & 2) && did_set_icon) ? oldicon : NULL); + ((which & SAVE_RESTORE_ICON) && did_set_icon) ? oldicon : NULL); + + // pop and push from/to the stack + term_pop_title(which); + term_push_title(which); } #endif /* FEAT_TITLE */ @@ -3412,7 +3416,9 @@ mch_exit(int r) { settmode(TMODE_COOK); #ifdef FEAT_TITLE - mch_restore_title(3); /* restore xterm title and icon name */ + // restore xterm title and icon name + mch_restore_title(SAVE_RESTORE_BOTH); + term_pop_title(SAVE_RESTORE_BOTH); #endif /* * When t_ti is not empty but it doesn't cause swapping terminal diff --git a/src/os_win32.c b/src/os_win32.c index 63572350b2..85c8a57d11 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -2695,7 +2695,7 @@ mch_exit(int r) if (g_fWindInitCalled) { #ifdef FEAT_TITLE - mch_restore_title(3); + mch_restore_title(SAVE_RESTORE_BOTH); /* * Restore both the small and big icons of the console window to * what they were at startup. Don't do this when the window is diff --git a/src/proto/term.pro b/src/proto/term.pro index 9a9606baf0..1b8ab5f0dd 100644 --- a/src/proto/term.pro +++ b/src/proto/term.pro @@ -31,6 +31,8 @@ void term_bg_color(int n); void term_fg_rgb_color(guicolor_T rgb); void term_bg_rgb_color(guicolor_T rgb); void term_settitle(char_u *title); +void term_push_title(int which); +void term_pop_title(int which); void ttest(int pairs); void add_long_to_buf(long_u val, char_u *dst); void check_shellsize(void); diff --git a/src/term.c b/src/term.c index ace467f6df..66f03ee108 100644 --- a/src/term.c +++ b/src/term.c @@ -922,6 +922,10 @@ static struct builtin_term builtin_termcaps[] = # endif {(int)KS_CBE, IF_EB("\033[?2004h", ESC_STR "[?2004h")}, {(int)KS_CBD, IF_EB("\033[?2004l", ESC_STR "[?2004l")}, + {(int)KS_CST, IF_EB("\033[22;2t", ESC_STR "[22;2t")}, + {(int)KS_CRT, IF_EB("\033[23;2t", ESC_STR "[23;2t")}, + {(int)KS_SSI, IF_EB("\033[22;1t", ESC_STR "[22;1t")}, + {(int)KS_SRI, IF_EB("\033[23;1t", ESC_STR "[23;1t")}, {K_UP, IF_EB("\033O*A", ESC_STR "O*A")}, {K_DOWN, IF_EB("\033O*B", ESC_STR "O*B")}, @@ -1600,6 +1604,8 @@ get_term_entries(int *height, int *width) {KS_8F, "8f"}, {KS_8B, "8b"}, {KS_CBE, "BE"}, {KS_CBD, "BD"}, {KS_CPS, "PS"}, {KS_CPE, "PE"}, + {KS_CST, "ST"}, {KS_CRT, "RT"}, + {KS_SSI, "Si"}, {KS_SRI, "Ri"}, {(enum SpecialKey)0, NULL} }; int i; @@ -2974,6 +2980,45 @@ term_settitle(char_u *title) out_str(T_FS); /* set title end */ out_flush(); } + +/* + * Tell the terminal to push (save) the title and/or icon, so that it can be + * popped (restored) later. + */ + void +term_push_title(int which) +{ + if ((which & SAVE_RESTORE_TITLE) && *T_CST != NUL) + { + OUT_STR(T_CST); + out_flush(); + } + + if ((which & SAVE_RESTORE_ICON) && *T_SSI != NUL) + { + OUT_STR(T_SSI); + out_flush(); + } +} + +/* + * Tell the terminal to pop the title and/or icon. + */ + void +term_pop_title(int which) +{ + if ((which & SAVE_RESTORE_TITLE) && *T_CRT != NUL) + { + OUT_STR(T_CRT); + out_flush(); + } + + if ((which & SAVE_RESTORE_ICON) && *T_SRI != NUL) + { + OUT_STR(T_SRI); + out_flush(); + } +} #endif /* diff --git a/src/term.h b/src/term.h index 8808f7db18..219a2083d2 100644 --- a/src/term.h +++ b/src/term.h @@ -101,10 +101,14 @@ enum SpecialKey KS_CBE, /* enable bracketed paste mode */ KS_CBD, /* disable bracketed paste mode */ KS_CPS, /* start of bracketed paste */ - KS_CPE /* end of bracketed paste */ + KS_CPE, /* end of bracketed paste */ + KS_CST, /* save window title */ + KS_CRT, /* restore window title */ + KS_SSI, /* save icon text */ + KS_SRI /* restore icon text */ }; -#define KS_LAST KS_CPE +#define KS_LAST KS_SRI /* * the terminal capabilities are stored in this array @@ -196,6 +200,10 @@ extern char_u *(term_strings[]); /* current terminal strings */ #define T_BD (TERM_STR(KS_CBD)) /* disable bracketed paste mode */ #define T_PS (TERM_STR(KS_CPS)) /* start of bracketed paste */ #define T_PE (TERM_STR(KS_CPE)) /* end of bracketed paste */ +#define T_CST (TERM_STR(KS_CST)) /* save window title */ +#define T_CRT (TERM_STR(KS_CRT)) /* restore window title */ +#define T_SSI (TERM_STR(KS_SSI)) /* save icon text */ +#define T_SRI (TERM_STR(KS_SRI)) /* restore icon text */ #define TMODE_COOK 0 /* terminal mode for external cmds and Ex mode */ #define TMODE_SLEEP 1 /* terminal mode for sleeping (cooked but no echo) */ diff --git a/src/version.c b/src/version.c index 4a4969c435..8b01248209 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 253, /**/ 252, /**/ diff --git a/src/vim.h b/src/vim.h index a85d47f5eb..524ed92132 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2548,4 +2548,16 @@ typedef enum { #define TERM_START_FORCEIT 2 #define TERM_START_SYSTEM 4 +#if defined(HAVE_DROP_FILE) \ + || (defined(FEAT_GUI_GTK) && defined(FEAT_DND)) \ + || defined(FEAT_GUI_MSWIN) \ + || defined(FEAT_GUI_MAC) +# define HAVE_HANDLE_DROP +#endif + +// Used for icon/title save and restore. +#define SAVE_RESTORE_TITLE 1 +#define SAVE_RESTORE_ICON 2 +#define SAVE_RESTORE_BOTH (SAVE_RESTORE_TITLE | SAVE_RESTORE_ICON) + #endif /* VIM__H */ From 980bab457ebb4df4b05d54b9d731520774f20d1d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 22:42:53 +0200 Subject: [PATCH 14/24] patch 8.1.0254: cannot build on MS-Windows; unused macro HAVE_HANDLE_DROP Problem: Cannot build on MS-Windows; Unused macro HAVE_HANDLE_DROP. Solution: Adjust #ifdef. Delete the macro. --- src/main.c | 2 +- src/version.c | 2 ++ src/vim.h | 7 ------- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/main.c b/src/main.c index b8390508d3..d3a509be3f 100644 --- a/src/main.c +++ b/src/main.c @@ -706,7 +706,7 @@ vim_main2(void) scroll_region_reset(); /* In case Rows changed */ scroll_start(); /* may scroll the screen to the right position */ -#ifdef FEAT_TITLE +#if defined(FEAT_TITLE) && (defined(UNIX) || defined(VMS) || defined(MACOS_X)) term_push_title(SAVE_RESTORE_BOTH); #endif diff --git a/src/version.c b/src/version.c index 8b01248209..099ea1fa28 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 254, /**/ 253, /**/ diff --git a/src/vim.h b/src/vim.h index 524ed92132..5166f533c4 100644 --- a/src/vim.h +++ b/src/vim.h @@ -2548,13 +2548,6 @@ typedef enum { #define TERM_START_FORCEIT 2 #define TERM_START_SYSTEM 4 -#if defined(HAVE_DROP_FILE) \ - || (defined(FEAT_GUI_GTK) && defined(FEAT_DND)) \ - || defined(FEAT_GUI_MSWIN) \ - || defined(FEAT_GUI_MAC) -# define HAVE_HANDLE_DROP -#endif - // Used for icon/title save and restore. #define SAVE_RESTORE_TITLE 1 #define SAVE_RESTORE_ICON 2 From f8f88f89e12df516c1fac5851b504238ebc1d2d4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 8 Aug 2018 11:02:32 +0200 Subject: [PATCH 15/24] patch 8.1.0255: backup test fails when using shadow directory Problem: Backup test fails when using shadow directory. Solution: Remove check for "src". --- src/testdir/test_backup.vim | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_backup.vim b/src/testdir/test_backup.vim index 3187b58878..0981efdcee 100644 --- a/src/testdir/test_backup.vim +++ b/src/testdir/test_backup.vim @@ -29,7 +29,7 @@ func Test_backup2() sp *Xbackup.txt~ call assert_equal(['line1', 'line2', 'line3'], getline(1,'$')) let f=expand('%') - call assert_match('src%testdir%Xbackup.txt\~', f) + call assert_match('%testdir%Xbackup.txt\~', f) bw! bw! call delete('Xbackup.txt') @@ -49,7 +49,7 @@ func Test_backup2_backupcopy() sp *Xbackup.txt~ call assert_equal(['line1', 'line2', 'line3'], getline(1,'$')) let f=expand('%') - call assert_match('src%testdir%Xbackup.txt\~', f) + call assert_match('%testdir%Xbackup.txt\~', f) bw! bw! call delete('Xbackup.txt') diff --git a/src/version.c b/src/version.c index 099ea1fa28..76d47dd63e 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 255, /**/ 254, /**/ From 9fa9506853516c82851baec643aa47458cb8b3bc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 8 Aug 2018 22:08:32 +0200 Subject: [PATCH 16/24] patch 8.1.0256: using setline() in TextChangedI splits undo Problem: Using setline() in TextChangedI splits undo. Solution: Use another solution for undo not working properly. --- src/edit.c | 57 +++++++++++++++++++++++------------- src/testdir/test_autocmd.vim | 4 +-- src/version.c | 2 ++ 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/edit.c b/src/edit.c index 8ee4643570..ff45bb7ee5 100644 --- a/src/edit.c +++ b/src/edit.c @@ -279,6 +279,7 @@ static colnr_T get_nolist_virtcol(void); #if defined(FEAT_EVAL) static char_u *do_insert_char_pre(int c); #endif +static int ins_apply_autocmds(event_T event); static colnr_T Insstart_textlen; /* length of line when insert started */ static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */ @@ -411,7 +412,7 @@ edit( set_vim_var_string(VV_INSERTMODE, ptr, 1); set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */ #endif - apply_autocmds(EVENT_INSERTENTER, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_INSERTENTER); /* Make sure the cursor didn't move. Do call check_cursor_col() in * case the text was modified. Since Insert mode was not started yet @@ -1061,8 +1062,7 @@ doESCkey: if (ins_esc(&count, cmdchar, nomove)) { if (cmdchar != 'r' && cmdchar != 'v') - apply_autocmds(EVENT_INSERTLEAVE, NULL, NULL, - FALSE, curbuf); + ins_apply_autocmds(EVENT_INSERTLEAVE); did_cursorhold = FALSE; return (c == Ctrl_O); } @@ -1275,7 +1275,7 @@ doESCkey: break; case K_CURSORHOLD: /* Didn't type something for a while. */ - apply_autocmds(EVENT_CURSORHOLDI, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_CURSORHOLDI); did_cursorhold = TRUE; break; @@ -1698,7 +1698,7 @@ ins_redraw( /* Make sure curswant is correct, an autocommand may call * getcurpos(). */ update_curswant(); - apply_autocmds(EVENT_CURSORMOVEDI, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_CURSORMOVEDI); } # ifdef FEAT_CONCEAL if (curwin->w_p_cole > 0) @@ -1721,24 +1721,16 @@ ins_redraw( ) { aco_save_T aco; - -#ifdef FEAT_EVAL - // Sync undo when the autocommand calls setline() or append(), so that - // it can be undone separately. - u_sync_once = 2; -#endif + varnumber_T tick = CHANGEDTICK(curbuf); // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); aucmd_restbuf(&aco); curbuf->b_last_changedtick = CHANGEDTICK(curbuf); - -#ifdef FEAT_EVAL - if (u_sync_once == 1) - ins_need_undo = TRUE; - u_sync_once = 0; -#endif + if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds() + u_save(curwin->w_cursor.lnum, + (linenr_T)(curwin->w_cursor.lnum + 1)); } #ifdef FEAT_INS_EXPAND @@ -1750,12 +1742,16 @@ ins_redraw( && pum_visible()) { aco_save_T aco; + varnumber_T tick = CHANGEDTICK(curbuf); // save and restore curwin and curbuf, in case the autocmd changes them aucmd_prepbuf(&aco, curbuf); apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf); aucmd_restbuf(&aco); curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); + if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds() + u_save(curwin->w_cursor.lnum, + (linenr_T)(curwin->w_cursor.lnum + 1)); } #endif @@ -4124,13 +4120,13 @@ ins_compl_prep(int c) #endif /* Trigger the CompleteDone event to give scripts a chance to act * upon the completion. */ - apply_autocmds(EVENT_COMPLETEDONE, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_COMPLETEDONE); } } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) /* Trigger the CompleteDone event to give scripts a chance to act * upon the (possibly failed) completion. */ - apply_autocmds(EVENT_COMPLETEDONE, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_COMPLETEDONE); /* reset continue_* if we left expansion-mode, if we stay they'll be * (re)set properly in ins_complete() */ @@ -8944,7 +8940,7 @@ ins_insert(int replaceState) : replaceState == VREPLACE ? "v" : "r"), 1); # endif - apply_autocmds(EVENT_INSERTCHANGE, NULL, NULL, FALSE, curbuf); + ins_apply_autocmds(EVENT_INSERTCHANGE); if (State & REPLACE_FLAG) State = INSERT | (State & LANGMAP); else @@ -10738,7 +10734,7 @@ do_insert_char_pre(int c) set_vim_var_string(VV_CHAR, buf, -1); /* set v:char */ res = NULL; - if (apply_autocmds(EVENT_INSERTCHARPRE, NULL, NULL, FALSE, curbuf)) + if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) { /* Get the value of v:char. It may be empty or more than one * character. Only use it when changed, otherwise continue with the @@ -10753,3 +10749,22 @@ do_insert_char_pre(int c) return res; } #endif + +/* + * Trigger "event" and take care of fixing undo. + */ + static int +ins_apply_autocmds(event_T event) +{ + varnumber_T tick = CHANGEDTICK(curbuf); + int r; + + r = apply_autocmds(event, NULL, NULL, FALSE, curbuf); + + // If u_savesub() was called then we are not prepared to start + // a new line. Call u_save() with no contents to fix that. + if (tick != CHANGEDTICK(curbuf)) + u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); + + return r; +} diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim index b52493fcb4..3d650e4736 100644 --- a/src/testdir/test_autocmd.vim +++ b/src/testdir/test_autocmd.vim @@ -1329,10 +1329,8 @@ func Test_TextChangedI_with_setline() call assert_equal('(', getline(1)) call assert_equal('x)', getline(2)) undo - call assert_equal('(', getline(1)) - call assert_equal('', getline(2)) - undo call assert_equal('', getline(1)) + call assert_equal('', getline(2)) call test_override('starting', 0) bwipe! diff --git a/src/version.c b/src/version.c index 76d47dd63e..8e21e98952 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 256, /**/ 255, /**/ From bfde0b482d25db43e9fc5a35c771b859b1eb8828 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 8 Aug 2018 22:27:31 +0200 Subject: [PATCH 17/24] patch 8.1.0257: no test for pathshorten() Problem: No test for pathshorten(). Solution: Add a test. (Dominique Pelle, closes #3295) --- src/testdir/test_functions.vim | 15 +++++++++++++++ src/version.c | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 41996bd451..13db0041e7 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -208,6 +208,21 @@ func Test_simplify() call assert_fails('call simplify(1.2)', 'E806:') endfunc +func Test_pathshorten() + call assert_equal('', pathshorten('')) + call assert_equal('foo', pathshorten('foo')) + call assert_equal('/foo', pathshorten('/foo')) + call assert_equal('f/', pathshorten('foo/')) + call assert_equal('f/bar', pathshorten('foo/bar')) + call assert_equal('f/b/foobar', pathshorten('foo/bar/foobar')) + call assert_equal('/f/b/foobar', pathshorten('/foo/bar/foobar')) + call assert_equal('.f/bar', pathshorten('.foo/bar')) + call assert_equal('~f/bar', pathshorten('~foo/bar')) + call assert_equal('~.f/bar', pathshorten('~.foo/bar')) + call assert_equal('.~f/bar', pathshorten('.~foo/bar')) + call assert_equal('~/f/bar', pathshorten('~/foo/bar')) +endfunc + func Test_strpart() call assert_equal('de', strpart('abcdefg', 3, 2)) call assert_equal('ab', strpart('abcdefg', -2, 4)) diff --git a/src/version.c b/src/version.c index 8e21e98952..36376e9e5d 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 257, /**/ 256, /**/ From af559d2c9f44bc88a7d94f9236b3c024563a8e73 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 8 Aug 2018 22:55:41 +0200 Subject: [PATCH 18/24] patch 8.1.0258: not enough testing for the CompleteDone event Problem: Not enough testing for the CompleteDone event. Solution: Add a test. (closes #3297) --- src/testdir/test_ins_complete.vim | 13 +++++++++++++ src/version.c | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 2cd29b5757..f7e1590efc 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -262,6 +262,19 @@ function Test_CompleteDoneList() au! CompleteDone endfunc +func Test_CompleteDone_undo() + au CompleteDone * call append(0, "prepend1") + new + call setline(1, ["line1", "line2"]) + call feedkeys("Go\\\\", "tx") + call assert_equal(["prepend1", "line1", "line2", "line1", ""], + \ getline(1, '$')) + undo + call assert_equal(["line1", "line2"], getline(1, '$')) + bwipe! + au! CompleteDone +endfunc + " Check that when using feedkeys() typeahead does not interrupt searching for " completions. func Test_compl_feedkeys() diff --git a/src/version.c b/src/version.c index 36376e9e5d..4f31d66e87 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 258, /**/ 257, /**/ From 3f347e4716c44cf6458be407e712e3d708d82580 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 9 Aug 2018 21:19:20 +0200 Subject: [PATCH 19/24] patch 8.1.0259: no test for fixed quickfix issue Problem: No test for fixed quickfix issue. Solution: Add a test. Clean up the code a bit. (Yegappan Lakshmanan) --- src/quickfix.c | 12 +++--------- src/testdir/test_quickfix.vim | 24 ++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index d4aa5090da..14fcfcff43 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -1506,7 +1506,6 @@ qf_list_empty(qf_info_T *qi, int qf_idx) return qi->qf_lists[qf_idx].qf_count <= 0; } - /* * Allocate the fields used for parsing lines and populating a quickfix list. */ @@ -3717,7 +3716,7 @@ qf_view_result(int split) if (IS_LL_WINDOW(curwin)) qi = GET_LOC_LIST(curwin); - if (qi == NULL || qi->qf_lists[qi->qf_curlist].qf_count == 0) + if (qf_list_empty(qi, qi->qf_curlist)) { EMSG(_(e_quickfix)); return; @@ -4349,7 +4348,8 @@ qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit) if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) qi->qf_curlist = qf_id2nr(qi, save_qfid); - if (qi->qf_lists[qi->qf_curlist].qf_count > 0) + // Autocommands might have cleared the list, check for it + if (!qf_list_empty(qi, qi->qf_curlist)) qf_jump(qi, 0, 0, forceit); } @@ -4873,10 +4873,8 @@ ex_cfile(exarg_T *eap) // free the list. if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile) && qflist_valid(wp, save_qfid)) - { // display the first error qf_jump_first(qi, save_qfid, eap->forceit); - } } /* @@ -6581,10 +6579,8 @@ ex_cbuffer(exarg_T *eap) if (res > 0 && (eap->cmdidx == CMD_cbuffer || eap->cmdidx == CMD_lbuffer) && qflist_valid(wp, save_qfid)) - { // display the first error qf_jump_first(qi, save_qfid, eap->forceit); - } } } } @@ -6661,10 +6657,8 @@ ex_cexpr(exarg_T *eap) if (res > 0 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) && qflist_valid(wp, save_qfid)) - { // display the first error qf_jump_first(qi, save_qfid, eap->forceit); - } } else EMSG(_("E777: String or List expected")); diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim index d41815f3ce..ce19e74d3f 100644 --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -3478,6 +3478,30 @@ func Xautocmd_changelist(cchar) call assert_equal(5, line('.')) autocmd! QuickFixCmdPost + " Test for autocommands clearing the quickfix list before jumping to the + " first error. This should not result in an error + autocmd QuickFixCmdPost * call g:Xsetlist([], 'r') + let v:errmsg = '' + " Test for cfile/lfile + Xfile Xerr + call assert_true(v:errmsg !~# 'E42:') + " Test for cbuffer/lbuffer + edit Xerr + Xbuffer + call assert_true(v:errmsg !~# 'E42:') + " Test for cexpr/lexpr + Xexpr 'Xtestfile2:4:Line4' + call assert_true(v:errmsg !~# 'E42:') + " Test for grep/lgrep + " The grepprg may not be set on non-Unix systems + if has('unix') + silent Xgrep Line5 Xtestfile2 + call assert_true(v:errmsg !~# 'E42:') + endif + " Test for vimgrep/lvimgrep + call assert_fails('silent Xvimgrep Line5 Xtestfile2', 'E480:') + autocmd! QuickFixCmdPost + call delete('Xerr') call delete('Xtestfile1') call delete('Xtestfile2') diff --git a/src/version.c b/src/version.c index 4f31d66e87..dadb978b31 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 259, /**/ 258, /**/ From 4d37557ac6c387621682c93125cd2931f9640986 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 9 Aug 2018 21:33:38 +0200 Subject: [PATCH 20/24] patch 8.1.0260: no LGTM logo in README file Problem: No LGTM logo in README file. Solution: Add one. (Bas van Schaik, closes #3305) --- README.md | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index bc592147bb..0ea8e4c976 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [![Coverage Status](https://coveralls.io/repos/vim/vim/badge.svg?branch=master&service=github)](https://coveralls.io/github/vim/vim?branch=master) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/o2qht2kjm02sgghk?svg=true)](https://ci.appveyor.com/project/chrisbra/vim) [![Coverity Scan](https://scan.coverity.com/projects/241/badge.svg)](https://scan.coverity.com/projects/vim) +[![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/vim/vim.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/vim/vim/context:cpp) [![Debian CI](https://badges.debian.net/badges/debian/testing/vim/version.svg)](https://buildd.debian.org/vim) diff --git a/src/version.c b/src/version.c index dadb978b31..962d173b65 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 260, /**/ 259, /**/ From 38efd1d17a6e6aa2add71efdf2cde4a788e5f5e5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 9 Aug 2018 21:52:24 +0200 Subject: [PATCH 21/24] patch 8.1.0261: Coverity complains about a negative array index Problem: Coverity complains about a negative array index. Solution: When qf_id2nr() cannot find the list then don't set qf_curlist. --- src/quickfix.c | 43 ++++++++++++++++++++++++------------------- src/version.c | 2 ++ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/quickfix.c b/src/quickfix.c index 14fcfcff43..244c7a4faa 100644 --- a/src/quickfix.c +++ b/src/quickfix.c @@ -2011,13 +2011,9 @@ ll_new_list(void) { qf_info_T *qi; - qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T)); + qi = (qf_info_T *)alloc_clear((unsigned)sizeof(qf_info_T)); if (qi != NULL) - { - vim_memset(qi, 0, (size_t)(sizeof(qf_info_T))); qi->qf_refcount++; - } - return qi; } @@ -4338,15 +4334,32 @@ qf_id2nr(qf_info_T *qi, int_u qfid) return INVALID_QFIDX; } +/* + * If the current list is not "save_qfid" and we can find the list with that ID + * then make it the current list. + * This is used when autocommands may have changed the current list. + */ + static void +qf_restore_list(qf_info_T *qi, int_u save_qfid) +{ + int curlist; + + if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) + { + curlist = qf_id2nr(qi, save_qfid); + if (curlist >= 0) + qi->qf_curlist = curlist; + // else: what if the list can't be found? + } +} + /* * Jump to the first entry if there is one. */ static void qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit) { - // If autocommands changed the current list, then restore it - if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) - qi->qf_curlist = qf_id2nr(qi, save_qfid); + qf_restore_list(qi, save_qfid); // Autocommands might have cleared the list, check for it if (!qf_list_empty(qi, qi->qf_curlist)) @@ -5012,10 +5025,7 @@ vgr_qflist_valid( } } - if (qi->qf_lists[qi->qf_curlist].qf_id != qfid) - /* Autocommands changed the quickfix list. Find the one we were - * using and restore it. */ - qi->qf_curlist = qf_id2nr(qi, qfid); + qf_restore_list(qi, qfid); return TRUE; } @@ -5361,9 +5371,7 @@ ex_vimgrep(exarg_T *eap) if (!qflist_valid(wp, save_qfid)) goto theend; - // If autocommands changed the current list, then restore it - if (qi->qf_lists[qi->qf_curlist].qf_id != save_qfid) - qi->qf_curlist = qf_id2nr(qi, save_qfid); + qf_restore_list(qi, save_qfid); /* Jump to first match. */ if (!qf_list_empty(qi, qi->qf_curlist)) @@ -5684,12 +5692,9 @@ qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict) if (l == NULL) return FAIL; - qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T)); + qi = ll_new_list(); if (qi != NULL) { - vim_memset(qi, 0, (size_t)(sizeof(qf_info_T))); - qi->qf_refcount++; - if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat, TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) { diff --git a/src/version.c b/src/version.c index 962d173b65..9e2ee2e8f8 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 261, /**/ 260, /**/ From 1598f9937a18c056d7b713dc254325c8f8456c8f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 9 Aug 2018 22:08:57 +0200 Subject: [PATCH 22/24] patch 8.1.0262: not enough testing for getftype() Problem: Not enough testing for getftype(). Solution: Add a test. (Dominique Pelle, closes #3300) --- src/evalfunc.c | 2 +- src/testdir/test_stat.vim | 35 +++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 31096d75db..9673a1ae3d 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5111,7 +5111,7 @@ f_getftype(typval_T *argvars, typval_T *rettv) # endif # ifdef S_ISSOCK else if (S_ISSOCK(st.st_mode)) - t = "fifo"; + t = "socket"; # endif else t = "other"; diff --git a/src/testdir/test_stat.vim b/src/testdir/test_stat.vim index 307cf5e640..c627266646 100644 --- a/src/testdir/test_stat.vim +++ b/src/testdir/test_stat.vim @@ -122,6 +122,41 @@ func Test_nonexistent_file() call assert_equal('', getfperm(fname)) endfunc +func Test_getftype() + call assert_equal('file', getftype(v:progpath)) + call assert_equal('dir', getftype('.')) + + if !has('unix') + return + endif + + silent !ln -s Xfile Xlink + call assert_equal('link', getftype('Xlink')) + call delete('Xlink') + + if executable('mkfifo') + silent !mkfifo Xfifo + call assert_equal('fifo', getftype('Xfifo')) + call delete('Xfifo') + endif + + for cdevfile in systemlist('find /dev -type c -maxdepth 2 2>/dev/null') + call assert_equal('cdev', getftype(cdevfile)) + endfor + + for bdevfile in systemlist('find /dev -type b -maxdepth 2 2>/dev/null') + call assert_equal('bdev', getftype(bdevfile)) + endfor + + " The /run/ directory typically contains socket files. + " If it does not, test won't fail but will not test socket files. + for socketfile in systemlist('find /run -type s -maxdepth 2 2>/dev/null') + call assert_equal('socket', getftype(socketfile)) + endfor + + " TODO: file type 'other' is not tested. How can we test it? +endfunc + func Test_win32_symlink_dir() " On Windows, non-admin users cannot create symlinks. " So we use an existing symlink for this test. diff --git a/src/version.c b/src/version.c index 9e2ee2e8f8..1cd58f0c82 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 262, /**/ 261, /**/ From 4b16ee743e26d65ecfb6231f7fd57869c3e5ff0d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 9 Aug 2018 22:15:34 +0200 Subject: [PATCH 23/24] patch 8.1.0263: channel log doesn't show part of channel Problem: Channel log doesn't show part of channel. Solution: Add "sock", "out", "err" or "in". (Ozaki Kiichi, closes #3303) --- src/channel.c | 18 ++++++++++++------ src/version.c | 2 ++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/channel.c b/src/channel.c index de2f50de2b..282340eefc 100644 --- a/src/channel.c +++ b/src/channel.c @@ -138,7 +138,7 @@ ch_log_active(void) } static void -ch_log_lead(const char *what, channel_T *ch) +ch_log_lead(const char *what, channel_T *ch, ch_part_T part) { if (log_fd != NULL) { @@ -150,7 +150,13 @@ ch_log_lead(const char *what, channel_T *ch) fprintf(log_fd, "%s ", profile_msg(&log_now)); #endif if (ch != NULL) - fprintf(log_fd, "%son %d: ", what, ch->ch_id); + { + if (part < PART_COUNT) + fprintf(log_fd, "%son %d(%s): ", + what, ch->ch_id, part_names[part]); + else + fprintf(log_fd, "%son %d: ", what, ch->ch_id); + } else fprintf(log_fd, "%s: ", what); } @@ -166,7 +172,7 @@ ch_log(channel_T *ch, const char *fmt, ...) { va_list ap; - ch_log_lead("", ch); + ch_log_lead("", ch, PART_COUNT); va_start(ap, fmt); vfprintf(log_fd, fmt, ap); va_end(ap); @@ -191,7 +197,7 @@ ch_error(channel_T *ch, const char *fmt, ...) { va_list ap; - ch_log_lead("ERR ", ch); + ch_log_lead("ERR ", ch, PART_COUNT); va_start(ap, fmt); vfprintf(log_fd, fmt, ap); va_end(ap); @@ -1849,7 +1855,7 @@ channel_save(channel_T *channel, ch_part_T part, char_u *buf, int len, if (ch_log_active() && lead != NULL) { - ch_log_lead(lead, channel); + ch_log_lead(lead, channel, part); fprintf(log_fd, "'"); ignored = (int)fwrite(buf, len, 1, log_fd); fprintf(log_fd, "'\n"); @@ -3718,7 +3724,7 @@ channel_send( if (ch_log_active()) { - ch_log_lead("SEND ", channel); + ch_log_lead("SEND ", channel, part); fprintf(log_fd, "'"); ignored = (int)fwrite(buf_arg, len_arg, 1, log_fd); fprintf(log_fd, "'\n"); diff --git a/src/version.c b/src/version.c index 1cd58f0c82..6543e91375 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 263, /**/ 262, /**/ From efe03738f69b1f63ea30226765db949539ee15f0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 9 Aug 2018 22:26:38 +0200 Subject: [PATCH 24/24] patch 8.1.0264: backup tests fail when CWD is in /tmp Problem: Backup tests fail when CWD is in /tmp. Solution: Make 'backupskip' empty. (Christian Brabandt, closes #3301) --- src/testdir/test_backup.vim | 12 ++++++------ src/version.c | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/testdir/test_backup.vim b/src/testdir/test_backup.vim index 0981efdcee..ce2bfe72bc 100644 --- a/src/testdir/test_backup.vim +++ b/src/testdir/test_backup.vim @@ -1,7 +1,7 @@ " Tests for the backup function func Test_backup() - set backup backupdir=. + set backup backupdir=. backupskip= new call setline(1, ['line1', 'line2']) :f Xbackup.txt @@ -12,13 +12,13 @@ func Test_backup() let l = readfile('Xbackup.txt~') call assert_equal(['line1', 'line2'], l) bw! - set backup&vim backupdir&vim + set backup&vim backupdir&vim backupskip&vim call delete('Xbackup.txt') call delete('Xbackup.txt~') endfunc func Test_backup2() - set backup backupdir=.// + set backup backupdir=.// backupskip= new call setline(1, ['line1', 'line2', 'line3']) :f Xbackup.txt @@ -34,11 +34,11 @@ func Test_backup2() bw! call delete('Xbackup.txt') call delete(f) - set backup&vim backupdir&vim + set backup&vim backupdir&vim backupskip&vim endfunc func Test_backup2_backupcopy() - set backup backupdir=.// backupcopy=yes + set backup backupdir=.// backupcopy=yes backupskip= new call setline(1, ['line1', 'line2', 'line3']) :f Xbackup.txt @@ -54,5 +54,5 @@ func Test_backup2_backupcopy() bw! call delete('Xbackup.txt') call delete(f) - set backup&vim backupdir&vim backupcopy&vim + set backup&vim backupdir&vim backupcopy&vim backupskip&vim endfunc diff --git a/src/version.c b/src/version.c index 6543e91375..2d047319d9 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 264, /**/ 263, /**/