From f52f9ea8f5fb3df51a308c56f2bf66f735ef3ca7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 27 Jun 2018 20:49:44 +0200 Subject: [PATCH 01/23] patch 8.1.0118: duplicate error message for put command Problem: Duplicate error message for put command. Solution: Check return value of u_save(). (Jason Franklin) --- src/ops.c | 7 +++--- src/testdir/test_messages.vim | 2 +- src/testdir/test_put.vim | 46 +++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/ops.c b/src/ops.c index 2dbc74889d..73f73d2f92 100644 --- a/src/ops.c +++ b/src/ops.c @@ -3551,9 +3551,10 @@ do_put( return; } - /* Autocommands may be executed when saving lines for undo, which may make - * y_array invalid. Start undo now to avoid that. */ - u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1); + /* Autocommands may be executed when saving lines for undo. This might + * make "y_array" invalid, so we start undo now to avoid that. */ + if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL) + goto end; if (insert_string != NULL) { diff --git a/src/testdir/test_messages.vim b/src/testdir/test_messages.vim index 384d2aa94f..a85799e263 100644 --- a/src/testdir/test_messages.vim +++ b/src/testdir/test_messages.vim @@ -39,7 +39,7 @@ function Test_messages() endtry endfunction -" Patch 7.4.1696 defined the "clearmode()" command for clearing the mode +" Patch 7.4.1696 defined the "clearmode()" function for clearing the mode " indicator (e.g., "-- INSERT --") when ":stopinsert" is invoked. Message " output could then be disturbed when 'cmdheight' was greater than one. " This test ensures that the bugfix for this issue remains in place. diff --git a/src/testdir/test_put.vim b/src/testdir/test_put.vim index 0a23a43919..e425c44f9f 100644 --- a/src/testdir/test_put.vim +++ b/src/testdir/test_put.vim @@ -1,3 +1,4 @@ +" Tests for put commands, e.g. ":put", "p", "gp", "P", "gP", etc. func Test_put_block() if !has('multi_byte') @@ -58,3 +59,48 @@ func Test_put_expr() call assert_equal(['A1','A2','A3','4A','5A','6A'], getline(1,'$')) bw! endfunc + +func Test_put_fails_when_nomodifiable() + new + set nomodifiable + + normal! yy + call assert_fails(':put', 'E21') + call assert_fails(':put!', 'E21') + call assert_fails(':normal! p', 'E21') + call assert_fails(':normal! gp', 'E21') + call assert_fails(':normal! P', 'E21') + call assert_fails(':normal! gP', 'E21') + + if has('mouse') + set mouse=n + call assert_fails('execute "normal! \"', 'E21') + set mouse& + endif + + bwipeout! +endfunc + +" A bug was discovered where the Normal mode put commands (e.g., "p") would +" output duplicate error messages when invoked in a non-modifiable buffer. +func Test_put_p_errmsg_nodup() + new + set nomodifiable + + normal! yy + + func Capture_p_error() + redir => s:p_err + normal! p + redir END + endfunc + + silent! call Capture_p_error() + + " Error message output within a function should be three lines (the function + " name, the line number, and the error message). + call assert_equal(3, count(s:p_err, "\n")) + + delfunction Capture_p_error + bwipeout! +endfunc diff --git a/src/version.c b/src/version.c index 88a6541854..ff3806af86 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 118, /**/ 117, /**/ From ec12d6490923fb5ff147ebf7e28d32f2b4977e3b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 27 Jun 2018 23:12:36 +0200 Subject: [PATCH 02/23] patch 8.1.0119: failing test goes unnoticed because messages is not written Problem: Failing test goes unnoticed because testdir/messages is not written. Solution: Set 'nomodifiable' only local to the buffer. --- src/testdir/test_put.vim | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/testdir/test_put.vim b/src/testdir/test_put.vim index e425c44f9f..61b74297ff 100644 --- a/src/testdir/test_put.vim +++ b/src/testdir/test_put.vim @@ -62,7 +62,7 @@ endfunc func Test_put_fails_when_nomodifiable() new - set nomodifiable + setlocal nomodifiable normal! yy call assert_fails(':put', 'E21') @@ -85,7 +85,7 @@ endfunc " output duplicate error messages when invoked in a non-modifiable buffer. func Test_put_p_errmsg_nodup() new - set nomodifiable + setlocal nomodifiable normal! yy diff --git a/src/version.c b/src/version.c index ff3806af86..a7a96b396a 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 119, /**/ 118, /**/ From dc9e955fb07f410d5d3e981ce18d895dd2847c85 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 11:28:08 +0200 Subject: [PATCH 03/23] patch 8.1.0120: buffer 'modified' set even when :sort has no changes Problem: Buffer 'modified' set even when :sort has no changes. Solution: Only set 'modified' when lines are moved. (Jason Franklin) --- src/ex_cmds.c | 18 ++++++++++--- src/testdir/test_sort.vim | 55 +++++++++++++++++++++++++++++++++------ src/version.c | 2 ++ 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 994ef0c5e9..3384fe85bf 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -398,6 +398,7 @@ ex_sort(exarg_T *eap) colnr_T end_col; int sort_what = 0; int format_found = 0; + int change_occurred = FALSE; // Buffer contents changed. /* Sorting one line is really quick! */ if (count <= 1) @@ -616,12 +617,19 @@ ex_sort(exarg_T *eap) lnum = eap->line2; for (i = 0; i < count; ++i) { - s = ml_get(nrs[eap->forceit ? count - i - 1 : i].lnum); + linenr_T get_lnum = nrs[eap->forceit ? count - i - 1 : i].lnum; + + // If the original line number of the line being placed is not the same + // as "lnum" (accounting for offset), we know that the buffer changed. + if (get_lnum + ((linenr_T)count - 1) != lnum) + change_occurred = TRUE; + + s = ml_get(get_lnum); if (!unique || i == 0 || (sort_ic ? STRICMP(s, sortbuf1) : STRCMP(s, sortbuf1)) != 0) { - /* Copy the line into a buffer, it may become invalid in - * ml_append(). And it's needed for "unique". */ + // Copy the line into a buffer, it may become invalid in + // ml_append(). And it's needed for "unique". STRCPY(sortbuf1, s); if (ml_append(lnum++, sortbuf1, (colnr_T)0, FALSE) == FAIL) break; @@ -644,7 +652,9 @@ ex_sort(exarg_T *eap) mark_adjust(eap->line2 - deleted, eap->line2, (long)MAXLNUM, -deleted); else if (deleted < 0) mark_adjust(eap->line2, MAXLNUM, -deleted, 0L); - changed_lines(eap->line1, 0, eap->line2 + 1, -deleted); + + if (change_occurred || deleted != 0) + changed_lines(eap->line1, 0, eap->line2 + 1, -deleted); curwin->w_cursor.lnum = eap->line1; beginline(BL_WHITE | BL_FIX); diff --git a/src/testdir/test_sort.vim b/src/testdir/test_sort.vim index 4fddb47b58..6dc1d468c0 100644 --- a/src/testdir/test_sort.vim +++ b/src/testdir/test_sort.vim @@ -1,13 +1,13 @@ -" Test sort() +" Tests for the "sort()" function and for the ":sort" command. -:func Compare1(a, b) abort +func Compare1(a, b) abort call sort(range(3), 'Compare2') return a:a - a:b -:endfunc +endfunc -:func Compare2(a, b) abort +func Compare2(a, b) abort return a:a - a:b -:endfunc +endfunc func Test_sort_strings() " numbers compared as strings @@ -45,7 +45,7 @@ func Test_sort_default() call assert_fails('call sort([3.3, 1, "2"], 3)', "E474") endfunc -" Tests for the :sort command +" Tests for the ":sort" command. func Test_sort_cmd() let tests = [ \ { @@ -1167,15 +1167,54 @@ func Test_sort_cmd() \ '1.234', \ '123.456' \ ] - \ } + \ }, + \ { + \ 'name' : 'alphabetical, sorted input', + \ 'cmd' : 'sort', + \ 'input' : [ + \ 'a', + \ 'b', + \ 'c', + \ ], + \ 'expected' : [ + \ 'a', + \ 'b', + \ 'c', + \ ] + \ }, + \ { + \ 'name' : 'alphabetical, sorted input, unique at end', + \ 'cmd' : 'sort u', + \ 'input' : [ + \ 'aa', + \ 'bb', + \ 'cc', + \ 'cc', + \ ], + \ 'expected' : [ + \ 'aa', + \ 'bb', + \ 'cc', + \ ] + \ }, \ ] for t in tests enew! call append(0, t.input) $delete _ - exe t.cmd + setlocal nomodified + execute t.cmd + call assert_equal(t.expected, getline(1, '$'), t.name) + + " Previously, the ":sort" command would set 'modified' even if the buffer + " contents did not change. Here, we check that this problem is fixed. + if t.input == t.expected + call assert_false(&modified, t.name . ': &mod is not correct') + else + call assert_true(&modified, t.name . ': &mod is not correct') + endif endfor call assert_fails('sort no', 'E474') diff --git a/src/version.c b/src/version.c index a7a96b396a..aa8a1de06b 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 120, /**/ 119, /**/ From ca4b613c692b927c9345dc9e3d6be5de35266be2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 12:05:11 +0200 Subject: [PATCH 04/23] patch 8.1.0121: crash when using ballooneval related to 'vartabstop' Problem: Crash when using ballooneval related to 'vartabstop'. Solution: Initialize balloonEval->vts to NULL. (Markus Braun) --- src/ex_cmds2.c | 2 +- src/gui.c | 5 +++++ src/gui_beval.c | 11 +---------- src/gui_w32.c | 9 +-------- src/version.c | 2 ++ 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c index 01bc357f43..5f58fedfb7 100644 --- a/src/ex_cmds2.c +++ b/src/ex_cmds2.c @@ -1419,7 +1419,7 @@ check_due_timer(void) bevalexpr_due_set = FALSE; if (balloonEval == NULL) { - balloonEval = (BalloonEval *)alloc(sizeof(BalloonEval)); + balloonEval = (BalloonEval *)alloc_clear(sizeof(BalloonEval)); balloonEvalForTerm = TRUE; } if (balloonEval != NULL) diff --git a/src/gui.c b/src/gui.c index 87ea5ce2b0..f51b81f867 100644 --- a/src/gui.c +++ b/src/gui.c @@ -745,7 +745,12 @@ gui_init(void) /* Always create the Balloon Evaluation area, but disable it when * 'ballooneval' is off. */ if (balloonEval != NULL) + { +# ifdef FEAT_VARTABS + vim_free(balloonEval->vts); +# endif vim_free(balloonEval); + } balloonEvalForTerm = FALSE; # ifdef FEAT_GUI_GTK balloonEval = gui_mch_create_beval_area(gui.drawarea, NULL, diff --git a/src/gui_beval.c b/src/gui_beval.c index 7e4625080f..49694cfdda 100644 --- a/src/gui_beval.c +++ b/src/gui_beval.c @@ -111,28 +111,19 @@ gui_mch_create_beval_area( return NULL; } - beval = (BalloonEval *)alloc(sizeof(BalloonEval)); + beval = (BalloonEval *)alloc_clear(sizeof(BalloonEval)); if (beval != NULL) { #ifdef FEAT_GUI_GTK beval->target = GTK_WIDGET(target); - beval->balloonShell = NULL; - beval->timerID = 0; #else beval->target = (Widget)target; - beval->balloonShell = NULL; - beval->timerID = (XtIntervalId)NULL; beval->appContext = XtWidgetToApplicationContext((Widget)target); #endif beval->showState = ShS_NEUTRAL; - beval->x = 0; - beval->y = 0; beval->msg = mesg; beval->msgCB = mesgCB; beval->clientData = clientData; -#ifdef FEAT_VARTABS - beval->vts = NULL; -#endif /* * Set up event handler which will keep its eyes on the pointer, diff --git a/src/gui_w32.c b/src/gui_w32.c index 855381108b..147d98b391 100644 --- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -8922,28 +8922,21 @@ gui_mch_create_beval_area( return NULL; } - beval = (BalloonEval *)alloc(sizeof(BalloonEval)); + beval = (BalloonEval *)alloc_clear(sizeof(BalloonEval)); if (beval != NULL) { beval->target = s_textArea; - beval->balloon = NULL; beval->showState = ShS_NEUTRAL; - beval->x = 0; - beval->y = 0; beval->msg = mesg; beval->msgCB = mesgCB; beval->clientData = clientData; -#ifdef FEAT_VARTABS - beval->vts = NULL; -#endif InitCommonControls(); cur_beval = beval; if (p_beval) gui_mch_enable_beval_area(beval); - } return beval; } diff --git a/src/version.c b/src/version.c index aa8a1de06b..5aacf2f11f 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 121, /**/ 120, /**/ From 0c183198727b80fd7e52fb29cc1dcd08d79a281c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 14:54:43 +0200 Subject: [PATCH 05/23] patch 8.1.0122: translators don't always understand the maintainer message Problem: Translators don't always understand the maintainer message. Solution: Add a comment that ends up in the generated po file. (Christian Brabandt, closes #3037) --- src/message.c | 4 ++++ src/version.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/message.c b/src/message.c index 4dac5ae04d..e46c514010 100644 --- a/src/message.c +++ b/src/message.c @@ -982,7 +982,11 @@ ex_messages(exarg_T *eap) { s = mch_getenv((char_u *)"LANG"); if (s != NULL && *s != NUL) + // The next comment is extracted by xgettext and put in po file for + // translators to read. msg_attr((char_u *) + // Translator: Please replace the name and email address + // with the appropriate text for your translation. _("Messages maintainer: Bram Moolenaar "), HL_ATTR(HLF_T)); } diff --git a/src/version.c b/src/version.c index 5aacf2f11f..eb119ca2a0 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 122, /**/ 121, /**/ From b0eb14f9392a8d95045182c4e520530319ce44c2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 15:29:52 +0200 Subject: [PATCH 06/23] patch 8.1.0123: MS-Windows: colors are wrong after setting 'notgc' Problem: MS-Windows: colors are wrong after setting 'notgc'. Solution: Only call control_console_color_rgb() for the win32 terminal. (Nobuhiro Takasaki, closes #3107) --- src/option.c | 5 ++++- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/option.c b/src/option.c index 1ba8a8c2e4..4fdfe10008 100644 --- a/src/option.c +++ b/src/option.c @@ -8819,10 +8819,13 @@ set_bool_option( # endif highlight_gui_started(); # ifdef FEAT_VTP - control_console_color_rgb(); /* reset t_Co */ if (is_term_win32()) + { + control_console_color_rgb(); set_termname(T_NAME); + init_highlight(TRUE, FALSE); + } # endif } #endif diff --git a/src/version.c b/src/version.c index eb119ca2a0..a2780f4707 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 123, /**/ 122, /**/ From d8b37a53bd29cab78c6997aa75207385213f23e2 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 15:50:28 +0200 Subject: [PATCH 07/23] patch 8.1.0124: has('vcon') returns true even for non-win32 terminal Problem: has('vcon') returns true even for non-win32 terminal. Solution: Check the terminal type. (Nobuhiro Takasaki, closes #3106) --- src/evalfunc.c | 2 +- src/version.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index cec6dabb4a..ce45ad82a5 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6609,7 +6609,7 @@ f_has(typval_T *argvars, typval_T *rettv) #endif #ifdef FEAT_VTP else if (STRICMP(name, "vcon") == 0) - n = has_vtp_working(); + n = is_term_win32() && has_vtp_working(); #endif #ifdef FEAT_NETBEANS_INTG else if (STRICMP(name, "netbeans_enabled") == 0) diff --git a/src/version.c b/src/version.c index a2780f4707..86e24fdc10 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 124, /**/ 123, /**/ From 630afe889a2a02b367ea8eaaa48e66ed81e77ff3 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 19:26:28 +0200 Subject: [PATCH 08/23] patch 8.1.0125: virtual edit replace with multi-byte fails at end of line Problem: Virtual edit replace with multi-byte fails at end of line. (Lukas Werling) Solution: use ins_char() to add the character. (Christian Brabandt, closes #3114) Rename PCHAR() to PBYTE() to avoid mistakes like this. --- src/macros.h | 4 ++-- src/ops.c | 41 +++++++++++++++++++++++--------- src/testdir/test_virtualedit.vim | 16 +++++++++++++ src/version.c | 2 ++ 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/macros.h b/src/macros.h index fcd1a829da..c91b4b6205 100644 --- a/src/macros.h +++ b/src/macros.h @@ -14,9 +14,9 @@ */ /* - * PCHAR(lp, c) - put character 'c' at position 'lp' + * PBYTE(lp, c) - put byte 'c' at position 'lp' */ -#define PCHAR(lp, c) (*(ml_get_buf(curbuf, (lp).lnum, TRUE) + (lp).col) = (c)) +#define PBYTE(lp, c) (*(ml_get_buf(curbuf, (lp).lnum, TRUE) + (lp).col) = (c)) /* * Position comparisons diff --git a/src/ops.c b/src/ops.c index 73f73d2f92..2e08a53291 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2146,6 +2146,25 @@ mb_adjust_opend(oparg_T *oap) #endif #if defined(FEAT_VISUALEXTRA) || defined(PROTO) + +# ifdef FEAT_MBYTE +/* + * Replace the character under the cursor with "c". + * This takes care of multi-byte characters. + */ + static void +replace_character(int c) +{ + int n = State; + + State = REPLACE; + ins_char(c); + State = n; + /* Backup to the replaced character. */ + dec_cursor(); +} + +# endif /* * Replace a whole area with one character. */ @@ -2331,12 +2350,7 @@ op_replace(oparg_T *oap, int c) * with a multi-byte and the other way around. */ if (curwin->w_cursor.lnum == oap->end.lnum) oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n); - n = State; - State = REPLACE; - ins_char(c); - State = n; - /* Backup to the replaced character. */ - dec_cursor(); + replace_character(c); } else #endif @@ -2358,7 +2372,7 @@ op_replace(oparg_T *oap, int c) getvpos(&oap->end, end_vcol); } #endif - PCHAR(curwin->w_cursor, c); + PBYTE(curwin->w_cursor, c); } } #ifdef FEAT_VIRTUALEDIT @@ -2377,9 +2391,14 @@ op_replace(oparg_T *oap, int c) curwin->w_cursor.col -= (virtcols + 1); for (; virtcols >= 0; virtcols--) { - PCHAR(curwin->w_cursor, c); - if (inc(&curwin->w_cursor) == -1) - break; +#ifdef FEAT_MBYTE + if ((*mb_char2len)(c) > 1) + replace_character(c); + else + #endif + PBYTE(curwin->w_cursor, c); + if (inc(&curwin->w_cursor) == -1) + break; } } #endif @@ -2619,7 +2638,7 @@ swapchar(int op_type, pos_T *pos) } else #endif - PCHAR(*pos, nc); + PBYTE(*pos, nc); return TRUE; } return FALSE; diff --git a/src/testdir/test_virtualedit.vim b/src/testdir/test_virtualedit.vim index d49025237b..abe79f6a4a 100644 --- a/src/testdir/test_virtualedit.vim +++ b/src/testdir/test_virtualedit.vim @@ -42,6 +42,22 @@ func Test_paste_end_of_line() set virtualedit= endfunc +func Test_replace_end_of_line() + new + set virtualedit=all + call setline(1, range(20)) + exe "normal! gg2jv10lr-" + call assert_equal(["1", "-----------", "3"], getline(2,4)) + if has('multi_byte') + call setline(1, range(20)) + exe "normal! gg2jv10lr\hh" + call assert_equal(["1", "───────────", "3"], getline(2,4)) + endif + + bwipe! + set virtualedit= +endfunc + func Test_edit_CTRL_G() new set virtualedit=insert diff --git a/src/version.c b/src/version.c index 86e24fdc10..31db840532 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 125, /**/ 124, /**/ From 307ac5c68e9e624ab713136d79f35bb73f780d2d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 28 Jun 2018 22:23:00 +0200 Subject: [PATCH 09/23] patch 8.1.0126: various problems with 'vartabstop' Problem: Various problems with 'vartabstop'. Solution: Fix memory leak. Fix crash. Add a few more tests. (Christian Brabandt, closes #3076) --- src/ex_cmds.c | 2 +- src/option.c | 6 ++++-- src/screen.c | 13 +++++++++---- src/testdir/test_vartabs.vim | 28 ++++++++++++++++++++++------ src/version.c | 2 ++ 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/ex_cmds.c b/src/ex_cmds.c index 3384fe85bf..a30178b641 100644 --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -866,7 +866,6 @@ ex_retab(exarg_T *eap) { set_string_option_direct((char_u *)"vts", -1, new_ts_str, OPT_FREE|OPT_LOCAL, 0); - vim_free(new_ts_str); curbuf->b_p_vts_array = new_vts_array; vim_free(old_vts_ary); } @@ -877,6 +876,7 @@ ex_retab(exarg_T *eap) curbuf->b_p_ts = tabstop_first(new_vts_array); vim_free(new_vts_array); } + vim_free(new_ts_str); } #else curbuf->b_p_ts = new_ts; diff --git a/src/option.c b/src/option.c index 4fdfe10008..50d42ebf7d 100644 --- a/src/option.c +++ b/src/option.c @@ -12870,7 +12870,7 @@ tabstop_start(colnr_T col, int ts, int *vts) tabstop_fromto( colnr_T start_col, colnr_T end_col, - int ts, + int ts_arg, int *vts, int *ntabs, int *nspcs) @@ -12880,12 +12880,14 @@ tabstop_fromto( int padding = 0; int tabcount; int t; + int ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg; if (vts == NULL || vts[0] == 0) { int tabs = 0; - int initspc = ts - (start_col % ts); + int initspc = 0; + initspc = ts - (start_col % ts); if (spaces >= initspc) { spaces -= initspc; diff --git a/src/screen.c b/src/screen.c index c03443fecd..954beef95e 100644 --- a/src/screen.c +++ b/src/screen.c @@ -4753,13 +4753,13 @@ win_line( n_extra = win_lbr_chartabsize(wp, line, p, (colnr_T)vcol, NULL) - 1; if (c == TAB && n_extra + col > wp->w_width) -#ifdef FEAT_VARTABS +# ifdef FEAT_VARTABS n_extra = tabstop_padding(vcol, wp->w_buffer->b_p_ts, - wp->w_buffer->b_p_vts_array) - 1; -#else + wp->w_buffer->b_p_vts_array) - 1; +# else n_extra = (int)wp->w_buffer->b_p_ts - vcol % (int)wp->w_buffer->b_p_ts - 1; - #endif +# endif # ifdef FEAT_MBYTE c_extra = mb_off > 0 ? MB_FILLER_CHAR : ' '; @@ -4902,6 +4902,11 @@ win_line( p_extra_free = p; for (i = 0; i < tab_len; i++) { + if (*p == NUL) + { + tab_len = i; + break; + } #ifdef FEAT_MBYTE mb_char2bytes(lcs_tab2, p); p += mb_char2len(lcs_tab2); diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim index 581ff8b9bb..c43e178309 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -262,21 +262,37 @@ func! Test_vartabs_breakindent() endfunc func! Test_vartabs_linebreak() - if winwidth(0) < 80 + if winwidth(0) < 40 return endif new - 70vnew + 40vnew %d - setl linebreak vartabstop=10,15,20,40 + setl linebreak vartabstop=10,20,30,40 call setline(1, "\tx\tx\tx\tx") - let lines = ScreenLines([1, 2], winwidth(0)) - let expect = [' x x x ', - \ ' x '] + let expect = [' x ', + \ 'x x ', + \ 'x '] + let lines = ScreenLines([1, 3], winwidth(0)) + call s:compare_lines(expect, lines) + setl list listchars=tab:>- + let expect = ['>---------x>------------------ ', + \ 'x>------------------x>------------------', + \ 'x '] + let lines = ScreenLines([1, 3], winwidth(0)) + call s:compare_lines(expect, lines) + setl linebreak vartabstop=40 + let expect = ['>---------------------------------------', + \ 'x>--------------------------------------', + \ 'x>--------------------------------------', + \ 'x>--------------------------------------', + \ 'x '] + let lines = ScreenLines([1, 5], winwidth(0)) call s:compare_lines(expect, lines) " cleanup bw! bw! + set nolist listchars&vim endfunc diff --git a/src/version.c b/src/version.c index 31db840532..4e3770e44e 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 126, /**/ 125, /**/ From 7c365fb190225d98af818daf195dc19921fe01ca Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 29 Jun 2018 20:28:31 +0200 Subject: [PATCH 10/23] patch 8.1.0127: build failure when disabling the session feature Problem: Build failure when disabling the session feature. (Pawel Slowik) Solution: Adjust #ifdef for vim_chdirfile(). --- src/misc2.c | 4 ++-- src/version.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/misc2.c b/src/misc2.c index e5b6781583..4a4908c199 100644 --- a/src/misc2.c +++ b/src/misc2.c @@ -3381,8 +3381,8 @@ same_directory(char_u *f1, char_u *f2) && pathcmp((char *)ffname, (char *)f2, (int)(t1 - ffname)) == 0); } -#if defined(FEAT_SESSION) || defined(MSWIN) || defined(FEAT_GUI_MAC) \ - || defined(FEAT_GUI_GTK) \ +#if defined(FEAT_SESSION) || defined(FEAT_AUTOCHDIR) \ + || defined(MSWIN) || defined(FEAT_GUI_MAC) || defined(FEAT_GUI_GTK) \ || defined(FEAT_SUN_WORKSHOP) || defined(FEAT_NETBEANS_INTG) \ || defined(PROTO) /* diff --git a/src/version.c b/src/version.c index 4e3770e44e..72e85473c4 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 127, /**/ 126, /**/ From 304925e75031751fc87b51e387eb079bf3ae2066 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jun 2018 16:27:02 +0200 Subject: [PATCH 11/23] patch 8.1.0128: building with MinGW does not work out-of-the-box Problem: Building with MinGW does not work out-of-the-box. Solution: Add instructions for MSYS2. Set default WINVER. Add batch files to set $PATH for MSYS2. --- Filelist | 2 + src/INSTALLpc.txt | 144 ++++++++++++++++++++++++++++++++---------- src/Make_cyg_ming.mak | 5 +- src/msys32.bat | 6 ++ src/msys64.bat | 6 ++ 5 files changed, 129 insertions(+), 34 deletions(-) create mode 100755 src/msys32.bat create mode 100755 src/msys64.bat diff --git a/Filelist b/Filelist index f141dc3055..07df2995c5 100644 --- a/Filelist +++ b/Filelist @@ -412,6 +412,8 @@ SRC_DOS = \ src/msvc2008.bat \ src/msvc2010.bat \ src/msvc2015.bat \ + src/msys32.bat \ + src/msys64.bat \ src/dimm.idl \ src/dlldata.c \ src/dosinst.c \ diff --git a/src/INSTALLpc.txt b/src/INSTALLpc.txt index fe1c9b790f..73d13dc90c 100644 --- a/src/INSTALLpc.txt +++ b/src/INSTALLpc.txt @@ -22,23 +22,24 @@ any faster, but you can edit files larger than 2 Gbyte. Contents: 1. Microsoft Visual C++ -2. Using MinGW -3. Cygwin -4. Borland -5. Cross compiling for Win32 from a Linux machine -6. Building with Python support -7. Building with Python3 support -8. Building with Racket or MzScheme support -9. Building with Lua support -10. Building with Perl support -11. Building with Ruby support -12. Building with Tcl support -13. Building with Terminal support -14. Building with DirectX (DirectWrite) support -15. Windows 3.1 -16. MS-DOS +2. Using MSYS2 with MinGW +3. Using MinGW +4. Cygwin +5. Borland +6. Cross compiling for Win32 from a Linux machine +7. Building with Python support +8. Building with Python3 support +9. Building with Racket or MzScheme support +10. Building with Lua support +11. Building with Perl support +12. Building with Ruby support +13. Building with Tcl support +14. Building with Terminal support +15. Building with DirectX (DirectWrite) support +16. Windows 3.1 +17. MS-DOS -17. Installing after building from sources +18. Installing after building from sources The currently recommended way (that means it has been verified to work) is @@ -261,8 +262,87 @@ Instructions for integrating the Platform SDK into VC Express: http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/default.aspx +2. MSYS2 with MinGW +=================== -2. MinGW +2.1. Setup the basic msys2 environment + +Go to the official page of MSYS2: https://www.msys2.org +Download an installer: + +* msys2-x86_64-YYYYMMDD.exe for 64-bit Windows + (Even if you want to build 32-bit Vim) +* msys2-i686-YYYYMMDD.exe for 32-bit Windows + +Execute the installer and follow the instructions to update basic packages. +At the end keep the checkbox checked to run msys2 now. If needed, you can +open the window from the start menu, MSYS2 64 bit / MSYS2 MSYS + +Execute: + $ pacman -Syu + +And restart MSYS2 window (select "MSYS2 MSYS" icon from the Start Menu). +Then execute: + $ pacman -Su + +If pacman complains that `catgets` and `libcatgets` conflict with another +package, select `y` to remove them. + + +2.2. Install additional packages for building Vim + +The following package groups are required for building Vim: + +* base-devel +* mingw-w64-i686-toolchain (for building 32-bit Vim) +* mingw-w64-x86_64-toolchain (for building 64-bit Vim) + +Use the following command to install them: + + $ pacman -S base-devel mingw-w64-i686-toolchain mingw-w64-x86_64-toolchain + +Or you can use the `pacboy` command to avoid long package names: + + $ pacboy -S base-devel: toolchain:m + +(See `pacboy help` for the help.) + + +2.3. Keep the build environment up-to-date + +After you have installed the build environment, you may want to keep it +up-to-date (E.g. always use the latest GCC). +In that case, you just need to execute the command: + $ pacman -Syu + + +# Build Vim + +Select one of the following icon from the Start Menu: + +* MSYS2 MinGW 32-bit (To build 32-bit versions of Vim) +* MSYS2 MinGW 64-bit (To build 64-bit versions of Vim) + +Go to the source directory of Vim, then execute the make command. E.g.: + + make -f Make_ming.mak + make -f Make_ming.mak GUI=no + make -f Make_ming.mak GUI=no DEBUG=yes + +NOTE: you can't execute the vim.exe in the MSYS console, open a normal Windows +console for that. You need to set $PATH to be able to build there, e.g.: + + set PATH=c:\msys64\mingw32\bin;c:\msys64\usr\bin;%PATH% + +This command is in msys32.bat. Or or the 64 bit compiler use msys64.bat: + + set PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;%PATH% + +If you have msys64 in another location you will need to adjust the paths for +that. + + +3. MinGW ======== (written by Ron Aaron: ) @@ -344,7 +424,7 @@ If you want National Language Support, read the file src/po/README_mingw.txt. You need to uncomment lines in Make_ming.mak to have NLS defined. -3. Cygwin +4. Cygwin ========= Use Make_cyg.mak with Cygwin's GCC. See @@ -356,14 +436,14 @@ running on Unix), while with Make_cyg.mak you get a Windows application (like with the other makefiles). -4. Borland +5. Borland =========== Use Make_bc5.mak with Borland C++ 5.x. See http://users.skynet.be/antoine.mechelynck/vim/compile.htm -5. Cross compiling for Win32 from a Linux machine +6. Cross compiling for Win32 from a Linux machine ================================================= [Update of 1) needs to be verified] @@ -383,7 +463,7 @@ your Linux (or other unix) box. To do this, you need to follow a few steps: Now you have created the Windows binary from your Linux box! Have fun... -6. Building with Python support +7. Building with Python support =============================== For building with MSVC 2008 the "Windows Installer" from www.python.org @@ -435,7 +515,7 @@ And if you use msys2 to build python support (as one line): You will end up with a Python-enabled, Win32 version. Enjoy! -7. Building with Python3 support +8. Building with Python3 support ================================ For building with MSVC 2008 the "Windows Installer" from www.python.org @@ -466,7 +546,7 @@ When using msys2 and link with Python3 bundled with msys2 (as one line): (This is for 64-bit builds. For 32-bit builds, replace mingw64 with mingw32.) -8. Building with Racket or MzScheme support +9. Building with Racket or MzScheme support ======================================== 1) Building with Racket support (newest) @@ -556,7 +636,7 @@ After a successful build, these dlls can be freely removed, leaving them in -9. Building with Lua support +10. Building with Lua support ============================ Vim with Lua support can be built with either MSVC or MinGW (or maybe Cygwin). @@ -611,7 +691,7 @@ Or when using Cygwin (as one line) (untested): LUA=/cygdrive/c/projects/lua53 DYNAMIC_LUA=yes LUA_VER=53 -10. Building with Perl support +11. Building with Perl support ============================== Vim with Perl support can be built with either MSVC or MinGW (or Cygwin). @@ -637,7 +717,7 @@ Or when using MinGW (as one line): PERL=C:/Perl DYNAMIC_PERL=yes PERL_VER=522 -11. Building with Ruby support +12. Building with Ruby support ============================== Vim with Ruby support can be built with either MSVC or MinGW (or Cygwin). @@ -745,7 +825,7 @@ Ruby 2.1 or later. (Default is 0x501.) -12. Building with Tcl support +13. Building with Tcl support ============================= Vim with Tcl support can be built with either MSVC or MinGW (or Cygwin). @@ -777,7 +857,7 @@ Or when using MinGW (as one line): TCL=C:/Tcl86 DYNAMIC_TCL=yes TCL_VER=86 TCL_VER_LONG=8.6 -13. Building with Terminal support +14. Building with Terminal support ================================== Vim with Terminal support can be built with either MSVC, MinGW or Cygwin. @@ -793,7 +873,7 @@ Or when using MinGW: mingw32-make -f Make_ming.mak TERMINAL=yes -14. Building with DirectX (DirectWrite) support +15. Building with DirectX (DirectWrite) support =============================================== Vim with DirectX (DirectWrite) support can be built with either MSVC or MinGW. @@ -827,20 +907,20 @@ Just set DIRECTX to yes: mingw32-make -f Make_ming.mak DIRECTX=yes -15. Windows 3.1x +16. Windows 3.1x ================ The Windows 3.1x support was removed in patch 7.4.1364. -16. MS-DOS +17. MS-DOS ========== The MS-DOS support was removed in patch 7.4.1399. Only very old Vim versions work on MS-DOS because of the limited amount of memory available. -17. Installing after building from sources +18. Installing after building from sources ========================================== [provided by Michael Soyka, updated by Ken Takata] diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak index cdec101fbb..16cd71259c 100644 --- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -75,9 +75,10 @@ POSTSCRIPT=no # Set to yes to enable OLE support. OLE=no -# Set the default $(WINVER) to make it work with WinXP. +# Set the default $(WINVER). Use 0x0501 to make it work with WinXP. ifndef WINVER -WINVER = 0x0501 +# WINVER = 0x0501 +WINVER = 0x0600 endif # Set to yes to enable Cscope support. diff --git a/src/msys32.bat b/src/msys32.bat new file mode 100755 index 0000000000..6c9b81dd9f --- /dev/null +++ b/src/msys32.bat @@ -0,0 +1,6 @@ +@echo off +rem To be used on MS-Windows for Msys2 with the 32 bit MinGW compiler. +rem Adjust the "c:\msys64" part to match your installation. +@echo on + +set PATH=c:\msys64\mingw32\bin;c:\msys64\usr\bin;%PATH% diff --git a/src/msys64.bat b/src/msys64.bat new file mode 100755 index 0000000000..dcfbbc973f --- /dev/null +++ b/src/msys64.bat @@ -0,0 +1,6 @@ +@echo off +rem To be used on MS-Windows for Msys2 with the 64 bit MinGW compiler. +rem Adjust the "c:\msys64" part to match your installation. +@echo on + +set PATH=c:\msys64\mingw64\bin;c:\msys64\usr\bin;%PATH% From 668324ef4fd59980dc57b2eefe57eddc57c7b920 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jun 2018 17:09:26 +0200 Subject: [PATCH 12/23] patch 8.1.0129: still some xterm-like terminals get a stray "p" Problem: Still some xterm-like terminals get a stray "p" on startup. Solution: Consider all terminals that reply with a version smaller than 95 as not an xterm. (James McCoy) --- src/term.c | 5 +++++ src/version.c | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/term.c b/src/term.c index 4bb8030cbe..80834ce615 100644 --- a/src/term.c +++ b/src/term.c @@ -4690,6 +4690,11 @@ check_termcode( && STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0) is_not_xterm = TRUE; + // Xterm first responded to this request at patch level + // 95, so assume anything below 95 is not xterm. + if (version < 95) + is_not_xterm = TRUE; + /* Only request the cursor style if t_SH and t_RS are * set. Only supported properly by xterm since version * 279 (otherwise it returns 0x18). diff --git a/src/version.c b/src/version.c index 72e85473c4..f4399cc5c9 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 129, /**/ 127, /**/ From ad6480961080f80a455b2394f27b02935a2ded52 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jun 2018 18:28:03 +0200 Subject: [PATCH 13/23] patch 8.1.0130: ":profdel func" does not work if func was called already Problem: ":profdel func" does not work if func was called already. (Dominique Pelle) Solution: Reset uf_profiling and add a flag to indicate initialization was done. --- src/structs.h | 1 + src/userfunc.c | 52 +++++++++++++++++++++++++++++--------------------- src/version.c | 2 ++ 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/structs.h b/src/structs.h index a2de2441e9..ec109eb893 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1345,6 +1345,7 @@ typedef struct garray_T uf_lines; /* function lines */ #ifdef FEAT_PROFILE int uf_profiling; /* TRUE when func is being profiled */ + int uf_prof_initialized; /* profiling the function as a whole */ int uf_tm_count; /* nr of calls */ proftime_T uf_tm_total; /* time spent in function + children */ diff --git a/src/userfunc.c b/src/userfunc.c index 08112689df..1c17737ac7 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -293,10 +293,6 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate) fp->uf_scoped = NULL; #ifdef FEAT_PROFILE - fp->uf_tml_count = NULL; - fp->uf_tml_total = NULL; - fp->uf_tml_self = NULL; - fp->uf_profiling = FALSE; if (prof_def_func()) func_do_profile(fp); #endif @@ -706,6 +702,7 @@ call_user_func( #ifdef FEAT_PROFILE proftime_T wait_start; proftime_T call_start; + int started_profiling = FALSE; #endif /* If depth of calling is getting too high, don't execute the function */ @@ -921,7 +918,10 @@ call_user_func( if (do_profiling == PROF_YES) { if (!fp->uf_profiling && has_profiling(FALSE, fp->uf_name, NULL)) + { + started_profiling = TRUE; func_do_profile(fp); + } if (fp->uf_profiling || (fc->caller != NULL && fc->caller->func->uf_profiling)) { @@ -965,6 +965,9 @@ call_user_func( profile_add(&fc->caller->func->uf_tm_children, &call_start); profile_add(&fc->caller->func->uf_tml_children, &call_start); } + if (started_profiling) + // make a ":profdel func" stop profiling the function + fp->uf_profiling = FALSE; } #endif @@ -2522,23 +2525,28 @@ func_do_profile(ufunc_T *fp) { int len = fp->uf_lines.ga_len; - if (len == 0) - len = 1; /* avoid getting error for allocating zero bytes */ - fp->uf_tm_count = 0; - profile_zero(&fp->uf_tm_self); - profile_zero(&fp->uf_tm_total); - if (fp->uf_tml_count == NULL) - fp->uf_tml_count = (int *)alloc_clear((unsigned) (sizeof(int) * len)); - if (fp->uf_tml_total == NULL) - fp->uf_tml_total = (proftime_T *)alloc_clear((unsigned) - (sizeof(proftime_T) * len)); - if (fp->uf_tml_self == NULL) - fp->uf_tml_self = (proftime_T *)alloc_clear((unsigned) - (sizeof(proftime_T) * len)); - fp->uf_tml_idx = -1; - if (fp->uf_tml_count == NULL || fp->uf_tml_total == NULL - || fp->uf_tml_self == NULL) - return; /* out of memory */ + if (!fp->uf_prof_initialized) + { + if (len == 0) + len = 1; /* avoid getting error for allocating zero bytes */ + fp->uf_tm_count = 0; + profile_zero(&fp->uf_tm_self); + profile_zero(&fp->uf_tm_total); + if (fp->uf_tml_count == NULL) + fp->uf_tml_count = (int *)alloc_clear( + (unsigned)(sizeof(int) * len)); + if (fp->uf_tml_total == NULL) + fp->uf_tml_total = (proftime_T *)alloc_clear( + (unsigned)(sizeof(proftime_T) * len)); + if (fp->uf_tml_self == NULL) + fp->uf_tml_self = (proftime_T *)alloc_clear( + (unsigned)(sizeof(proftime_T) * len)); + fp->uf_tml_idx = -1; + if (fp->uf_tml_count == NULL || fp->uf_tml_total == NULL + || fp->uf_tml_self == NULL) + return; /* out of memory */ + fp->uf_prof_initialized = TRUE; + } fp->uf_profiling = TRUE; } @@ -2568,7 +2576,7 @@ func_dump_profile(FILE *fd) { --todo; fp = HI2UF(hi); - if (fp->uf_profiling) + if (fp->uf_prof_initialized) { if (sorttab != NULL) sorttab[st_len++] = fp; diff --git a/src/version.c b/src/version.c index f4399cc5c9..bc3d06a321 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 130, /**/ 129, /**/ From 1fbfe7c48cb711f5a6deae535b3ec3bfe7952ce9 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jun 2018 21:18:13 +0200 Subject: [PATCH 14/23] patch 8.1.0131: :profdel is not tested Problem: :profdel is not tested. Solution: Add a test. (Dominique Pelle, closes #3123) --- src/testdir/test_profile.vim | 100 +++++++++++++++++++++++++++++------ src/version.c | 2 + 2 files changed, 87 insertions(+), 15 deletions(-) diff --git a/src/testdir/test_profile.vim b/src/testdir/test_profile.vim index ee617760f8..6c24d31100 100644 --- a/src/testdir/test_profile.vim +++ b/src/testdir/test_profile.vim @@ -5,6 +5,8 @@ endif func Test_profile_func() let lines = [ + \ 'profile start Xprofile_func.log', + \ 'profile func Foo*"', \ "func! Foo1()", \ "endfunc", \ "func! Foo2()", @@ -33,9 +35,7 @@ func Test_profile_func() call writefile(lines, 'Xprofile_func.vim') call system(v:progpath - \ . ' -es -u NONE -U NONE -i NONE --noplugin' - \ . ' -c "profile start Xprofile_func.log"' - \ . ' -c "profile func Foo*"' + \ . ' -es --clean' \ . ' -c "so Xprofile_func.vim"' \ . ' -c "qall!"') call assert_equal(0, v:shell_error) @@ -97,7 +97,7 @@ func Test_profile_file() call writefile(lines, 'Xprofile_file.vim') call system(v:progpath - \ . ' -es -u NONE -U NONE -i NONE --noplugin' + \ . ' -es --clean' \ . ' -c "profile start Xprofile_file.log"' \ . ' -c "profile file Xprofile_file.vim"' \ . ' -c "so Xprofile_file.vim"' @@ -152,17 +152,17 @@ func Test_profile_file_with_cont() let lines = readfile('Xprofile_file.log') call assert_equal(11, len(lines)) - call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0]) - call assert_equal('Sourced 1 time', lines[1]) - call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2]) - call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3]) - call assert_equal('', lines[4]) - call assert_equal('count total (s) self (s)', lines[5]) - call assert_match(' 1 0.\d\+ echo "hello', lines[6]) - call assert_equal(' \ world"', lines[7]) - call assert_match(' 1 0.\d\+ echo "foo ', lines[8]) - call assert_equal(' \bar"', lines[9]) - call assert_equal('', lines[10]) + call assert_match('^SCRIPT .*Xprofile_file.vim$', lines[0]) + call assert_equal('Sourced 1 time', lines[1]) + call assert_match('^Total time:\s\+\d\+\.\d\+$', lines[2]) + call assert_match('^ Self time:\s\+\d\+\.\d\+$', lines[3]) + call assert_equal('', lines[4]) + call assert_equal('count total (s) self (s)', lines[5]) + call assert_match(' 1 0.\d\+ echo "hello', lines[6]) + call assert_equal(' \ world"', lines[7]) + call assert_match(' 1 0.\d\+ echo "foo ', lines[8]) + call assert_equal(' \bar"', lines[9]) + call assert_equal('', lines[10]) call delete('Xprofile_file.vim') call delete('Xprofile_file.log') @@ -222,3 +222,73 @@ func Test_profile_truncate_mbyte() call delete('Xprofile_file.vim') call delete('Xprofile_file.log') endfunc + +func Test_profdel_func() + let lines = [ + \ 'profile start Xprofile_file.log', + \ 'func! Foo1()', + \ 'endfunc', + \ 'func! Foo2()', + \ 'endfunc', + \ 'func! Foo3()', + \ 'endfunc', + \ '', + \ 'profile func Foo1', + \ 'profile func Foo2', + \ 'call Foo1()', + \ 'call Foo2()', + \ '', + \ 'profile func Foo3', + \ 'profdel func Foo2', + \ 'profdel func Foo3', + \ 'call Foo1()', + \ 'call Foo2()', + \ 'call Foo3()' ] + call writefile(lines, 'Xprofile_file.vim') + call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q') + call assert_equal(0, v:shell_error) + + let lines = readfile('Xprofile_file.log') + call assert_equal(24, len(lines)) + + " Check that: + " - Foo1() is called twice (profdel not invoked) + " - Foo2() is called once (profdel invoked after it was called) + " - Foo3() is not called (profdel invoked before it was called) + call assert_equal('FUNCTION Foo1()', lines[0]) + call assert_equal('Called 2 times', lines[1]) + call assert_equal('FUNCTION Foo2()', lines[7]) + call assert_equal('Called 1 time', lines[8]) + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[14]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[19]) + + call delete('Xprofile_file.vim') + call delete('Xprofile_file.log') +endfunc + +func Test_profdel_star() + " Foo() is invoked once before and once after 'profdel *'. + " So profiling should report it only once. + let lines = [ + \ 'profile start Xprofile_file.log', + \ 'func! Foo()', + \ 'endfunc', + \ 'profile func Foo', + \ 'call Foo()', + \ 'profdel *', + \ 'call Foo()' ] + call writefile(lines, 'Xprofile_file.vim') + call system(v:progpath . ' -es --clean -c "so Xprofile_file.vim" -c q') + call assert_equal(0, v:shell_error) + + let lines = readfile('Xprofile_file.log') + call assert_equal(15, len(lines)) + + call assert_equal('FUNCTION Foo()', lines[0]) + call assert_equal('Called 1 time', lines[1]) + call assert_equal('FUNCTIONS SORTED ON TOTAL TIME', lines[7]) + call assert_equal('FUNCTIONS SORTED ON SELF TIME', lines[11]) + + call delete('Xprofile_file.vim') + call delete('Xprofile_file.log') +endfunc diff --git a/src/version.c b/src/version.c index bc3d06a321..0efebc67a6 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 131, /**/ 130, /**/ From 4ff4814b383bc85fbf5d8f62c8022f4379d7a490 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jun 2018 21:50:25 +0200 Subject: [PATCH 15/23] patch 8.1.0132: lua tests are old style Problem: Lua tests are old style. Solution: Convert to new style tests. Improve coverage. (Dominique Pelle, closes #3091) --- src/Makefile | 2 +- src/testdir/Make_all.mak | 1 - src/testdir/Make_amiga.mak | 1 - src/testdir/Make_vms.mms | 11 +- src/testdir/test85.in | 86 ------- src/testdir/test_lua.vim | 490 ++++++++++++++++++++++++++++++++++++- src/version.c | 2 + 7 files changed, 487 insertions(+), 106 deletions(-) delete mode 100644 src/testdir/test85.in diff --git a/src/Makefile b/src/Makefile index e9a15a0cfa..ad9045104c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2119,7 +2119,7 @@ test1 \ test52 test59 \ test64 test69 \ test70 test72 \ - test85 test86 test87 test88 \ + test86 test87 test88 \ test94 test95 test99 test108: cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTESTTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak index 94e527ba2c..45f45d7fd8 100644 --- a/src/testdir/Make_all.mak +++ b/src/testdir/Make_all.mak @@ -36,7 +36,6 @@ SCRIPTS_ALL = \ SCRIPTS_MORE1 = \ test11.out \ test52.out \ - test85.out \ test86.out \ test87.out diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak index d894001325..6cb3ed8cdb 100644 --- a/src/testdir/Make_amiga.mak +++ b/src/testdir/Make_amiga.mak @@ -14,7 +14,6 @@ include Make_all.mak # test10 'errorformat' is different # test11 "cat" doesn't work properly # test52 only for Win32 -# test85 no Lua interface # test86, 87 no Python interface SCRIPTS = $(SCRIPTS_ALL) $(SCRIPTS_MORE4) diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms index f27a6b4e7b..e97ad27a8e 100644 --- a/src/testdir/Make_vms.mms +++ b/src/testdir/Make_vms.mms @@ -93,7 +93,6 @@ SCRIPT = test1.out test3.out \ # # test72: bug - Vim hangs at :rename (while rename works well otherwise) # test78: bug - Vim dies at :recover Xtest -# test85: no Lua interface # test89: bug - findfile() does not work on VMS (just in the current directory) # test102: Just ODS-5 supports space and special chars in the filename. # On ODS-2 tests fail. @@ -119,9 +118,9 @@ SCRIPT_SPELL = test59.out SCRIPT_MZSCH = test70.out .ENDIF -.IFDEF HAVE_ODS5 -SCRIPT_ODS5 = test102.out -.ENDIF +.IFDEF HAVE_ODS5 +SCRIPT_ODS5 = test102.out +.ENDIF .IFDEF HAVE_GZIP SCRIPT_GZIP = test11.out @@ -131,10 +130,6 @@ SCRIPT_GZIP = test11.out SCRIPT_GDIFF = test47.out .ENDIF -.IFDEF HAVE_LUA -SCRIPT_LUA = test85.out -.ENDIF - .IFDEF HAVE_PYTHON SCRIPT_PYTHON = test86.out test87.out .ENDIF diff --git a/src/testdir/test85.in b/src/testdir/test85.in deleted file mode 100644 index 0a13394752..0000000000 --- a/src/testdir/test85.in +++ /dev/null @@ -1,86 +0,0 @@ -Test for Lua interface and luaeval() function - -STARTTEST -:so small.vim -:set belloff=all -:so lua.vim -:set nocompatible viminfo+=nviminfo -:lua l = vim.list():add"item0":add"dictionary with list OK":add"item2" -:lua h = vim.dict(); h.list = l -:call garbagecollect() -/^1 -:" change buffer contents -:lua curbuf = vim.buffer() -:lua curline = vim.eval"line('.')" -:lua curbuf[curline] = "1 changed line 1" -:" scalar test -:let tmp_string = luaeval('"string"') -:let tmp_1000 = luaeval('1000') -:if printf("%s%.0f", tmp_string, tmp_1000) == "string1000" -:let scalar_res = "OK" -:else -:let scalar_res = "FAILED" -:endif -:call append(search("^1"), "scalar test " . scalar_res) -:" dictionary containing a list -:let tmp = luaeval("h").list[1] -:/^2/put =tmp -:" circular list (at the same time test lists containing lists) -:lua l[2] = l -:let l2 = luaeval("h").list -:if l2[2] == l2 -:let res = "OK" -:else -:let res = "FAILED" -:endif -:call setline(search("^3"), "circular test " . res) - -:let l = [] -:lua l = vim.eval("l") -:lua l:add(123) -:lua l:add("abc") -:lua l:add(vim.eval("[1, 2, 3]")) -:lua l:add(vim.eval("{'a':1, 'b':2, 'c':3}")) -:lua l:insert(123) -:lua l:insert("abc") -:lua l:insert(vim.eval("[1, 2, 3]")) -:lua l:insert(vim.eval("{'a':1, 'b':2, 'c':3}")) -:lua l[0] = l[0] -:lua l[1] = l[1] -:lua l[2] = l[2] -:lua l[3] = l[3] -:lua l[0] = 123 -:lua l[1] = "abc" -:lua l[2] = vim.eval("[1, 2, 3]") -:lua l[3] = vim.eval("{'a':1, 'b':2, 'c':3}") -:lua l[3] = nil -:lua l[2] = nil -:lua l[1] = nil -:lua l[0] = nil -:lua l = nil -:$put =string(l) - -:let d = {} -:lua d = vim.eval("d") -:lua d[0] = 123 -:lua d[1] = "abc" -:lua d[2] = vim.eval("[1, 2, 3]") -:lua d[3] = vim.eval("{'a':1, 'b':2, 'c':3}") -:lua d[4] = d[0] -:lua d[5] = d[1] -:lua d[6] = d[2] -:lua d[7] = d[3] -:lua d[3] = nil -:lua d[2] = nil -:lua d[1] = nil -:lua d[0] = nil -:lua d = nil -:$put =string(d) - -:?^1?,$w! test.out -:qa! -ENDTEST - -1 line 1 -2 line 2 -3 line 3 diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 944ad903fe..840466aff8 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -1,22 +1,494 @@ " Tests for Lua. -" TODO: move tests from test85.in here. if !has('lua') finish endif -func Test_luado() - new - call setline(1, ['one', 'two', 'three']) - luado vim.command("%d_") - bwipe! - - " Check switching to another buffer does not trigger ml_get error. +" Check that switching to another buffer does not trigger ml_get error. +func Test_command_new_no_ml_get_error() new let wincount = winnr('$') call setline(1, ['one', 'two', 'three']) luado vim.command("new") call assert_equal(wincount + 1, winnr('$')) - bwipe! + %bwipe! +endfunc + +" Test vim.command() +func Test_command() + new + call setline(1, ['one', 'two', 'three']) + luado vim.command("1,2d_") + call assert_equal(['three'], getline(1, '$')) + bwipe! +endfunc + +" Test vim.eval() +func Test_eval() + " lua.eval with a number + lua v = vim.eval('123') + call assert_equal('number', luaeval('vim.type(v)')) + call assert_equal(123.0, luaeval('v')) + + " lua.eval with a string + lua v = vim.eval('"abc"') + call assert_equal('string', luaeval('vim.type(v)')) + call assert_equal('abc', luaeval('v')) + + " lua.eval with a list + lua v = vim.eval("['a']") + call assert_equal('list', luaeval('vim.type(v)')) + call assert_equal(['a'], luaeval('v')) + + " lua.eval with a dict + lua v = vim.eval("{'a':'b'}") + call assert_equal('dict', luaeval('vim.type(v)')) + call assert_equal({'a':'b'}, luaeval('v')) + + call assert_fails('lua v = vim.eval(nil)', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got nil)") + call assert_fails('lua v = vim.eval(true)', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got boolean)") + call assert_fails('lua v = vim.eval({})', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got table)") + call assert_fails('lua v = vim.eval(print)', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got function)") + call assert_fails('lua v = vim.eval(vim.buffer())', + \ "[string \"vim chunk\"]:1: bad argument #1 to 'eval' (string expected, got userdata)") + + lua v = nil +endfunc + +" Test vim.window() +func Test_window() + e Xfoo2 + new Xfoo1 + + " Window 1 (top window) contains Xfoo1 + " Window 2 (bottom window) contains Xfoo2 + call assert_equal('Xfoo1', luaeval('vim.window(1):buffer().name')) + call assert_equal('Xfoo2', luaeval('vim.window(2):buffer().name')) + + " Window 3 does not exist so vim.window(3) should return nil + call assert_equal('nil', luaeval('tostring(vim.window(3))')) + + %bwipe! +endfunc + +" Test vim.window().height +func Test_window_height() + new + lua vim.window().height = 2 + call assert_equal(2, winheight(0)) + lua vim.window().height = vim.window().height + 1 + call assert_equal(3, winheight(0)) + bwipe! +endfunc + +" Test vim.window().width +func Test_window_width() + vert new + lua vim.window().width = 2 + call assert_equal(2, winwidth(0)) + lua vim.window().width = vim.window().width + 1 + call assert_equal(3, winwidth(0)) + bwipe! +endfunc + +" Test vim.window().line and vim.window.col +func Test_window_line_col() + new + call setline(1, ['line1', 'line2', 'line3']) + lua vim.window().line = 2 + lua vim.window().col = 4 + call assert_equal([0, 2, 4, 0], getpos('.')) + lua vim.window().line = vim.window().line + 1 + lua vim.window().col = vim.window().col - 1 + call assert_equal([0, 3, 3, 0], getpos('.')) + + call assert_fails('lua vim.window().line = 10', + \ '[string "vim chunk"]:1: line out of range') + bwipe! +endfunc + +" Test setting the current window +func Test_window_set_current() + new Xfoo1 + lua w1 = vim.window() + new Xfoo2 + lua w2 = vim.window() + + call assert_equal('Xfoo2', bufname('%')) + lua w1() + call assert_equal('Xfoo1', bufname('%')) + lua w2() + call assert_equal('Xfoo2', bufname('%')) + + lua w1, w2 = nil, nil + %bwipe! +endfunc + +" Test vim.window().buffer +func Test_window_buffer() + new Xfoo1 + lua w1 = vim.window() + lua b1 = w1.buffer() + new Xfoo2 + lua w2 = vim.window() + lua b2 = w2.buffer() + + lua b1() + call assert_equal('Xfoo1', bufname('%')) + lua b2() + call assert_equal('Xfoo2', bufname('%')) + + lua b1, b2 = nil, nil + %bwipe! +endfunc + +" Test vim.window():previous() and vim.window():next() +func Test_window_next_previous() + new Xfoo1 + new Xfoo2 + new Xfoo3 + wincmd j + + call assert_equal('Xfoo2', luaeval('vim.window().buffer().name')) + call assert_equal('Xfoo1', luaeval('vim.window():next():buffer().name')) + call assert_equal('Xfoo3', luaeval('vim.window():previous():buffer().name')) + + %bwipe! +endfunc + +" Test vim.window():isvalid() +func Test_window_isvalid() + new Xfoo + lua w = vim.window() + call assert_true(luaeval('w:isvalid()')) + + " FIXME: how to test the case when isvalid() returns v:false? + " isvalid() gives errors when the window is deleted. Is it a bug? + + lua w = nil + bwipe! +endfunc + +" Test vim.buffer() with and without argument +func Test_buffer() + new Xfoo1 + let bn1 = bufnr('%') + new Xfoo2 + let bn2 = bufnr('%') + + " Test vim.buffer() without argument. + call assert_equal('Xfoo2', luaeval("vim.buffer().name")) + + " Test vim.buffer() with string argument. + call assert_equal('Xfoo1', luaeval("vim.buffer('Xfoo1').name")) + call assert_equal('Xfoo2', luaeval("vim.buffer('Xfoo2').name")) + + " Test vim.buffer() with integer argument. + call assert_equal('Xfoo1', luaeval("vim.buffer(" . bn1 . ").name")) + call assert_equal('Xfoo2', luaeval("vim.buffer(" . bn2 . ").name")) + + lua bn1, bn2 = nil, nil + %bwipe! +endfunc + +" Test vim.buffer().name and vim.buffer().fname +func Test_buffer_name() + new + " FIXME: for an unnamed buffer, I would expect + " vim.buffer().name to give an empty string, but + " it returns 0. Is it a bug? + " so this assert_equal is commented out. + " call assert_equal('', luaeval('vim.buffer().name')) + bwipe! + + new Xfoo + call assert_equal('Xfoo', luaeval('vim.buffer().name')) + call assert_equal(expand('%:p'), luaeval('vim.buffer().fname')) + bwipe! +endfunc + +" Test vim.buffer().number +func Test_buffer_number() + " All numbers in Lua are floating points number (no integers). + call assert_equal(bufnr('%'), float2nr(luaeval('vim.buffer().number'))) +endfunc + +" Test inserting lines in buffer. +func Test_buffer_insert() + new + lua vim.buffer()[1] = '3' + lua vim.buffer():insert('1', 0) + lua vim.buffer():insert('2', 1) + lua vim.buffer():insert('4', 10) + + call assert_equal(['1', '2', '3', '4'], getline(1, '$')) + bwipe! +endfunc + +" Test deleting line in buffer +func Test_buffer_delete() + new + call setline(1, ['1', '2', '3']) + lua vim.buffer()[2] = nil + call assert_equal(['1', '3'], getline(1, '$')) + + call assert_fails('lua vim.buffer()[3] = nil', + \ '[string "vim chunk"]:1: invalid line number') + bwipe! +endfunc + +" Test #vim.buffer() i.e. number of lines in buffer +func Test_buffer_number_lines() + new + call setline(1, ['a', 'b', 'c']) + call assert_equal(3.0, luaeval('#vim.buffer()')) + bwipe! +endfunc + +" Test vim.buffer():next() and vim.buffer():previous() +" Note that these functions get the next or previous buffers +" but do not switch buffer. +func Test_buffer_next_previous() + new Xfoo1 + new Xfoo2 + new Xfoo3 + b Xfoo2 + + lua bn = vim.buffer():next() + lua bp = vim.buffer():previous() + + call assert_equal('Xfoo2', luaeval('vim.buffer().name')) + call assert_equal('Xfoo1', luaeval('bp.name')) + call assert_equal('Xfoo3', luaeval('bn.name')) + + call assert_equal('Xfoo2', bufname('%')) + + lua bn() + call assert_equal('Xfoo3', luaeval('vim.buffer().name')) + call assert_equal('Xfoo3', bufname('%')) + + lua bp() + call assert_equal('Xfoo1', luaeval('vim.buffer().name')) + call assert_equal('Xfoo1', bufname('%')) + + lua bn, bp = nil, nil + %bwipe! +endfunc + +" Test vim.buffer():isvalid() +func Test_buffer_isvalid() + new Xfoo + lua b = vim.buffer() + call assert_true(luaeval('b:isvalid()')) + + " FIXME: how to test the case when isvalid() returns v:false? + " isvalid() gives errors when the buffer is wiped. Is it a bug? + + lua b = nil + bwipe! +endfunc + +func Test_list() + call assert_equal([], luaeval('vim.list()')) + + " Same example as in :help lua-vim. + " FIXME: test is disabled because it does not work. + " See https://github.com/vim/vim/issues/3086 + " lua t = {math.pi, false, say = 'hi'} + " call assert_equal([3.141593, 0], luaeval('vim.list(t)')) + + let l = [] + lua l = vim.eval('l') + lua l:add(123) + lua l:add('abc') + lua l:add(true) + lua l:add(false) + lua l:add(vim.eval("[1, 2, 3]")) + lua l:add(vim.eval("{'a':1, 'b':2, 'c':3}")) + call assert_equal([123.0, 'abc', v:true, v:false, [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}], l) + call assert_equal(6.0, luaeval('#l')) + call assert_match('^list: 0x\x\+$', luaeval('tostring(l)')) + + lua l[0] = 124 + lua l[4] = nil + lua l:insert('first') + lua l:insert('xx', 3) + call assert_equal(['first', 124.0, 'abc', 'xx', v:true, v:false, {'a': 1, 'b': 2, 'c': 3}], l) + + lua l = nil +endfunc + +" Test l() i.e. iterator on list +func Test_list_iter() + lua l = vim.list():add('foo'):add('bar') + lua str = '' + lua for v in l() do str = str .. v end + call assert_equal('foobar', luaeval('str')) + + lua str, v, l = nil, nil, nil +endfunc + +func Test_recursive_list() + lua l = vim.list():add(1):add(2) + lua l = l:add(l) + + call assert_equal(1.0, luaeval('l[0]')) + call assert_equal(2.0, luaeval('l[1]')) + + call assert_equal(1.0, luaeval('l[2][0]')) + call assert_equal(2.0, luaeval('l[2][1]')) + + call assert_equal(1.0, luaeval('l[2][2][0]')) + call assert_equal(2.0, luaeval('l[2][2][1]')) + + call assert_equal('[1.0, 2.0, [...]]', string(luaeval('l'))) + + call assert_match('^list: 0x\x\+$', luaeval('tostring(l)')) + call assert_equal(luaeval('tostring(l)'), luaeval('tostring(l[2])')) + + call assert_equal(luaeval('l'), luaeval('l[2]')) + call assert_equal(luaeval('l'), luaeval('l[2][2]')) + + lua l = nil +endfunc + +func Test_dict() + call assert_equal({}, luaeval('vim.dict()')) + + " Same example as in :help lua-vim. + " FIXME: test is disabled because it does not work. + " See https://github.com/vim/vim/issues/3086 + " lua t = {math.pi, false, say = 'hi'} + " call assert_equal({'say' : 'hi'}, luaeval('vim.dict(t)')) + + let d = {} + lua d = vim.eval('d') + lua d[0] = 123 + lua d[1] = "abc" + lua d[2] = true + lua d[3] = false + lua d[4] = vim.eval("[1, 2, 3]") + lua d[5] = vim.eval("{'a':1, 'b':2, 'c':3}") + call assert_equal({'0':123.0, '1':'abc', '2':v:true, '3':v:false, '4': [1, 2, 3], '5': {'a':1, 'b':2, 'c':3}}, d) + call assert_equal(6.0, luaeval('#d')) + call assert_match('^dict: 0x\x\+$', luaeval('tostring(d)')) + + call assert_equal('abc', luaeval('d[1]')) + + lua d[0] = 124 + lua d[4] = nil + call assert_equal({'0':124.0, '1':'abc', '2':v:true, '3':v:false, '5': {'a':1, 'b':2, 'c':3}}, d) + + lua d = nil +endfunc + +" Test d() i.e. iterator on dictionary +func Test_dict_iter() + let d = {'a': 1, 'b':2} + lua d = vim.eval('d') + lua str = '' + lua for k,v in d() do str = str .. k ..':' .. v .. ',' end + call assert_equal('a:1,b:2,', luaeval('str')) + + lua str, k, v, d = nil, nil, nil, nil +endfunc + +" Test vim.type() +func Test_type() + " The following values are identical to Lua's type function. + call assert_equal('string', luaeval('vim.type("foo")')) + call assert_equal('number', luaeval('vim.type(1)')) + call assert_equal('number', luaeval('vim.type(1.2)')) + call assert_equal('function', luaeval('vim.type(print)')) + call assert_equal('table', luaeval('vim.type({})')) + call assert_equal('boolean', luaeval('vim.type(true)')) + call assert_equal('boolean', luaeval('vim.type(false)')) + call assert_equal('nil', luaeval('vim.type(nil)')) + + " The following values are specific to Vim. + call assert_equal('window', luaeval('vim.type(vim.window())')) + call assert_equal('buffer', luaeval('vim.type(vim.buffer())')) + call assert_equal('list', luaeval('vim.type(vim.list())')) + call assert_equal('dict', luaeval('vim.type(vim.dict())')) +endfunc + +" Test vim.open() +func Test_open() + call assert_notmatch('XOpen', execute('ls')) + + " Open a buffer XOpen1, but do not jump to it. + lua b = vim.open('XOpen1') + call assert_equal('XOpen1', luaeval('b.name')) + call assert_equal('', bufname('%')) + + call assert_match('XOpen1', execute('ls')) + call assert_notequal('XOpen2', bufname('%')) + + " Open a buffer XOpen2 and jump to it. + lua b = vim.open('XOpen2')() + call assert_equal('XOpen2', luaeval('b.name')) + call assert_equal('XOpen2', bufname('%')) + + lua b = nil + %bwipe! +endfunc + +" Test vim.line() +func Test_line() + new + call setline(1, ['first line', 'second line']) + 1 + call assert_equal('first line', luaeval('vim.line()')) + 2 + call assert_equal('second line', luaeval('vim.line()')) + bwipe! +endfunc + +" Test vim.beep() +func Test_beep() + call assert_beeps('lua vim.beep()') +endfunc + +" Test errors in luaeval() +func Test_luaeval_error() + " Compile error + call assert_fails("call luaeval('-nil')", + \ '[string "luaeval"]:1: attempt to perform arithmetic on a nil value') + call assert_fails("call luaeval(']')", + \ "[string \"luaeval\"]:1: unexpected symbol near ']'") +endfunc + +" Test :luafile foo.lua +func Test_luafile() + call delete('Xlua_file') + call writefile(["str = 'hello'", "num = 123.0" ], 'Xlua_file') + call setfperm('Xlua_file', 'r-xr-xr-x') + + luafile Xlua_file + call assert_equal('hello', luaeval('str')) + call assert_equal(123.0, luaeval('num')) + + lua str, num = nil, nil + call delete('Xlua_file') +endfunc + +" Test :luafile % +func Test_luafile_percent() + new Xlua_file + append + str, num = 'foo', 321.0 + print(string.format('str=%s, num=%d', str, num)) +. + w! + luafile % + let msg = split(execute('message'), "\n")[-1] + call assert_equal('str=foo, num=321', msg) + + lua str, num = nil, nil + call delete('Xlua_file') bwipe! endfunc diff --git a/src/version.c b/src/version.c index 0efebc67a6..572b8f184c 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 132, /**/ 131, /**/ From 46577b5e5445c4aaa1e7ae1764373d11dae71663 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 30 Jun 2018 22:40:42 +0200 Subject: [PATCH 16/23] patch 8.1.0133: tagfiles() can have duplicate entries Problem: tagfiles() can have duplicate entries. Solution: Simplify the filename to make checking for duplicates work better. Add a test. (Dominique Pelle, closes #2979) --- src/tag.c | 21 ++++++++++++++++++--- src/testdir/test_taglist.vim | 25 ++++++++++++++++++++++++- src/version.c | 2 ++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/src/tag.c b/src/tag.c index 92ed2a7c4c..b23cb5aabb 100644 --- a/src/tag.c +++ b/src/tag.c @@ -2595,7 +2595,6 @@ findtag_end: } static garray_T tag_fnames = GA_EMPTY; -static void found_tagfile_cb(char_u *fname, void *cookie); /* * Callback function for finding all "tags" and "tags-??" files in @@ -2605,8 +2604,15 @@ static void found_tagfile_cb(char_u *fname, void *cookie); found_tagfile_cb(char_u *fname, void *cookie UNUSED) { if (ga_grow(&tag_fnames, 1) == OK) - ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = - vim_strsave(fname); + { + char_u *tag_fname = vim_strsave(fname); + +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(tag_fname); +#endif + simplify_filename(tag_fname); + ((char_u **)(tag_fnames.ga_data))[tag_fnames.ga_len++] = tag_fname; + } } #if defined(EXITFREE) || defined(PROTO) @@ -2638,6 +2644,7 @@ get_tagfname( { char_u *fname = NULL; char_u *r_ptr; + int i; if (first) vim_memset(tnp, 0, sizeof(tagname_T)); @@ -2679,6 +2686,14 @@ get_tagfname( ++tnp->tn_hf_idx; STRCPY(buf, p_hf); STRCPY(gettail(buf), "tags"); +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(buf); +#endif + simplify_filename(buf); + + for (i = 0; i < tag_fnames.ga_len; ++i) + if (STRCMP(buf, ((char_u **)(tag_fnames.ga_data))[i]) == 0) + return FAIL; // avoid duplicate file names } else vim_strncpy(buf, ((char_u **)(tag_fnames.ga_data))[ diff --git a/src/testdir/test_taglist.vim b/src/testdir/test_taglist.vim index 3ad2025915..0a9350adc7 100644 --- a/src/testdir/test_taglist.vim +++ b/src/testdir/test_taglist.vim @@ -1,4 +1,4 @@ -" test 'taglist' function and :tags command +" test taglist(), tagfiles() functions and :tags command func Test_taglist() call writefile([ @@ -61,3 +61,26 @@ func Test_tags_too_long() call assert_fails('tag ' . repeat('x', 1020), 'E426') tags endfunc + +func Test_tagfiles() + call assert_equal([], tagfiles()) + + call writefile(["FFoo\tXfoo\t1"], 'Xtags1') + call writefile(["FBar\tXbar\t1"], 'Xtags2') + set tags=Xtags1,Xtags2 + call assert_equal(['Xtags1', 'Xtags2'], tagfiles()) + + help + let tf = tagfiles() + call assert_equal(1, len(tf)) + call assert_equal(fnamemodify(expand('$VIMRUNTIME/doc/tags'), ':p:gs?\\?/?'), + \ fnamemodify(tf[0], ':p:gs?\\?/?')) + helpclose + call assert_equal(['Xtags1', 'Xtags2'], tagfiles()) + set tags& + call assert_equal([], tagfiles()) + + call delete('Xtags1') + call delete('Xtags2') + bd +endfunc diff --git a/src/version.c b/src/version.c index 572b8f184c..c724159d1b 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 133, /**/ 132, /**/ From ffd112edc6a8f72b66c06207bff4431f6aec7b6f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Jul 2018 14:22:31 +0200 Subject: [PATCH 17/23] Fix missing patch number. --- src/version.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/version.c b/src/version.c index c724159d1b..2bc0eab40e 100644 --- a/src/version.c +++ b/src/version.c @@ -799,6 +799,8 @@ static int included_patches[] = 130, /**/ 129, +/**/ + 128, /**/ 127, /**/ From ca06da92432a57e5dcf3e0eebd322fae80941a6b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Jul 2018 15:12:05 +0200 Subject: [PATCH 18/23] patch 8.1.0134: Lua interface does not support funcref Problem: Lua interface does not support funcref. Solution: Add funcref support. (Luis Carvalho) --- src/if_lua.c | 265 +++++++++++++++++++++++++++++++++++---- src/testdir/test_lua.vim | 24 ++++ src/version.c | 2 + 3 files changed, 264 insertions(+), 27 deletions(-) diff --git a/src/if_lua.c b/src/if_lua.c index bc7029389e..df0ef34545 100644 --- a/src/if_lua.c +++ b/src/if_lua.c @@ -28,10 +28,16 @@ typedef buf_T *luaV_Buffer; typedef win_T *luaV_Window; typedef dict_T *luaV_Dict; typedef list_T *luaV_List; +typedef struct { + typval_T tv; // funcref + typval_T args; + dict_T *self; // selfdict +} luaV_Funcref; typedef void (*msgfunc_T)(char_u *); static const char LUAVIM_DICT[] = "dict"; static const char LUAVIM_LIST[] = "list"; +static const char LUAVIM_FUNCREF[] = "funcref"; static const char LUAVIM_BUFFER[] = "buffer"; static const char LUAVIM_WINDOW[] = "window"; static const char LUAVIM_FREE[] = "luaV_free"; @@ -55,9 +61,15 @@ static const char LUAVIM_SETREF[] = "luaV_setref"; if (sandbox) luaL_error((L), "not allowed in sandbox") #define luaV_msg(L) luaV_msgfunc((L), (msgfunc_T) msg) #define luaV_emsg(L) luaV_msgfunc((L), (msgfunc_T) emsg) +#define luaV_checktypval(L, a, v, msg) \ + do { \ + if (luaV_totypval(L, a, v) == FAIL) \ + luaL_error(L, msg ": cannot convert value"); \ + } while (0) -static luaV_List *luaV_pushlist (lua_State *L, list_T *lis); -static luaV_Dict *luaV_pushdict (lua_State *L, dict_T *dic); +static luaV_List *luaV_pushlist(lua_State *L, list_T *lis); +static luaV_Dict *luaV_pushdict(lua_State *L, dict_T *dic); +static luaV_Funcref *luaV_pushfuncref(lua_State *L, typval_T *tv); #if LUA_VERSION_NUM <= 501 #define luaV_openlib(L, l, n) luaL_openlib(L, NULL, l, n) @@ -506,16 +518,25 @@ luaV_pushtypval(lua_State *L, typval_T *tv) else lua_pushnil(L); break; + case VAR_FUNC: + luaV_pushfuncref(L, tv); + break; default: lua_pushnil(L); } } -/* converts lua value at 'pos' to typval 'tv' */ - static void -luaV_totypval (lua_State *L, int pos, typval_T *tv) +/* + * Converts lua value at 'pos' to typval 'tv'. + * Returns OK or FAIL. + */ + static int +luaV_totypval(lua_State *L, int pos, typval_T *tv) { - switch(lua_type(L, pos)) { + int status = OK; + + switch (lua_type(L, pos)) + { case LUA_TBOOLEAN: tv->v_type = VAR_SPECIAL; tv->vval.v_number = (varnumber_T) lua_toboolean(L, pos); @@ -533,8 +554,10 @@ luaV_totypval (lua_State *L, int pos, typval_T *tv) tv->vval.v_number = (varnumber_T) lua_tointeger(L, pos); #endif break; - case LUA_TUSERDATA: { + case LUA_TUSERDATA: + { void *p = lua_touserdata(L, pos); + if (lua_getmetatable(L, pos)) /* has metatable? */ { /* check list */ @@ -545,7 +568,7 @@ luaV_totypval (lua_State *L, int pos, typval_T *tv) tv->vval.v_list = *((luaV_List *) p); ++tv->vval.v_list->lv_refcount; lua_pop(L, 2); /* MTs */ - return; + break; } /* check dict */ luaV_getfield(L, LUAVIM_DICT); @@ -555,16 +578,27 @@ luaV_totypval (lua_State *L, int pos, typval_T *tv) tv->vval.v_dict = *((luaV_Dict *) p); ++tv->vval.v_dict->dv_refcount; lua_pop(L, 3); /* MTs */ - return; + break; } - lua_pop(L, 3); /* MTs */ + /* check funcref */ + luaV_getfield(L, LUAVIM_FUNCREF); + if (lua_rawequal(L, -1, -4)) + { + luaV_Funcref *f = (luaV_Funcref *) p; + copy_tv(&f->tv, tv); + lua_pop(L, 4); /* MTs */ + break; + } + lua_pop(L, 4); /* MTs */ } - break; } + /* FALLTHROUGH */ default: tv->v_type = VAR_NUMBER; tv->vval.v_number = 0; + status = FAIL; } + return status; } /* similar to luaL_addlstring, but replaces \0 with \n if toline and @@ -646,7 +680,7 @@ luaV_msgfunc(lua_State *L, msgfunc_T mf) #define luaV_pushtype(typ,tname,luatyp) \ static luatyp * \ - luaV_push##tname (lua_State *L, typ *obj) \ + luaV_push##tname(lua_State *L, typ *obj) \ { \ luatyp *o = NULL; \ if (obj == NULL) \ @@ -766,7 +800,7 @@ luaV_list_newindex (lua_State *L) else { typval_T v; - luaV_totypval(L, 3, &v); + luaV_checktypval(L, 3, &v, "setting list item"); clear_tv(&li->li_tv); copy_tv(&v, &li->li_tv); clear_tv(&v); @@ -783,11 +817,11 @@ luaV_list_add (lua_State *L) if (l->lv_lock) luaL_error(L, "list is locked"); lua_settop(L, 2); - luaV_totypval(L, 2, &v); + luaV_checktypval(L, 2, &v, "adding list item"); if (list_append_tv(l, &v) == FAIL) { clear_tv(&v); - luaL_error(L, "Failed to add item to list"); + luaL_error(L, "failed to add item to list"); } clear_tv(&v); lua_settop(L, 1); @@ -811,11 +845,11 @@ luaV_list_insert (lua_State *L) luaL_error(L, "invalid position"); } lua_settop(L, 2); - luaV_totypval(L, 2, &v); + luaV_checktypval(L, 2, &v, "inserting list item"); if (list_insert_tv(l, &v, li) == FAIL) { clear_tv(&v); - luaL_error(L, "Failed to add item to list"); + luaL_error(L, "failed to add item to list"); } clear_tv(&v); lua_settop(L, 1); @@ -894,26 +928,43 @@ luaV_dict_call (lua_State *L) } static int -luaV_dict_index (lua_State *L) +luaV_dict_index(lua_State *L) { dict_T *d = luaV_unbox(L, luaV_Dict, 1); char_u *key = (char_u *) luaL_checkstring(L, 2); dictitem_T *di = dict_find(d, key, -1); + if (di == NULL) lua_pushnil(L); else + { luaV_pushtypval(L, &di->di_tv); + if (di->di_tv.v_type == VAR_FUNC) /* funcref? */ + { + luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, -1); + f->self = d; /* keep "self" reference */ + d->dv_refcount++; + } + } return 1; } static int -luaV_dict_newindex (lua_State *L) +luaV_dict_newindex(lua_State *L) { dict_T *d = luaV_unbox(L, luaV_Dict, 1); char_u *key = (char_u *) luaL_checkstring(L, 2); dictitem_T *di; + typval_T v; if (d->dv_lock) luaL_error(L, "dict is locked"); + if (key != NULL && *key == NUL) + luaL_error(L, "empty key"); + if (!lua_isnil(L, 3)) { /* read value? */ + luaV_checktypval(L, 3, &v, "setting dict item"); + if (d->dv_scope == VAR_DEF_SCOPE && v.v_type == VAR_FUNC) + luaL_error(L, "cannot assign funcref to builtin scope"); + } di = dict_find(d, key, -1); if (di == NULL) /* non-existing key? */ { @@ -934,9 +985,8 @@ luaV_dict_newindex (lua_State *L) hash_remove(&d->dv_hashtab, hi); dictitem_free(di); } - else { - typval_T v; - luaV_totypval(L, 3, &v); + else + { copy_tv(&v, &di->di_tv); clear_tv(&v); } @@ -953,6 +1003,92 @@ static const luaL_Reg luaV_Dict_mt[] = { }; +/* ======= Funcref type ======= */ + + static luaV_Funcref * +luaV_newfuncref(lua_State *L, char_u *name) +{ + luaV_Funcref *f = (luaV_Funcref *)lua_newuserdata(L, sizeof(luaV_Funcref)); + + if (name != NULL) + { + func_ref(name); /* as in copy_tv */ + f->tv.vval.v_string = vim_strsave(name); + } + f->tv.v_type = VAR_FUNC; + f->args.v_type = VAR_LIST; + f->self = NULL; + luaV_getfield(L, LUAVIM_FUNCREF); + lua_setmetatable(L, -2); + return f; +} + + static luaV_Funcref * +luaV_pushfuncref(lua_State *L, typval_T *tv) +{ + luaV_Funcref *f = luaV_newfuncref(L, NULL); + copy_tv(tv, &f->tv); + clear_tv(tv); + return f; +} + + +luaV_type_tostring(funcref, LUAVIM_FUNCREF) + + static int +luaV_funcref_gc(lua_State *L) +{ + luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1); + + func_unref(f->tv.vval.v_string); + vim_free(f->tv.vval.v_string); + dict_unref(f->self); + return 0; +} + +/* equivalent to string(funcref) */ + static int +luaV_funcref_len(lua_State *L) +{ + luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1); + + lua_pushstring(L, (const char *) f->tv.vval.v_string); + return 1; +} + + static int +luaV_funcref_call(lua_State *L) +{ + luaV_Funcref *f = (luaV_Funcref *) lua_touserdata(L, 1); + int i, n = lua_gettop(L) - 1; /* #args */ + int status; + typval_T v, rettv; + + f->args.vval.v_list = list_alloc(); + rettv.v_type = VAR_UNKNOWN; /* as in clear_tv */ + for (i = 0; i < n; i++) { + luaV_checktypval(L, i + 2, &v, "calling funcref"); + list_append_tv(f->args.vval.v_list, &v); + } + status = func_call(f->tv.vval.v_string, &f->args, NULL, f->self, &rettv); + if (status == OK) + luaV_pushtypval(L, &rettv); + clear_tv(&f->args); + clear_tv(&rettv); + if (status != OK) + luaL_error(L, "cannot call funcref"); + return 1; +} + +static const luaL_Reg luaV_Funcref_mt[] = { + {"__tostring", luaV_funcref_tostring}, + {"__gc", luaV_funcref_gc}, + {"__len", luaV_funcref_len}, + {"__call", luaV_funcref_call}, + {NULL, NULL} +}; + + /* ======= Buffer type ======= */ luaV_newtype(buf_T, buffer, luaV_Buffer, LUAVIM_BUFFER) @@ -1033,7 +1169,8 @@ luaV_buffer_newindex(lua_State *L) curbuf = buf; luaL_error(L, "cannot delete line"); } - else { + else + { deleted_lines_mark(n, 1L); if (b == curwin->w_buffer) /* fix cursor in current window? */ { @@ -1371,22 +1508,84 @@ luaV_line(lua_State *L) static int luaV_list(lua_State *L) { - list_T *l = list_alloc(); + list_T *l; + int initarg = !lua_isnoneornil(L, 1); + + if (initarg && lua_type(L, 1) != LUA_TTABLE) + luaL_error(L, "table expected, got %s", luaL_typename(L, 1)); + l = list_alloc(); if (l == NULL) lua_pushnil(L); else + { luaV_newlist(L, l); + if (initarg) { /* traverse table to init dict */ + int notnil, i = 0; + typval_T v; + do { + lua_rawgeti(L, 1, ++i); + notnil = !lua_isnil(L, -1); + if (notnil) { + luaV_checktypval(L, -1, &v, "vim.list"); + list_append_tv(l, &v); + } + lua_pop(L, 1); /* value */ + } while (notnil); + } + } return 1; } static int luaV_dict(lua_State *L) { - dict_T *d = dict_alloc(); + dict_T *d; + int initarg = !lua_isnoneornil(L, 1); + + if (initarg && lua_type(L, 1) != LUA_TTABLE) + luaL_error(L, "table expected, got %s", luaL_typename(L, 1)); + d = dict_alloc(); if (d == NULL) lua_pushnil(L); else + { luaV_newdict(L, d); + if (initarg) /* traverse table to init dict */ + { + lua_pushnil(L); + while (lua_next(L, 1)) + { + char_u *key; + dictitem_T *di; + typval_T v; + lua_pushvalue(L, -2); /* dup key in case it's a number */ + key = (char_u *) lua_tostring(L, -1); + if (key != NULL && *key == NUL) + luaL_error(L, "table has empty key"); + luaV_checktypval(L, -2, &v, "vim.dict"); /* value */ + di = dictitem_alloc(key); + if (di == NULL || dict_add(d, di) == FAIL) { + vim_free(di); + lua_pushnil(L); + return 1; + } + copy_tv(&v, &di->di_tv); + clear_tv(&v); + lua_pop(L, 2); /* key copy and value */ + } + } + } + return 1; +} + + static int +luaV_funcref(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + /* note: not checking if function exists (needs function_exists) */ + if (name == NULL || *name == NUL || VIM_ISDIGIT(*name)) + luaL_error(L, "invalid function name: %s", name); + luaV_newfuncref(L, (char_u *) name); return 1; } @@ -1402,7 +1601,8 @@ luaV_buffer(lua_State *L) FOR_ALL_BUFFERS(buf) if (buf->b_fnum == n) break; } - else { /* by name */ + else // by name + { size_t l; const char *s = lua_tolstring(L, 1, &l); FOR_ALL_BUFFERS(buf) @@ -1472,6 +1672,12 @@ luaV_type(lua_State *L) lua_pushstring(L, "dict"); return 1; } + luaV_getfield(L, LUAVIM_FUNCREF); + if (lua_rawequal(L, -1, 2)) + { + lua_pushstring(L, "funcref"); + return 1; + } luaV_getfield(L, LUAVIM_BUFFER); if (lua_rawequal(L, -1, 2)) { @@ -1497,6 +1703,7 @@ static const luaL_Reg luaV_module[] = { {"line", luaV_line}, {"list", luaV_list}, {"dict", luaV_dict}, + {"funcref", luaV_funcref}, {"buffer", luaV_buffer}, {"window", luaV_window}, {"open", luaV_open}, @@ -1537,7 +1744,8 @@ luaV_luaeval (lua_State *L) luaV_emsg(L); return 0; } - luaV_totypval(L, -1, rettv); + if (luaV_totypval(L, -1, rettv) == FAIL) + EMSG("luaeval: cannot convert value"); return 0; } @@ -1612,6 +1820,9 @@ luaopen_vim(lua_State *L) luaV_newmetatable(L, LUAVIM_DICT); lua_pushvalue(L, 1); luaV_openlib(L, luaV_Dict_mt, 1); + luaV_newmetatable(L, LUAVIM_FUNCREF); + lua_pushvalue(L, 1); + luaV_openlib(L, luaV_Funcref_mt, 1); luaV_newmetatable(L, LUAVIM_BUFFER); lua_pushvalue(L, 1); /* cache table */ luaV_openlib(L, luaV_Buffer_mt, 1); diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 840466aff8..30ce48e2eb 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -397,6 +397,29 @@ func Test_dict_iter() lua str, k, v, d = nil, nil, nil, nil endfunc +func Test_funcref() + function I(x) + return a:x + endfunction + let R = function('I') + lua i1 = vim.funcref"I" + lua i2 = vim.eval"R" + lua msg = "funcref|test|" .. (#i2(i1) == #i1(i2) and "OK" or "FAIL") + lua msg = vim.funcref"tr"(msg, "|", " ") + call assert_equal("funcref test OK", luaeval('msg')) + + " dict funcref + function Mylen() dict + return len(self.data) + endfunction + let l = [0, 1, 2, 3] + let mydict = {'data': l} + lua d = vim.eval"mydict" + lua d.len = vim.funcref"Mylen" -- assign d as 'self' + lua res = (d.len() == vim.funcref"len"(vim.eval"l")) and "OK" or "FAIL" + call assert_equal("OK", luaeval('res')) +endfunc + " Test vim.type() func Test_type() " The following values are identical to Lua's type function. @@ -414,6 +437,7 @@ func Test_type() call assert_equal('buffer', luaeval('vim.type(vim.buffer())')) call assert_equal('list', luaeval('vim.type(vim.list())')) call assert_equal('dict', luaeval('vim.type(vim.dict())')) + call assert_equal('funcref', luaeval('vim.type(vim.funcref("Test_type"))')) endfunc " Test vim.open() diff --git a/src/version.c b/src/version.c index 2bc0eab40e..94a17018e3 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 134, /**/ 133, /**/ From e0429681aed5448d1c3b8399d152a2b1a05ea6d7 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Jul 2018 16:44:03 +0200 Subject: [PATCH 19/23] patch 8.1.0135: undo message delays screen update for CTRL-O u Problem: Undo message delays screen update for CTRL-O u. Solution: Add smsg_attr_keep(). (closes #3125) --- src/message.c | 14 ++++++++++++++ src/proto.h | 6 ++++++ src/undo.c | 2 +- src/version.c | 2 ++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/message.c b/src/message.c index e46c514010..d5727b1352 100644 --- a/src/message.c +++ b/src/message.c @@ -399,6 +399,20 @@ smsg_attr(int attr, char_u *s, ...) return msg_attr(IObuff, attr); } + int +# ifdef __BORLANDC__ +_RTLENTRYF +# endif +smsg_attr_keep(int attr, char_u *s, ...) +{ + va_list arglist; + + va_start(arglist, s); + vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist); + va_end(arglist); + return msg_attr_keep(IObuff, attr, TRUE); +} + #endif /* diff --git a/src/proto.h b/src/proto.h index 655b72cac5..8570af947b 100644 --- a/src/proto.h +++ b/src/proto.h @@ -115,6 +115,12 @@ _RTLENTRYF # endif smsg_attr(int, char_u *, ...); +int +# ifdef __BORLANDC__ +_RTLENTRYF +# endif +smsg_attr_keep(int, char_u *, ...); + int # ifdef __BORLANDC__ _RTLENTRYF diff --git a/src/undo.c b/src/undo.c index 117321ea62..be4e22ed69 100644 --- a/src/undo.c +++ b/src/undo.c @@ -2968,7 +2968,7 @@ u_undo_end( } #endif - smsg((char_u *)_("%ld %s; %s #%ld %s"), + smsg_attr_keep(0, (char_u *)_("%ld %s; %s #%ld %s"), u_oldcount < 0 ? -u_oldcount : u_oldcount, _(msgstr), did_undo ? _("before") : _("after"), diff --git a/src/version.c b/src/version.c index 94a17018e3..2d0246118f 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 135, /**/ 134, /**/ From 2f362bf7f9acc9ec87799d1e41bf0ae7712d1f7a Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Jul 2018 19:49:27 +0200 Subject: [PATCH 20/23] patch 8.1.0136: Lua tests don't cover new features Problem: Lua tests don't cover new features. Solution: Add more tests. (Dominique Pelle, closes #3130) --- runtime/doc/if_lua.txt | 7 ++-- src/testdir/test_lua.vim | 82 ++++++++++++++++++++++++++++++---------- src/version.c | 2 + 3 files changed, 67 insertions(+), 24 deletions(-) diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt index 51e332df71..5984d5b69f 100644 --- a/runtime/doc/if_lua.txt +++ b/runtime/doc/if_lua.txt @@ -127,7 +127,7 @@ Vim evaluation and command execution, and others. rules. Example: > :lua t = {math.pi, false, say = 'hi'} :echo luaeval('vim.list(t)') - :" [3.141593, 0], 'say' is ignored + :" [3.141593, v:false], 'say' is ignored < vim.dict([arg]) Returns an empty dictionary or, if "arg" is a Lua table, returns a dict d such that d[k] = @@ -141,8 +141,7 @@ Vim evaluation and command execution, and others. :" {'say': 'hi'}, numeric keys ignored < vim.funcref({name}) Returns a Funcref to function {name} (see - |Funcref|). It is equivalent to Vim's - "function". NOT IMPLEMENTED YET + |Funcref|). It is equivalent to Vim's function(). vim.buffer([arg]) If "arg" is a number, returns buffer with number "arg" in the buffer list or, if "arg" @@ -166,7 +165,7 @@ Vim evaluation and command execution, and others. or window, respectively. Examples: > :lua l = vim.list() :lua print(type(l), vim.type(l)) - :" userdata list + :" list < vim.command({cmd}) Executes the vim (ex-mode) command {cmd}. Examples: > diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index 30ce48e2eb..acd5b17558 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -124,7 +124,7 @@ func Test_window_set_current() lua w2() call assert_equal('Xfoo2', bufname('%')) - lua w1, w2 = nil, nil + lua w1, w2 = nil %bwipe! endfunc @@ -142,7 +142,7 @@ func Test_window_buffer() lua b2() call assert_equal('Xfoo2', bufname('%')) - lua b1, b2 = nil, nil + lua b1, b2, w1, w2 = nil %bwipe! endfunc @@ -191,7 +191,7 @@ func Test_buffer() call assert_equal('Xfoo1', luaeval("vim.buffer(" . bn1 . ").name")) call assert_equal('Xfoo2', luaeval("vim.buffer(" . bn2 . ").name")) - lua bn1, bn2 = nil, nil + lua bn1, bn2 = nil %bwipe! endfunc @@ -275,7 +275,7 @@ func Test_buffer_next_previous() call assert_equal('Xfoo1', luaeval('vim.buffer().name')) call assert_equal('Xfoo1', bufname('%')) - lua bn, bp = nil, nil + lua bn, bp = nil %bwipe! endfunc @@ -295,12 +295,6 @@ endfunc func Test_list() call assert_equal([], luaeval('vim.list()')) - " Same example as in :help lua-vim. - " FIXME: test is disabled because it does not work. - " See https://github.com/vim/vim/issues/3086 - " lua t = {math.pi, false, say = 'hi'} - " call assert_equal([3.141593, 0], luaeval('vim.list(t)')) - let l = [] lua l = vim.eval('l') lua l:add(123) @@ -319,9 +313,26 @@ func Test_list() lua l:insert('xx', 3) call assert_equal(['first', 124.0, 'abc', 'xx', v:true, v:false, {'a': 1, 'b': 2, 'c': 3}], l) + lockvar 1 l + call assert_fails('lua l:add("x")', '[string "vim chunk"]:1: list is locked') + lua l = nil endfunc +func Test_list_table() + " See :help lua-vim + " Non-numeric keys should not be used to initialize the list + " so say = 'hi' should be ignored. + lua t = {3.14, 'hello', false, true, say = 'hi'} + call assert_equal([3.14, 'hello', v:false, v:true], luaeval('vim.list(t)')) + lua t = nil + + call assert_fails('lua vim.list(1)', '[string "vim chunk"]:1: table expected, got number') + call assert_fails('lua vim.list("x")', '[string "vim chunk"]:1: table expected, got string') + call assert_fails('lua vim.list(print)', '[string "vim chunk"]:1: table expected, got function') + call assert_fails('lua vim.list(true)', '[string "vim chunk"]:1: table expected, got boolean') +endfunc + " Test l() i.e. iterator on list func Test_list_iter() lua l = vim.list():add('foo'):add('bar') @@ -329,7 +340,7 @@ func Test_list_iter() lua for v in l() do str = str .. v end call assert_equal('foobar', luaeval('str')) - lua str, v, l = nil, nil, nil + lua str, l = nil endfunc func Test_recursive_list() @@ -359,12 +370,6 @@ endfunc func Test_dict() call assert_equal({}, luaeval('vim.dict()')) - " Same example as in :help lua-vim. - " FIXME: test is disabled because it does not work. - " See https://github.com/vim/vim/issues/3086 - " lua t = {math.pi, false, say = 'hi'} - " call assert_equal({'say' : 'hi'}, luaeval('vim.dict(t)')) - let d = {} lua d = vim.eval('d') lua d[0] = 123 @@ -383,9 +388,32 @@ func Test_dict() lua d[4] = nil call assert_equal({'0':124.0, '1':'abc', '2':v:true, '3':v:false, '5': {'a':1, 'b':2, 'c':3}}, d) + lockvar 1 d + call assert_fails('lua d[6] = 1', '[string "vim chunk"]:1: dict is locked') + lua d = nil endfunc +func Test_dict_table() + lua t = {key1 = 'x', key2 = 3.14, key3 = true, key4 = false} + call assert_equal({'key1': 'x', 'key2': 3.14, 'key3': v:true, 'key4': v:false}, + \ luaeval('vim.dict(t)')) + + " Same example as in :help lua-vim. + lua t = {math.pi, false, say = 'hi'} + " FIXME: commented out as it currently does not work as documented: + " Expected {'say': 'hi'} + " but got {'1': 3.141593, '2': v:false, 'say': 'hi'} + " Is the documentation or the code wrong? + "call assert_equal({'say' : 'hi'}, luaeval('vim.dict(t)')) + lua t = nil + + call assert_fails('lua vim.dict(1)', '[string "vim chunk"]:1: table expected, got number') + call assert_fails('lua vim.dict("x")', '[string "vim chunk"]:1: table expected, got string') + call assert_fails('lua vim.dict(print)', '[string "vim chunk"]:1: table expected, got function') + call assert_fails('lua vim.dict(true)', '[string "vim chunk"]:1: table expected, got boolean') +endfunc + " Test d() i.e. iterator on dictionary func Test_dict_iter() let d = {'a': 1, 'b':2} @@ -394,7 +422,7 @@ func Test_dict_iter() lua for k,v in d() do str = str .. k ..':' .. v .. ',' end call assert_equal('a:1,b:2,', luaeval('str')) - lua str, k, v, d = nil, nil, nil, nil + lua str, d = nil endfunc func Test_funcref() @@ -418,6 +446,8 @@ func Test_funcref() lua d.len = vim.funcref"Mylen" -- assign d as 'self' lua res = (d.len() == vim.funcref"len"(vim.eval"l")) and "OK" or "FAIL" call assert_equal("OK", luaeval('res')) + + lua i1, i2, msg, d, res = nil endfunc " Test vim.type() @@ -496,7 +526,7 @@ func Test_luafile() call assert_equal('hello', luaeval('str')) call assert_equal(123.0, luaeval('num')) - lua str, num = nil, nil + lua str, num = nil call delete('Xlua_file') endfunc @@ -512,7 +542,19 @@ func Test_luafile_percent() let msg = split(execute('message'), "\n")[-1] call assert_equal('str=foo, num=321', msg) - lua str, num = nil, nil + lua str, num = nil + call delete('Xlua_file') + bwipe! +endfunc + +" Test :luafile with syntax error +func Test_luafile_error() + new Xlua_file + call writefile(['nil = 0' ], 'Xlua_file') + call setfperm('Xlua_file', 'r-xr-xr-x') + + call assert_fails('luafile Xlua_file', "Xlua_file:1: unexpected symbol near 'nil'") + call delete('Xlua_file') bwipe! endfunc diff --git a/src/version.c b/src/version.c index 2d0246118f..4e88163469 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 136, /**/ 135, /**/ From ade55787978e15fe57c5cedf38c9f85bfe1d983c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 1 Jul 2018 21:12:55 +0200 Subject: [PATCH 21/23] patch 8.1.0137: CI does not run with TCL Problem: CI does not run with TCL. Solution: Add TCL to the travis config. (Dominique Pelle, closes #3133) --- .travis.yml | 15 ++++++++------- src/version.c | 2 ++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 60e7604621..4485cc9ea3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,18 +11,18 @@ compiler: env: - BUILD=yes TEST=scripttests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" - BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes - BUILD=yes TEST=test COVERAGE=no FEATURES=normal CONFOPT= SHADOWOPT="-C src/shadow" SRCDIR=./src/shadow CHECK_AUTOCONF=no - BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - BUILD=yes TEST=test COVERAGE=no FEATURES=tiny CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no # Mac OSX build - BUILD=yes TEST=test COVERAGE=no FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" # ASAN build - BUILD=yes TEST=test SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer" FEATURES=huge SRCDIR=./src CHECK_AUTOCONF=no ASAN_OPTIONS="print_stacktrace=1 log_path=asan" LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/src/testdir/lsan-suppress.txt" - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" sudo: false @@ -39,16 +39,16 @@ matrix: env: BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - os: osx env: BUILD=yes TEST=scripttests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" - os: osx env: BUILD=yes TEST=test SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer" FEATURES=huge SRCDIR=./src CHECK_AUTOCONF=no ASAN_OPTIONS="print_stacktrace=1 log_path=asan" LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/src/testdir/lsan-suppress.txt" - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" - os: linux compiler: clang env: BUILD=yes TEST=test SANITIZER_CFLAGS="-g -O1 -DABORT_ON_INTERNAL_ERROR -DEXITFREE -fsanitize=address -fno-omit-frame-pointer" FEATURES=huge SRCDIR=./src CHECK_AUTOCONF=no ASAN_OPTIONS="print_stacktrace=1 log_path=asan" LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/src/testdir/lsan-suppress.txt" - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" - os: linux compiler: clang env: BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes @@ -57,7 +57,7 @@ matrix: env: BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - os: linux env: BUILD=yes TEST=test COVERAGE=no FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no - "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'" + "CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp --enable-tclinterp'" branches: except: @@ -75,6 +75,7 @@ addons: - liblua5.2-dev - lua5.2 - ruby-dev + - tcl-dev - cscope - libgtk2.0-dev diff --git a/src/version.c b/src/version.c index 4e88163469..9c79148d06 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 137, /**/ 136, /**/ From 33d5ab3795720b7d986f9f17f660ee9e448466e0 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 2 Jul 2018 20:51:24 +0200 Subject: [PATCH 22/23] patch 8.1.0138: negative value of 'softtabstop' not used correctly Problem: Negative value of 'softtabstop' not used correctly. Solution: Use get_sts_value(). (Tom Ryder) --- src/Makefile | 1 + src/edit.c | 6 +++--- src/option.c | 2 +- src/testdir/test_tab.vim | 36 ++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Makefile b/src/Makefile index ad9045104c..86dae884a2 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2288,6 +2288,7 @@ test_arglist \ test_syn_attr \ test_syntax \ test_system \ + test_tab \ test_tabline \ test_tabpage \ test_tagcase \ diff --git a/src/edit.c b/src/edit.c index d4de825af1..0519a015ed 100644 --- a/src/edit.c +++ b/src/edit.c @@ -9373,7 +9373,7 @@ ins_bs( if (p_sta && in_indent) want_vcol = (want_vcol / curbuf->b_p_sw) * curbuf->b_p_sw; else - want_vcol = tabstop_start(want_vcol, curbuf->b_p_sts, + want_vcol = tabstop_start(want_vcol, get_sts_value(), curbuf->b_p_vsts_array); #else want_vcol = (want_vcol / ts) * ts; @@ -10203,9 +10203,9 @@ ins_tab(void) temp = (int)curbuf->b_p_sw; temp -= get_nolist_virtcol() % temp; } - else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts > 0) + else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0) /* use 'softtabstop' when set */ - temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_sts, + temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(), curbuf->b_p_vsts_array); else /* otherwise use 'tabstop' */ temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts, diff --git a/src/option.c b/src/option.c index 50d42ebf7d..504b92a71a 100644 --- a/src/option.c +++ b/src/option.c @@ -13016,7 +13016,7 @@ get_sw_value(buf_T *buf) /* * Return the effective softtabstop value for the current buffer, using the - * 'tabstop' value when 'softtabstop' is negative. + * 'shiftwidth' value when 'softtabstop' is negative. */ long get_sts_value(void) diff --git a/src/testdir/test_tab.vim b/src/testdir/test_tab.vim index b847dbd962..3be30245b9 100644 --- a/src/testdir/test_tab.vim +++ b/src/testdir/test_tab.vim @@ -1,3 +1,4 @@ +" Various tests for inserting a Tab. " Tests for "r" with 'smarttab' and 'expandtab' set/not set. " Also test that dv_ works correctly @@ -43,3 +44,38 @@ func Test_smarttab() enew! set expandtab& smartindent& copyindent& ts& sw& sts& endfunc + +func Test_softtabstop() + new + set sts=0 sw=0 + exe "normal ix\x\" + call assert_equal("x\tx", getline(1)) + + call setline(1, '') + set sts=4 + exe "normal ix\x\" + call assert_equal("x x", getline(1)) + + call setline(1, '') + set sts=-1 sw=4 + exe "normal ix\x\" + call assert_equal("x x", getline(1)) + + call setline(1, 'x ') + set sts=0 sw=0 backspace=start + exe "normal A\x\" + call assert_equal("x x", getline(1)) + + call setline(1, 'x ') + set sts=4 + exe "normal A\x\" + call assert_equal("x x", getline(1)) + + call setline(1, 'x ') + set sts=-1 sw=4 + exe "normal A\x\" + call assert_equal("x x", getline(1)) + + set sts=0 sw=0 backspace& + bwipe! +endfunc diff --git a/src/version.c b/src/version.c index 9c79148d06..2e92878258 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 138, /**/ 137, /**/ From a8a60d0c6b292216e55f005cf9637789a771d34b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 2 Jul 2018 22:54:36 +0200 Subject: [PATCH 23/23] patch 8.1.0139: Lua tests fail on some platforms Problem: Lua tests fail on some platforms. Solution: Accept a hex number with and without "0x". (Ken Takata, closes #3137) --- src/testdir/test_lua.vim | 6 +++--- src/version.c | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim index acd5b17558..73134718d3 100644 --- a/src/testdir/test_lua.vim +++ b/src/testdir/test_lua.vim @@ -305,7 +305,7 @@ func Test_list() lua l:add(vim.eval("{'a':1, 'b':2, 'c':3}")) call assert_equal([123.0, 'abc', v:true, v:false, [1, 2, 3], {'a': 1, 'b': 2, 'c': 3}], l) call assert_equal(6.0, luaeval('#l')) - call assert_match('^list: 0x\x\+$', luaeval('tostring(l)')) + call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)')) lua l[0] = 124 lua l[4] = nil @@ -358,7 +358,7 @@ func Test_recursive_list() call assert_equal('[1.0, 2.0, [...]]', string(luaeval('l'))) - call assert_match('^list: 0x\x\+$', luaeval('tostring(l)')) + call assert_match('^list: \%(0x\)\?\x\+$', luaeval('tostring(l)')) call assert_equal(luaeval('tostring(l)'), luaeval('tostring(l[2])')) call assert_equal(luaeval('l'), luaeval('l[2]')) @@ -380,7 +380,7 @@ func Test_dict() lua d[5] = vim.eval("{'a':1, 'b':2, 'c':3}") call assert_equal({'0':123.0, '1':'abc', '2':v:true, '3':v:false, '4': [1, 2, 3], '5': {'a':1, 'b':2, 'c':3}}, d) call assert_equal(6.0, luaeval('#d')) - call assert_match('^dict: 0x\x\+$', luaeval('tostring(d)')) + call assert_match('^dict: \%(0x\)\?\x\+$', luaeval('tostring(d)')) call assert_equal('abc', luaeval('d[1]')) diff --git a/src/version.c b/src/version.c index 2e92878258..0fdf075f20 100644 --- a/src/version.c +++ b/src/version.c @@ -789,6 +789,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 139, /**/ 138, /**/