From e31e256ba1769a3a3ed7840d5cc9a01ab058b8bc Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 10 Jun 2018 13:12:55 +0200 Subject: [PATCH 01/14] patch 8.1.0040: warnings from 64-bit compiler Problem: Warnings from 64-bit compiler. Solution: Add type casts. (Mike Williams) --- src/edit.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/edit.c b/src/edit.c index 7c7fadd10a..731b9dc7ff 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1894,7 +1894,7 @@ init_prompt(int cmdchar_todo) || Insstart_orig.col != (int)STRLEN(prompt)) { Insstart.lnum = curwin->w_cursor.lnum; - Insstart.col = STRLEN(prompt); + Insstart.col = (int)STRLEN(prompt); Insstart_orig = Insstart; Insstart_textlen = Insstart.col; Insstart_blank_vcol = MAXCOL; @@ -1904,7 +1904,7 @@ init_prompt(int cmdchar_todo) if (cmdchar_todo == 'A') coladvance((colnr_T)MAXCOL); if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) - curwin->w_cursor.col = STRLEN(prompt); + curwin->w_cursor.col = (int)STRLEN(prompt); /* Make sure the cursor is in a valid position. */ check_cursor(); } diff --git a/src/version.c b/src/version.c index 0c804b9a55..88c1fb110c 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 40, /**/ 39, /**/ From e950f9992b291a07e4fb41cb561156f5b382cd5d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 10 Jun 2018 13:55:55 +0200 Subject: [PATCH 02/14] patch 8.1.0041: attribute "width" missing from python window attribute list Problem: Attribute "width" missing from python window attribute list. Solution: Add the item. (Ken Takata) Order the list like the items are used in the WindowAttr() function. --- src/if_py_both.h | 15 +++++++++++++-- src/testdir/test86.ok | 2 +- src/testdir/test87.ok | 2 +- src/version.c | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/if_py_both.h b/src/if_py_both.h index 247fc9a088..526cbd7848 100644 --- a/src/if_py_both.h +++ b/src/if_py_both.h @@ -3836,9 +3836,20 @@ get_firstwin(TabPageObject *tabObject) else return firstwin; } + +// Use the same order as in the WindowAttr() function. static char *WindowAttrs[] = { - "buffer", "cursor", "height", "vars", "options", "number", "row", "col", - "tabpage", "valid", + "buffer", + "cursor", + "height", + "row", + "width", + "col", + "vars", + "options", + "number", + "tabpage", + "valid", NULL }; diff --git a/src/testdir/test86.ok b/src/testdir/test86.ok index 58e776a6dd..f8d4ceb577 100644 --- a/src/testdir/test86.ok +++ b/src/testdir/test86.ok @@ -443,7 +443,7 @@ vim.current.window:Window:True vim.current.tabpage:TabPage:True current:__dir__,__members__,buffer,line,range,tabpage,window buffer:__dir__,__members__,append,mark,name,number,options,range,valid,vars -window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars +window:__dir__,__members__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars,width tabpage:__dir__,__members__,number,valid,vars,window,windows range:__dir__,__members__,append,end,start dictionary:__dir__,__members__,get,has_key,items,keys,locked,pop,popitem,scope,update,values diff --git a/src/testdir/test87.ok b/src/testdir/test87.ok index 72b59b631f..9ca4b624cf 100644 --- a/src/testdir/test87.ok +++ b/src/testdir/test87.ok @@ -443,7 +443,7 @@ vim.current.window:Window:True vim.current.tabpage:TabPage:True current:__dir__,buffer,line,range,tabpage,window buffer:__dir__,append,mark,name,number,options,range,valid,vars -window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars +window:__dir__,buffer,col,cursor,height,number,options,row,tabpage,valid,vars,width tabpage:__dir__,number,valid,vars,window,windows range:__dir__,append,end,start dictionary:__dir__,get,has_key,items,keys,locked,pop,popitem,scope,update,values diff --git a/src/version.c b/src/version.c index 88c1fb110c..71283ed0db 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 41, /**/ 40, /**/ From f98b845dd185dfadfa7a622a42452bfa6809d4e0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 10 Jun 2018 14:39:52 +0200 Subject: [PATCH 03/14] patch 8.1.0042: if omni completion opens a window Insert mode is stopped Problem: If omni completion opens a window Insert mode is stopped. (Hirohito Higashi) Solution: Only set stop_insert_mode in a prompt buffer window. --- src/version.c | 2 ++ src/window.c | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/version.c b/src/version.c index 71283ed0db..4ab241eb90 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 42, /**/ 41, /**/ diff --git a/src/window.c b/src/window.c index 27ef9d5cc2..74e3c04698 100644 --- a/src/window.c +++ b/src/window.c @@ -2107,17 +2107,22 @@ win_equal_rec( static void leaving_window(win_T *win) { + // Only matters for a prompt window. + if (!bt_prompt(win->w_buffer)) + return; + // When leaving a prompt window stop Insert mode and perhaps restart // it when entering that window again. win->w_buffer->b_prompt_insert = restart_edit; restart_edit = NUL; // When leaving the window (or closing the window) was done from a - // callback we need to break out of the Insert mode loop. + // callback we need to break out of the Insert mode loop and restart Insert + // mode when entering the window again. if (State & INSERT) { stop_insert_mode = TRUE; - if (bt_prompt(win->w_buffer) && win->w_buffer->b_prompt_insert == NUL) + if (win->w_buffer->b_prompt_insert == NUL) win->w_buffer->b_prompt_insert = 'A'; } } @@ -2125,12 +2130,17 @@ leaving_window(win_T *win) static void entering_window(win_T *win) { + // Only matters for a prompt window. + if (!bt_prompt(win->w_buffer)) + return; + // When switching to a prompt buffer that was in Insert mode, don't stop // Insert mode, it may have been set in leaving_window(). - if (bt_prompt(win->w_buffer) && win->w_buffer->b_prompt_insert != NUL) + if (win->w_buffer->b_prompt_insert != NUL) stop_insert_mode = FALSE; - // When entering the prompt window may restart Insert mode. + // When entering the prompt window restart Insert mode if we were in Insert + // mode when we left it. restart_edit = win->w_buffer->b_prompt_insert; } #endif From 7580849df9d6c7c515f5ed784019336d8a8ec0f0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 12:39:41 +0200 Subject: [PATCH 04/14] patch 8.1.0043: ++bad argument of :edit does not work properly Problem: ++bad argument of :edit does not work properly. Solution: Return FAIL from get_bad_opt() only when there is no valid argument. (Dominique Pelle, Christian Brabandt, closes #2966, closes #2947) --- src/ex_docmd.c | 4 +++- src/testdir/test_plus_arg_edit.vim | 32 ++++++++++++++++++++++++++++-- src/version.c | 2 ++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 342dec2229..3bc86f5ac8 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -5318,7 +5318,9 @@ get_bad_opt(char_u *p, exarg_T *eap) eap->bad_char = BAD_DROP; else if (MB_BYTE2LEN(*p) == 1 && p[1] == NUL) eap->bad_char = *p; - return FAIL; + else + return FAIL; + return OK; } #endif diff --git a/src/testdir/test_plus_arg_edit.vim b/src/testdir/test_plus_arg_edit.vim index 71dbea1991..e91a6e467a 100644 --- a/src/testdir/test_plus_arg_edit.vim +++ b/src/testdir/test_plus_arg_edit.vim @@ -1,10 +1,38 @@ " Tests for complicated + argument to :edit command function Test_edit() - call writefile(["foo|bar"], "Xfile1") - call writefile(["foo/bar"], "Xfile2") + call writefile(["foo|bar"], "Xfile1") + call writefile(["foo/bar"], "Xfile2") edit +1|s/|/PIPE/|w Xfile1| e Xfile2|1 | s/\//SLASH/|w call assert_equal(["fooPIPEbar"], readfile("Xfile1")) call assert_equal(["fooSLASHbar"], readfile("Xfile2")) call delete('Xfile1') call delete('Xfile2') endfunction + +func Test_edit_bad() + if !has('multi_byte') + finish + endif + + " Test loading a utf8 file with bad utf8 sequences. + call writefile(["[\xff][\xc0][\xe2\x89\xf0][\xc2\xc2]"], "Xfile") + new + + " Without ++bad=..., the default behavior is like ++bad=? + e! ++enc=utf8 Xfile + call assert_equal('[?][?][???][??]', getline(1)) + + e! ++enc=utf8 ++bad=_ Xfile + call assert_equal('[_][_][___][__]', getline(1)) + + e! ++enc=utf8 ++bad=drop Xfile + call assert_equal('[][][][]', getline(1)) + + e! ++enc=utf8 ++bad=keep Xfile + call assert_equal("[\xff][\xc0][\xe2\x89\xf0][\xc2\xc2]", getline(1)) + + call assert_fails('e! ++enc=utf8 ++bad=foo Xfile', 'E474:') + + bw! + call delete('Xfile') +endfunc diff --git a/src/version.c b/src/version.c index 4ab241eb90..100506b0b1 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 43, /**/ 42, /**/ From 8903676d3d4c3fcb37d2a55c67370f30806b1626 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 14:58:39 +0200 Subject: [PATCH 05/14] patch 8.1.0044: if a test function exists Vim this may go unnoticed Problem: If a test function exists Vim this may go unnoticed. Solution: Check for a test funtion quitting Vim. Fix tests that did exit Vim. --- src/testdir/runtest.vim | 12 ++++++++++++ src/testdir/test_assert.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 20 insertions(+) diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim index 5b8126d5d1..4f508a4875 100644 --- a/src/testdir/runtest.vim +++ b/src/testdir/runtest.vim @@ -124,7 +124,10 @@ func RunTheTest(test) exe 'call ' . a:test else try + let s:test = a:test + au VimLeavePre * call EarlyExit(s:test) exe 'call ' . a:test + au! VimLeavePre catch /^\cskipped/ call add(s:messages, ' Skipped') call add(s:skipped, 'SKIPPED ' . a:test . ': ' . substitute(v:exception, '^\S*\s\+', '', '')) @@ -174,6 +177,15 @@ func AfterTheTest() endif endfunc +func EarlyExit(test) + " It's OK for the test we use to test the quit detection. + if a:test != 'Test_zz_quit_detected()' + call add(v:errors, 'Test caused Vim to exit: ' . a:test) + endif + + call FinishTesting() +endfunc + " This function can be called by a test if it wants to abort testing. func FinishTesting() call AfterTheTest() diff --git a/src/testdir/test_assert.vim b/src/testdir/test_assert.vim index 61147286fb..28db289b2a 100644 --- a/src/testdir/test_assert.vim +++ b/src/testdir/test_assert.vim @@ -198,3 +198,9 @@ func Test_user_is_happy() smile sleep 300m endfunc + +" Must be last. +func Test_zz_quit_detected() + " Verify that if a test function ends Vim the test script detects this. + quit +endfunc diff --git a/src/version.c b/src/version.c index 100506b0b1..dfdc07d59f 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 44, /**/ 43, /**/ From ae0f30b761eb62e1b6bfc83fb4a6d1a47bf48320 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 15:22:43 +0200 Subject: [PATCH 06/14] patch 8.1.0045: popup test isn't run completely Problem: Popup test isn't run completely. Solution: Remove "finish". Clean up function definitions. --- src/testdir/test_popup.vim | 54 ++++++++++++++++++-------------------- src/version.c | 2 ++ 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/testdir/test_popup.vim b/src/testdir/test_popup.vim index cb61be21c8..9c25687ad3 100644 --- a/src/testdir/test_popup.vim +++ b/src/testdir/test_popup.vim @@ -6,7 +6,7 @@ source screendump.vim let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] let g:setting = '' -func! ListMonths() +func ListMonths() if g:setting != '' exe ":set" g:setting endif @@ -19,7 +19,7 @@ func! ListMonths() return '' endfunc -func! Test_popup_complete2() +func Test_popup_complete2() " Although the popupmenu is not visible, this does not mean completion mode " has ended. After pressing to complete the currently typed char, Vim " still stays in the first state of the completion (:h ins-completion-menu), @@ -34,9 +34,9 @@ func! Test_popup_complete2() call assert_equal(["Dece", "", "December2015"], getline(1,3)) %d bw! -endfu +endfunc -func! Test_popup_complete() +func Test_popup_complete() new inoremap =ListMonths() @@ -215,10 +215,10 @@ func! Test_popup_complete() call feedkeys("aM\\\", 'tx') call assert_equal(["March", "M", "March"], getline(1,4)) %d -endfu +endfunc -func! Test_popup_completion_insertmode() +func Test_popup_completion_insertmode() new inoremap =ListMonths() @@ -247,20 +247,16 @@ func! Test_popup_completion_insertmode() iunmap endfunc -" TODO: Fix what breaks after this line. -" - Do not use "q!", it may exit Vim if there is an error -finish - func Test_noinsert_complete() - function! s:complTest1() abort + func! s:complTest1() abort call complete(1, ['source', 'soundfold']) return '' - endfunction + endfunc - function! s:complTest2() abort + func! s:complTest2() abort call complete(1, ['source', 'soundfold']) return '' - endfunction + endfunc new set completeopt+=noinsert @@ -281,9 +277,9 @@ func Test_noinsert_complete() endfunc func Test_compl_vim_cmds_after_register_expr() - function! s:test_func() + func! s:test_func() return 'autocmd ' - endfunction + endfunc augroup AAAAA_Group au! augroup END @@ -330,7 +326,7 @@ func DummyCompleteTwo(findstart, base) else return ['twodef', 'twoDEF'] endif -endfunction +endfunc " Test that nothing happens if the 'completefunc' opens " a new window (no completion, no crash) @@ -407,7 +403,7 @@ func Test_omnifunc_with_check() q! endfunc -function UndoComplete() +func UndoComplete() call complete(1, ['January', 'February', 'March', \ 'April', 'May', 'June', 'July', 'August', 'September', \ 'October', 'November', 'December']) @@ -444,7 +440,7 @@ func Test_complete_no_undo() q! endfunc -function! DummyCompleteFive(findstart, base) +func DummyCompleteFive(findstart, base) if a:findstart return 0 else @@ -489,7 +485,7 @@ func Test_completion_ctrl_e_without_autowrap() q! endfunc -function! DummyCompleteSix() +func DummyCompleteSix() call complete(1, ['Hello', 'World']) return '' endfunction @@ -577,7 +573,7 @@ func Test_completion_comment_formatting() bwipe! endfunc -fun MessCompleteMonths() +func MessCompleteMonths() for m in split("Jan Feb Mar Apr May Jun Jul Aug Sep") call complete_add(m) if complete_check() @@ -585,14 +581,14 @@ fun MessCompleteMonths() endif endfor return [] -endfun +endfunc -fun MessCompleteMore() +func MessCompleteMore() call complete(1, split("Oct Nov Dec")) return [] -endfun +endfunc -fun MessComplete(findstart, base) +func MessComplete(findstart, base) if a:findstart let line = getline('.') let start = col('.') - 1 @@ -605,7 +601,7 @@ fun MessComplete(findstart, base) call MessCompleteMore() return [] endif -endf +endfunc func Test_complete_func_mess() " Calling complete() after complete_add() in 'completefunc' is wrong, but it @@ -835,7 +831,7 @@ func Test_popup_complete_backwards_ctrl_p() bwipe! endfunc -fun! Test_complete_o_tab() +func Test_complete_o_tab() let s:o_char_pressed = 0 fun! s:act_on_text_changed() @@ -843,7 +839,7 @@ fun! Test_complete_o_tab() let s:o_char_pressed = 0 call feedkeys("\\", 'i') endif - endf + endfunc set completeopt=menu,noselect new @@ -862,7 +858,7 @@ fun! Test_complete_o_tab() bwipe! set completeopt& delfunc s:act_on_text_changed -endf +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index dfdc07d59f..e18a8c05fd 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 45, /**/ 44, /**/ From 1c3c10492a291270fa89b3c8df11828792f927d3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 16:49:30 +0200 Subject: [PATCH 07/14] patch 8.1.0046: loading a session file fails if 'winheight' is big Problem: Loading a session file fails if 'winheight' is a big number. Solution: Set 'minwinheight' to zero at first. Don't give an error when setting 'minwinheight' while 'winheight' is a big number. Fix using vertical splits. Fix setting 'minwinwidth'. (closes #2970) --- src/option.c | 10 ++++----- src/proto/window.pro | 1 + src/testdir/test_mksession.vim | 11 +++++++++- src/version.c | 2 ++ src/window.c | 40 +++++++++++++++++++++++++++------- 5 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/option.c b/src/option.c index 7d79b3ca1c..0200b207c7 100644 --- a/src/option.c +++ b/src/option.c @@ -8796,6 +8796,7 @@ set_num_option( */ if (pp == &p_wh || pp == &p_hh) { + // 'winheight' and 'helpheight' if (p_wh < 1) { errmsg = e_positive; @@ -8821,10 +8822,9 @@ set_num_option( win_setheight((int)p_hh); } } - - /* 'winminheight' */ else if (pp == &p_wmh) { + // 'winminheight' if (p_wmh < 0) { errmsg = e_positive; @@ -8839,6 +8839,7 @@ set_num_option( } else if (pp == &p_wiw) { + // 'winwidth' if (p_wiw < 1) { errmsg = e_positive; @@ -8854,10 +8855,9 @@ set_num_option( if (!ONE_WINDOW && curwin->w_width < p_wiw) win_setwidth((int)p_wiw); } - - /* 'winminwidth' */ else if (pp == &p_wmw) { + // 'winminwidth' if (p_wmw < 0) { errmsg = e_positive; @@ -8868,7 +8868,7 @@ set_num_option( errmsg = e_winwidth; p_wmw = p_wiw; } - win_setminheight(); + win_setminwidth(); } /* (re)set last window status line */ diff --git a/src/proto/window.pro b/src/proto/window.pro index b21b4633f2..7ed8042f7b 100644 --- a/src/proto/window.pro +++ b/src/proto/window.pro @@ -54,6 +54,7 @@ void win_setheight_win(int height, win_T *win); void win_setwidth(int width); void win_setwidth_win(int width, win_T *wp); void win_setminheight(void); +void win_setminwidth(void); void win_drag_status_line(win_T *dragwin, int offset); void win_drag_vsep_line(win_T *dragwin, int offset); void set_fraction(win_T *wp); diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim index 81883b5d76..e81d9b3e32 100644 --- a/src/testdir/test_mksession.vim +++ b/src/testdir/test_mksession.vim @@ -106,13 +106,22 @@ endfunc func Test_mksession_winheight() new - set winheight=10 winminheight=2 + set winheight=10 + set winminheight=2 mksession! Xtest_mks.out source Xtest_mks.out call delete('Xtest_mks.out') endfunc +func Test_mksession_large_winheight() + set winheight=999 + mksession! Xtest_mks_winheight.out + set winheight& + source Xtest_mks_winheight.out + call delete('Xtest_mks_winheight.out') +endfunc + func Test_mksession_arglist() argdel * next file1 file2 file3 file4 diff --git a/src/version.c b/src/version.c index e18a8c05fd..2ce060c500 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 46, /**/ 45, /**/ diff --git a/src/window.c b/src/window.c index 74e3c04698..4f4f08b675 100644 --- a/src/window.c +++ b/src/window.c @@ -5430,23 +5430,21 @@ frame_setwidth(frame_T *curfrp, int width) } /* - * Check 'winminheight' for a valid value. + * Check 'winminheight' for a valid value and reduce it if needed. */ void win_setminheight(void) { int room; + int needed; int first = TRUE; - win_T *wp; - /* loop until there is a 'winminheight' that is possible */ + // loop until there is a 'winminheight' that is possible while (p_wmh > 0) { - /* TODO: handle vertical splits */ - room = -p_wh; - FOR_ALL_WINDOWS(wp) - room += VISIBLE_HEIGHT(wp) - p_wmh; - if (room >= 0) + room = Rows - p_ch; + needed = frame_minheight(topframe, NULL); + if (room >= needed) break; --p_wmh; if (first) @@ -5457,6 +5455,32 @@ win_setminheight(void) } } +/* + * Check 'winminwidth' for a valid value and reduce it if needed. + */ + void +win_setminwidth(void) +{ + int room; + int needed; + int first = TRUE; + + // loop until there is a 'winminheight' that is possible + while (p_wmw > 0) + { + room = Columns; + needed = frame_minwidth(topframe, NULL); + if (room >= needed) + break; + --p_wmw; + if (first) + { + EMSG(_(e_noroom)); + first = FALSE; + } + } +} + #if defined(FEAT_MOUSE) || defined(PROTO) /* From 19834010889fc5bfa0f88b3ba83133dae6c0a35d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 17:03:39 +0200 Subject: [PATCH 08/14] patch 8.1.0047: no completion for :unlet $VAR Problem: No completion for :unlet $VAR. Solution: Add completion. (Jason Franklin) --- src/ex_docmd.c | 13 ++++++++++++- src/testdir/test_unlet.vim | 10 ++++++++++ src/version.c | 2 ++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 3bc86f5ac8..5229e0e73b 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -4056,8 +4056,16 @@ set_one_cmd_context( case CMD_unlet: while ((xp->xp_pattern = vim_strchr(arg, ' ')) != NULL) arg = xp->xp_pattern + 1; + xp->xp_context = EXPAND_USER_VARS; xp->xp_pattern = arg; + + if (*xp->xp_pattern == '$') + { + xp->xp_context = EXPAND_ENV_VARS; + ++xp->xp_pattern; + } + break; case CMD_function: @@ -11277,7 +11285,10 @@ makeopens( * winminheight and winminwidth need to be set to avoid an error if the * user has set winheight or winwidth. */ - if (put_line(fd, "set winminheight=1 winheight=1 winminwidth=1 winwidth=1") == FAIL) + if (put_line(fd, "set winminheight=0") == FAIL + || put_line(fd, "set winheight=1") == FAIL + || put_line(fd, "set winminwidth=0") == FAIL + || put_line(fd, "set winwidth=1") == FAIL) return FAIL; if (nr > 1 && ses_winsizes(fd, restore_size, tab_firstwin) == FAIL) return FAIL; diff --git a/src/testdir/test_unlet.vim b/src/testdir/test_unlet.vim index 6636f6d66b..0a9f3c61b1 100644 --- a/src/testdir/test_unlet.vim +++ b/src/testdir/test_unlet.vim @@ -45,3 +45,13 @@ func Test_unlet_env() unlet $MUST_NOT_BE_AN_ERROR endfunc + +func Test_unlet_complete() + let g:FOOBAR = 1 + call feedkeys(":unlet g:FOO\t\n", 'tx') + call assert_true(!exists('g:FOOBAR')) + + let $FOOBAR = 1 + call feedkeys(":unlet $FOO\t\n", 'tx') + call assert_true(!exists('$FOOBAR') || empty($FOOBAR)) +endfunc diff --git a/src/version.c b/src/version.c index 2ce060c500..d290fda6fd 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 47, /**/ 46, /**/ From 07ccf7ce7fb948fd4d080b817e9fbaea9e721dab Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 17:25:36 +0200 Subject: [PATCH 09/14] patch 8.1.0048: vim_str2nr() does not handle numbers close to the maximum Problem: vim_str2nr() does not handle numbers close to the maximum. Solution: Check for overflow more precisely. (Ken Takata, closes #2746) --- src/charset.c | 15 +++++++++------ src/version.c | 2 ++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/charset.c b/src/charset.c index e6657ce84c..179fc89db3 100644 --- a/src/charset.c +++ b/src/charset.c @@ -1928,8 +1928,8 @@ vim_str2nr( while ('0' <= *ptr && *ptr <= '1') { /* avoid ubsan error for overflow */ - if (un < UVARNUM_MAX / 2) - un = 2 * un + (unsigned long)(*ptr - '0'); + if (un <= UVARNUM_MAX / 2) + un = 2 * un + (uvarnumber_T)(*ptr - '0'); else un = UVARNUM_MAX; ++ptr; @@ -1943,7 +1943,7 @@ vim_str2nr( while ('0' <= *ptr && *ptr <= '7') { /* avoid ubsan error for overflow */ - if (un < UVARNUM_MAX / 8) + if (un <= UVARNUM_MAX / 8) un = 8 * un + (uvarnumber_T)(*ptr - '0'); else un = UVARNUM_MAX; @@ -1960,7 +1960,7 @@ vim_str2nr( while (vim_isxdigit(*ptr)) { /* avoid ubsan error for overflow */ - if (un < UVARNUM_MAX / 16) + if (un <= UVARNUM_MAX / 16) un = 16 * un + (uvarnumber_T)hex2nr(*ptr); else un = UVARNUM_MAX; @@ -1974,9 +1974,12 @@ vim_str2nr( /* decimal */ while (VIM_ISDIGIT(*ptr)) { + uvarnumber_T digit = (uvarnumber_T)(*ptr - '0'); + /* avoid ubsan error for overflow */ - if (un < UVARNUM_MAX / 10) - un = 10 * un + (uvarnumber_T)(*ptr - '0'); + if (un < UVARNUM_MAX / 10 + || (un == UVARNUM_MAX / 10 && digit <= UVARNUM_MAX % 10)) + un = 10 * un + digit; else un = UVARNUM_MAX; ++ptr; diff --git a/src/version.c b/src/version.c index d290fda6fd..fc68f8ef2e 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 48, /**/ 47, /**/ From d7a137fb0d980545dd567bee9c24cf7b9c3a2eae Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 18:05:24 +0200 Subject: [PATCH 10/14] patch 8.1.0049: shell cannot tell running in a terminal window Problem: Shell cannot tell running in a terminal window. Solution: Add the VIM_TERMINAL environment variable. (Christian Brabandt) --- runtime/doc/terminal.txt | 1 + src/os_unix.c | 6 ++++++ src/os_win32.c | 30 ++++++++++++++++++++++++------ src/testdir/test_terminal.vim | 15 +++++++++++---- src/version.c | 2 ++ 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/runtime/doc/terminal.txt b/runtime/doc/terminal.txt index b3fe522864..e4cca34438 100644 --- a/runtime/doc/terminal.txt +++ b/runtime/doc/terminal.txt @@ -376,6 +376,7 @@ Environment variables are used to pass information to the running job: COLUMNS number of columns in the terminal initially COLORS number of colors, 't_Co' (256*256*256 in the GUI) VIM_SERVERNAME v:servername + VIM_TERMINAL v:version MS-Windows ~ diff --git a/src/os_unix.c b/src/os_unix.c index 1609bb8e2d..a9fb3b51c8 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4169,6 +4169,7 @@ set_child_environment(long rows, long columns, char *term) static char envbuf_Lines[20]; static char envbuf_Columns[20]; static char envbuf_Colors[20]; + static char envbuf_Version[20]; # ifdef FEAT_CLIENTSERVER static char envbuf_Servername[60]; # endif @@ -4189,6 +4190,8 @@ set_child_environment(long rows, long columns, char *term) setenv("COLUMNS", (char *)envbuf, 1); sprintf((char *)envbuf, "%ld", colors); setenv("COLORS", (char *)envbuf, 1); + sprintf((char *)envbuf, "%ld", get_vim_var_nr(VV_VERSION)); + setenv("VIM_TERMINAL", (char *)envbuf, 1); # ifdef FEAT_CLIENTSERVER setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1); # endif @@ -4209,6 +4212,9 @@ set_child_environment(long rows, long columns, char *term) putenv(envbuf_Columns); vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors); putenv(envbuf_Colors); + vim_snprintf(envbuf_Version, sizeof(envbuf_Version), "VIM_TERMINAL=%ld", + get_vim_var_nr(VV_VERSION)); + putenv(envbuf_Version); # ifdef FEAT_CLIENTSERVER vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername), "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName); diff --git a/src/os_win32.c b/src/os_win32.c index 602ef8aa21..3b0291e9b1 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5275,25 +5275,43 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) } } -# ifdef FEAT_CLIENTSERVER if (is_terminal) { +# ifdef FEAT_CLIENTSERVER char_u *servername = get_vim_var_str(VV_SEND_SERVER); - size_t lval = STRLEN(servername); - size_t n; + size_t servername_len = STRLEN(servername); +# endif + char_u *version = get_vim_var_str(VV_VERSION); + size_t version_len = STRLEN(version); + // size of "VIM_SERVERNAME=" and value, + // plus "VIM_TERMINAL=" and value, + // plus two terminating NULs + size_t n = 0 +# ifdef FEAT_CLIENTSERVER + + 15 + servername_len +# endif + + 13 + version_len + 2; - if (ga_grow(gap, (int)(14 + lval + 2)) == OK) + if (ga_grow(gap, (int)n) == OK) { +# ifdef FEAT_CLIENTSERVER for (n = 0; n < 15; n++) *((WCHAR*)gap->ga_data + gap->ga_len++) = (WCHAR)"VIM_SERVERNAME="[n]; - for (n = 0; n < lval; n++) + for (n = 0; n < servername_len; n++) *((WCHAR*)gap->ga_data + gap->ga_len++) = (WCHAR)servername[n]; *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; +# endif + for (n = 0; n < 13; n++) + *((WCHAR*)gap->ga_data + gap->ga_len++) = + (WCHAR)"VIM_TERMINAL="[n]; + for (n = 0; n < version_len; n++) + *((WCHAR*)gap->ga_data + gap->ga_len++) = + (WCHAR)version[n]; + *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; } } -# endif } void diff --git a/src/testdir/test_terminal.vim b/src/testdir/test_terminal.vim index 3d06eb3876..c082b3b73e 100644 --- a/src/testdir/test_terminal.vim +++ b/src/testdir/test_terminal.vim @@ -482,18 +482,25 @@ func Test_terminal_servername() if !has('clientserver') return endif + call s:test_environment("VIM_SERVERNAME", v:servername) +endfunc + +func Test_terminal_version() + call s:test_environment("VIM_TERMINAL", string(v:version)) +endfunc + +func s:test_environment(name, value) let buf = Run_shell_in_terminal({}) " Wait for the shell to display a prompt call WaitForAssert({-> assert_notequal('', term_getline(buf, 1))}) if has('win32') - call term_sendkeys(buf, "echo %VIM_SERVERNAME%\r") + call term_sendkeys(buf, "echo %" . a:name . "%\r") else - call term_sendkeys(buf, "echo $VIM_SERVERNAME\r") + call term_sendkeys(buf, "echo $" . a:name . "\r") endif call term_wait(buf) call Stop_shell_in_terminal(buf) - call WaitFor('getline(2) == v:servername') - call assert_equal(v:servername, getline(2)) + call WaitForAssert({-> assert_equal(a:value, getline(2))}) exe buf . 'bwipe' unlet buf diff --git a/src/version.c b/src/version.c index fc68f8ef2e..770eea8f04 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 49, /**/ 48, /**/ From 493359eb3b10377d5c3524e91d911809b8ac7a76 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 20:25:52 +0200 Subject: [PATCH 11/14] patch 8.1.0050: $VIM_TERMINAL is also set when not in a terminal window Problem: $VIM_TERMINAL is also set when not in a terminal window. Solution: Pass a flag to indicate whether the job runs in a terminal. --- src/channel.c | 8 ++++++-- src/evalfunc.c | 2 +- src/os_unix.c | 41 +++++++++++++++++++++++++++++------------ src/os_win32.c | 40 +++++++++++++++++++++++++--------------- src/proto/channel.pro | 2 +- src/proto/os_unix.pro | 2 +- src/terminal.c | 2 +- src/version.c | 2 ++ 8 files changed, 66 insertions(+), 33 deletions(-) diff --git a/src/channel.c b/src/channel.c index 40a3e955d8..d654dc06d3 100644 --- a/src/channel.c +++ b/src/channel.c @@ -5525,7 +5525,11 @@ job_check_ended(void) * Returns NULL when out of memory. */ job_T * -job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg) +job_start( + typval_T *argvars, + char **argv_arg, + jobopt_T *opt_arg, + int is_terminal UNUSED) { job_T *job; char_u *cmd = NULL; @@ -5679,7 +5683,7 @@ job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg) ch_log(NULL, "Starting job: %s", (char *)ga.ga_data); ga_clear(&ga); } - mch_job_start(argv, job, &opt); + mch_job_start(argv, job, &opt, is_terminal); #else ch_log(NULL, "Starting job: %s", (char *)cmd); mch_job_start((char *)cmd, job, &opt); diff --git a/src/evalfunc.c b/src/evalfunc.c index 3cd3c3d35a..2bbeb25692 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -7254,7 +7254,7 @@ f_job_start(typval_T *argvars, typval_T *rettv) rettv->v_type = VAR_JOB; if (check_restricted() || check_secure()) return; - rettv->vval.v_job = job_start(argvars, NULL, NULL); + rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE); } /* diff --git a/src/os_unix.c b/src/os_unix.c index a9fb3b51c8..71886538e1 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4159,7 +4159,11 @@ wait4pid(pid_t child, waitstatus *status) * Set the environment for a child process. */ static void -set_child_environment(long rows, long columns, char *term) +set_child_environment( + long rows, + long columns, + char *term, + int is_terminal UNUSED) { # ifdef HAVE_SETENV char envbuf[50]; @@ -4169,7 +4173,9 @@ set_child_environment(long rows, long columns, char *term) static char envbuf_Lines[20]; static char envbuf_Columns[20]; static char envbuf_Colors[20]; +# ifdef FEAT_TERMINAL static char envbuf_Version[20]; +# endif # ifdef FEAT_CLIENTSERVER static char envbuf_Servername[60]; # endif @@ -4190,8 +4196,13 @@ set_child_environment(long rows, long columns, char *term) setenv("COLUMNS", (char *)envbuf, 1); sprintf((char *)envbuf, "%ld", colors); setenv("COLORS", (char *)envbuf, 1); - sprintf((char *)envbuf, "%ld", get_vim_var_nr(VV_VERSION)); - setenv("VIM_TERMINAL", (char *)envbuf, 1); +# ifdef FEAT_TERMINAL + if (is_terminal) + { + sprintf((char *)envbuf, "%ld", get_vim_var_nr(VV_VERSION)); + setenv("VIM_TERMINAL", (char *)envbuf, 1); + } +# endif # ifdef FEAT_CLIENTSERVER setenv("VIM_SERVERNAME", serverName == NULL ? "" : (char *)serverName, 1); # endif @@ -4212,9 +4223,14 @@ set_child_environment(long rows, long columns, char *term) putenv(envbuf_Columns); vim_snprintf(envbuf_Colors, sizeof(envbuf_Colors), "COLORS=%ld", colors); putenv(envbuf_Colors); - vim_snprintf(envbuf_Version, sizeof(envbuf_Version), "VIM_TERMINAL=%ld", - get_vim_var_nr(VV_VERSION)); - putenv(envbuf_Version); +# ifdef FEAT_TERMINAL + if (is_terminal) + { + vim_snprintf(envbuf_Version, sizeof(envbuf_Version), + "VIM_TERMINAL=%ld", get_vim_var_nr(VV_VERSION)); + putenv(envbuf_Version); + } +# endif # ifdef FEAT_CLIENTSERVER vim_snprintf(envbuf_Servername, sizeof(envbuf_Servername), "VIM_SERVERNAME=%s", serverName == NULL ? "" : (char *)serverName); @@ -4224,9 +4240,9 @@ set_child_environment(long rows, long columns, char *term) } static void -set_default_child_environment(void) +set_default_child_environment(int is_terminal) { - set_child_environment(Rows, Columns, "dumb"); + set_child_environment(Rows, Columns, "dumb", is_terminal); } #endif @@ -4689,7 +4705,7 @@ mch_call_shell_fork( # endif } # endif - set_default_child_environment(); + set_default_child_environment(FALSE); /* * stderr is only redirected when using the GUI, so that a @@ -5367,7 +5383,7 @@ mch_call_shell( #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) void -mch_job_start(char **argv, job_T *job, jobopt_T *options) +mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal) { pid_t pid; int fd_in[2] = {-1, -1}; /* for stdin */ @@ -5515,11 +5531,12 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options) set_child_environment( (long)options->jo_term_rows, (long)options->jo_term_cols, - term); + term, + is_terminal); } else # endif - set_default_child_environment(); + set_default_child_environment(is_terminal); if (options->jo_env != NULL) { diff --git a/src/os_win32.c b/src/os_win32.c index 3b0291e9b1..f340949aa8 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5275,26 +5275,31 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) } } - if (is_terminal) +# if defined(FEAT_CLIENTSERVER) || defined(FEAT_TERMINAL) { -# ifdef FEAT_CLIENTSERVER +# ifdef FEAT_CLIENTSERVER char_u *servername = get_vim_var_str(VV_SEND_SERVER); size_t servername_len = STRLEN(servername); -# endif +# endif +# ifdef FEAT_TERMINAL char_u *version = get_vim_var_str(VV_VERSION); size_t version_len = STRLEN(version); +# endif // size of "VIM_SERVERNAME=" and value, // plus "VIM_TERMINAL=" and value, // plus two terminating NULs size_t n = 0 -# ifdef FEAT_CLIENTSERVER +# ifdef FEAT_CLIENTSERVER + 15 + servername_len -# endif - + 13 + version_len + 2; +# endif +# ifdef FEAT_TERMINAL + + 13 + version_len + 2 +# endif + ; if (ga_grow(gap, (int)n) == OK) { -# ifdef FEAT_CLIENTSERVER +# ifdef FEAT_CLIENTSERVER for (n = 0; n < 15; n++) *((WCHAR*)gap->ga_data + gap->ga_len++) = (WCHAR)"VIM_SERVERNAME="[n]; @@ -5302,14 +5307,19 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) *((WCHAR*)gap->ga_data + gap->ga_len++) = (WCHAR)servername[n]; *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; -# endif - for (n = 0; n < 13; n++) - *((WCHAR*)gap->ga_data + gap->ga_len++) = - (WCHAR)"VIM_TERMINAL="[n]; - for (n = 0; n < version_len; n++) - *((WCHAR*)gap->ga_data + gap->ga_len++) = - (WCHAR)version[n]; - *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; +# endif +# ifdef FEAT_TERMINAL + if (is_terminal) + { + for (n = 0; n < 13; n++) + *((WCHAR*)gap->ga_data + gap->ga_len++) = + (WCHAR)"VIM_TERMINAL="[n]; + for (n = 0; n < version_len; n++) + *((WCHAR*)gap->ga_data + gap->ga_len++) = + (WCHAR)version[n]; + *((WCHAR*)gap->ga_data + gap->ga_len++) = L'\0'; + } +# endif } } } diff --git a/src/proto/channel.pro b/src/proto/channel.pro index e6c95089b8..5326276ef1 100644 --- a/src/proto/channel.pro +++ b/src/proto/channel.pro @@ -66,7 +66,7 @@ void job_set_options(job_T *job, jobopt_T *opt); void job_stop_on_exit(void); int has_pending_job(void); void job_check_ended(void); -job_T *job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg); +job_T *job_start(typval_T *argvars, char **argv_arg, jobopt_T *opt_arg, int is_terminal); char *job_status(job_T *job); void job_info(job_T *job, dict_T *dict); void job_info_all(list_T *l); diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 5d90c0e84e..262a8d54de 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -62,7 +62,7 @@ void mch_set_shellsize(void); void mch_new_shellsize(void); void may_send_sigint(int c, pid_t pid, pid_t wpid); int mch_call_shell(char_u *cmd, int options); -void mch_job_start(char **argv, job_T *job, jobopt_T *options); +void mch_job_start(char **argv, job_T *job, jobopt_T *options, int is_terminal); char *mch_job_status(job_T *job); job_T *mch_detect_ended_job(job_T *job_list); int mch_signal_job(job_T *job, char_u *how); diff --git a/src/terminal.c b/src/terminal.c index 275a5a7ba3..9b7bc038d2 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -5769,7 +5769,7 @@ term_and_job_init( #endif /* This may change a string in "argvar". */ - term->tl_job = job_start(argvar, argv, opt); + term->tl_job = job_start(argvar, argv, opt, TRUE); if (term->tl_job != NULL) ++term->tl_job->jv_refcount; diff --git a/src/version.c b/src/version.c index 770eea8f04..29cb801d3f 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 50, /**/ 49, /**/ From 79c6b51e403d4ea755b6637b01d1426a06ca9f9a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 21:11:12 +0200 Subject: [PATCH 12/14] patch 8.1.0051: MS-Windows: missing #endif Problem: MS-Windows: missing #endif. Solution: Add the #endif. --- src/os_win32.c | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/os_win32.c b/src/os_win32.c index f340949aa8..bece2c4c61 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -5322,6 +5322,7 @@ win32_build_env(dict_T *env, garray_T *gap, int is_terminal) # endif } } +# endif } void diff --git a/src/version.c b/src/version.c index 29cb801d3f..5ff56fdb03 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 51, /**/ 50, /**/ From 83f4cbd973731872b633d6ba0caf850fb708d70c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 21:35:40 +0200 Subject: [PATCH 13/14] patch 8.1.0052: when mapping to times out the next mapping is skipped Problem: When a mapping to times out the next mapping is skipped. Solution: Reset "timedout" when waiting for a character. (Christian Brabandt, closes #2921) --- src/getchar.c | 5 +++++ src/version.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/getchar.c b/src/getchar.c index ff03905b44..ce7508c569 100644 --- a/src/getchar.c +++ b/src/getchar.c @@ -2856,6 +2856,11 @@ vgetorpeek(int advance) /* * get a character: 3. from the user - get it */ + if (typebuf.tb_len == 0) + // timedout may have been set while waiting for a mapping + // that has a RHS. + timedout = FALSE; + wait_tb_len = typebuf.tb_len; c = inchar(typebuf.tb_buf + typebuf.tb_off + typebuf.tb_len, typebuf.tb_buflen - typebuf.tb_off - typebuf.tb_len - 1, diff --git a/src/version.c b/src/version.c index 5ff56fdb03..3187cf2845 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 52, /**/ 51, /**/ From ffa9684150f5441e84d492e7184ef73587bd6c6c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 12 Jun 2018 22:05:14 +0200 Subject: [PATCH 14/14] patch 8.1.0053: first argument of 'completefunc' has inconsistent type Problem: The first argument given to 'completefunc' can be Number or String, depending on the value. Solution: Avoid guessing the type of an argument, use typval_T in the callers of call_vim_function(). (Ozaki Kiichi, closes #2993) --- src/edit.c | 20 +++++--- src/eval.c | 78 +++++++------------------------ src/ex_getln.c | 23 +++++---- src/mbyte.c | 9 ++-- src/normal.c | 10 ++-- src/proto/eval.pro | 8 ++-- src/testdir/test_ins_complete.vim | 25 ++++++++++ src/version.c | 2 + 8 files changed, 86 insertions(+), 89 deletions(-) diff --git a/src/edit.c b/src/edit.c index 731b9dc7ff..92c9d6ad44 100644 --- a/src/edit.c +++ b/src/edit.c @@ -4201,7 +4201,7 @@ expand_by_function( { list_T *matchlist = NULL; dict_T *matchdict = NULL; - char_u *args[2]; + typval_T args[3]; char_u *funcname; pos_T pos; win_T *curwin_save; @@ -4213,15 +4213,18 @@ expand_by_function( return; /* Call 'completefunc' to obtain the list of matches. */ - args[0] = (char_u *)"0"; - args[1] = base; + args[0].v_type = VAR_NUMBER; + args[0].vval.v_number = 0; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = base != NULL ? base : (char_u *)""; + args[2].v_type = VAR_UNKNOWN; pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; /* Call a function, which returns a list or dict. */ - if (call_vim_function(funcname, 2, args, FALSE, FALSE, &rettv) == OK) + if (call_vim_function(funcname, 2, args, &rettv, FALSE) == OK) { switch (rettv.v_type) { @@ -5528,7 +5531,7 @@ ins_complete(int c, int enable_pum) * Call user defined function 'completefunc' with "a:findstart" * set to 1 to obtain the length of text to use for completion. */ - char_u *args[2]; + typval_T args[3]; int col; char_u *funcname; pos_T pos; @@ -5548,8 +5551,11 @@ ins_complete(int c, int enable_pum) return FAIL; } - args[0] = (char_u *)"1"; - args[1] = NULL; + args[0].v_type = VAR_NUMBER; + args[0].vval.v_number = 1; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = (char_u *)""; + args[2].v_type = VAR_UNKNOWN; pos = curwin->w_cursor; curwin_save = curwin; curbuf_save = curbuf; diff --git a/src/eval.c b/src/eval.c index 2ba9e82a80..26aa0e34e7 100644 --- a/src/eval.c +++ b/src/eval.c @@ -1011,63 +1011,22 @@ eval_expr(char_u *arg, char_u **nextcmd) /* * Call some Vim script function and return the result in "*rettv". - * Uses argv[argc] for the function arguments. Only Number and String - * arguments are currently supported. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] + * should have type VAR_UNKNOWN. * Returns OK or FAIL. */ int call_vim_function( char_u *func, int argc, - char_u **argv, - int safe, /* use the sandbox */ - int str_arg_only, /* all arguments are strings */ - typval_T *rettv) + typval_T *argv, + typval_T *rettv, + int safe) /* use the sandbox */ { - typval_T *argvars; - varnumber_T n; - int len; - int i; int doesrange; void *save_funccalp = NULL; int ret; - argvars = (typval_T *)alloc((unsigned)((argc + 1) * sizeof(typval_T))); - if (argvars == NULL) - return FAIL; - - for (i = 0; i < argc; i++) - { - /* Pass a NULL or empty argument as an empty string */ - if (argv[i] == NULL || *argv[i] == NUL) - { - argvars[i].v_type = VAR_STRING; - argvars[i].vval.v_string = (char_u *)""; - continue; - } - - if (str_arg_only) - len = 0; - else - { - /* Recognize a number argument, the others must be strings. A dash - * is a string too. */ - vim_str2nr(argv[i], NULL, &len, STR2NR_ALL, &n, NULL, 0); - if (len == 1 && *argv[i] == '-') - len = 0; - } - if (len != 0 && len == (int)STRLEN(argv[i])) - { - argvars[i].v_type = VAR_NUMBER; - argvars[i].vval.v_number = n; - } - else - { - argvars[i].v_type = VAR_STRING; - argvars[i].vval.v_string = argv[i]; - } - } - if (safe) { save_funccalp = save_funccal(); @@ -1075,7 +1034,7 @@ call_vim_function( } rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */ - ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars, NULL, + ret = call_func(func, (int)STRLEN(func), rettv, argc, argv, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &doesrange, TRUE, NULL, NULL); if (safe) @@ -1083,7 +1042,6 @@ call_vim_function( --sandbox; restore_funccal(save_funccalp); } - vim_free(argvars); if (ret == FAIL) clear_tv(rettv); @@ -1094,20 +1052,20 @@ call_vim_function( /* * Call Vim script function "func" and return the result as a number. * Returns -1 when calling the function fails. - * Uses argv[argc] for the function arguments. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should + * have type VAR_UNKNOWN. */ varnumber_T call_func_retnr( char_u *func, int argc, - char_u **argv, + typval_T *argv, int safe) /* use the sandbox */ { typval_T rettv; varnumber_T retval; - /* All arguments are passed as strings, no conversion to number. */ - if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) return -1; retval = get_tv_number_chk(&rettv, NULL); @@ -1122,20 +1080,20 @@ call_func_retnr( /* * Call Vim script function "func" and return the result as a string. * Returns NULL when calling the function fails. - * Uses argv[argc] for the function arguments. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should + * have type VAR_UNKNOWN. */ void * call_func_retstr( char_u *func, int argc, - char_u **argv, + typval_T *argv, int safe) /* use the sandbox */ { typval_T rettv; char_u *retval; - /* All arguments are passed as strings, no conversion to number. */ - if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) return NULL; retval = vim_strsave(get_tv_string(&rettv)); @@ -1146,20 +1104,20 @@ call_func_retstr( /* * Call Vim script function "func" and return the result as a List. - * Uses argv[argc] for the function arguments. + * Uses argv[0] to argv[argc - 1] for the function arguments. argv[argc] should + * have type VAR_UNKNOWN. * Returns NULL when there is something wrong. */ void * call_func_retlist( char_u *func, int argc, - char_u **argv, + typval_T *argv, int safe) /* use the sandbox */ { typval_T rettv; - /* All arguments are passed as strings, no conversion to number. */ - if (call_vim_function(func, argc, argv, safe, TRUE, &rettv) == FAIL) + if (call_vim_function(func, argc, argv, &rettv, safe) == FAIL) return NULL; if (rettv.v_type != VAR_LIST) diff --git a/src/ex_getln.c b/src/ex_getln.c index c4b9acd75d..063900a388 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -5266,7 +5266,7 @@ expand_shellcmd( # if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) -static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, char_u **, int), expand_T *xp, int *num_file, char_u ***file); +static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, typval_T *, int), expand_T *xp, int *num_file, char_u ***file); /* * Call "user_expand_func()" to invoke a user defined Vim script function and @@ -5274,15 +5274,15 @@ static void * call_user_expand_func(void *(*user_expand_func)(char_u *, int, cha */ static void * call_user_expand_func( - void *(*user_expand_func)(char_u *, int, char_u **, int), + void *(*user_expand_func)(char_u *, int, typval_T *, int), expand_T *xp, int *num_file, char_u ***file) { int keep = 0; - char_u num[50]; - char_u *args[3]; + typval_T args[4]; int save_current_SID = current_SID; + char_u *pat = NULL; void *ret; struct cmdline_info save_ccline; @@ -5297,10 +5297,15 @@ call_user_expand_func( ccline.cmdbuff[ccline.cmdlen] = 0; } - args[0] = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); - args[1] = xp->xp_line; - sprintf((char *)num, "%d", xp->xp_col); - args[2] = num; + pat = vim_strnsave(xp->xp_pattern, xp->xp_pattern_len); + + args[0].v_type = VAR_STRING; + args[0].vval.v_string = pat; + args[1].v_type = VAR_STRING; + args[1].vval.v_string = xp->xp_line; + args[2].v_type = VAR_NUMBER; + args[2].vval.v_number = xp->xp_col; + args[3].v_type = VAR_UNKNOWN; /* Save the cmdline, we don't know what the function may do. */ save_ccline = ccline; @@ -5315,7 +5320,7 @@ call_user_expand_func( if (ccline.cmdbuff != NULL) ccline.cmdbuff[ccline.cmdlen] = keep; - vim_free(args[0]); + vim_free(pat); return ret; } diff --git a/src/mbyte.c b/src/mbyte.c index b79783527a..545a40db0f 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -4795,12 +4795,11 @@ iconv_end(void) static void call_imactivatefunc(int active) { - char_u *argv[1]; + typval_T argv[2]; - if (active) - argv[0] = (char_u *)"1"; - else - argv[0] = (char_u *)"0"; + argv[0].v_type = VAR_NUMBER; + argv[0].vval.v_number = active ? 1 : 0; + argv[1].v_type = VAR_NUMBER; (void)call_func_retnr(p_imaf, 1, argv, FALSE); } diff --git a/src/normal.c b/src/normal.c index a01a434867..4d51c33206 100644 --- a/src/normal.c +++ b/src/normal.c @@ -2219,7 +2219,7 @@ op_colon(oparg_T *oap) op_function(oparg_T *oap UNUSED) { #ifdef FEAT_EVAL - char_u *(argv[1]); + typval_T argv[2]; # ifdef FEAT_VIRTUALEDIT int save_virtual_op = virtual_op; # endif @@ -2235,12 +2235,14 @@ op_function(oparg_T *oap UNUSED) /* Exclude the end position. */ decl(&curbuf->b_op_end); + argv[0].v_type = VAR_STRING; if (oap->block_mode) - argv[0] = (char_u *)"block"; + argv[0].vval.v_string = (char_u *)"block"; else if (oap->motion_type == MLINE) - argv[0] = (char_u *)"line"; + argv[0].vval.v_string = (char_u *)"line"; else - argv[0] = (char_u *)"char"; + argv[0].vval.v_string = (char_u *)"char"; + argv[1].v_type = VAR_UNKNOWN; # ifdef FEAT_VIRTUALEDIT /* Reset virtual_op so that 'virtualedit' can be changed in the diff --git a/src/proto/eval.pro b/src/proto/eval.pro index a096156ae0..0906a68d3f 100644 --- a/src/proto/eval.pro +++ b/src/proto/eval.pro @@ -19,10 +19,10 @@ varnumber_T eval_to_number(char_u *expr); list_T *eval_spell_expr(char_u *badword, char_u *expr); int get_spellword(list_T *list, char_u **pp); typval_T *eval_expr(char_u *arg, char_u **nextcmd); -int call_vim_function(char_u *func, int argc, char_u **argv, int safe, int str_arg_only, typval_T *rettv); -varnumber_T call_func_retnr(char_u *func, int argc, char_u **argv, int safe); -void *call_func_retstr(char_u *func, int argc, char_u **argv, int safe); -void *call_func_retlist(char_u *func, int argc, char_u **argv, int safe); +int call_vim_function(char_u *func, int argc, typval_T *argv, typval_T *rettv, int safe); +varnumber_T call_func_retnr(char_u *func, int argc, typval_T *argv, int safe); +void *call_func_retstr(char_u *func, int argc, typval_T *argv, int safe); +void *call_func_retlist(char_u *func, int argc, typval_T *argv, int safe); int eval_foldexpr(char_u *arg, int *cp); void ex_let(exarg_T *eap); void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first); diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim index 020e228820..2b4356ea38 100644 --- a/src/testdir/test_ins_complete.vim +++ b/src/testdir/test_ins_complete.vim @@ -117,6 +117,31 @@ func Test_omni_dash() set omnifunc= endfunc +func Test_completefunc_args() + let s:args = [] + func! CompleteFunc(findstart, base) + let s:args += [[a:findstart, empty(a:base)]] + endfunc + new + + set completefunc=CompleteFunc + call feedkeys("i\\\", 'x') + call assert_equal(s:args[0], [1, 1]) + call assert_equal(s:args[1][0], 0) + set completefunc= + + let s:args = [] + set omnifunc=CompleteFunc + call feedkeys("i\\\", 'x') + call assert_equal(s:args[0], [1, 1]) + call assert_equal(s:args[1][0], 0) + set omnifunc= + + bwipe! + unlet s:args + delfunc CompleteFunc +endfunc + function! s:CompleteDone_CompleteFuncDict( findstart, base ) if a:findstart return 0 diff --git a/src/version.c b/src/version.c index 3187cf2845..2ea298bc3b 100644 --- a/src/version.c +++ b/src/version.c @@ -761,6 +761,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 53, /**/ 52, /**/