From dc73b4b75de0134db3dffa6e631daf6cae817545 Mon Sep 17 00:00:00 2001 From: "K.Takata" Date: Tue, 8 Jun 2021 18:32:36 +0200 Subject: [PATCH 01/49] patch 8.2.2962: MS-Windows command line arguments have wrong encoding Problem: MS-Windows command line arguments have wrong encoding. Solution: Always use utf-8 in get_cmd_argsW(). (Ken Takata, closes #8347) --- src/os_win32.c | 8 ++++---- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/os_win32.c b/src/os_win32.c index 874a2c69d8..a966c53495 100644 --- a/src/os_win32.c +++ b/src/os_win32.c @@ -7558,7 +7558,7 @@ myresetstkoflw(void) /* - * The command line arguments in UCS2 + * The command line arguments in UTF-16 */ static int nArgsW = 0; static LPWSTR *ArglistW = NULL; @@ -7601,8 +7601,8 @@ get_cmd_argsW(char ***argvp) { int len; - // Convert each Unicode argument to the current codepage. - WideCharToMultiByte_alloc(GetACP(), 0, + // Convert each Unicode argument to UTF-8. + WideCharToMultiByte_alloc(CP_UTF8, 0, ArglistW[i], (int)wcslen(ArglistW[i]) + 1, (LPSTR *)&argv[i], &len, 0, 0); if (argv[i] == NULL) @@ -7678,7 +7678,7 @@ set_alist_count(void) /* * Fix the encoding of the command line arguments. Invoked when 'encoding' - * has been changed while starting up. Use the UCS-2 command line arguments + * has been changed while starting up. Use the UTF-16 command line arguments * and convert them to 'encoding'. */ void diff --git a/src/version.c b/src/version.c index bbf13dddf5..08cb9c98e8 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2962, /**/ 2961, /**/ From 445f11d5bcfddfa194ebd12b029228c7e957f94c Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 8 Jun 2021 20:13:31 +0200 Subject: [PATCH 02/49] patch 8.2.2963: GUI: mouse move may start Visual mode with a popup visible Problem: GUI: mouse move may start Visual mode with a popup visible. Solution: Add special code for mouse move. (closes #8318) --- src/gui.c | 5 ++++- src/keymap.h | 5 +++-- src/term.c | 4 ++++ src/version.c | 2 ++ src/vim.h | 2 ++ 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/gui.c b/src/gui.c index 2539a4f642..b5ec007405 100644 --- a/src/gui.c +++ b/src/gui.c @@ -3071,6 +3071,9 @@ gui_send_mouse_event( */ switch (button) { + case MOUSE_MOVE: + button_char = KE_MOUSEMOVE_XY; + goto button_set; case MOUSE_X1: button_char = KE_X1MOUSE; goto button_set; @@ -4925,7 +4928,7 @@ gui_mouse_moved(int x, int y) if (popup_visible) // Generate a mouse-moved event, so that the popup can perhaps be // closed, just like in the terminal. - gui_send_mouse_event(MOUSE_DRAG, x, y, FALSE, 0); + gui_send_mouse_event(MOUSE_MOVE, x, y, FALSE, 0); #endif } diff --git a/src/keymap.h b/src/keymap.h index 6efb13d065..4ce5144d15 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -273,8 +273,9 @@ enum key_extra , KE_FOCUSGAINED = 98 // focus gained , KE_FOCUSLOST = 99 // focus lost , KE_MOUSEMOVE = 100 // mouse moved with no button down - , KE_CANCEL = 101 // return from vgetc() - , KE_COMMAND = 102 // special key + , KE_MOUSEMOVE_XY = 101 // KE_MOUSEMOVE with coordinates + , KE_CANCEL = 102 // return from vgetc() + , KE_COMMAND = 103 // special key }; /* diff --git a/src/term.c b/src/term.c index 99b33d4399..cec16b608a 100644 --- a/src/term.c +++ b/src/term.c @@ -5588,6 +5588,7 @@ check_termcode( && key_name[0] == (int)KS_EXTRA && (key_name[1] == (int)KE_X1MOUSE || key_name[1] == (int)KE_X2MOUSE + || key_name[1] == (int)KE_MOUSEMOVE_XY || key_name[1] == (int)KE_MOUSELEFT || key_name[1] == (int)KE_MOUSERIGHT || key_name[1] == (int)KE_MOUSEDOWN @@ -5601,6 +5602,9 @@ check_termcode( mouse_col = 128 * (bytes[0] - ' ' - 1) + bytes[1] - ' ' - 1; mouse_row = 128 * (bytes[2] - ' ' - 1) + bytes[3] - ' ' - 1; slen += num_bytes; + // equal to K_MOUSEMOVE + if (key_name[1] == (int)KE_MOUSEMOVE_XY) + key_name[1] = (int)KE_MOUSEMOVE; } else #endif diff --git a/src/version.c b/src/version.c index 08cb9c98e8..cea97e8c5e 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2963, /**/ 2962, /**/ diff --git a/src/vim.h b/src/vim.h index 10f032f2b2..61afe97309 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1859,6 +1859,8 @@ typedef int sock_T; #define MOUSE_6 0x500 // scroll wheel left #define MOUSE_7 0x600 // scroll wheel right +#define MOUSE_MOVE 0x700 // report mouse moved + // 0x20 is reserved by xterm #define MOUSE_DRAG_XTERM 0x40 From a733042b124357225e4081e10ef28591236c6077 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 8 Jun 2021 20:46:45 +0200 Subject: [PATCH 03/49] patch 8.2.2964: Vim9: hang when using space after -> Problem: Vim9: hang when using space after ->. (Naohiro Ono) Solution: Skip over white space to find the function name. (closes #8341) --- src/eval.c | 5 +++-- src/testdir/test_vim9_expr.vim | 4 ++++ src/version.c | 2 ++ src/vim9compile.c | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/eval.c b/src/eval.c index d0007bbd3e..46d8ca3a82 100644 --- a/src/eval.c +++ b/src/eval.c @@ -5786,8 +5786,9 @@ handle_subscript( p = eval_next_non_blank(*arg, evalarg, &getnext); if (getnext && ((rettv->v_type == VAR_DICT && *p == '.' && eval_isdictc(p[1])) - || (p[0] == '-' && p[1] == '>' - && (p[2] == '{' || ASCII_ISALPHA(p[2]))))) + || (p[0] == '-' && p[1] == '>' && (p[2] == '{' + || ASCII_ISALPHA(in_vim9script() ? *skipwhite(p + 2) + : p[2]))))) { *arg = eval_next_line(evalarg); p = *arg; diff --git a/src/testdir/test_vim9_expr.vim b/src/testdir/test_vim9_expr.vim index dc6858fc78..6b51bc78a5 100644 --- a/src/testdir/test_vim9_expr.vim +++ b/src/testdir/test_vim9_expr.vim @@ -2961,6 +2961,10 @@ def Test_expr7_method_call() var Join = (l) => join(l, 'x') assert_equal('axb', ['a', 'b']->(Join)()) + + var sorted = [3, 1, 2] + -> sort() + assert_equal([1, 2, 3], sorted) END CheckDefAndScriptSuccess(lines) enddef diff --git a/src/version.c b/src/version.c index cea97e8c5e..de03654afa 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2964, /**/ 2963, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 1256bfaac4..28108bfe7d 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -4108,7 +4108,8 @@ compile_subscript( // Also if a following line starts with ".x". if (next != NULL && ((next[0] == '-' && next[1] == '>' - && (next[2] == '{' || ASCII_ISALPHA(next[2]))) + && (next[2] == '{' + || ASCII_ISALPHA(*skipwhite(next + 2)))) || (next[0] == '.' && eval_isdictc(next[1])))) { next = next_line_from_context(cctx, TRUE); From b55d618f193d9f413612d8d4e62758056e842e46 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 8 Jun 2021 22:01:53 +0200 Subject: [PATCH 04/49] patch 8.2.2965: Vim9: crash when calling function that failed to compile Problem: Vim9: crash when calling function that failed to compile. Solution: Fail when trying to call the function. (closes #8344) --- src/errors.h | 2 ++ src/testdir/test_vim9_func.vim | 16 ++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 6 ++++++ 4 files changed, 26 insertions(+) diff --git a/src/errors.h b/src/errors.h index 94a752ae68..fac3e26d8b 100644 --- a/src/errors.h +++ b/src/errors.h @@ -423,3 +423,5 @@ EXTERN char e_one_argument_too_few[] INIT(= N_("E1190: One argument too few")); EXTERN char e_nr_arguments_too_few[] INIT(= N_("E1190: %d arguments too few")); +EXTERN char e_call_to_function_that_failed_to_compile_str[] + INIT(= N_("E1191: Call to function that failed to compile: %s")); diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 7e21b37883..cd2a15d2da 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -74,6 +74,22 @@ def TestCompilingErrorInTry() delete('Xdir', 'rf') enddef +def Test_compile_error_in_called_function() + var lines =<< trim END + vim9script + var n: number + def Foo() + &hls = n + enddef + def Bar() + Foo() + enddef + silent! Foo() + Bar() + END + CheckScriptFailureList(lines, ['E1012:', 'E1191:']) +enddef + def Test_autoload_name_mismatch() var dir = 'Xdir/autoload' mkdir(dir, 'p') diff --git a/src/version.c b/src/version.c index de03654afa..aee9dcff22 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2965, /**/ 2964, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 28108bfe7d..6fcad3db44 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1950,6 +1950,12 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) PROFILING(ufunc), NULL) == FAIL) return FAIL; } + if (ufunc->uf_def_status == UF_COMPILE_ERROR) + { + emsg_funcname(_(e_call_to_function_that_failed_to_compile_str), + ufunc->uf_name); + return FAIL; + } if ((isn = generate_instr(cctx, ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL From e3f50ad640fb30f27027f85a616280288bbc14ca Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 9 Jun 2021 12:33:40 +0200 Subject: [PATCH 05/49] patch 8.2.2966: ml_get errors after recovering a file Problem: ml_get errors after recovering a file. (Yegappan Lakshmanan) Solution: Fix the cursor position after deleting lines. --- src/memline.c | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/memline.c b/src/memline.c index a0b642908d..58582c9d69 100644 --- a/src/memline.c +++ b/src/memline.c @@ -1696,6 +1696,7 @@ ml_recover(int checkext) && !(curbuf->b_ml.ml_flags & ML_EMPTY)) ml_delete(curbuf->b_ml.ml_line_count); curbuf->b_flags |= BF_RECOVERED; + check_cursor(); recoverymode = FALSE; if (got_int) diff --git a/src/version.c b/src/version.c index aee9dcff22..f57d692676 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2966, /**/ 2965, /**/ From c04f2a4cd40f32120b7a94fdea7bfa62e8640041 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 9 Jun 2021 19:30:03 +0200 Subject: [PATCH 06/49] patch 8.2.2967: Vim9: crash when using two levels of partials Problem: Vim9: crash when using two levels of partials. Solution: Add outer_ref_T and use it in the execution context. --- src/structs.h | 2 +- src/testdir/test_vim9_func.vim | 13 ++++ src/version.c | 2 + src/vim9execute.c | 128 +++++++++++++++++++++------------ 4 files changed, 99 insertions(+), 46 deletions(-) diff --git a/src/structs.h b/src/structs.h index a923a35edc..10f1025c17 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1995,7 +1995,7 @@ struct outer_S { garray_T *out_stack; // stack from outer scope int out_frame_idx; // index of stack frame in out_stack outer_T *out_up; // outer scope of outer scope or NULL - int out_up_is_copy; // don't free out_up + partial_T *out_up_partial; // partial owning out_up or NULL }; struct partial_S diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index cd2a15d2da..8d891d2b1f 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -2128,6 +2128,19 @@ def Test_nested_lambda() CheckScriptSuccess(lines) enddef +def Test_double_nested_lambda() + var lines =<< trim END + vim9script + def F(head: string): func(string): func(string): string + return (sep: string): func(string): string => ((tail: string): string => { + return head .. sep .. tail + }) + enddef + assert_equal('hello-there', F('hello')('-')('there')) + END + CheckScriptSuccess(lines) +enddef + def Test_nested_inline_lambda() # TODO: use the "text" argument var lines =<< trim END diff --git a/src/version.c b/src/version.c index f57d692676..77b4ed08ba 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2967, /**/ 2966, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index 5a8a112a6a..767dcea3c8 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -43,6 +43,14 @@ typedef struct { int floc_restore_cmdmod_stacklen; } funclocal_T; +// Structure to hold a reference to an outer_T, with information of whether it +// was allocated. +typedef struct { + outer_T *or_outer; + partial_T *or_partial; // decrement "or_partial->pt_refcount" later + int or_outer_allocated; // free "or_outer" later +} outer_ref_T; + // A stack is used to store: // - arguments passed to a :def function // - info about the calling function, to use when returning @@ -70,7 +78,7 @@ struct ectx_S { int ec_frame_idx; // index in ec_stack: context of ec_dfunc_idx int ec_initial_frame_idx; // frame index when called - outer_T *ec_outer; // outer scope used for closures, allocated + outer_ref_T *ec_outer_ref; // outer scope used for closures, allocated funclocal_T ec_funclocal; garray_T ec_trystack; // stack of trycmd_T values @@ -143,7 +151,7 @@ exe_newlist(int count, ectx_T *ectx) * Call compiled function "cdf_idx" from compiled code. * This adds a stack frame and sets the instruction pointer to the start of the * called function. - * If "pt" is not null use "pt->pt_outer" for ec_outer. + * If "pt" is not null use "pt->pt_outer" for ec_outer_ref->or_outer. * * Stack has: * - current arguments (already there) @@ -280,7 +288,8 @@ call_dfunc( STACK_TV_BOT(STACK_FRAME_FUNC_OFF)->vval.v_number = ectx->ec_dfunc_idx; STACK_TV_BOT(STACK_FRAME_IIDX_OFF)->vval.v_number = ectx->ec_iidx; STACK_TV_BOT(STACK_FRAME_INSTR_OFF)->vval.v_string = (void *)ectx->ec_instr; - STACK_TV_BOT(STACK_FRAME_OUTER_OFF)->vval.v_string = (void *)ectx->ec_outer; + STACK_TV_BOT(STACK_FRAME_OUTER_OFF)->vval.v_string = + (void *)ectx->ec_outer_ref; STACK_TV_BOT(STACK_FRAME_FUNCLOCAL_OFF)->vval.v_string = (void *)floc; STACK_TV_BOT(STACK_FRAME_IDX_OFF)->vval.v_number = ectx->ec_frame_idx; ectx->ec_frame_idx = ectx->ec_stack.ga_len; @@ -300,30 +309,40 @@ call_dfunc( if (pt != NULL || ufunc->uf_partial != NULL || (ufunc->uf_flags & FC_CLOSURE)) { - outer_T *outer = ALLOC_CLEAR_ONE(outer_T); + outer_ref_T *ref = ALLOC_CLEAR_ONE(outer_ref_T); - if (outer == NULL) + if (ref == NULL) return FAIL; if (pt != NULL) { - *outer = pt->pt_outer; - outer->out_up_is_copy = TRUE; + ref->or_outer = &pt->pt_outer; + ++pt->pt_refcount; + ref->or_partial = pt; } else if (ufunc->uf_partial != NULL) { - *outer = ufunc->uf_partial->pt_outer; - outer->out_up_is_copy = TRUE; + ref->or_outer = &ufunc->uf_partial->pt_outer; + ++ufunc->uf_partial->pt_refcount; + ref->or_partial = ufunc->uf_partial; } else { - outer->out_stack = &ectx->ec_stack; - outer->out_frame_idx = ectx->ec_frame_idx; - outer->out_up = ectx->ec_outer; + ref->or_outer = ALLOC_CLEAR_ONE(outer_T); + if (ref->or_outer == NULL) + { + vim_free(ref); + return FAIL; + } + ref->or_outer_allocated = TRUE; + ref->or_outer->out_stack = &ectx->ec_stack; + ref->or_outer->out_frame_idx = ectx->ec_frame_idx; + if (ectx->ec_outer_ref != NULL) + ref->or_outer->out_up = ectx->ec_outer_ref->or_outer; } - ectx->ec_outer = outer; + ectx->ec_outer_ref = ref; } else - ectx->ec_outer = NULL; + ectx->ec_outer_ref = NULL; ++ufunc->uf_calls; @@ -476,7 +495,6 @@ handle_closure_in_use(ectx_T *ectx, int free_arguments) pt->pt_funcstack = funcstack; pt->pt_outer.out_stack = &funcstack->fs_ga; pt->pt_outer.out_frame_idx = ectx->ec_frame_idx - top; - pt->pt_outer.out_up = ectx->ec_outer; } } } @@ -587,7 +605,13 @@ func_return(ectx_T *ectx) if (ret_idx == ectx->ec_frame_idx + STACK_FRAME_IDX_OFF) ret_idx = 0; - vim_free(ectx->ec_outer); + if (ectx->ec_outer_ref != NULL) + { + if (ectx->ec_outer_ref->or_outer_allocated) + vim_free(ectx->ec_outer_ref->or_outer); + partial_unref(ectx->ec_outer_ref->or_partial); + vim_free(ectx->ec_outer_ref); + } // Restore the previous frame. ectx->ec_dfunc_idx = prev_dfunc_idx; @@ -595,7 +619,7 @@ func_return(ectx_T *ectx) + STACK_FRAME_IIDX_OFF)->vval.v_number; ectx->ec_instr = (void *)STACK_TV(ectx->ec_frame_idx + STACK_FRAME_INSTR_OFF)->vval.v_string; - ectx->ec_outer = (void *)STACK_TV(ectx->ec_frame_idx + ectx->ec_outer_ref = (void *)STACK_TV(ectx->ec_frame_idx + STACK_FRAME_OUTER_OFF)->vval.v_string; floc = (void *)STACK_TV(ectx->ec_frame_idx + STACK_FRAME_FUNCLOCAL_OFF)->vval.v_string; @@ -696,7 +720,7 @@ call_bfunc(int func_idx, int argcount, ectx_T *ectx) * If the function is compiled this will add a stack frame and set the * instruction pointer at the start of the function. * Otherwise the function is called here. - * If "pt" is not null use "pt->pt_outer" for ec_outer. + * If "pt" is not null use "pt->pt_outer" for ec_outer_ref->or_outer. * "iptr" can be used to replace the instruction with a more efficient one. */ static int @@ -1295,24 +1319,31 @@ fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx) dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ectx->ec_dfunc_idx; - // The closure needs to find arguments and local - // variables in the current stack. + // The closure may need to find arguments and local variables in the + // current stack. pt->pt_outer.out_stack = &ectx->ec_stack; pt->pt_outer.out_frame_idx = ectx->ec_frame_idx; - pt->pt_outer.out_up = ectx->ec_outer; - pt->pt_outer.out_up_is_copy = TRUE; + if (ectx->ec_outer_ref != NULL) + { + // The current context already has a context, link to that one. + pt->pt_outer.out_up = ectx->ec_outer_ref->or_outer; + if (ectx->ec_outer_ref->or_partial != NULL) + { + pt->pt_outer.out_up_partial = ectx->ec_outer_ref->or_partial; + ++pt->pt_outer.out_up_partial->pt_refcount; + } + } - // If this function returns and the closure is still - // being used, we need to make a copy of the context - // (arguments and local variables). Store a reference - // to the partial so we can handle that. + // If this function returns and the closure is still being used, we + // need to make a copy of the context (arguments and local variables). + // Store a reference to the partial so we can handle that. if (ga_grow(&ectx->ec_funcrefs, 1) == FAIL) { vim_free(pt); return FAIL; } - // Extra variable keeps the count of closures created - // in the current function call. + // Extra variable keeps the count of closures created in the current + // function call. ++(((typval_T *)ectx->ec_stack.ga_data) + ectx->ec_frame_idx + STACK_FRAME_SIZE + dfunc->df_varcount)->vval.v_number; @@ -2355,7 +2386,8 @@ exec_instructions(ectx_T *ectx) case ISN_STOREOUTER: { int depth = iptr->isn_arg.outer.outer_depth; - outer_T *outer = ectx->ec_outer; + outer_T *outer = ectx->ec_outer_ref == NULL ? NULL + : ectx->ec_outer_ref->or_outer; while (depth > 1 && outer != NULL) { @@ -2774,7 +2806,7 @@ exec_instructions(ectx_T *ectx) } break; - // push a function reference to a compiled function + // push a partial, a reference to a compiled function case ISN_FUNCREF: { partial_T *pt = ALLOC_CLEAR_ONE(partial_T); @@ -2791,7 +2823,6 @@ exec_instructions(ectx_T *ectx) if (fill_partial_and_closure(pt, pt_dfunc->df_ufunc, ectx) == FAIL) goto theend; - tv = STACK_TV_BOT(0); ++ectx->ec_stack.ga_len; tv->vval.v_partial = pt; @@ -4384,22 +4415,31 @@ call_def_function( // by copy_func(). if (partial != NULL || base_ufunc->uf_partial != NULL) { - ectx.ec_outer = ALLOC_CLEAR_ONE(outer_T); - if (ectx.ec_outer == NULL) + ectx.ec_outer_ref = ALLOC_CLEAR_ONE(outer_ref_T); + if (ectx.ec_outer_ref == NULL) goto failed_early; if (partial != NULL) { if (partial->pt_outer.out_stack == NULL && current_ectx != NULL) { - if (current_ectx->ec_outer != NULL) - *ectx.ec_outer = *current_ectx->ec_outer; + if (current_ectx->ec_outer_ref != NULL + && current_ectx->ec_outer_ref->or_outer != NULL) + ectx.ec_outer_ref->or_outer = + current_ectx->ec_outer_ref->or_outer; } else - *ectx.ec_outer = partial->pt_outer; + { + ectx.ec_outer_ref->or_outer = &partial->pt_outer; + ++partial->pt_refcount; + ectx.ec_outer_ref->or_partial = partial; + } } else - *ectx.ec_outer = base_ufunc->uf_partial->pt_outer; - ectx.ec_outer->out_up_is_copy = TRUE; + { + ectx.ec_outer_ref->or_outer = &base_ufunc->uf_partial->pt_outer; + ++base_ufunc->uf_partial->pt_refcount; + ectx.ec_outer_ref->or_partial = base_ufunc->uf_partial; + } } } @@ -4516,14 +4556,12 @@ failed_early: vim_free(ectx.ec_stack.ga_data); vim_free(ectx.ec_trystack.ga_data); - - while (ectx.ec_outer != NULL) + if (ectx.ec_outer_ref != NULL) { - outer_T *up = ectx.ec_outer->out_up_is_copy - ? NULL : ectx.ec_outer->out_up; - - vim_free(ectx.ec_outer); - ectx.ec_outer = up; + if (ectx.ec_outer_ref->or_outer_allocated) + vim_free(ectx.ec_outer_ref->or_outer); + partial_unref(ectx.ec_outer_ref->or_partial); + vim_free(ectx.ec_outer_ref); } // Not sure if this is necessary. From 54656015d384a96ef814dfcf2a18e47f5ba3df14 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Wed, 9 Jun 2021 20:50:46 +0200 Subject: [PATCH 07/49] patch 8.2.2968: Vim9: memory leak Problem: Vim9: memory leak Solution: Unreference pt_outer of partial. --- src/eval.c | 3 +++ src/version.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/eval.c b/src/eval.c index 46d8ca3a82..b6bee5af50 100644 --- a/src/eval.c +++ b/src/eval.c @@ -4301,6 +4301,9 @@ partial_free(partial_T *pt) else func_ptr_unref(pt->pt_func); + // "out_up" is no longer used, decrement refcount on partial that owns it. + partial_unref(pt->pt_outer.out_up_partial); + // Decrease the reference count for the context of a closure. If down // to the minimum it may be time to free it. if (pt->pt_funcstack != NULL) diff --git a/src/version.c b/src/version.c index 77b4ed08ba..d031136028 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2968, /**/ 2967, /**/ From a42e6e0082a6d564dbfa55317d4a698ac12ae898 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 10 Jun 2021 18:43:25 +0200 Subject: [PATCH 08/49] patch 8.2.2969: subtracting from number option fails when result is zero Problem: Subtracting from number option fails when result is zero. (Ingo Karkat) Solution: Reset the string value when using the numeric value. (closes #8351) --- src/evalvars.c | 1 + src/testdir/test_vimscript.vim | 9 +++++++++ src/version.c | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/evalvars.c b/src/evalvars.c index f3b4da222b..7581a14177 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -1439,6 +1439,7 @@ ex_let_one( case '%': n = (long)num_modulus(numval, n, &failed); break; } + s = NULL; } else if (opt_type == gov_string && stringval != NULL && s != NULL) diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim index f12d810e02..89c100189b 100644 --- a/src/testdir/test_vimscript.vim +++ b/src/testdir/test_vimscript.vim @@ -7083,6 +7083,15 @@ func Test_compound_assignment_operators() call assert_fails('let &scrolljump .= "j"', 'E734:') set scrolljump&vim + let &foldlevelstart = 2 + let &foldlevelstart -= 1 + call assert_equal(1, &foldlevelstart) + let &foldlevelstart -= 1 + call assert_equal(0, &foldlevelstart) + let &foldlevelstart = 2 + let &foldlevelstart -= 2 + call assert_equal(0, &foldlevelstart) + " Test for register let @/ = 1 call assert_fails('let @/ += 1', 'E734:') diff --git a/src/version.c b/src/version.c index d031136028..055179cd2d 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2969, /**/ 2968, /**/ From 31e299c08f250b126b2c2c0ecce12ee563b70fdc Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Thu, 10 Jun 2021 18:50:55 +0200 Subject: [PATCH 09/49] patch 8.2.2970: Python configure check uses deprecated command Problem: Python configure check uses deprecated command. Solution: Use sysconfig instead of distutils if possible. (Zdenek Dohnal, closes #8354) --- src/auto/configure | 5 ++++- src/configure.ac | 5 ++++- src/version.c | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/auto/configure b/src/auto/configure index 5702a21718..7ecc40ca51 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -6755,7 +6755,10 @@ else vi_cv_path_python3_conf= config_dir="config-${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" - d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"` + d=`${vi_cv_path_python3} -c "import sysconfig; print(sysconfig.get_config_var('LIBPL'))" 2> /dev/null` + if test "x$d" = "x"; then + d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"` + fi if test -d "$d" && test -f "$d/config.c"; then vi_cv_path_python3_conf="$d" else diff --git a/src/configure.ac b/src/configure.ac index 2db04496ff..9810ea1fc4 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -1487,7 +1487,10 @@ if test "$enable_python3interp" = "yes" -o "$enable_python3interp" = "dynamic"; [ vi_cv_path_python3_conf= config_dir="config-${vi_cv_var_python3_version}${vi_cv_var_python3_abiflags}" - d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"` + d=`${vi_cv_path_python3} -c "import sysconfig; print(sysconfig.get_config_var('LIBPL'))" 2> /dev/null` + if test "x$d" = "x"; then + d=`${vi_cv_path_python3} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('LIBPL'))"` + fi if test -d "$d" && test -f "$d/config.c"; then vi_cv_path_python3_conf="$d" else diff --git a/src/version.c b/src/version.c index 055179cd2d..6286581995 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2970, /**/ 2969, /**/ From 544a38e44db0f25ec4fa7a2a4666cf28a2336f33 Mon Sep 17 00:00:00 2001 From: Christian Brabandt Date: Thu, 10 Jun 2021 19:39:11 +0200 Subject: [PATCH 10/49] patch 8.2.2971: cannot yank a block without trailing spaces Problem: Cannot yank a block without trailing spaces. Solution: Add the "zy" command. (Christian Brabandt, closes #8292) --- runtime/doc/change.txt | 13 ++++++++- runtime/doc/index.txt | 1 + src/normal.c | 3 ++ src/ops.c | 3 ++ src/register.c | 26 ++++++++++++++---- src/structs.h | 4 ++- src/testdir/test_visual.vim | 55 +++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 8 files changed, 99 insertions(+), 8 deletions(-) diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 6040926f62..6c6a0c9bd9 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1042,6 +1042,10 @@ inside of strings can change! Also see 'softtabstop' option. > cursor to the end of line (which is more logical, but not Vi-compatible) use ":map Y y$". + *zy* +["x]zy{motion} Yank {motion} text [into register x]. Only differs + from `y` when selecting a block of text, see |v_zy|. + *v_y* {Visual}["x]y Yank the highlighted text [into register x] (for {Visual} see |Visual-mode|). @@ -1050,6 +1054,12 @@ inside of strings can change! Also see 'softtabstop' option. > {Visual}["x]Y Yank the highlighted lines [into register x] (for {Visual} see |Visual-mode|). + *v_zy* +{Visual}["x]zy Yank the highlighted text [into register x]. Trailing + whitespace at the end of each line of a selected block + won't be yanked. Especially useful in combination + with `zp`. (for {Visual} see |Visual-mode|) + *:y* *:yank* *E850* :[range]y[ank] [x] Yank [range] lines [into register x]. Yanking to the "* or "+ registers is possible only when the @@ -1129,7 +1139,8 @@ inside of strings can change! Also see 'softtabstop' option. > ["x]zp or *zp* *zP* ["x]zP Like "p" and "P", except without adding trailing spaces when pasting a block. Thus the inserted text will not - always be a rectangle. + always be a rectangle. Especially useful in + combination with |v_zy|. You can use these commands to copy text from one place to another. Do this by first getting the text into a register with a yank, delete or change diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt index 118bc22179..00db07606f 100644 --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -878,6 +878,7 @@ tag char note action in Normal mode ~ |zv| zv open enough folds to view the cursor line |zw| zw permanently mark word as incorrectly spelled |zx| zx re-apply 'foldlevel' and do "zv" +|zy| zy yank without trailing spaces |zz| zz redraw, cursor line at center of window |z| z same as "zh" |z| z same as "zl" diff --git a/src/normal.c b/src/normal.c index fe47e2b74d..b2d0c011ea 100644 --- a/src/normal.c +++ b/src/normal.c @@ -2985,6 +2985,9 @@ dozet: case 'P': case 'p': nv_put(cap); break; + // "zy" Yank without trailing spaces + case 'y': nv_operator(cap); + break; #ifdef FEAT_FOLDING // "zF": create fold command // "zf": create fold operator diff --git a/src/ops.c b/src/ops.c index 48d629df27..73faa1649e 100644 --- a/src/ops.c +++ b/src/ops.c @@ -78,6 +78,8 @@ get_op_type(int char1, int char2) return OP_NR_ADD; if (char1 == 'g' && char2 == Ctrl_X) // subtract return OP_NR_SUB; + if (char1 == 'z' && char2 == 'y') // OP_YANK + return OP_YANK; for (i = 0; ; ++i) { if (opchars[i][0] == char1 && opchars[i][1] == char2) @@ -3894,6 +3896,7 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank) #ifdef FEAT_LINEBREAK curwin->w_p_lbr = lbr_saved; #endif + oap->excl_tr_ws = cap->cmdchar == 'z'; (void)op_yank(oap, FALSE, !gui_yank); } check_cursor_col(); diff --git a/src/register.c b/src/register.c index 5dc8f2896a..c30787afef 100644 --- a/src/register.c +++ b/src/register.c @@ -32,7 +32,7 @@ static int stuff_yank(int, char_u *); static void put_reedit_in_typebuf(int silent); static int put_in_typebuf(char_u *s, int esc, int colon, int silent); -static int yank_copy_line(struct block_def *bd, long y_idx); +static int yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space); #ifdef FEAT_CLIPBOARD static void copy_yank_reg(yankreg_T *reg); #endif @@ -1208,20 +1208,20 @@ op_yank(oparg_T *oap, int deleting, int mess) { case MBLOCK: block_prep(oap, &bd, lnum, FALSE); - if (yank_copy_line(&bd, y_idx) == FAIL) + if (yank_copy_line(&bd, y_idx, oap->excl_tr_ws) == FAIL) goto fail; break; case MLINE: if ((y_current->y_array[y_idx] = - vim_strsave(ml_get(lnum))) == NULL) + vim_strsave(ml_get(lnum))) == NULL) goto fail; break; case MCHAR: { colnr_T startcol = 0, endcol = MAXCOL; - int is_oneChar = FALSE; + int is_oneChar = FALSE; colnr_T cs, ce; p = ml_get(lnum); @@ -1282,7 +1282,7 @@ op_yank(oparg_T *oap, int deleting, int mess) else bd.textlen = endcol - startcol + oap->inclusive; bd.textstart = p + startcol; - if (yank_copy_line(&bd, y_idx) == FAIL) + if (yank_copy_line(&bd, y_idx, FALSE) == FAIL) goto fail; break; } @@ -1443,8 +1443,12 @@ fail: // free the allocated lines return FAIL; } +/* + * Copy a block range into a register. + * If "exclude_trailing_space" is set, do not copy trailing whitespaces. + */ static int -yank_copy_line(struct block_def *bd, long y_idx) +yank_copy_line(struct block_def *bd, long y_idx, int exclude_trailing_space) { char_u *pnew; @@ -1458,6 +1462,16 @@ yank_copy_line(struct block_def *bd, long y_idx) pnew += bd->textlen; vim_memset(pnew, ' ', (size_t)bd->endspaces); pnew += bd->endspaces; + if (exclude_trailing_space) + { + int s = bd->textlen + bd->endspaces; + + while (VIM_ISWHITE(*(bd->textstart + s - 1)) && s > 0) + { + s = s - (*mb_head_off)(bd->textstart, bd->textstart + s - 1) - 1; + pnew--; + } + } *pnew = NUL; return OK; } diff --git a/src/structs.h b/src/structs.h index 10f1025c17..26ab315feb 100644 --- a/src/structs.h +++ b/src/structs.h @@ -3772,7 +3772,7 @@ typedef struct oparg_S int use_reg_one; // TRUE if delete uses reg 1 even when not // linewise int inclusive; // TRUE if char motion is inclusive (only - // valid when motion_type is MCHAR + // valid when motion_type is MCHAR) int end_adjusted; // backuped b_op_end one char (only used by // do_format()) pos_T start; // start of the operator @@ -3789,6 +3789,8 @@ typedef struct oparg_S colnr_T end_vcol; // end col for block mode operator long prev_opcount; // ca.opcount saved for K_CURSORHOLD long prev_count0; // ca.count0 saved for K_CURSORHOLD + int excl_tr_ws; // exclude trailing whitespace for yank of a + // block } oparg_T; /* diff --git a/src/testdir/test_visual.vim b/src/testdir/test_visual.vim index 51ef5ae812..fb26750829 100644 --- a/src/testdir/test_visual.vim +++ b/src/testdir/test_visual.vim @@ -1171,4 +1171,59 @@ func Test_visual_put_in_block_using_zp() bwipe! endfunc +func Test_visual_put_in_block_using_zy_and_zp() + new + + " Test 1) Paste using zp - after the cursor without trailing spaces + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;hzp + call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 2) Paste using zP - in front of the cursor without trailing spaces + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;zP + call assert_equal(['/path/subdir;text', '/path/longsubdir;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 3) Paste using p - with trailing spaces + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;hp + call assert_equal(['/path/subdir ;text', '/path/longsubdir ;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 4) Paste using P - with trailing spaces + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /subdir columntext', + \ 'texttext /longsubdir columntext', + \ 'texttext /longlongsubdir columntext']) + exe "normal! 5G0f/\2jezy" + norm! 1G0f;P + call assert_equal(['/path/subdir ;text', '/path/longsubdir ;text', '/path/longlongsubdir;text'], getline(1, 3)) + + " Test 5) Yank with spaces inside the block + %d + call setline(1, ['/path;text', '/path;text', '/path;text', '', + \ 'texttext /sub dir/ columntext', + \ 'texttext /lon gsubdir/ columntext', + \ 'texttext /lon glongsubdir/ columntext']) + exe "normal! 5G0f/\2jf/zy" + norm! 1G0f;zP + call assert_equal(['/path/sub dir/;text', '/path/lon gsubdir/;text', '/path/lon glongsubdir/;text'], getline(1, 3)) + bwipe! +endfunc + + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index 6286581995..fb6d550ea7 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2971, /**/ 2970, /**/ From 7b4f76c0300f0bd9bf54ca1968fe9ae5e4dbdef4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 10 Jun 2021 21:07:48 +0200 Subject: [PATCH 11/49] patch 8.2.2972: "%bd" tries to delete popup window buffers, which fails Problem: "%bd" tries to delete popup window buffers, which fails. (Ralf Schandl) Solution: Do not try to delete a popup window buffer. (closes #8349) --- src/buffer.c | 266 ++++++++++++++++++---------------- src/testdir/test_popupwin.vim | 6 + src/version.c | 2 + src/vim.h | 4 + 4 files changed, 155 insertions(+), 123 deletions(-) diff --git a/src/buffer.c b/src/buffer.c index d8b7ed4f23..d038e3c922 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1180,122 +1180,6 @@ handle_swap_exists(bufref_T *old_curbuf) swap_exists_action = SEA_NONE; } -/* - * do_bufdel() - delete or unload buffer(s) - * - * addr_count == 0: ":bdel" - delete current buffer - * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete - * buffer "end_bnr", then any other arguments. - * addr_count == 2: ":N,N bdel" - delete buffers in range - * - * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or - * DOBUF_DEL (":bdel") - * - * Returns error message or NULL - */ - char * -do_bufdel( - int command, - char_u *arg, // pointer to extra arguments - int addr_count, - int start_bnr, // first buffer number in a range - int end_bnr, // buffer nr or last buffer nr in a range - int forceit) -{ - int do_current = 0; // delete current buffer? - int deleted = 0; // number of buffers deleted - char *errormsg = NULL; // return value - int bnr; // buffer number - char_u *p; - - if (addr_count == 0) - { - (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); - } - else - { - if (addr_count == 2) - { - if (*arg) // both range and argument is not allowed - return ex_errmsg(e_trailing_arg, arg); - bnr = start_bnr; - } - else // addr_count == 1 - bnr = end_bnr; - - for ( ;!got_int; ui_breakcheck()) - { - /* - * delete the current buffer last, otherwise when the - * current buffer is deleted, the next buffer becomes - * the current one and will be loaded, which may then - * also be deleted, etc. - */ - if (bnr == curbuf->b_fnum) - do_current = bnr; - else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr, - forceit) == OK) - ++deleted; - - /* - * find next buffer number to delete/unload - */ - if (addr_count == 2) - { - if (++bnr > end_bnr) - break; - } - else // addr_count == 1 - { - arg = skipwhite(arg); - if (*arg == NUL) - break; - if (!VIM_ISDIGIT(*arg)) - { - p = skiptowhite_esc(arg); - bnr = buflist_findpat(arg, p, - command == DOBUF_WIPE || command == DOBUF_WIPE_REUSE, - FALSE, FALSE); - if (bnr < 0) // failed - break; - arg = p; - } - else - bnr = getdigits(&arg); - } - } - if (!got_int && do_current && do_buffer(command, DOBUF_FIRST, - FORWARD, do_current, forceit) == OK) - ++deleted; - - if (deleted == 0) - { - if (command == DOBUF_UNLOAD) - STRCPY(IObuff, _("E515: No buffers were unloaded")); - else if (command == DOBUF_DEL) - STRCPY(IObuff, _("E516: No buffers were deleted")); - else - STRCPY(IObuff, _("E517: No buffers were wiped out")); - errormsg = (char *)IObuff; - } - else if (deleted >= p_report) - { - if (command == DOBUF_UNLOAD) - smsg(NGETTEXT("%d buffer unloaded", - "%d buffers unloaded", deleted), deleted); - else if (command == DOBUF_DEL) - smsg(NGETTEXT("%d buffer deleted", - "%d buffers deleted", deleted), deleted); - else - smsg(NGETTEXT("%d buffer wiped out", - "%d buffers wiped out", deleted), deleted); - } - } - - - return errormsg; -} - /* * Make the current buffer empty. * Used when it is wiped out and it's the last buffer. @@ -1354,13 +1238,13 @@ empty_curbuf( * * Return FAIL or OK. */ - int -do_buffer( + static int +do_buffer_ext( int action, int start, int dir, // FORWARD or BACKWARD int count, // buffer number or number of buffers - int forceit) // TRUE for :...! + int flags) // DOBUF_FORCEIT etc. { buf_T *buf; buf_T *bp; @@ -1446,6 +1330,14 @@ do_buffer( emsg(_("E88: Cannot go before first buffer")); return FAIL; } +#ifdef FEAT_PROP_POPUP + if ((flags & DOBUF_NOPOPUP) && bt_popup(buf) +# ifdef FEAT_TERMINAL + && !bt_terminal(buf) +#endif + ) + return OK; +#endif #ifdef FEAT_GUI need_mouse_correct = TRUE; @@ -1470,7 +1362,7 @@ do_buffer( && buf->b_ml.ml_mfp == NULL && !buf->b_p_bl) return FAIL; - if (!forceit && bufIsChanged(buf)) + if ((flags & DOBUF_FORCEIT) == 0 && bufIsChanged(buf)) { #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) @@ -1506,7 +1398,7 @@ do_buffer( if (bp->b_p_bl && bp != buf) break; if (bp == NULL && buf == curbuf) - return empty_curbuf(TRUE, forceit, action); + return empty_curbuf(TRUE, (flags & DOBUF_FORCEIT), action); /* * If the deleted buffer is the current one, close the current window @@ -1633,7 +1525,7 @@ do_buffer( { // Autocommands must have wiped out all other buffers. Only option // now is to make the current buffer empty. - return empty_curbuf(FALSE, forceit, action); + return empty_curbuf(FALSE, (flags & DOBUF_FORCEIT), action); } /* @@ -1660,7 +1552,7 @@ do_buffer( /* * Check if the current buffer may be abandoned. */ - if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit)) + if (action == DOBUF_GOTO && !can_abandon(curbuf, (flags & DOBUF_FORCEIT))) { #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write) @@ -1695,6 +1587,134 @@ do_buffer( return OK; } + int +do_buffer( + int action, + int start, + int dir, // FORWARD or BACKWARD + int count, // buffer number or number of buffers + int forceit) // TRUE when using ! +{ + return do_buffer_ext(action, start, dir, count, + forceit ? DOBUF_FORCEIT : 0); +} + +/* + * do_bufdel() - delete or unload buffer(s) + * + * addr_count == 0: ":bdel" - delete current buffer + * addr_count == 1: ":N bdel" or ":bdel N [N ..]" - first delete + * buffer "end_bnr", then any other arguments. + * addr_count == 2: ":N,N bdel" - delete buffers in range + * + * command can be DOBUF_UNLOAD (":bunload"), DOBUF_WIPE (":bwipeout") or + * DOBUF_DEL (":bdel") + * + * Returns error message or NULL + */ + char * +do_bufdel( + int command, + char_u *arg, // pointer to extra arguments + int addr_count, + int start_bnr, // first buffer number in a range + int end_bnr, // buffer nr or last buffer nr in a range + int forceit) +{ + int do_current = 0; // delete current buffer? + int deleted = 0; // number of buffers deleted + char *errormsg = NULL; // return value + int bnr; // buffer number + char_u *p; + + if (addr_count == 0) + { + (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit); + } + else + { + if (addr_count == 2) + { + if (*arg) // both range and argument is not allowed + return ex_errmsg(e_trailing_arg, arg); + bnr = start_bnr; + } + else // addr_count == 1 + bnr = end_bnr; + + for ( ;!got_int; ui_breakcheck()) + { + /* + * Delete the current buffer last, otherwise when the + * current buffer is deleted, the next buffer becomes + * the current one and will be loaded, which may then + * also be deleted, etc. + */ + if (bnr == curbuf->b_fnum) + do_current = bnr; + else if (do_buffer_ext(command, DOBUF_FIRST, FORWARD, (int)bnr, + DOBUF_NOPOPUP | (forceit ? DOBUF_FORCEIT : 0)) == OK) + ++deleted; + + /* + * find next buffer number to delete/unload + */ + if (addr_count == 2) + { + if (++bnr > end_bnr) + break; + } + else // addr_count == 1 + { + arg = skipwhite(arg); + if (*arg == NUL) + break; + if (!VIM_ISDIGIT(*arg)) + { + p = skiptowhite_esc(arg); + bnr = buflist_findpat(arg, p, + command == DOBUF_WIPE || command == DOBUF_WIPE_REUSE, + FALSE, FALSE); + if (bnr < 0) // failed + break; + arg = p; + } + else + bnr = getdigits(&arg); + } + } + if (!got_int && do_current && do_buffer(command, DOBUF_FIRST, + FORWARD, do_current, forceit) == OK) + ++deleted; + + if (deleted == 0) + { + if (command == DOBUF_UNLOAD) + STRCPY(IObuff, _("E515: No buffers were unloaded")); + else if (command == DOBUF_DEL) + STRCPY(IObuff, _("E516: No buffers were deleted")); + else + STRCPY(IObuff, _("E517: No buffers were wiped out")); + errormsg = (char *)IObuff; + } + else if (deleted >= p_report) + { + if (command == DOBUF_UNLOAD) + smsg(NGETTEXT("%d buffer unloaded", + "%d buffers unloaded", deleted), deleted); + else if (command == DOBUF_DEL) + smsg(NGETTEXT("%d buffer deleted", + "%d buffers deleted", deleted), deleted); + else + smsg(NGETTEXT("%d buffer wiped out", + "%d buffers wiped out", deleted), deleted); + } + } + + + return errormsg; +} + /* * Set current buffer to "buf". Executes autocommands and closes current * buffer. "action" tells how to close the current buffer: diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index 13957e57c4..faadfe2777 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -3918,5 +3918,11 @@ func Test_popup_prop_not_visible() call delete('XtestPropNotVisble') endfunction +func Test_bufdel_skips_popupwin_buffer() + let id = popup_create("Some text", {}) + %bd + call popup_close(id) +endfunc + " vim: shiftwidth=2 sts=2 diff --git a/src/version.c b/src/version.c index fb6d550ea7..af6c11c03a 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2972, /**/ 2971, /**/ diff --git a/src/vim.h b/src/vim.h index 61afe97309..e1e68f9650 100644 --- a/src/vim.h +++ b/src/vim.h @@ -994,6 +994,10 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); #define DOBUF_LAST 2 // "count" buffer from last buffer #define DOBUF_MOD 3 // "count" mod. buffer from current buffer +// Values for flags argument of do_buffer() +#define DOBUF_FORCEIT 1 // :cmd! +#define DOBUF_NOPOPUP 2 // skip popup window buffers + // Values for sub_cmd and which_pat argument for search_regcomp() // Also used for which_pat argument for searchit() #define RE_SEARCH 0 // save/use pat in/from search_pattern From 3044324e8dccd470bd854cf7d9457232cc9c220e Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Thu, 10 Jun 2021 21:52:15 +0200 Subject: [PATCH 12/49] patch 8.2.2973: fix for recovery and diff mode not tested Problem: Fix for recovery and diff mode not tested. Solution: Add a few more tests. (Yegappan Lakshmanan, closes #8352) --- src/testdir/test_diffmode.vim | 119 ++++++++++++++++++++++++++++- src/testdir/test_prompt_buffer.vim | 2 + src/testdir/test_recover.vim | 44 +++++++++++ src/version.c | 2 + 4 files changed, 166 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_diffmode.vim b/src/testdir/test_diffmode.vim index 96a8d2c069..4a54f8c84c 100644 --- a/src/testdir/test_diffmode.vim +++ b/src/testdir/test_diffmode.vim @@ -243,6 +243,36 @@ func Test_diffput_two() bwipe! b endfunc +" Test for :diffget/:diffput with a range that is inside a diff chunk +func Test_diffget_diffput_range() + call setline(1, range(1, 10)) + new + call setline(1, range(11, 20)) + windo diffthis + 3,5diffget + call assert_equal(['13', '14', '15'], getline(3, 5)) + call setline(1, range(1, 10)) + 4,8diffput + wincmd p + call assert_equal(['13', '4', '5', '6', '7', '8', '19'], getline(3, 9)) + %bw! +endfunc + +" Test for :diffget/:diffput with an empty buffer and a non-empty buffer +func Test_diffget_diffput_empty_buffer() + %d _ + new + call setline(1, 'one') + windo diffthis + diffget + call assert_equal(['one'], getline(1, '$')) + %d _ + diffput + wincmd p + call assert_equal([''], getline(1, '$')) + %bw! +endfunc + " :diffput and :diffget completes names of buffers which " are in diff mode and which are different then current buffer. " No completion when the current window is not in diff mode. @@ -329,7 +359,7 @@ func Test_dp_do_buffer() call assert_equal('10', getline('.')) 21 call assert_equal('two', getline('.')) - diffget one + diffget one call assert_equal('20', getline('.')) 31 @@ -645,7 +675,11 @@ func Test_diffexpr() call assert_equal(normattr, screenattr(1, 1)) call assert_equal(normattr, screenattr(2, 1)) call assert_notequal(normattr, screenattr(3, 1)) + diffoff! + " Try using an non-existing function for 'diffexpr'. + set diffexpr=NewDiffFunc() + call assert_fails('windo diffthis', ['E117:', 'E97:']) diffoff! %bwipe! set diffexpr& diffopt& @@ -1220,5 +1254,88 @@ func Test_diff_filler_cursorcolumn() call delete('Xtest_diff_cuc') endfunc +" Test for adding/removing lines inside diff chunks, between diff chunks +" and before diff chunks +func Test_diff_modify_chunks() + enew! + let w2_id = win_getid() + call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']) + new + let w1_id = win_getid() + call setline(1, ['a', '2', '3', 'd', 'e', 'f', '7', '8', 'i']) + windo diffthis + + " remove a line between two diff chunks and create a new diff chunk + call win_gotoid(w2_id) + 5d + call win_gotoid(w1_id) + call diff_hlID(5, 1)->synIDattr('name')->assert_equal('DiffAdd') + + " add a line between two diff chunks + call win_gotoid(w2_id) + normal! 4Goe + call win_gotoid(w1_id) + call diff_hlID(4, 1)->synIDattr('name')->assert_equal('') + call diff_hlID(5, 1)->synIDattr('name')->assert_equal('') + + " remove all the lines in a diff chunk. + call win_gotoid(w2_id) + 7,8d + call win_gotoid(w1_id) + let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', 'DiffText', 'DiffText', '', '', '', 'DiffAdd', + \ 'DiffAdd', ''], hl) + + " remove lines from one diff chunk to just before the next diff chunk + call win_gotoid(w2_id) + call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']) + 2,6d + call win_gotoid(w1_id) + let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', 'DiffText', 'DiffText', 'DiffAdd', 'DiffAdd', + \ 'DiffAdd', 'DiffAdd', 'DiffAdd', ''], hl) + + " remove lines just before the top of a diff chunk + call win_gotoid(w2_id) + call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']) + 5,6d + call win_gotoid(w1_id) + let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', 'DiffText', 'DiffText', '', 'DiffText', 'DiffText', + \ 'DiffAdd', 'DiffAdd', ''], hl) + + " remove line after the end of a diff chunk + call win_gotoid(w2_id) + call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']) + 4d + call win_gotoid(w1_id) + let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', 'DiffText', 'DiffText', 'DiffAdd', '', '', 'DiffText', + \ 'DiffText', ''], hl) + + " remove lines starting from the end of one diff chunk and ending inside + " another diff chunk + call win_gotoid(w2_id) + call setline(1, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']) + 4,7d + call win_gotoid(w1_id) + let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', 'DiffText', 'DiffText', 'DiffText', 'DiffAdd', + \ 'DiffAdd', 'DiffAdd', 'DiffAdd', ''], hl) + + " removing the only remaining diff chunk should make the files equal + call win_gotoid(w2_id) + call setline(1, ['a', '2', '3', 'x', 'd', 'e', 'f', 'x', '7', '8', 'i']) + 8d + let hl = range(1, 10)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', '', '', 'DiffAdd', '', '', '', '', '', ''], hl) + call win_gotoid(w2_id) + 4d + call win_gotoid(w1_id) + let hl = range(1, 9)->map({_, lnum -> diff_hlID(lnum, 1)->synIDattr('name')}) + call assert_equal(['', '', '', '', '', '', '', '', ''], hl) + + %bw! +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_prompt_buffer.vim b/src/testdir/test_prompt_buffer.vim index 2a1ae67f57..32ed21e640 100644 --- a/src/testdir/test_prompt_buffer.vim +++ b/src/testdir/test_prompt_buffer.vim @@ -150,6 +150,8 @@ func Test_prompt_buffer_edit() call assert_beeps('normal! S') call assert_beeps("normal! \") call assert_beeps("normal! \") + call assert_beeps("normal! dp") + call assert_beeps("normal! do") " pressing CTRL-W in the prompt buffer should trigger the window commands call assert_equal(1, winnr()) exe "normal A\\" diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index 63225f31d9..0df2082e33 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -390,4 +390,48 @@ func Test_recover_symbolic_link() call delete('.Xfile1.swp') endfunc +" Test for recovering a file when an autocmd moves the cursor to an invalid +" line. This used to result in an internal error (E315) which is fixed +" by 8.2.2966. +func Test_recover_invalid_cursor_pos() + call writefile([], 'Xfile1') + edit Xfile1 + preserve + let b = readblob('.Xfile1.swp') + bw! + augroup Test + au! + au BufReadPost Xfile1 normal! 3G + augroup END + call writefile(range(1, 3), 'Xfile1') + call writefile(b, '.Xfile1.swp') + try + recover Xfile1 + catch /E308:/ + " this test is for the :E315 internal error. + " ignore the 'E308: Original file may have been changed' error + endtry + redraw! + augroup Test + au! + augroup END + augroup! Test + call delete('Xfile1') + call delete('.Xfile1.swp') +endfunc + +" Test for recovering a buffer without a name +func Test_noname_buffer() + new + call setline(1, ['one', 'two']) + preserve + let sn = swapname('') + let b = readblob(sn) + bw! + call writefile(b, sn) + exe "recover " .. sn + call assert_equal(['one', 'two'], getline(1, '$')) + call delete(sn) +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index af6c11c03a..25f2d156dc 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2973, /**/ 2972, /**/ From 4f135275984722c1b1e9ace72eeeb7ce7e4ec983 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 11 Jun 2021 19:07:40 +0200 Subject: [PATCH 13/49] patch 8.2.2974: Greek spell checking uses wrong case folding Problem: Greek spell checking uses wrong case folding. Solution: Fold capital sigma depending on whether it is at the end of a word or not. (closes #299) --- src/proto/spell.pro | 2 +- src/spell.c | 27 ++++++++++++++++++++++----- src/spellfile.c | 6 +++--- src/spellsuggest.c | 7 ++++--- src/version.c | 2 ++ 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/proto/spell.pro b/src/proto/spell.pro index 6b1f84bc38..3f97008a3e 100644 --- a/src/proto/spell.pro +++ b/src/proto/spell.pro @@ -27,7 +27,7 @@ void clear_spell_chartab(spelltab_T *sp); void init_spell_chartab(void); int spell_iswordp(char_u *p, win_T *wp); int spell_iswordp_nmw(char_u *p, win_T *wp); -int spell_casefold(char_u *str, int len, char_u *buf, int buflen); +int spell_casefold(win_T *wp, char_u *str, int len, char_u *buf, int buflen); int check_need_cap(linenr_T lnum, colnr_T col); void ex_spellrepall(exarg_T *eap); void onecap_copy(char_u *word, char_u *wcopy, int upper); diff --git a/src/spell.c b/src/spell.c index d43056660e..0b693c7d7b 100644 --- a/src/spell.c +++ b/src/spell.c @@ -249,7 +249,7 @@ spell_check( if (*mi.mi_fend != NUL) MB_PTR_ADV(mi.mi_fend); - (void)spell_casefold(ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, + (void)spell_casefold(wp, ptr, (int)(mi.mi_fend - ptr), mi.mi_fword, MAXWLEN + 1); mi.mi_fwordlen = (int)STRLEN(mi.mi_fword); @@ -736,7 +736,8 @@ find_word(matchinf_T *mip, int mode) { // "fword" is only needed for checking syllables. if (ptr == mip->mi_word) - (void)spell_casefold(ptr, wlen, fword, MAXWLEN); + (void)spell_casefold(mip->mi_win, + ptr, wlen, fword, MAXWLEN); else vim_strncpy(fword, ptr, endlen[endidxcnt]); } @@ -1213,7 +1214,7 @@ fold_more(matchinf_T *mip) if (*mip->mi_fend != NUL) MB_PTR_ADV(mip->mi_fend); - (void)spell_casefold(p, (int)(mip->mi_fend - p), + (void)spell_casefold(mip->mi_win, p, (int)(mip->mi_fend - p), mip->mi_fword + mip->mi_fwordlen, MAXWLEN - mip->mi_fwordlen); flen = (int)STRLEN(mip->mi_fword + mip->mi_fwordlen); @@ -2737,6 +2738,7 @@ spell_iswordp_w(int *p, win_T *wp) */ int spell_casefold( + win_T *wp, char_u *str, int len, char_u *buf, @@ -2765,7 +2767,21 @@ spell_casefold( return FAIL; } c = mb_cptr2char_adv(&p); - outi += mb_char2bytes(SPELL_TOFOLD(c), buf + outi); + + // Exception: greek capital sigma 0x03A3 folds to 0x03C3, except + // when it is the last character in a word, then it folds to + // 0x03C2. + if (c == 0x03a3 || c == 0x03c2) + { + if (p == str + len || !spell_iswordp(p, wp)) + c = 0x03c2; + else + c = 0x03c3; + } + else + c = SPELL_TOFOLD(c); + + outi += mb_char2bytes(c, buf + outi); } buf[outi] = NUL; } @@ -3097,7 +3113,8 @@ spell_soundfold( word = inword; else { - (void)spell_casefold(inword, (int)STRLEN(inword), fword, MAXWLEN); + (void)spell_casefold(curwin, + inword, (int)STRLEN(inword), fword, MAXWLEN); word = fword; } diff --git a/src/spellfile.c b/src/spellfile.c index 20181695a2..264264c621 100644 --- a/src/spellfile.c +++ b/src/spellfile.c @@ -3429,9 +3429,9 @@ add_fromto( if (ga_grow(gap, 1) == OK) { ftp = ((fromto_T *)gap->ga_data) + gap->ga_len; - (void)spell_casefold(from, (int)STRLEN(from), word, MAXWLEN); + (void)spell_casefold(curwin, from, (int)STRLEN(from), word, MAXWLEN); ftp->ft_from = getroom_save(spin, word); - (void)spell_casefold(to, (int)STRLEN(to), word, MAXWLEN); + (void)spell_casefold(curwin, to, (int)STRLEN(to), word, MAXWLEN); ftp->ft_to = getroom_save(spin, word); ++gap->ga_len; } @@ -4391,7 +4391,7 @@ store_word( int res = OK; char_u *p; - (void)spell_casefold(word, len, foldword, MAXWLEN); + (void)spell_casefold(curwin, word, len, foldword, MAXWLEN); for (p = pfxlist; res == OK; ++p) { if (!need_affix || (p != NULL && *p != NUL)) diff --git a/src/spellsuggest.c b/src/spellsuggest.c index 3de9ff2112..2951eea2ea 100644 --- a/src/spellsuggest.c +++ b/src/spellsuggest.c @@ -791,7 +791,7 @@ spell_find_suggest( if (su->su_badlen >= MAXWLEN) su->su_badlen = MAXWLEN - 1; // just in case vim_strncpy(su->su_badword, su->su_badptr, su->su_badlen); - (void)spell_casefold(su->su_badptr, su->su_badlen, + (void)spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword, MAXWLEN); // TODO: make this work if the case-folded text is longer than the original // text. Currently an illegal byte causes wrong pointer computations. @@ -1176,7 +1176,7 @@ suggest_try_change(suginfo_T *su) STRCPY(fword, su->su_fbadword); n = (int)STRLEN(fword); p = su->su_badptr + su->su_badlen; - (void)spell_casefold(p, (int)STRLEN(p), fword + n, MAXWLEN - n); + (void)spell_casefold(curwin, p, (int)STRLEN(p), fword + n, MAXWLEN - n); for (lpi = 0; lpi < curwin->w_s->b_langp.ga_len; ++lpi) { @@ -3005,7 +3005,8 @@ stp_sal_score( else { // soundfold the bad word with more characters following - (void)spell_casefold(su->su_badptr, stp->st_orglen, fword, MAXWLEN); + (void)spell_casefold(curwin, + su->su_badptr, stp->st_orglen, fword, MAXWLEN); // When joining two words the sound often changes a lot. E.g., "t he" // sounds like "t h" while "the" sounds like "@". Avoid that by diff --git a/src/version.c b/src/version.c index 25f2d156dc..99a635b469 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2974, /**/ 2973, /**/ From f0a4069e3df904ac6bd57718ec06e56c5d7363e4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 11 Jun 2021 22:05:47 +0200 Subject: [PATCH 14/49] patch 8.2.2975: Vim9: can only use an autoload function name as a string Problem: Vim9: can only use an autoload function name as a string. Solution: Load the autoload script when encountered. (closes #8124) --- src/evalvars.c | 5 +++-- src/scriptfile.c | 3 +++ src/testdir/test_vim9_func.vim | 28 ++++++++++++++++++++++++++++ src/version.c | 2 ++ src/vim9compile.c | 8 +++++++- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/evalvars.c b/src/evalvars.c index 7581a14177..cd1f1702ff 100644 --- a/src/evalvars.c +++ b/src/evalvars.c @@ -2921,8 +2921,9 @@ find_var_ht(char_u *name, char_u **varname) if (ht != NULL) return ht; // local variable - // in Vim9 script items at the script level are script-local - if (in_vim9script()) + // In Vim9 script items at the script level are script-local, except + // for autoload names. + if (in_vim9script() && vim_strchr(name, AUTOLOAD_CHAR) == NULL) { ht = get_script_local_ht(); if (ht != NULL) diff --git a/src/scriptfile.c b/src/scriptfile.c index bbc415664e..eefe39a139 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1128,6 +1128,7 @@ do_source( proftime_T wait_start; #endif int trigger_source_post = FALSE; + int save_estack_compiling = estack_compiling; ESTACK_CHECK_DECLARATION p = expand_env_save(fname); @@ -1142,6 +1143,7 @@ do_source( smsg(_("Cannot source a directory: \"%s\""), fname); goto theend; } + estack_compiling = FALSE; #ifdef FEAT_EVAL // See if we loaded this script before. @@ -1508,6 +1510,7 @@ almosttheend: theend: vim_free(fname_exp); + estack_compiling = save_estack_compiling; return retval; } diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 8d891d2b1f..96e144f5dc 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -114,6 +114,34 @@ def Test_autoload_name_mismatch() delete(dir, 'rf') enddef +def Test_autoload_names() + var dir = 'Xdir/autoload' + mkdir(dir, 'p') + + var lines =<< trim END + func foobar#function() + return 'yes' + endfunc + let foobar#var = 'no' + END + writefile(lines, dir .. '/foobar.vim') + + var save_rtp = &rtp + exe 'set rtp=' .. getcwd() .. '/Xdir' + + lines =<< trim END + assert_equal('yes', foobar#function()) + var Function = foobar#function + assert_equal('yes', Function()) + + assert_equal('no', foobar#var) + END + CheckDefAndScriptSuccess(lines) + + &rtp = save_rtp + delete(dir, 'rf') +enddef + def CallRecursive(n: number): number return CallRecursive(n + 1) enddef diff --git a/src/version.c b/src/version.c index 99a635b469..0a113f4326 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2975, /**/ 2974, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 6fcad3db44..44c082d415 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3084,7 +3084,13 @@ compile_load( if (name == NULL) return FAIL; - if (arg_exists(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK) + if (vim_strchr(name, AUTOLOAD_CHAR) != NULL) + { + script_autoload(name, FALSE); + res = generate_LOAD(cctx, ISN_LOADAUTO, 0, name, &t_any); + } + else if (arg_exists(*arg, len, &idx, &type, &gen_load_outer, cctx) + == OK) { if (gen_load_outer == 0) gen_load = TRUE; From 8de901e1f1b051e02a61ae76ad7c925e4c0642e5 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 11 Jun 2021 22:21:24 +0200 Subject: [PATCH 15/49] patch 8.2.2976: build failure without the +eval feature Problem: Build failure without the +eval feature. Solution: Add #ifdefs. --- src/scriptfile.c | 6 ++++-- src/version.c | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/scriptfile.c b/src/scriptfile.c index eefe39a139..587aa29a0d 100644 --- a/src/scriptfile.c +++ b/src/scriptfile.c @@ -1119,6 +1119,7 @@ do_source( int save_debug_break_level = debug_break_level; int sid; scriptitem_T *si = NULL; + int save_estack_compiling = estack_compiling; #endif #ifdef STARTUPTIME struct timeval tv_rel; @@ -1128,7 +1129,6 @@ do_source( proftime_T wait_start; #endif int trigger_source_post = FALSE; - int save_estack_compiling = estack_compiling; ESTACK_CHECK_DECLARATION p = expand_env_save(fname); @@ -1143,9 +1143,9 @@ do_source( smsg(_("Cannot source a directory: \"%s\""), fname); goto theend; } +#ifdef FEAT_EVAL estack_compiling = FALSE; -#ifdef FEAT_EVAL // See if we loaded this script before. for (sid = script_items.ga_len; sid > 0; --sid) { @@ -1510,7 +1510,9 @@ almosttheend: theend: vim_free(fname_exp); +#ifdef FEAT_EVAL estack_compiling = save_estack_compiling; +#endif return retval; } diff --git a/src/version.c b/src/version.c index 0a113f4326..08f06cf4dc 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2976, /**/ 2975, /**/ From 22db0d549f64aa3d8a6e366b70eb8d7e66933b82 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 12:16:55 +0200 Subject: [PATCH 16/49] patch 8.2.2977: crash when using a null function reference Problem: Crash when using a null function reference. (Naohiro Ono) Solution: Check for an invalid function name. (closes #8367) --- src/errors.h | 2 ++ src/eval.c | 8 ++++++++ src/testdir/test_functions.vim | 4 +++- src/version.c | 2 ++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/errors.h b/src/errors.h index fac3e26d8b..63e2659f73 100644 --- a/src/errors.h +++ b/src/errors.h @@ -425,3 +425,5 @@ EXTERN char e_nr_arguments_too_few[] INIT(= N_("E1190: %d arguments too few")); EXTERN char e_call_to_function_that_failed_to_compile_str[] INIT(= N_("E1191: Call to function that failed to compile: %s")); +EXTERN char e_empty_function_name[] + INIT(= N_("E1192: Empty function name")); diff --git a/src/eval.c b/src/eval.c index b6bee5af50..0d15a70e2b 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3772,7 +3772,14 @@ call_func_rettv( s = partial_name(pt); } else + { s = functv.vval.v_string; + if (s == NULL || *s == NUL) + { + emsg(_(e_empty_function_name)); + goto theend; + } + } } else s = (char_u *)""; @@ -3786,6 +3793,7 @@ call_func_rettv( funcexe.basetv = basetv; ret = get_func_tv(s, -1, rettv, arg, evalarg, &funcexe); +theend: // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). if (evaluate) diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index 1309554395..d63bec498e 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2174,9 +2174,11 @@ func Test_call() call assert_fails("call call('Mylen', [], 0)", 'E715:') call assert_fails('call foo', 'E107:') - " This once caused a crash. + " These once caused a crash. call call(test_null_function(), []) call call(test_null_partial(), []) + call assert_fails('call test_null_function()()', 'E1192:') + call assert_fails('call test_null_partial()()', 'E117:') endfunc func Test_char2nr() diff --git a/src/version.c b/src/version.c index 08f06cf4dc..19a159d7ed 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2977, /**/ 2976, /**/ From 744aecf8777e86fac6d30f072e90e2de353b8ea1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 12:33:48 +0200 Subject: [PATCH 17/49] patch 8.2.2978: warning for uninitialized variable Problem: Warning for uninitialized variable. Solution: Set return value to FAIL. --- src/eval.c | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/eval.c b/src/eval.c index 0d15a70e2b..ca181d524f 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3777,6 +3777,7 @@ call_func_rettv( if (s == NULL || *s == NUL) { emsg(_(e_empty_function_name)); + ret = FAIL; goto theend; } } diff --git a/src/version.c b/src/version.c index 19a159d7ed..6ae66ae28a 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2978, /**/ 2977, /**/ From 5958549760652c173b703613b9cbf09b25a4eddb Mon Sep 17 00:00:00 2001 From: Yegappan Lakshmanan Date: Sat, 12 Jun 2021 13:46:41 +0200 Subject: [PATCH 18/49] patch 8.2.2979: not all options code is covered by tests Problem: Not all options code is covered by tests. Solution: Add more tests for options. (Yegappan Lakshmanan, closes #8369) --- src/testdir/test_edit.vim | 24 ++++++++++++++++++++++++ src/testdir/test_excmd.vim | 6 ++++++ src/testdir/test_help.vim | 10 ++++++++++ src/testdir/test_mksession.vim | 13 +++++++++++++ src/testdir/test_options.vim | 31 +++++++++++++++++++++++++++++++ src/testdir/test_vartabs.vim | 13 +++++++++++++ src/testdir/test_window_cmd.vim | 10 +++++++++- src/version.c | 2 ++ 8 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/testdir/test_edit.vim b/src/testdir/test_edit.vim index 39cb6aa350..3fcc11f2d8 100644 --- a/src/testdir/test_edit.vim +++ b/src/testdir/test_edit.vim @@ -1871,4 +1871,28 @@ func Test_read_invalid() set encoding=utf-8 endfunc +" Test for the 'revins' option +func Test_edit_revins() + CheckFeature rightleft + new + set revins + exe "normal! ione\ttwo three" + call assert_equal("eerht owt\teno", getline(1)) + call setline(1, "one\ttwo three") + normal! gg$bi a + call assert_equal("one\ttwo a three", getline(1)) + exe "normal! $bi\\" + call assert_equal("one\ttwo a ree", getline(1)) + exe "normal! 0wi\" + call assert_equal("one\t a ree", getline(1)) + exe "normal! 0wi\" + call assert_equal("one\t ", getline(1)) + " newline in insert mode starts at the end of the line + call setline(1, 'one two three') + exe "normal! wi\nfour" + call assert_equal(['one two three', 'ruof'], getline(1, '$')) + set revins& + bw! +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_excmd.vim b/src/testdir/test_excmd.vim index 60753a6e82..de82b5b77e 100644 --- a/src/testdir/test_excmd.vim +++ b/src/testdir/test_excmd.vim @@ -593,6 +593,12 @@ func Sandbox_tests() if has('unix') call assert_fails('cd `pwd`', 'E48:') endif + " some options cannot be changed in a sandbox + call assert_fails('set exrc', 'E48:') + call assert_fails('set cdpath', 'E48:') + if has('xim') + call assert_fails('set imstyle', 'E48:') + endif endfunc func Test_sandbox() diff --git a/src/testdir/test_help.vim b/src/testdir/test_help.vim index ff2bc41b7a..15cc642d17 100644 --- a/src/testdir/test_help.vim +++ b/src/testdir/test_help.vim @@ -123,5 +123,15 @@ func Test_helptag_cmd_readonly() call delete('Xdir', 'rf') endfunc +" Test for setting the 'helpheight' option in the help window +func Test_help_window_height() + let &cmdheight = &lines - 24 + set helpheight=10 + help + set helpheight=14 + call assert_equal(14, winheight(0)) + set helpheight& cmdheight=1 + close +endfunc " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_mksession.vim b/src/testdir/test_mksession.vim index 66e6e292ac..a0a2cb461e 100644 --- a/src/testdir/test_mksession.vim +++ b/src/testdir/test_mksession.vim @@ -1019,6 +1019,19 @@ func Test_mkvimrc() endfor call s:ClearMappings() + + " the 'pastetoggle', 'wildchar' and 'wildcharm' option values should be + " stored as key names in the vimrc file + set pastetoggle= + set wildchar= + set wildcharm= + call assert_fails('mkvimrc Xtestvimrc') + mkvimrc! Xtestvimrc + call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set pastetoggle=')) + call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set wildchar=')) + call assert_notequal(-1, index(readfile('Xtestvimrc'), 'set wildcharm=')) + set pastetoggle& wildchar& wildcharm& + call delete('Xtestvimrc') endfunc diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim index d789a461ea..d640426453 100644 --- a/src/testdir/test_options.vim +++ b/src/testdir/test_options.vim @@ -434,6 +434,7 @@ func Test_set_errors() set nomodifiable call assert_fails('set fileencoding=latin1', 'E21:') set modifiable& + call assert_fails('set t_#-&', 'E522:') endfunc func CheckWasSet(name) @@ -946,6 +947,18 @@ func Test_opt_local_to_global() call assert_equal('gnewprg', &l:equalprg) call assert_equal('gnewprg', &equalprg) set equalprg& + + " Test for setting the global/local value of a boolean option + setglobal autoread + setlocal noautoread + call assert_false(&autoread) + set autoread< + call assert_true(&autoread) + setglobal noautoread + setlocal autoread + setlocal autoread< + call assert_false(&autoread) + set autoread& endfunc " Test for incrementing, decrementing and multiplying a number option value @@ -1121,4 +1134,22 @@ func Test_VIM_POSIX() call setenv('VIM_POSIX', saved_VIM_POSIX) endfunc +" Test for setting an option to a Vi or Vim default +func Test_opt_default() + set formatoptions&vi + call assert_equal('vt', &formatoptions) + set formatoptions&vim + call assert_equal('tcq', &formatoptions) +endfunc + +" Test for the 'cmdheight' option +func Test_cmdheight() + %bw! + let ht = &lines + set cmdheight=9999 + call assert_equal(1, winheight(0)) + call assert_equal(ht - 1, &cmdheight) + set cmdheight& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_vartabs.vim b/src/testdir/test_vartabs.vim index 0ff1ea8ac9..3b8a9ce0b1 100644 --- a/src/testdir/test_vartabs.vim +++ b/src/testdir/test_vartabs.vim @@ -419,4 +419,17 @@ func Test_varsofttabstop() close! endfunc +" Setting 'shiftwidth' to a negative value, should set it to either the value +" of 'tabstop' (if 'vartabstop' is not set) or to the first value in +" 'vartabstop' +func Test_shiftwidth_vartabstop() + setlocal tabstop=7 vartabstop= + call assert_fails('set shiftwidth=-1', 'E487:') + call assert_equal(7, &shiftwidth) + setlocal tabstop=7 vartabstop=5,7,10 + call assert_fails('set shiftwidth=-1', 'E487:') + call assert_equal(5, &shiftwidth) + setlocal shiftwidth& vartabstop& tabstop& +endfunc + " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/testdir/test_window_cmd.vim b/src/testdir/test_window_cmd.vim index fda34eb463..af7c63a19c 100644 --- a/src/testdir/test_window_cmd.vim +++ b/src/testdir/test_window_cmd.vim @@ -397,7 +397,15 @@ func Test_window_width() call assert_inrange(ww1, ww1 + 1, ww2) call assert_inrange(ww3, ww3 + 1, ww2) - bw Xa Xb Xc + " when the current window width is less than the new 'winwidth', the current + " window width should be increased. + enew | only + split + 10vnew + set winwidth=15 + call assert_equal(15, winwidth(0)) + + %bw! endfunc func Test_equalalways_on_close() diff --git a/src/version.c b/src/version.c index 6ae66ae28a..d55ab1a244 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2979, /**/ 2978, /**/ From 0b71955552c4b18f1853c1769ca64d696f8b60c1 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 13:59:03 +0200 Subject: [PATCH 19/49] patch 8.2.2980: popup window test is a bit flaky Problem: Popup window test is a bit flaky. Solution: Add a redraw command. --- src/testdir/test_popupwin.vim | 1 + src/version.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim index faadfe2777..147a3a4ae6 100644 --- a/src/testdir/test_popupwin.vim +++ b/src/testdir/test_popupwin.vim @@ -1552,6 +1552,7 @@ func Test_popup_filter() call assert_equal(9, getcurpos()[2]) call feedkeys('0', 'xt') call assert_equal('0', g:ignored) + redraw call assert_equal(1, getcurpos()[2]) " x closes the popup diff --git a/src/version.c b/src/version.c index d55ab1a244..ac5cc997b9 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2980, /**/ 2979, /**/ From 6654ca702ca64c99965efcad3243ea5f95473252 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Sat, 12 Jun 2021 14:05:41 +0200 Subject: [PATCH 20/49] patch 8.2.2981: recovery test is not run on big-endian systems Problem: Recovery test is not run on big-endian systems. Solution: Make it work on big-endian systems. (James McCoy, closes #8368) --- src/testdir/test_recover.vim | 173 +++++++++++++++++------------------ src/version.c | 2 + 2 files changed, 88 insertions(+), 87 deletions(-) diff --git a/src/testdir/test_recover.vim b/src/testdir/test_recover.vim index 0df2082e33..2db662f017 100644 --- a/src/testdir/test_recover.vim +++ b/src/testdir/test_recover.vim @@ -198,103 +198,102 @@ func Test_recover_corrupted_swap_file() let b = readblob(sn) let save_b = copy(b) bw! - " Run these tests only on little-endian systems. These tests fail on a - " big-endian system (IBM S390x system). - if b[1008:1011] == 0z33323130 - \ && b[4096:4097] == 0z7470 - \ && b[8192:8193] == 0z6164 - " clear the B0_MAGIC_LONG field - let b[1008:1011] = 0z00000000 - call writefile(b, sn) - let msg = execute('recover Xfile1') - call assert_match('the file has been damaged', msg) - call assert_equal('Xfile1', @%) - call assert_equal([''], getline(1, '$')) - bw! + " Not all fields are written in a system-independent manner. Detect whether + " the test is running on a little or big-endian system, so the correct + " corruption values can be set. + let little_endian = b[1008:1015] == 0z33323130.00000000 - " reduce the page size - let b = copy(save_b) - let b[12:15] = 0z00010000 - call writefile(b, sn) - let msg = execute('recover Xfile1') - call assert_match('page size is smaller than minimum value', msg) - call assert_equal('Xfile1', @%) - call assert_equal([''], getline(1, '$')) - bw! + " clear the B0_MAGIC_LONG field + let b[1008:1015] = 0z0000000000000000 + call writefile(b, sn) + let msg = execute('recover Xfile1') + call assert_match('the file has been damaged', msg) + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! - " clear the pointer ID - let b = copy(save_b) - let b[4096:4097] = 0z0000 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E310:') - call assert_equal('Xfile1', @%) - call assert_equal([''], getline(1, '$')) - bw! + " reduce the page size + let b = copy(save_b) + let b[12:15] = 0z00010000 + call writefile(b, sn) + let msg = execute('recover Xfile1') + call assert_match('page size is smaller than minimum value', msg) + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! - " set the number of pointers in a pointer block to zero - let b = copy(save_b) - let b[4098:4099] = 0z0000 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['???EMPTY BLOCK'], getline(1, '$')) - bw! + " clear the pointer ID + let b = copy(save_b) + let b[4096:4097] = 0z0000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E310:') + call assert_equal('Xfile1', @%) + call assert_equal([''], getline(1, '$')) + bw! - " set the block number in a pointer entry to a negative number - let b = copy(save_b) - let b[4104:4111] = 0z00000000.00000080 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['???LINES MISSING'], getline(1, '$')) - bw! + " set the number of pointers in a pointer block to zero + let b = copy(save_b) + let b[4098:4099] = 0z0000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???EMPTY BLOCK'], getline(1, '$')) + bw! - " clear the data block ID - let b = copy(save_b) - let b[8192:8193] = 0z0000 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['???BLOCK MISSING'], getline(1, '$')) - bw! + " set the block number in a pointer entry to a negative number + let b = copy(save_b) + let b[4104:4111] = little_endian ? 0z00000000.00000080 : 0z80000000.00000000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???LINES MISSING'], getline(1, '$')) + bw! - " set the number of lines in the data block to zero - let b = copy(save_b) - let b[8208:8211] = 0z00000000 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['??? from here until ???END lines may have been inserted/deleted', - \ '???END'], getline(1, '$')) - bw! + " clear the data block ID + let b = copy(save_b) + let b[8192:8193] = 0z0000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???BLOCK MISSING'], getline(1, '$')) + bw! - " use an invalid text start for the lines in a data block - let b = copy(save_b) - let b[8216:8219] = 0z00000000 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['???'], getline(1, '$')) - bw! + " set the number of lines in the data block to zero + let b = copy(save_b) + let b[8208:8215] = 0z00000000.00000000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['??? from here until ???END lines may have been inserted/deleted', + \ '???END'], getline(1, '$')) + bw! - " use an incorrect text end (db_txt_end) for the data block - let b = copy(save_b) - let b[8204:8207] = 0z80000000 - call writefile(b, sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['??? from here until ???END lines may be messed up', '', - \ '???END'], getline(1, '$')) - bw! + " use an invalid text start for the lines in a data block + let b = copy(save_b) + let b[8216:8219] = 0z00000000 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???'], getline(1, '$')) + bw! - " remove the data block - let b = copy(save_b) - call writefile(b[:8191], sn) - call assert_fails('recover Xfile1', 'E312:') - call assert_equal('Xfile1', @%) - call assert_equal(['???MANY LINES MISSING'], getline(1, '$')) - endif + " use an incorrect text end (db_txt_end) for the data block + let b = copy(save_b) + let b[8204:8207] = little_endian ? 0z80000000 : 0z00000080 + call writefile(b, sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['??? from here until ???END lines may be messed up', '', + \ '???END'], getline(1, '$')) + bw! + + " remove the data block + let b = copy(save_b) + call writefile(b[:8191], sn) + call assert_fails('recover Xfile1', 'E312:') + call assert_equal('Xfile1', @%) + call assert_equal(['???MANY LINES MISSING'], getline(1, '$')) bw! call delete(sn) diff --git a/src/version.c b/src/version.c index ac5cc997b9..15ee76aed6 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2981, /**/ 2980, /**/ From 742357718000927d652b1a98d313a3950571c8ec Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 14:53:05 +0200 Subject: [PATCH 21/49] patch 8.2.2982: Vim9: future commands are not reserved yet Problem: Vim9: future commands are not reserved yet. Solution: Add commands to be implemented later. Make "this" a reserved name. --- runtime/doc/vim9.txt | 76 +++++++++++++++++++++++++++----- src/ex_cmdidxs.h | 60 ++++++++++++------------- src/ex_cmds.h | 12 +++++ src/testdir/test_vim9_assign.vim | 2 + src/version.c | 2 + src/vim9script.c | 1 + 6 files changed, 111 insertions(+), 42 deletions(-) diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 6c2588271c..406aedcfee 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 8.2. Last change: 2021 May 26 +*vim9.txt* For Vim version 8.2. Last change: 2021 Jun 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -169,6 +169,14 @@ created yet. In this case you can call `execute()` to invoke it at runtime. > used for the command or inside a `:try` block), does not get a range passed cannot be a "dict" function, and can always be a closure. +Later classes will be added, which replaces the "dict function" mechanism. +For now you will need to pass the dictionary explicitly: > + def DictFunc(d: dict, arg: string) + echo d[arg] + enddef + var d = {item: 'value', func: DictFunc} + d.func(d, 'item') + The argument types and return type need to be specified. The "any" type can be used, type checking will then be done at runtime, like with legacy functions. @@ -445,7 +453,7 @@ it is the start of a lambda or a dictionary, which is now more complicated because of the use of argument types. To avoid these problems Vim9 script uses a different syntax for a lambda, -which is similar to Javascript: > +which is similar to JavaScript: > var Lambda = (arg) => expression No line break is allowed in the arguments of a lambda up to and including the @@ -522,7 +530,7 @@ And when a dict spans multiple lines: > one: 1, two: 2, } -Function call: > +With a function call: > var result = Func( arg1, arg2 @@ -555,10 +563,31 @@ at the start of the line indicates line continuation: > | echo 'match' | endif +Note that this means that in heredoc the first line cannot be a bar: > + var lines =<< trim END + | this doesn't work + END +Either use an empty line at the start or do not use heredoc. Or temporarily +add the "C" flag to 'cpoptions': > + set cpo+=C + var lines =<< trim END + | this doesn't work + END + set cpo-=C +If the heredoc is inside a function 'cpoptions' must be set before :def and +restored after the :enddef. + +In places where line continuation with a backslash is still needed, such as +splitting up a long Ex command, comments can start with #\ instead of "\: > + syn region Text + \ start='foo' + #\ comment + \ end='bar' + < *E1050* To make it possible for the operator at the start of the line to be -recognized, it is required to put a colon before a range. This will add -"start" and print: > +recognized, it is required to put a colon before a range. This example will +add "start" and print: > var result = start + print Like this: > @@ -610,6 +639,9 @@ Notes: < This does not work: > echo [1, 2] [3, 4] +- In some cases it is difficult for Vim to parse a command, especially when + commands are used as an argument to another command, such as `windo`. In + those cases the line continuation with a backslash has to be used. White space ~ @@ -1240,9 +1272,10 @@ Exporting an item can be written as: > export const someValue = ... export def MyFunc() ... export class MyClass ... + export interface MyClass ... As this suggests, only constants, variables, `:def` functions and classes can -be exported. {not implemented yet: export class} +be exported. {not implemented yet: class, interface} *E1042* `:export` can only be used in Vim9 script, at the script level. @@ -1342,27 +1375,46 @@ implementing classes is going to be a lot of work, it is left for the future. For now we'll just make sure classes can be added later. Thoughts: -- `class` / `endclass`, everything in one file -- Class names are always CamelCase -- Single constructor +- `class` / `endclass`, the whole class must be in one file +- Class names are always CamelCase (to avoid a name clash with builtin types) +- A single constructor called "constructor" - Single inheritance with `class ThisClass extends BaseClass` -- `abstract class` -- `interface` (Abstract class without any implementation) +- `abstract class` (class with incomplete implementation) +- `interface` / `endinterface` (abstract class without any implementation) - `class SomeClass implements SomeInterface` - Generics for class: `class ` - Generics for function: `def GetLast(key: Tkey)` -Again, much of this is from TypeScript. +Again, much of this is from TypeScript with a slightly different syntax. Some things that look like good additions: - Use a class as an interface (like Dart) - Extend a class with methods, using an import (like Dart) +- Mixins +- For testing: Mock mechanism An important class that will be provided is "Promise". Since Vim is single threaded, connecting asynchronous operations is a natural way of allowing plugins to do their work without blocking the user. It's a uniform way to invoke callbacks and handle timeouts and errors. +Some examples: > + + abstract class Person + static const prefix = 'xxx' + var name: string + + def constructor(name: string) + this.name = name; + enddef + + def display(): void + echo name + enddef + + abstract def find(string): Person + endclass + ============================================================================== 9. Rationale *vim9-rationale* diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h index 76b6dff052..3ad1cd8ecf 100644 --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -6,31 +6,31 @@ static const unsigned short cmdidxs1[26] = { /* a */ 0, - /* b */ 19, - /* c */ 43, - /* d */ 110, - /* e */ 135, - /* f */ 162, - /* g */ 179, - /* h */ 185, - /* i */ 194, - /* j */ 213, - /* k */ 215, - /* l */ 220, - /* m */ 283, - /* n */ 301, - /* o */ 321, - /* p */ 333, - /* q */ 372, - /* r */ 375, - /* s */ 395, - /* t */ 464, - /* u */ 510, - /* v */ 521, - /* w */ 542, - /* x */ 556, - /* y */ 566, - /* z */ 567 + /* b */ 20, + /* c */ 44, + /* d */ 111, + /* e */ 136, + /* f */ 164, + /* g */ 181, + /* h */ 187, + /* i */ 196, + /* j */ 216, + /* k */ 218, + /* l */ 223, + /* m */ 286, + /* n */ 304, + /* o */ 324, + /* p */ 336, + /* q */ 375, + /* r */ 378, + /* s */ 398, + /* t */ 468, + /* u */ 514, + /* v */ 525, + /* w */ 546, + /* x */ 560, + /* y */ 570, + /* z */ 571 }; /* @@ -41,15 +41,15 @@ static const unsigned short cmdidxs1[26] = */ static const unsigned char cmdidxs2[26][26] = { /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ - /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 }, + /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 7, 0, 0, 0, 8, 16, 0, 17, 0, 0, 0, 0, 0 }, /* b */ { 2, 0, 0, 5, 6, 8, 0, 0, 0, 0, 0, 9, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 23, 0, 0, 0 }, /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 38, 41, 47, 57, 59, 60, 61, 0, 63, 0, 66, 0, 0, 0 }, /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 8, 18, 0, 19, 0, 0, 20, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0 }, - /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 11, 0, 0, 0, 0, 0, 0, 0, 21, 0, 22, 0, 0 }, + /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 8, 10, 11, 0, 0, 0, 0, 0, 0, 0, 22, 0, 23, 0, 0 }, /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0 }, /* g */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 4, 5, 0, 0, 0, 0 }, /* h */ { 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 14, 0, 16, 0, 0, 0, 0, 0 }, + /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 15, 0, 17, 0, 0, 0, 0, 0 }, /* j */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, /* k */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* l */ { 3, 11, 15, 19, 20, 25, 28, 33, 0, 0, 0, 35, 38, 41, 45, 51, 0, 53, 62, 54, 55, 59, 61, 0, 0, 0 }, @@ -59,7 +59,7 @@ static const unsigned char cmdidxs2[26][26] = /* p */ { 1, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 0, 0, 16, 17, 26, 0, 27, 0, 28, 0 }, /* q */ { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* r */ { 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 19, 0, 0, 0, 0 }, - /* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 63, 64, 0, 65, 0 }, + /* s */ { 2, 6, 15, 0, 19, 23, 0, 25, 26, 0, 0, 29, 31, 35, 39, 41, 0, 50, 0, 51, 0, 64, 65, 0, 66, 0 }, /* t */ { 2, 0, 19, 0, 24, 26, 0, 27, 0, 28, 0, 29, 33, 36, 38, 39, 0, 40, 42, 0, 43, 0, 0, 0, 45, 0 }, /* u */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* v */ { 1, 0, 0, 0, 2, 0, 0, 0, 5, 0, 0, 0, 12, 15, 0, 0, 0, 0, 18, 0, 19, 0, 0, 0, 0, 0 }, @@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][26] = /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; -static const int command_count = 584; +static const int command_count = 588; diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 8a1ed5ed68..8ddac37b55 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -122,6 +122,9 @@ EXCMD(CMD_abclear, "abclear", ex_abclear, EXCMD(CMD_aboveleft, "aboveleft", ex_wrongmodifier, EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM, ADDR_NONE), +EXCMD(CMD_abstract, "abstract", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_all, "all", ex_all, EX_BANG|EX_RANGE|EX_COUNT|EX_TRLBAR, ADDR_OTHER), @@ -551,6 +554,9 @@ EXCMD(CMD_emenu, "emenu", ex_emenu, EXCMD(CMD_endif, "endif", ex_endif, EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), +EXCMD(CMD_endinterface, "endinterface", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_endclass, "endclass", ex_ni, EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), @@ -734,6 +740,9 @@ EXCMD(CMD_inoremenu, "inoremenu", ex_menu, EXCMD(CMD_intro, "intro", ex_intro, EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), +EXCMD(CMD_interface, "interface", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_isearch, "isearch", ex_findpat, EX_BANG|EX_RANGE|EX_DFLALL|EX_WHOLEFOLD|EX_EXTRA|EX_CMDWIN|EX_LOCK_OK, ADDR_LINES), @@ -1463,6 +1472,9 @@ EXCMD(CMD_startgreplace, "startgreplace", ex_startinsert, EXCMD(CMD_startreplace, "startreplace", ex_startinsert, EX_BANG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), +EXCMD(CMD_static, "static", ex_ni, + EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, + ADDR_NONE), EXCMD(CMD_stopinsert, "stopinsert", ex_stopinsert, EX_BANG|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK, ADDR_NONE), diff --git a/src/testdir/test_vim9_assign.vim b/src/testdir/test_vim9_assign.vim index b8c6433638..7b7b62305b 100644 --- a/src/testdir/test_vim9_assign.vim +++ b/src/testdir/test_vim9_assign.vim @@ -982,6 +982,8 @@ def Test_assignment_failure() CheckDefFailure(['var true = 1'], 'E1034:') CheckDefFailure(['var false = 1'], 'E1034:') + CheckDefFailure(['var null = 1'], 'E1034:') + CheckDefFailure(['var this = 1'], 'E1034:') CheckDefFailure(['[a; b; c] = g:list'], 'E452:') CheckDefExecFailure(['var a: number', diff --git a/src/version.c b/src/version.c index 15ee76aed6..17ae9a4de2 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2982, /**/ 2981, /**/ diff --git a/src/vim9script.c b/src/vim9script.c index fbb815c28e..7078cbe9cc 100644 --- a/src/vim9script.c +++ b/src/vim9script.c @@ -979,6 +979,7 @@ static char *reserved[] = { "true", "false", "null", + "this", NULL }; From a9931535387e5eb4e6ce62f2a661484de4a1757d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 15:58:16 +0200 Subject: [PATCH 22/49] patch 8.2.2983: Vim9: an inline function requires specifying the return type Problem: Vim9: an inline function requires specifying the return type. Solution: Make the return type optional. --- src/eval.c | 8 ++++++-- src/testdir/test_vim9_func.vim | 20 ++++++++++++++++++++ src/userfunc.c | 2 +- src/version.c | 2 ++ src/vim9compile.c | 15 ++++++++++++--- 5 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/eval.c b/src/eval.c index ca181d524f..8a6539e3fc 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3530,9 +3530,13 @@ eval7( { ufunc_T *ufunc = rettv->vval.v_partial->pt_func; - // compile it here to get the return type + // Compile it here to get the return type. The return + // type is optional, when it's missing use t_unknown. + // This is recognized in compile_return(). + if (ufunc->uf_ret_type->tt_type == VAR_VOID) + ufunc->uf_ret_type = &t_unknown; if (compile_def_function(ufunc, - TRUE, PROFILING(ufunc), NULL) == FAIL) + FALSE, PROFILING(ufunc), NULL) == FAIL) { clear_tv(rettv); ret = FAIL; diff --git a/src/testdir/test_vim9_func.vim b/src/testdir/test_vim9_func.vim index 96e144f5dc..925e7c82a1 100644 --- a/src/testdir/test_vim9_func.vim +++ b/src/testdir/test_vim9_func.vim @@ -948,6 +948,26 @@ def Test_lambda_return_type() echo FilterWithCond('foo', (v) => v .. '^b') END CheckDefAndScriptFailure(lines, 'E1013: Argument 2: type mismatch, expected func(string): bool but got func(any): string', 1) + + lines =<< trim END + var Lambda1 = (x) => { + return x + } + assert_equal('asdf', Lambda1('asdf')) + var Lambda2 = (x): string => { + return x + } + assert_equal('foo', Lambda2('foo')) + END + CheckDefAndScriptSuccess(lines) + + lines =<< trim END + var Lambda = (x): string => { + return x + } + echo Lambda(['foo']) + END + CheckDefExecAndScriptFailure(lines, 'E1012:') enddef def Test_lambda_uses_assigned_var() diff --git a/src/userfunc.c b/src/userfunc.c index 64e815d042..f610c022d6 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -1377,7 +1377,7 @@ get_lambda_tv( goto errret; } else - fp->uf_ret_type = &t_any; + fp->uf_ret_type = &t_unknown; } fp->uf_lines = newlines; diff --git a/src/version.c b/src/version.c index 17ae9a4de2..fcb0d927a1 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2983, /**/ 2982, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 44c082d415..dfd5aaa3cb 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -3565,8 +3565,12 @@ compile_lambda(char_u **arg, cctx_T *cctx) ++ufunc->uf_refcount; clear_tv(&rettv); - // Compile the function into instructions. - compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx); + // Compile it here to get the return type. The return type is optional, + // when it's missing use t_unknown. This is recognized in + // compile_return(). + if (ufunc->uf_ret_type->tt_type == VAR_VOID) + ufunc->uf_ret_type = &t_unknown; + compile_def_function(ufunc, FALSE, PROFILING(ufunc), cctx); // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg" // points into it. Point to the original line to avoid a dangling pointer. @@ -5398,10 +5402,15 @@ compile_return(char_u *arg, int check_return_type, int legacy, cctx_T *cctx) if (cctx->ctx_skip != SKIP_YES) { + // "check_return_type" with uf_ret_type set to &t_unknown is used + // for an inline function without a specified return type. Set the + // return type here. stack_type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; - if (check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL + if ((check_return_type && (cctx->ctx_ufunc->uf_ret_type == NULL || cctx->ctx_ufunc->uf_ret_type == &t_unknown || cctx->ctx_ufunc->uf_ret_type == &t_any)) + || (!check_return_type + && cctx->ctx_ufunc->uf_ret_type == &t_unknown)) { cctx->ctx_ufunc->uf_ret_type = stack_type; } From 4a27aefe3b5652ee58b2eb85e9d09b542b087aaa Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 16:12:16 +0200 Subject: [PATCH 23/49] Add links to discussion forums. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 0a985d4125..1cb89fc5e0 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,12 @@ For translations of this README see the end. +If you find a bug or want to discuss the best way to add a new feature, please +open an [issue](https://github.com/vim/vim/issues). +If you have a question or want to discuss the best way to do something with +Vim, you can use [StackExchange](https://vi.stackexchange.com/) +or one of the [Maillists](https://www.vim.org/community.php). + ## What is Vim? ## From e6174fd58d459722847c76f8c5aa1b08a49c3e0d Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sat, 12 Jun 2021 18:30:56 +0200 Subject: [PATCH 24/49] patch 8.2.2984: Vim9: test fails because of missing return statement Problem: Vim9: Test fails because of missing return statement. Solution: When type is unknown set type to void. --- src/version.c | 2 ++ src/vim9compile.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/version.c b/src/version.c index fcb0d927a1..7f459c27af 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2984, /**/ 2983, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index dfd5aaa3cb..47847af3aa 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -9596,7 +9596,9 @@ nextline: if (!cctx.ctx_had_return) { - if (ufunc->uf_ret_type->tt_type != VAR_VOID) + if (ufunc->uf_ret_type->tt_type == VAR_UNKNOWN) + ufunc->uf_ret_type = &t_void; + else if (ufunc->uf_ret_type->tt_type != VAR_VOID) { emsg(_(e_missing_return_statement)); goto erret; From e99d422bbd3e47620915bf89671673f0711671b4 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 14:01:26 +0200 Subject: [PATCH 25/49] patch 8.2.2985: Vim9: a compiled function cannot be debugged Problem: Vim9: a compiled function cannot be debugged. Solution: Add initial debugging support. --- src/eval.c | 2 +- src/proto/vim9compile.pro | 4 +- src/testdir/test_debugger.vim | 21 ++--- src/testdir/test_vim9_disassemble.vim | 16 +++- src/userfunc.c | 2 +- src/version.c | 2 + src/vim.h | 11 ++- src/vim9.h | 4 + src/vim9compile.c | 125 +++++++++++++++++--------- src/vim9execute.c | 84 +++++++++++++---- src/vim9type.c | 2 +- 11 files changed, 196 insertions(+), 77 deletions(-) diff --git a/src/eval.c b/src/eval.c index 8a6539e3fc..ffc7122cde 100644 --- a/src/eval.c +++ b/src/eval.c @@ -3536,7 +3536,7 @@ eval7( if (ufunc->uf_ret_type->tt_type == VAR_VOID) ufunc->uf_ret_type = &t_unknown; if (compile_def_function(ufunc, - FALSE, PROFILING(ufunc), NULL) == FAIL) + FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL) { clear_tv(rettv); ret = FAIL; diff --git a/src/proto/vim9compile.pro b/src/proto/vim9compile.pro index 39624aef19..881dddc510 100644 --- a/src/proto/vim9compile.pro +++ b/src/proto/vim9compile.pro @@ -3,7 +3,7 @@ int check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg); int check_compare_types(exprtype_T type, typval_T *tv1, typval_T *tv2); int use_typecheck(type_T *actual, type_T *expected); int need_type(type_T *actual, type_T *expected, int offset, int arg_idx, cctx_T *cctx, int silent, int actual_is_const); -int func_needs_compiling(ufunc_T *ufunc, int profile); +int func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type); int get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx); imported_T *find_imported(char_u *name, size_t len, cctx_T *cctx); imported_T *find_imported_in_script(char_u *name, size_t len, int sid); @@ -17,7 +17,7 @@ void fill_exarg_from_cctx(exarg_T *eap, cctx_T *cctx); int assignment_len(char_u *p, int *heredoc); void vim9_declare_error(char_u *name); int check_vim9_unlet(char_u *name); -int compile_def_function(ufunc_T *ufunc, int check_return_type, int profiling, cctx_T *outer_cctx); +int compile_def_function(ufunc_T *ufunc, int check_return_type, compiletype_T compile_type, cctx_T *outer_cctx); void set_function_type(ufunc_T *ufunc); void delete_instr(isn_T *isn); void unlink_def_function(ufunc_T *ufunc); diff --git a/src/testdir/test_debugger.vim b/src/testdir/test_debugger.vim index 029b9dbc9c..ed4baccf11 100644 --- a/src/testdir/test_debugger.vim +++ b/src/testdir/test_debugger.vim @@ -884,19 +884,20 @@ func Test_Backtrace_DefFunction() \ ':debug call GlobalFunction()', \ ['cmd: call GlobalFunction()']) - " FIXME: Vim9 lines are not debugged! - call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) + call RunDbgCmd(buf, 'step', ['line 1: CallAFunction()']) - " But they do appear in the backtrace + " FIXME: not quite right call RunDbgCmd(buf, 'backtrace', [ \ '\V>backtrace', - \ '\V 2 function GlobalFunction[1]', - \ '\V 1 \.\*_CallAFunction[1]', - \ '\V->0 \.\*_SourceAnotherFile', - \ '\Vline 1: source Xtest2.vim'], + \ '\V->0 function GlobalFunction', + \ '\Vline 1: CallAFunction()', + \ ], \ #{match: 'pattern'}) - + call RunDbgCmd(buf, 'step', ['line 1: SourceAnotherFile()']) + call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) + " FIXME: repeated line + call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim']) call RunDbgCmd(buf, 'step', ['line 1: vim9script']) call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number']) call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()']) @@ -913,7 +914,7 @@ func Test_Backtrace_DefFunction() \ #{match: 'pattern'}) " Don't step into compiled functions... - call RunDbgCmd(buf, 'step', ['line 15: End of sourced file']) + call RunDbgCmd(buf, 'next', ['line 15: End of sourced file']) call RunDbgCmd(buf, 'backtrace', [ \ '\V>backtrace', \ '\V 3 function GlobalFunction[1]', @@ -923,7 +924,6 @@ func Test_Backtrace_DefFunction() \ '\Vline 15: End of sourced file'], \ #{match: 'pattern'}) - call StopVimInTerminal(buf) call delete('Xtest1.vim') call delete('Xtest2.vim') @@ -1116,6 +1116,7 @@ func Test_debug_backtrace_level() \ [ 'E121: Undefined variable: s:file1_var' ] ) call RunDbgCmd(buf, 'echo s:file2_var', [ 'file2' ] ) + call RunDbgCmd(buf, 'cont') call StopVimInTerminal(buf) call delete('Xtest1.vim') call delete('Xtest2.vim') diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim index 965399bca1..e1ed6754db 100644 --- a/src/testdir/test_vim9_disassemble.vim +++ b/src/testdir/test_vim9_disassemble.vim @@ -2153,7 +2153,7 @@ def Test_profiled() if !has('profile') MissingFeature 'profile' endif - var res = execute('disass! s:Profiled') + var res = execute('disass profile s:Profiled') assert_match('\d*_Profiled\_s*' .. 'echo "profiled"\_s*' .. '\d PROFILE START line 1\_s*' .. @@ -2168,6 +2168,20 @@ def Test_profiled() res) enddef +def Test_debugged() + var res = execute('disass debug s:Profiled') + assert_match('\d*_Profiled\_s*' .. + 'echo "profiled"\_s*' .. + '\d DEBUG line 1\_s*' .. + '\d PUSHS "profiled"\_s*' .. + '\d ECHO 1\_s*' .. + 'return "done"\_s*' .. + '\d DEBUG line 2\_s*' .. + '\d PUSHS "done"\_s*' .. + '\d RETURN\_s*', + res) +enddef + def s:EchoMessages() echohl ErrorMsg | echom v:exception | echohl NONE enddef diff --git a/src/userfunc.c b/src/userfunc.c index f610c022d6..56b7df32f5 100644 --- a/src/userfunc.c +++ b/src/userfunc.c @@ -4395,7 +4395,7 @@ ex_defcompile(exarg_T *eap UNUSED) && ufunc->uf_def_status == UF_TO_BE_COMPILED && (ufunc->uf_flags & FC_DEAD) == 0) { - (void)compile_def_function(ufunc, FALSE, FALSE, NULL); + (void)compile_def_function(ufunc, FALSE, CT_NONE, NULL); if (func_hashtab.ht_changed != changed) { diff --git a/src/version.c b/src/version.c index 7f459c27af..ad399ce486 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2985, /**/ 2984, /**/ diff --git a/src/vim.h b/src/vim.h index e1e68f9650..784fa3a8c0 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1794,10 +1794,17 @@ typedef struct timeval proftime_T; typedef int proftime_T; // dummy for function prototypes #endif +// Type of compilation passed to compile_def_function() +typedef enum { + CT_NONE, // use df_instr + CT_PROFILE, // use df_instr_prof + CT_DEBUG // use df_instr_debug, overrules CT_PROFILE +} compiletype_T; + #ifdef FEAT_PROFILE -# define PROFILING(ufunc) (do_profiling == PROF_YES && (ufunc)->uf_profiling) +# define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE) #else -# define PROFILING(ufunc) FALSE +# define COMPILE_TYPE(ufunc) debug_break_level > 0 ? CT_DEBUG : CT_NONE #endif /* diff --git a/src/vim9.h b/src/vim9.h index d4d3b7d6c1..f434602d2b 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -168,6 +168,8 @@ typedef enum { ISN_PROF_START, // start a line for profiling ISN_PROF_END, // end a line for profiling + ISN_DEBUG, // check for debug breakpoint + ISN_UNPACK, // unpack list into items, uses isn_arg.unpack ISN_SHUFFLE, // move item on stack up or down ISN_DROP, // pop stack and discard value @@ -453,6 +455,8 @@ struct dfunc_S { isn_T *df_instr_prof; // like "df_instr" with profiling int df_instr_prof_count; // size of "df_instr_prof" #endif + isn_T *df_instr_debug; // like "df_instr" with debugging + int df_instr_debug_count; // size of "df_instr_debug" int df_varcount; // number of local variables int df_has_closure; // one if a closure was created diff --git a/src/vim9compile.c b/src/vim9compile.c index 47847af3aa..7c0190677f 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -174,7 +174,7 @@ struct cctx_S { char_u *ctx_line_start; // start of current line or NULL garray_T ctx_instr; // generated instructions - int ctx_profiling; // when TRUE generate ISN_PROF_START + compiletype_T ctx_compile_type; garray_T ctx_locals; // currently visible local variables int ctx_locals_count; // total number of local variables @@ -1857,7 +1857,7 @@ generate_BLOBAPPEND(cctx_T *cctx) * "profile" indicates profiling is to be done. */ int -func_needs_compiling(ufunc_T *ufunc, int profile UNUSED) +func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type) { switch (ufunc->uf_def_status) { @@ -1866,15 +1866,18 @@ func_needs_compiling(ufunc_T *ufunc, int profile UNUSED) case UF_COMPILED: { -#ifdef FEAT_PROFILE dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; - return profile ? dfunc->df_instr_prof == NULL - : dfunc->df_instr == NULL; -#else - break; -#endif + switch (compile_type) + { + case CT_NONE: + return dfunc->df_instr == NULL; + case CT_PROFILE: + return dfunc->df_instr_prof == NULL; + case CT_DEBUG: + return dfunc->df_instr_debug == NULL; + } } case UF_NOT_COMPILED: @@ -1945,9 +1948,9 @@ generate_CALL(cctx_T *cctx, ufunc_T *ufunc, int pushed_argcount) return FAIL; } } - if (func_needs_compiling(ufunc, PROFILING(ufunc)) + if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) && compile_def_function(ufunc, ufunc->uf_ret_type == NULL, - PROFILING(ufunc), NULL) == FAIL) + COMPILE_TYPE(ufunc), NULL) == FAIL) return FAIL; } if (ufunc->uf_def_status == UF_COMPILE_ERROR) @@ -2313,14 +2316,28 @@ current_instr_idx(cctx_T *cctx) garray_T *instr = &cctx->ctx_instr; int idx = instr->ga_len; - if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1] + while (idx > 0) + { + if (cctx->ctx_has_cmdmod && ((isn_T *)instr->ga_data)[idx - 1] .isn_type == ISN_CMDMOD) - --idx; + { + --idx; + continue; + } #ifdef FEAT_PROFILE - if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[idx - 1] - .isn_type == ISN_PROF_START) - --idx; + if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_PROF_START) + { + --idx; + continue; + } #endif + if (((isn_T *)instr->ga_data)[idx - 1].isn_type == ISN_DEBUG) + { + --idx; + continue; + } + break; + } return idx; } @@ -2328,7 +2345,7 @@ current_instr_idx(cctx_T *cctx) static void may_generate_prof_end(cctx_T *cctx, int prof_lnum) { - if (cctx->ctx_profiling && prof_lnum >= 0) + if (cctx->ctx_compile_type == CT_PROFILE && prof_lnum >= 0) generate_instr(cctx, ISN_PROF_END); } #endif @@ -2972,8 +2989,8 @@ generate_funcref(cctx_T *cctx, char_u *name) return FAIL; // Need to compile any default values to get the argument types. - if (func_needs_compiling(ufunc, PROFILING(ufunc)) - && compile_def_function(ufunc, TRUE, PROFILING(ufunc), NULL) + if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) + && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), NULL) == FAIL) return FAIL; return generate_PUSHFUNC(cctx, ufunc->uf_name, ufunc->uf_func_type); @@ -3570,7 +3587,7 @@ compile_lambda(char_u **arg, cctx_T *cctx) // compile_return(). if (ufunc->uf_ret_type->tt_type == VAR_VOID) ufunc->uf_ret_type = &t_unknown; - compile_def_function(ufunc, FALSE, PROFILING(ufunc), cctx); + compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), cctx); // evalarg.eval_tofree_cmdline may have a copy of the last line and "*arg" // points into it. Point to the original line to avoid a dangling pointer. @@ -5566,8 +5583,8 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx) } } - if (func_needs_compiling(ufunc, PROFILING(ufunc)) - && compile_def_function(ufunc, TRUE, PROFILING(ufunc), cctx) + if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) + && compile_def_function(ufunc, TRUE, COMPILE_TYPE(ufunc), cctx) == FAIL) { func_ptr_unref(ufunc); @@ -7376,7 +7393,7 @@ compile_if(char_u *arg, cctx_T *cctx) scope->se_u.se_if.is_if_label = -1; #ifdef FEAT_PROFILE - if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES + if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES && skip_save != SKIP_YES) { // generated a profile start, need to generate a profile end, since it @@ -7457,13 +7474,19 @@ compile_elseif(char_u *arg, cctx_T *cctx) { cctx->ctx_skip = SKIP_UNKNOWN; #ifdef FEAT_PROFILE - if (cctx->ctx_profiling) + if (cctx->ctx_compile_type == CT_PROFILE) { // the previous block was skipped, need to profile this line generate_instr(cctx, ISN_PROF_START); instr_count = instr->ga_len; } #endif + if (cctx->ctx_compile_type == CT_DEBUG) + { + // the previous block was skipped, may want to debug this line + generate_instr(cctx, ISN_DEBUG); + instr_count = instr->ga_len; + } } if (compile_expr1(&p, cctx, &ppconst) == FAIL) { @@ -7531,12 +7554,13 @@ compile_else(char_u *arg, cctx_T *cctx) scope->se_u.se_if.is_seen_else = TRUE; #ifdef FEAT_PROFILE - if (cctx->ctx_profiling) + if (cctx->ctx_compile_type == CT_PROFILE) { if (cctx->ctx_skip == SKIP_NOT && ((isn_T *)instr->ga_data)[instr->ga_len - 1] .isn_type == ISN_PROF_START) - // the previous block was executed, do not count "else" for profiling + // the previous block was executed, do not count "else" for + // profiling --instr->ga_len; if (cctx->ctx_skip == SKIP_YES && !scope->se_u.se_if.is_seen_skip_not) { @@ -7612,7 +7636,7 @@ compile_endif(char_u *arg, cctx_T *cctx) #ifdef FEAT_PROFILE // even when skipping we count the endif as executed, unless the block it's // in is skipped - if (cctx->ctx_profiling && cctx->ctx_skip == SKIP_YES + if (cctx->ctx_compile_type == CT_PROFILE && cctx->ctx_skip == SKIP_YES && scope->se_skip_save != SKIP_YES) { cctx->ctx_skip = SKIP_NOT; @@ -8183,7 +8207,8 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) { #ifdef FEAT_PROFILE // the profile-start should be after the jump - if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + if (cctx->ctx_compile_type == CT_PROFILE + && ((isn_T *)instr->ga_data)[instr->ga_len - 1] .isn_type == ISN_PROF_START) --instr->ga_len; #endif @@ -8203,7 +8228,7 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) isn->isn_arg.jump.jump_where = instr->ga_len; } #ifdef FEAT_PROFILE - if (cctx->ctx_profiling) + if (cctx->ctx_compile_type == CT_PROFILE) { // a "throw" that jumps here needs to be counted generate_instr(cctx, ISN_PROF_END); @@ -8211,6 +8236,8 @@ compile_catch(char_u *arg, cctx_T *cctx UNUSED) generate_instr(cctx, ISN_PROF_START); } #endif + if (cctx->ctx_compile_type == CT_DEBUG) + generate_instr(cctx, ISN_DEBUG); } p = skipwhite(arg); @@ -8298,7 +8325,8 @@ compile_finally(char_u *arg, cctx_T *cctx) this_instr = instr->ga_len; #ifdef FEAT_PROFILE - if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + if (cctx->ctx_compile_type == CT_PROFILE + && ((isn_T *)instr->ga_data)[instr->ga_len - 1] .isn_type == ISN_PROF_START) // jump to the profile start of the "finally" --this_instr; @@ -8367,7 +8395,8 @@ compile_endtry(char_u *arg, cctx_T *cctx) } #ifdef FEAT_PROFILE - if (cctx->ctx_profiling && ((isn_T *)instr->ga_data)[instr->ga_len - 1] + if (cctx->ctx_compile_type == CT_PROFILE + && ((isn_T *)instr->ga_data)[instr->ga_len - 1] .isn_type == ISN_PROF_START) // move the profile start after "endtry" so that it's not counted when // the exception is rethrown. @@ -8399,7 +8428,7 @@ compile_endtry(char_u *arg, cctx_T *cctx) && generate_instr(cctx, ISN_ENDTRY) == NULL) return NULL; #ifdef FEAT_PROFILE - if (cctx->ctx_profiling) + if (cctx->ctx_compile_type == CT_PROFILE) generate_instr(cctx, ISN_PROF_START); #endif } @@ -8965,10 +8994,10 @@ add_def_function(ufunc_T *ufunc) */ int compile_def_function( - ufunc_T *ufunc, - int check_return_type, - int profiling UNUSED, - cctx_T *outer_cctx) + ufunc_T *ufunc, + int check_return_type, + compiletype_T compile_type, + cctx_T *outer_cctx) { char_u *line = NULL; char_u *line_to_free = NULL; @@ -8987,6 +9016,7 @@ compile_def_function( #ifdef FEAT_PROFILE int prof_lnum = -1; #endif + int debug_lnum = -1; // When using a function that was compiled before: Free old instructions. // The index is reused. Otherwise add a new entry in "def_functions". @@ -9007,9 +9037,7 @@ compile_def_function( CLEAR_FIELD(cctx); -#ifdef FEAT_PROFILE - cctx.ctx_profiling = profiling; -#endif + cctx.ctx_compile_type = compile_type; cctx.ctx_ufunc = ufunc; cctx.ctx_lnum = -1; cctx.ctx_outer = outer_cctx; @@ -9159,8 +9187,8 @@ compile_def_function( } #ifdef FEAT_PROFILE - if (cctx.ctx_profiling && cctx.ctx_lnum != prof_lnum && - cctx.ctx_skip != SKIP_YES) + if (cctx.ctx_compile_type == CT_PROFILE && cctx.ctx_lnum != prof_lnum + && cctx.ctx_skip != SKIP_YES) { may_generate_prof_end(&cctx, prof_lnum); @@ -9168,6 +9196,12 @@ compile_def_function( generate_instr(&cctx, ISN_PROF_START); } #endif + if (cctx.ctx_compile_type == CT_DEBUG && cctx.ctx_lnum != debug_lnum + && cctx.ctx_skip != SKIP_YES) + { + debug_lnum = cctx.ctx_lnum; + generate_instr(&cctx, ISN_DEBUG); + } // Some things can be recognized by the first character. switch (*ea.cmd) @@ -9617,13 +9651,19 @@ nextline: dfunc->df_deleted = FALSE; dfunc->df_script_seq = current_sctx.sc_seq; #ifdef FEAT_PROFILE - if (cctx.ctx_profiling) + if (cctx.ctx_compile_type == CT_PROFILE) { dfunc->df_instr_prof = instr->ga_data; dfunc->df_instr_prof_count = instr->ga_len; } else #endif + if (cctx.ctx_compile_type == CT_DEBUG) + { + dfunc->df_instr_debug = instr->ga_data; + dfunc->df_instr_debug_count = instr->ga_len; + } + else { dfunc->df_instr = instr->ga_data; dfunc->df_instr_count = instr->ga_len; @@ -9919,6 +9959,7 @@ delete_instr(isn_T *isn) case ISN_COMPARESTRING: case ISN_CONCAT: case ISN_COND2BOOL: + case ISN_DEBUG: case ISN_DROP: case ISN_ECHO: case ISN_ECHOERR: @@ -9927,6 +9968,7 @@ delete_instr(isn_T *isn) case ISN_EXECCONCAT: case ISN_EXECUTE: case ISN_FINALLY: + case ISN_FINISH: case ISN_FOR: case ISN_GETITEM: case ISN_JUMP: @@ -9949,7 +9991,6 @@ delete_instr(isn_T *isn) case ISN_NEWLIST: case ISN_OPANY: case ISN_OPFLOAT: - case ISN_FINISH: case ISN_OPNR: case ISN_PCALL: case ISN_PCALL_END: diff --git a/src/vim9execute.c b/src/vim9execute.c index 767dcea3c8..c1e40a68f4 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -204,8 +204,8 @@ call_dfunc( // Profiling might be enabled/disabled along the way. This should not // fail, since the function was compiled before and toggling profiling // doesn't change any errors. - if (func_needs_compiling(ufunc, PROFILING(ufunc)) - && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL) + if (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) + && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL) return FAIL; } @@ -264,6 +264,7 @@ call_dfunc( // If depth of calling is getting too high, don't execute the function. if (funcdepth_increment() == FAIL) return FAIL; + ++ex_nesting_level; // Only make a copy of funclocal if it contains something to restore. if (ectx->ec_funclocal.floc_restore_cmdmod) @@ -647,6 +648,7 @@ func_return(ectx_T *ectx) ectx->ec_stack.ga_len = top; funcdepth_decrement(); + --ex_nesting_level; return OK; } @@ -737,13 +739,15 @@ call_ufunc( int idx; int did_emsg_before = did_emsg; #ifdef FEAT_PROFILE - int profiling = do_profiling == PROF_YES && ufunc->uf_profiling; + compiletype_T compile_type = do_profiling == PROF_YES + && ufunc->uf_profiling ? CT_PROFILE : CT_NONE; #else -# define profiling FALSE +# define compile_type CT_NONE #endif - if (func_needs_compiling(ufunc, profiling) - && compile_def_function(ufunc, FALSE, profiling, NULL) == FAIL) + if (func_needs_compiling(ufunc, compile_type) + && compile_def_function(ufunc, FALSE, compile_type, NULL) + == FAIL) return FAIL; if (ufunc->uf_def_status == UF_COMPILED) { @@ -4099,6 +4103,22 @@ exec_instructions(ectx_T *ectx) } break; + case ISN_DEBUG: + if (ex_nesting_level <= debug_break_level) + { + char_u *line; + ufunc_T *ufunc = (((dfunc_T *)def_functions.ga_data) + + ectx->ec_dfunc_idx)->df_ufunc; + + SOURCING_LNUM = iptr->isn_lnum; + line = ((char_u **)ufunc->uf_lines.ga_data)[ + iptr->isn_lnum - 1]; + if (line == NULL) + line = (char_u *)"[empty]"; + do_debug(line); + } + break; + case ISN_SHUFFLE: { typval_T tmp_tv; @@ -4258,6 +4278,7 @@ call_def_function( int save_emsg_silent_def = emsg_silent_def; int save_did_emsg_def = did_emsg_def; int orig_funcdepth; + int orig_nesting_level = ex_nesting_level; // Get pointer to item in the stack. #undef STACK_TV @@ -4273,8 +4294,8 @@ call_def_function( if (ufunc->uf_def_status == UF_NOT_COMPILED || ufunc->uf_def_status == UF_COMPILE_ERROR - || (func_needs_compiling(ufunc, PROFILING(ufunc)) - && compile_def_function(ufunc, FALSE, PROFILING(ufunc), NULL) + || (func_needs_compiling(ufunc, COMPILE_TYPE(ufunc)) + && compile_def_function(ufunc, FALSE, COMPILE_TYPE(ufunc), NULL) == FAIL)) { if (did_emsg_cumul + did_emsg == did_emsg_before) @@ -4310,6 +4331,7 @@ call_def_function( ga_init2(&ectx.ec_trystack, sizeof(trycmd_T), 10); ga_init2(&ectx.ec_funcrefs, sizeof(partial_T *), 10); ectx.ec_did_emsg_before = did_emsg_before; + ++ex_nesting_level; idx = argc - ufunc->uf_args.ga_len; if (idx > 0 && ufunc->uf_va_name == NULL) @@ -4553,6 +4575,7 @@ failed_early: // Free all local variables, but not arguments. for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx) clear_tv(STACK_TV(idx)); + ex_nesting_level = orig_nesting_level; vim_free(ectx.ec_stack.ga_data); vim_free(ectx.ec_trystack.ga_data); @@ -5315,13 +5338,18 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) case ISN_CMDMOD_REV: smsg("%s%4d CMDMOD_REV", pfx, current); break; case ISN_PROF_START: - smsg("%s%4d PROFILE START line %d", pfx, current, iptr->isn_lnum); + smsg("%s%4d PROFILE START line %d", pfx, current, + iptr->isn_lnum); break; case ISN_PROF_END: smsg("%s%4d PROFILE END", pfx, current); break; + case ISN_DEBUG: + smsg("%s%4d DEBUG line %d", pfx, current, iptr->isn_lnum); + break; + case ISN_UNPACK: smsg("%s%4d UNPACK %d%s", pfx, current, iptr->isn_arg.unpack.unp_count, iptr->isn_arg.unpack.unp_semicolon ? " semicolon" : ""); @@ -5358,6 +5386,18 @@ ex_disassemble(exarg_T *eap) isn_T *instr; int instr_count; int is_global = FALSE; + compiletype_T compile_type = CT_NONE; + + if (STRNCMP(arg, "profile", 7) == 0) + { + compile_type = CT_PROFILE; + arg = skipwhite(arg + 7); + } + else if (STRNCMP(arg, "debug", 5) == 0) + { + compile_type = CT_DEBUG; + arg = skipwhite(arg + 5); + } if (STRNCMP(arg, "", 8) == 0) { @@ -5389,8 +5429,8 @@ ex_disassemble(exarg_T *eap) semsg(_(e_cannot_find_function_str), eap->arg); return; } - if (func_needs_compiling(ufunc, eap->forceit) - && compile_def_function(ufunc, FALSE, eap->forceit, NULL) == FAIL) + if (func_needs_compiling(ufunc, compile_type) + && compile_def_function(ufunc, FALSE, compile_type, NULL) == FAIL) return; if (ufunc->uf_def_status != UF_COMPILED) { @@ -5403,14 +5443,24 @@ ex_disassemble(exarg_T *eap) msg((char *)ufunc->uf_name); dfunc = ((dfunc_T *)def_functions.ga_data) + ufunc->uf_dfunc_idx; + switch (compile_type) + { + case CT_PROFILE: #ifdef FEAT_PROFILE - instr = eap->forceit ? dfunc->df_instr_prof : dfunc->df_instr; - instr_count = eap->forceit ? dfunc->df_instr_prof_count - : dfunc->df_instr_count; -#else - instr = dfunc->df_instr; - instr_count = dfunc->df_instr_count; + instr = dfunc->df_instr_prof; + instr_count = dfunc->df_instr_prof_count; + break; #endif + // FALLTHROUGH + case CT_NONE: + instr = dfunc->df_instr; + instr_count = dfunc->df_instr_count; + break; + case CT_DEBUG: + instr = dfunc->df_instr_debug; + instr_count = dfunc->df_instr_debug_count; + break; + } list_instructions("", instr, instr_count, ufunc); } diff --git a/src/vim9type.c b/src/vim9type.c index 4dec1e7704..f3718e4685 100644 --- a/src/vim9type.c +++ b/src/vim9type.c @@ -349,7 +349,7 @@ typval2type_int(typval_T *tv, int copyID, garray_T *type_gap, int do_member) // May need to get the argument types from default values by // compiling the function. if (ufunc->uf_def_status == UF_TO_BE_COMPILED - && compile_def_function(ufunc, TRUE, FALSE, NULL) + && compile_def_function(ufunc, TRUE, CT_NONE, NULL) == FAIL) return NULL; if (ufunc->uf_func_type == NULL) From d9f31c13d217b4b97f724774a67a6d1f8640e8ae Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 14:15:29 +0200 Subject: [PATCH 26/49] patch 8.2.2986: build failure without the profile feature Problem: Build failure without the profile feature. Solution: Add #ifdef. --- src/version.c | 2 ++ src/vim9compile.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/version.c b/src/version.c index ad399ce486..52e4a462b4 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2986, /**/ 2985, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 7c0190677f..1747f30fd9 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1871,10 +1871,12 @@ func_needs_compiling(ufunc_T *ufunc, compiletype_T compile_type) switch (compile_type) { + case CT_PROFILE: +#ifdef FEAT_PROFILE + return dfunc->df_instr_prof == NULL; +#endif case CT_NONE: return dfunc->df_instr == NULL; - case CT_PROFILE: - return dfunc->df_instr_prof == NULL; case CT_DEBUG: return dfunc->df_instr_debug == NULL; } From 6d1792d4085c9905c9da6ff27065b57cb7cddc57 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 14:33:20 +0200 Subject: [PATCH 27/49] patch 8.2.2987: build failure with normal features Problem: Build failure with normal features. Solution: Remove #define. --- src/version.c | 2 ++ src/vim9execute.c | 11 +++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/version.c b/src/version.c index 52e4a462b4..2800cf4a33 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2987, /**/ 2986, /**/ diff --git a/src/vim9execute.c b/src/vim9execute.c index c1e40a68f4..04c1ee2f29 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -738,13 +738,12 @@ call_ufunc( int error; int idx; int did_emsg_before = did_emsg; -#ifdef FEAT_PROFILE - compiletype_T compile_type = do_profiling == PROF_YES - && ufunc->uf_profiling ? CT_PROFILE : CT_NONE; -#else -# define compile_type CT_NONE -#endif + compiletype_T compile_type = CT_NONE; +#ifdef FEAT_PROFILE + if (do_profiling == PROF_YES && ufunc->uf_profiling) + compile_type = CT_PROFILE; +#endif if (func_needs_compiling(ufunc, compile_type) && compile_def_function(ufunc, FALSE, compile_type, NULL) == FAIL) From c3a27bbd53a4653c2d8122a047a4cf2cfc52ed21 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 15:16:01 +0200 Subject: [PATCH 28/49] patch 8.2.2988: Vim9: debugger test fails Problem: Vim9: debugger test fails. Solution: Get the debugger instructions when needed. --- src/version.c | 2 ++ src/vim.h | 1 + src/vim9.h | 13 ++++++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/version.c b/src/version.c index 2800cf4a33..61a5f0d5c2 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2988, /**/ 2987, /**/ diff --git a/src/vim.h b/src/vim.h index 784fa3a8c0..05af5a1882 100644 --- a/src/vim.h +++ b/src/vim.h @@ -1801,6 +1801,7 @@ typedef enum { CT_DEBUG // use df_instr_debug, overrules CT_PROFILE } compiletype_T; +// Keep in sync with INSTRUCTIONS(). #ifdef FEAT_PROFILE # define COMPILE_TYPE(ufunc) (debug_break_level > 0 ? CT_DEBUG : do_profiling == PROF_YES && (ufunc)->uf_profiling ? CT_PROFILE : CT_NONE) #else diff --git a/src/vim9.h b/src/vim9.h index f434602d2b..dd390716b5 100644 --- a/src/vim9.h +++ b/src/vim9.h @@ -493,10 +493,17 @@ extern garray_T def_functions; // Used for "lnum" when a range is to be taken from the stack and "!" is used. #define LNUM_VARIABLE_RANGE_ABOVE -888 +// Keep in sync with COMPILE_TYPE() #ifdef FEAT_PROFILE # define INSTRUCTIONS(dfunc) \ - ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \ - ? (dfunc)->df_instr_prof : (dfunc)->df_instr) + (debug_break_level > 0 \ + ? (dfunc)->df_instr_debug \ + : ((do_profiling == PROF_YES && (dfunc->df_ufunc)->uf_profiling) \ + ? (dfunc)->df_instr_prof \ + : (dfunc)->df_instr)) #else -# define INSTRUCTIONS(dfunc) ((dfunc)->df_instr) +# define INSTRUCTIONS(dfunc) \ + (debug_break_level > 0 \ + ? (dfunc)->df_instr_debug \ + : (dfunc)->df_instr) #endif From c2dec4cac4087af90dd4f64f4912a8e14a5fdd56 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 15:39:00 +0200 Subject: [PATCH 29/49] patch 8.2.2989: Vim9: memory leak when debugging a :def function Problem: Vim9: memory leak when debugging a :def function. Solution: Free the debug instructions. --- src/version.c | 2 ++ src/vim9compile.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/version.c b/src/version.c index 61a5f0d5c2..ce78fc5e1f 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2989, /**/ 2988, /**/ diff --git a/src/vim9compile.c b/src/vim9compile.c index 1747f30fd9..be8f304528 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -10045,6 +10045,13 @@ delete_def_function_contents(dfunc_T *dfunc, int mark_deleted) VIM_CLEAR(dfunc->df_instr); dfunc->df_instr = NULL; } + if (dfunc->df_instr_debug != NULL) + { + for (idx = 0; idx < dfunc->df_instr_debug_count; ++idx) + delete_instr(dfunc->df_instr_debug + idx); + VIM_CLEAR(dfunc->df_instr_debug); + dfunc->df_instr_debug = NULL; + } #ifdef FEAT_PROFILE if (dfunc->df_instr_prof != NULL) { From 2e66b0d1373891f40e2561ccd2d3369de1614bcd Mon Sep 17 00:00:00 2001 From: kompowiec2 Date: Sun, 13 Jun 2021 17:03:06 +0200 Subject: [PATCH 30/49] patch 8.2.2990: Jupyter Notebook files are not recognized Problem: Jupyter Notebook files are not recognized. Solution: Recognize *.ipynb. (closes #8375) --- runtime/filetype.vim | 3 +++ src/testdir/test_filetype.vim | 2 +- src/version.c | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 8ca6f6a77b..0f06391de1 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -855,6 +855,9 @@ au BufNewFile,BufRead *.jov,*.j73,*.jovial setf jovial " JSON au BufNewFile,BufRead *.json,*.jsonp,*.webmanifest setf json +" Jupyter Notebook is also json +au BufNewFile,BufRead *.ipynb setf json + " Kixtart au BufNewFile,BufRead *.kix setf kix diff --git a/src/testdir/test_filetype.vim b/src/testdir/test_filetype.vim index ac227fee17..0b670acf74 100644 --- a/src/testdir/test_filetype.vim +++ b/src/testdir/test_filetype.vim @@ -257,7 +257,7 @@ let s:filename_checks = { \ 'jgraph': ['file.jgr'], \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'], - \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest', 'Pipfile.lock'], + \ 'json': ['file.json', 'file.jsonp', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'], \ 'jsp': ['file.jsp'], \ 'kconfig': ['Kconfig', 'Kconfig.debug', 'Kconfig.file'], \ 'kivy': ['file.kv'], diff --git a/src/version.c b/src/version.c index ce78fc5e1f..dfe1f8b1fb 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2990, /**/ 2989, /**/ From e70e12b32f193addae88ae8df933b04fc234550f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 17:20:08 +0200 Subject: [PATCH 31/49] patch 8.2.2991: Vim9: no completion for :vim9 and :legacy Problem: Vim9: no completion for :vim9 and :legacy. Solution: Expand argument as a command. (closes #8377) --- src/cmdexpand.c | 2 ++ src/testdir/test_cmdline.vim | 6 ++++++ src/version.c | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/cmdexpand.c b/src/cmdexpand.c index c5b8f70585..ba31e928c0 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -1370,6 +1370,8 @@ set_one_cmd_context( case CMD_verbose: case CMD_vertical: case CMD_windo: + case CMD_vim9cmd: + case CMD_legacy: return arg; case CMD_filter: diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index cf3362d63e..a05d010d44 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -804,6 +804,12 @@ func Test_cmdline_complete_various() call feedkeys(":topleft new\\\"\", 'xt') call assert_equal("\"topleft new", @:) + " completion for vim9 and legacy commands + call feedkeys(":vim9 call strle\\\"\", 'xt') + call assert_equal("\"vim9 call strlen(", @:) + call feedkeys(":legac call strle\\\"\", 'xt') + call assert_equal("\"legac call strlen(", @:) + " completion for the :match command call feedkeys(":match Search /pat/\\\"\", 'xt') call assert_equal("\"match Search /pat/\", @:) diff --git a/src/version.c b/src/version.c index dfe1f8b1fb..07c775b41b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2991, /**/ 2990, /**/ From 4ee9d8e04daa97a3d0a19d7d2eed76b7721301e6 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 18:38:48 +0200 Subject: [PATCH 32/49] patch 8.2.2992: Vim9: completion for :disassemble is incomplete Problem: Vim9: completion for :disassemble is incomplete. Solution: Recognize the "debug" and "profile" arguments. --- src/cmdexpand.c | 5 ++++- src/proto/vim9execute.pro | 2 ++ src/testdir/test_cmdline.vim | 10 ++++++++++ src/version.c | 2 ++ src/vim.h | 1 + src/vim9execute.c | 34 ++++++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/cmdexpand.c b/src/cmdexpand.c index ba31e928c0..9b6d9aa81d 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -1557,10 +1557,12 @@ set_one_cmd_context( case CMD_function: case CMD_delfunction: - case CMD_disassemble: xp->xp_context = EXPAND_USER_FUNC; xp->xp_pattern = arg; break; + case CMD_disassemble: + set_context_in_disassemble_cmd(xp, arg); + break; case CMD_echohl: set_context_in_echohl_cmd(xp, arg); @@ -2120,6 +2122,7 @@ ExpandFromContext( {EXPAND_USER_VARS, get_user_var_name, FALSE, TRUE}, {EXPAND_FUNCTIONS, get_function_name, FALSE, TRUE}, {EXPAND_USER_FUNC, get_user_func_name, FALSE, TRUE}, + {EXPAND_DISASSEMBLE, get_disassemble_argument, FALSE, TRUE}, {EXPAND_EXPRESSION, get_expr_name, FALSE, TRUE}, # endif # ifdef FEAT_MENU diff --git a/src/proto/vim9execute.pro b/src/proto/vim9execute.pro index 4b6444a347..5712fcf76f 100644 --- a/src/proto/vim9execute.pro +++ b/src/proto/vim9execute.pro @@ -7,6 +7,8 @@ int fill_partial_and_closure(partial_T *pt, ufunc_T *ufunc, ectx_T *ectx); int exe_typval_instr(typval_T *tv, typval_T *rettv); char_u *exe_substitute_instr(void); int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, typval_T *rettv); +void set_context_in_disassemble_cmd(expand_T *xp, char_u *arg); +char_u *get_disassemble_argument(expand_T *xp, int idx); void ex_disassemble(exarg_T *eap); int tv2bool(typval_T *tv); void emsg_using_string_as(typval_T *tv, int as_number); diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim index a05d010d44..90afe4516c 100644 --- a/src/testdir/test_cmdline.vim +++ b/src/testdir/test_cmdline.vim @@ -810,6 +810,16 @@ func Test_cmdline_complete_various() call feedkeys(":legac call strle\\\"\", 'xt') call assert_equal("\"legac call strlen(", @:) + " completion for the :disassemble command + call feedkeys(":disas deb\\\"\", 'xt') + call assert_equal("\"disas debug", @:) + call feedkeys(":disas pro\\\"\", 'xt') + call assert_equal("\"disas profile", @:) + call feedkeys(":disas debug Test_cmdline_complete_var\\\"\", 'xt') + call assert_equal("\"disas debug Test_cmdline_complete_various", @:) + call feedkeys(":disas profile Test_cmdline_complete_var\\\"\", 'xt') + call assert_equal("\"disas profile Test_cmdline_complete_various", @:) + " completion for the :match command call feedkeys(":match Search /pat/\\\"\", 'xt') call assert_equal("\"match Search /pat/\", @:) diff --git a/src/version.c b/src/version.c index 07c775b41b..441826b95b 100644 --- a/src/version.c +++ b/src/version.c @@ -750,6 +750,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 2992, /**/ 2991, /**/ diff --git a/src/vim.h b/src/vim.h index 05af5a1882..22fe8d5fed 100644 --- a/src/vim.h +++ b/src/vim.h @@ -777,6 +777,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring); #define EXPAND_MAPCLEAR 47 #define EXPAND_ARGLIST 48 #define EXPAND_DIFF_BUFFERS 49 +#define EXPAND_DISASSEMBLE 50 // Values for exmode_active (0 is no exmode) #define EXMODE_NORMAL 1 diff --git a/src/vim9execute.c b/src/vim9execute.c index 04c1ee2f29..d55fa0c9d3 100644 --- a/src/vim9execute.c +++ b/src/vim9execute.c @@ -5370,6 +5370,40 @@ list_instructions(char *pfx, isn_T *instr, int instr_count, ufunc_T *ufunc) } } +/* + * Handle command line completion for the :disassemble command. + */ + void +set_context_in_disassemble_cmd(expand_T *xp, char_u *arg) +{ + char_u *p; + + // Default: expand user functions, "debug" and "profile" + xp->xp_context = EXPAND_DISASSEMBLE; + xp->xp_pattern = arg; + + // first argument already typed: only user function names + if (*arg != NUL && *(p = skiptowhite(arg)) != NUL) + { + xp->xp_context = EXPAND_USER_FUNC; + xp->xp_pattern = skipwhite(p); + } +} + +/* + * Function given to ExpandGeneric() to obtain the list of :disassemble + * arguments. + */ + char_u * +get_disassemble_argument(expand_T *xp, int idx) +{ + if (idx == 0) + return (char_u *)"debug"; + if (idx == 1) + return (char_u *)"profile"; + return get_user_func_name(xp, idx - 2); +} + /* * ":disassemble". * We don't really need this at runtime, but we do have tests that require it, From 2346a6378483c9871016f9fc821ec5cbea638f13 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 13 Jun 2021 19:02:49 +0200 Subject: [PATCH 33/49] Update runtime files --- runtime/doc/autocmd.txt | 2 +- runtime/doc/change.txt | 2 +- runtime/doc/eval.txt | 32 +++--- runtime/doc/filetype.txt | 2 +- runtime/doc/ft_raku.txt | 2 +- runtime/doc/help.txt | 5 +- runtime/doc/motion.txt | 9 +- runtime/doc/options.txt | 2 +- runtime/doc/os_vms.txt | 6 +- runtime/doc/pattern.txt | 2 +- runtime/doc/pi_netrw.txt | 2 +- runtime/doc/repeat.txt | 8 +- runtime/doc/syntax.txt | 10 +- runtime/doc/tags | 8 ++ runtime/doc/term.txt | 4 +- runtime/doc/todo.txt | 65 ++++-------- runtime/doc/usr_41.txt | 2 +- runtime/doc/various.txt | 2 +- runtime/doc/vim.1 | 2 +- runtime/doc/vim.man | 6 +- runtime/doc/vim9.txt | 10 +- runtime/doc/vimdiff.1 | 6 +- runtime/doc/vimdiff.man | 19 ++-- runtime/filetype.vim | 2 +- runtime/gvim.desktop | 1 + runtime/indent/html.vim | 63 ++++++----- runtime/syntax/gvpr.vim | 85 +++++++++++++++ runtime/vim.desktop | 1 + src/INSTALLpc.txt | 3 +- src/po/sr.po | 221 ++++++++++++++++++++++++++++++--------- 30 files changed, 399 insertions(+), 185 deletions(-) create mode 100644 runtime/syntax/gvpr.vim diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 4536d5b3e5..5f1231ccb0 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -54,7 +54,7 @@ effects. Be careful not to destroy your text. :au[tocmd] [group] {event} {pat} [++once] [++nested] {cmd} Add {cmd} to the list of commands that Vim will execute automatically on {event} for a file matching - {pat} |autocmd-patterns|. + {pat} |autocmd-patterns|. Here {event} cannot be "*". *E1155* Note: A quote character is seen as argument to the :autocmd and won't start a comment. diff --git a/runtime/doc/change.txt b/runtime/doc/change.txt index 6c6a0c9bd9..62a69b78f0 100644 --- a/runtime/doc/change.txt +++ b/runtime/doc/change.txt @@ -1,4 +1,4 @@ -*change.txt* For Vim version 8.2. Last change: 2021 Mar 01 +*change.txt* For Vim version 8.2. Last change: 2021 Jun 10 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 97585ad6c5..fdc63eaa3d 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4 +1,4 @@ -*eval.txt* For Vim version 8.2. Last change: 2021 May 07 +*eval.txt* For Vim version 8.2. Last change: 2021 Jun 07 VIM REFERENCE MANUAL by Bram Moolenaar @@ -2102,7 +2102,7 @@ v:null An empty String. Used to put "null" in JSON. See v:numbermax Maximum value of a number. *v:numbermin* *numbermin-variable* -v:numbermin Minimum value of a number (negative) +v:numbermin Minimum value of a number (negative). *v:numbersize* *numbersize-variable* v:numbersize Number of bits in a Number. This is normally 64, but on some @@ -2508,7 +2508,7 @@ char2nr({expr} [, {utf8}]) Number ASCII/UTF8 value of first char in {expr} charclass({string}) Number character class of {string} charcol({expr}) Number column number of cursor or mark charidx({string}, {idx} [, {countcc}]) - Number char index of byte {idx} in {string} + Number char index of byte {idx} in {string} chdir({dir}) String change current working directory cindent({lnum}) Number C indent for line {lnum} clearmatches([{win}]) none clear all matches @@ -2529,7 +2529,7 @@ cscope_connection([{num}, {dbpath} [, {prepend}]]) cursor({lnum}, {col} [, {off}]) Number move cursor to {lnum}, {col}, {off} cursor({list}) Number move cursor to position in {list} -debugbreak({pid}) Number interrupt process being debugged +debugbreak({pid}) Number interrupt process being debugged deepcopy({expr} [, {noref}]) any make a full copy of {expr} delete({fname} [, {flags}]) Number delete the file or directory {fname} deletebufline({expr}, {first} [, {last}]) @@ -4951,7 +4951,7 @@ funcref({name} [, {arglist}] [, {dict}]) Can also be used as a |method|: > GetFuncname()->funcref([arg]) < - *function()* *E700* *E922* *E923* + *function()* *partial* *E700* *E922* *E923* function({name} [, {arglist}] [, {dict}]) Return a |Funcref| variable that refers to function {name}. {name} can be the name of a user defined function or an @@ -5500,8 +5500,8 @@ getcurpos([{winid}]) Can also be used as a |method|: > GetWinid()->getcurpos() - -< *getcursorcharpos()* +< + *getcursorcharpos()* getcursorcharpos([{winid}]) Same as |getcurpos()| but the column number in the returned List is a character index instead of a byte index. @@ -5510,8 +5510,8 @@ getcursorcharpos([{winid}]) With the cursor on '보' in line 3 with text "여보세요": > getcursorcharpos() returns [0, 3, 2, 0, 3] getcurpos() returns [0, 3, 4, 0, 3] - -< Can also be used as a |method|: > +< + Can also be used as a |method|: > GetWinid()->getcursorcharpos() < *getcwd()* @@ -5736,11 +5736,11 @@ getmarklist([{expr}]) *getmarklist()* see |bufname()|. Each item in the returned List is a |Dict| with the following: - name - name of the mark prefixed by "'" - pos - a |List| with the position of the mark: + mark name of the mark prefixed by "'" + pos a |List| with the position of the mark: [bufnum, lnum, col, off] - Refer to |getpos()| for more information. - file - file name + Refer to |getpos()| for more information. + file file name Refer to |getpos()| for getting information about a specific mark. @@ -5822,7 +5822,7 @@ getpos({expr}) Get the position for {expr}. For possible values of {expr} '> is a large number. The column number in the returned List is the byte position within the line. To get the character position in the line, - use |getcharpos()| + use |getcharpos()|. The column number can be very large, e.g. 2147483647, in which case it means "after the end of the line". This can be used to save and restore the position of a mark: > @@ -7637,7 +7637,7 @@ matchfuzzypos({list}, {str} [, {dict}]) *matchfuzzypos()* Same as |matchfuzzy()|, but returns the list of matched strings, the list of character positions where characters in {str} matches and a list of matching scores. You can - use |byteidx()|to convert a character position to a byte + use |byteidx()| to convert a character position to a byte position. If {str} matches multiple times in a string, then only the @@ -9961,7 +9961,7 @@ sinh({expr}) *sinh()* {only available when compiled with the |+float| feature} -slice({expr}, {start} [, {end}]) *slice()* +slice({expr}, {start} [, {end}]) *slice()* Similar to using a |slice| "expr[start : end]", but "end" is used exclusive. And for a string the indexes are used as character indexes instead of byte indexes, like in diff --git a/runtime/doc/filetype.txt b/runtime/doc/filetype.txt index 318507c16b..8295d67780 100644 --- a/runtime/doc/filetype.txt +++ b/runtime/doc/filetype.txt @@ -632,7 +632,7 @@ For fish, add to the config file MARKDOWN *ft-markdown-plugin* To enable folding use this: > - let g:markdown_folding = 1 + let g:markdown_folding = 1 < PDF *ft-pdf-plugin* diff --git a/runtime/doc/ft_raku.txt b/runtime/doc/ft_raku.txt index 26ada8a140..8439de5727 100644 --- a/runtime/doc/ft_raku.txt +++ b/runtime/doc/ft_raku.txt @@ -45,7 +45,7 @@ Numbers, subscripts and superscripts are available with 's' and 'S': 1s ₁ 1S ¹ ~ 2s ₂ 9S ⁹ ~ -But some don´t come defined by default. Those are digraph definitions you can +But some don't come defined by default. Those are digraph definitions you can add in your ~/.vimrc file. > exec 'digraph \\ '.char2nr('∖') exec 'digraph \< '.char2nr('≼') diff --git a/runtime/doc/help.txt b/runtime/doc/help.txt index 1b3839edc9..f5c3e6d986 100644 --- a/runtime/doc/help.txt +++ b/runtime/doc/help.txt @@ -132,7 +132,7 @@ Advanced editing ~ |windows.txt| commands for using multiple windows and buffers |tabpage.txt| commands for using multiple tab pages |spell.txt| spell checking -|diff.txt| working with two to four versions of the same file +|diff.txt| working with two to eight versions of the same file |autocmd.txt| automatically executing commands on an event |eval.txt| expression evaluation, conditional commands |channel.txt| Jobs, Channels, inter-process communication @@ -145,6 +145,7 @@ Special issues ~ |term.txt| using different terminals and mice |terminal.txt| Terminal window support |popup.txt| popup window support +|vim9.txt| using Vim9 script Programming language support ~ |indent.txt| automatic indenting for C and other languages @@ -153,6 +154,8 @@ Programming language support ~ |filetype.txt| settings done specifically for a type of file |quickfix.txt| commands for a quick edit-compile-fix cycle |ft_ada.txt| Ada (the programming language) support +|ft_ps1.txt| Filetype plugin for Windows PowerShell +|ft_raku.txt| Filetype plugin for Raku |ft_rust.txt| Filetype plugin for Rust |ft_sql.txt| about the SQL filetype plugin diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt index 4dc0e2e28c..a8ae19c444 100644 --- a/runtime/doc/motion.txt +++ b/runtime/doc/motion.txt @@ -1,4 +1,4 @@ -*motion.txt* For Vim version 8.2. Last change: 2021 Mar 28 +*motion.txt* For Vim version 8.2. Last change: 2021 Jun 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -59,9 +59,14 @@ or change text. The following operators are available: |<| < shift left |zf| zf define a fold |g@| g@ call function set with the 'operatorfunc' option - + *motion-count-multiplied* If the motion includes a count and the operator also had a count before it, the two counts are multiplied. For example: "2d3w" deletes six words. + *operator-doubled* +When doubling the operator it operates on a line. When using a count, before +or after the first character, that many lines are operated upon. Thus `3dd` +deletes three lines. A count before and after the first character is +multiplied, thus `2y3y` yanks six lines. After applying the operator the cursor is mostly left at the start of the text that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe" diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index d3adbd0c90..e600dd91dd 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 8.2. Last change: 2021 May 16 +*options.txt* For Vim version 8.2. Last change: 2021 May 31 VIM REFERENCE MANUAL by Bram Moolenaar diff --git a/runtime/doc/os_vms.txt b/runtime/doc/os_vms.txt index 6eb2993bc7..0ebc774872 100644 --- a/runtime/doc/os_vms.txt +++ b/runtime/doc/os_vms.txt @@ -767,12 +767,12 @@ GNU_TOOLS.ZIP package downloadable from http://www.polarhome.com/vim/ Version 8.2 - make all changes needed for clean compile build of v8.2 on VMS on all platforms -- fix the call mkdir bug (vicente_polo@yahoo.es) +- fix the call mkdir bug (vicente_polo@yahoo.es) - test on VSI OpenVMS Alpha and Itanium platforms - added LUA support - added XPM support - Motif GUI with toolbar on all platforms -- XPM v3.4.11 libraries for IA64, AXP and VAX are added -- start integrating the new test scripts +- XPM v3.4.11 libraries for IA64, AXP and VAX are added +- start integrating the new test scripts Version 8.1 - make necessary changes to build v8.1 on VMS diff --git a/runtime/doc/pattern.txt b/runtime/doc/pattern.txt index 20fed5523c..c23fdb444a 100644 --- a/runtime/doc/pattern.txt +++ b/runtime/doc/pattern.txt @@ -1217,7 +1217,7 @@ x A single character, with no special meaning, matches itself \%d123 Matches the character specified with a decimal number. Must be followed by a non-digit. -\%o40 Matches the character specified with an octal number up to 0377. +\%o40 Matches the character specified with an octal number up to 0o377. Numbers below 0o40 must be followed by a non-octal digit or a non-digit. \%x2a Matches the character specified with up to two hexadecimal characters. diff --git a/runtime/doc/pi_netrw.txt b/runtime/doc/pi_netrw.txt index b293d9b15f..421b12f60d 100644 --- a/runtime/doc/pi_netrw.txt +++ b/runtime/doc/pi_netrw.txt @@ -3809,7 +3809,7 @@ netrw: Decho.vim is provided as a "vimball"; see |vimball-intro|. You should edit the Decho.vba.gz file and source it in: > - vim Decho.vba.gz + vim Decho.vba.gz :so % :q < diff --git a/runtime/doc/repeat.txt b/runtime/doc/repeat.txt index 18149fcf8f..c6b4b9e9f6 100644 --- a/runtime/doc/repeat.txt +++ b/runtime/doc/repeat.txt @@ -1,4 +1,4 @@ -*repeat.txt* For Vim version 8.2. Last change: 2021 May 08 +*repeat.txt* For Vim version 8.2. Last change: 2021 Jun 11 VIM REFERENCE MANUAL by Bram Moolenaar @@ -279,7 +279,9 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. ftdetect scripts are loaded, only the matching directories are added to 'runtimepath'. This is useful in your .vimrc. The plugins will then be - loaded during initialization, see |load-plugins|. + loaded during initialization, see |load-plugins| (note + that the loading order will be reversed, because each + directory is inserted before others). Note that for ftdetect scripts to be loaded you will need to write `filetype plugin indent on` AFTER all `packadd!` commands. @@ -372,7 +374,7 @@ For writing a Vim script, see chapter 41 of the user manual |usr_41.txt|. for some commands. See |:vim9cmd| for executing one command with Vim9 syntax and semantics. - + *:scr* *:scriptnames* :scr[iptnames] List all sourced script names, in the order they were first sourced. The number is used for the script ID diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt index d457067c8f..ab35aca7a1 100644 --- a/runtime/doc/syntax.txt +++ b/runtime/doc/syntax.txt @@ -3430,8 +3430,8 @@ syntax highlighting script handles this with the following logic: Tex: Match Check Control~ Sometimes one actually wants mismatched parentheses, square braces, - and or curly braces; for example, \text{(1,10] is a range from but - not including 1 to and including 10}. This wish, of course, conflicts + and or curly braces; for example, \text{(1,10]} is a range from but + not including 1 to and including 10. This wish, of course, conflicts with the desire to provide delimiter mismatch detection. To accommodate these conflicting goals, syntax/tex.vim provides > g:tex_matchcheck = '[({[]' @@ -4084,7 +4084,7 @@ match in the same position overrules an earlier one). The "transparent" argument makes the "myVim" match use the same highlighting as "myString". But it does not contain anything. If the "contains=NONE" argument would be left out, then "myVim" would use the contains argument from myString and allow -"myWord" to be contained, which will be highlighted as a Constant. This +"myWord" to be contained, which will be highlighted as a Comment. This happens because a contained match doesn't match inside itself in the same position, thus the "myVim" match doesn't overrule the "myWord" match here. @@ -4970,8 +4970,8 @@ ctermul={color-nr} *highlight-ctermul* *tmux* When using tmux you may want to use this in the tmux config: > # tmux colors - set -g default-terminal "xterm-256color" - set -ag terminal-overrides ",xterm-256color:Tc" + set -s default-terminal "tmux-256color" + set -as terminal-overrides ",*-256color:Tc" < More info at: https://github.com/tmux/tmux/wiki/FAQ#how-do-i-use-a-256-colour-terminal https://github.com/tmux/tmux/wiki/FAQ#how-do-i-use-rgb-colour diff --git a/runtime/doc/tags b/runtime/doc/tags index 18f71f1e84..5b1457c896 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -7000,6 +7000,7 @@ getchar() eval.txt /*getchar()* getcharmod() eval.txt /*getcharmod()* getcharpos() eval.txt /*getcharpos()* getcharsearch() eval.txt /*getcharsearch()* +getcharstr() eval.txt /*getcharstr()* getcmdline() eval.txt /*getcmdline()* getcmdpos() eval.txt /*getcmdpos()* getcmdtype() eval.txt /*getcmdtype()* @@ -7901,6 +7902,7 @@ moo.vim syntax.txt /*moo.vim* more-compatible version5.txt /*more-compatible* more-prompt message.txt /*more-prompt* more-variables eval.txt /*more-variables* +motion-count-multiplied motion.txt /*motion-count-multiplied* motion.txt motion.txt /*motion.txt* mouse-mode-table term.txt /*mouse-mode-table* mouse-overview term.txt /*mouse-overview* @@ -8348,6 +8350,7 @@ omni-sql-completion ft_sql.txt /*omni-sql-completion* online-help helphelp.txt /*online-help* opening-window windows.txt /*opening-window* operator motion.txt /*operator* +operator-doubled motion.txt /*operator-doubled* operator-pending-index index.txt /*operator-pending-index* operator-variable eval.txt /*operator-variable* option-backslash options.txt /*option-backslash* @@ -8401,6 +8404,7 @@ page_up intro.txt /*page_up* pager message.txt /*pager* papp.vim syntax.txt /*papp.vim* paragraph motion.txt /*paragraph* +partial eval.txt /*partial* pascal.vim syntax.txt /*pascal.vim* patches-8 version8.txt /*patches-8* patches-8.1 version8.txt /*patches-8.1* @@ -10066,6 +10070,7 @@ v_u change.txt /*v_u* v_v visual.txt /*v_v* v_x change.txt /*v_x* v_y change.txt /*v_y* +v_zy change.txt /*v_zy* v_~ change.txt /*v_~* vab motion.txt /*vab* val-variable eval.txt /*val-variable* @@ -10435,6 +10440,7 @@ zOS-PuTTY os_390.txt /*zOS-PuTTY* zOS-has-ebcdic os_390.txt /*zOS-has-ebcdic* zOS-limitations os_390.txt /*zOS-limitations* zOS-open-source os_390.txt /*zOS-open-source* +zP change.txt /*zP* zR fold.txt /*zR* zW spell.txt /*zW* zX fold.txt /*zX* @@ -10462,6 +10468,7 @@ zl scroll.txt /*zl* zm fold.txt /*zm* zn fold.txt /*zn* zo fold.txt /*zo* +zp change.txt /*zp* zr fold.txt /*zr* zs scroll.txt /*zs* zsh.vim syntax.txt /*zsh.vim* @@ -10473,6 +10480,7 @@ zuw spell.txt /*zuw* zv fold.txt /*zv* zw spell.txt /*zw* zx fold.txt /*zx* +zy change.txt /*zy* zz scroll.txt /*zz* { motion.txt /*{* {Visual} intro.txt /*{Visual}* diff --git a/runtime/doc/term.txt b/runtime/doc/term.txt index 8eea4a59e7..811d507524 100644 --- a/runtime/doc/term.txt +++ b/runtime/doc/term.txt @@ -373,10 +373,10 @@ Added by Vim (there are no standard codes for these): t_Ri restore icon text from stack *t_Ri* *'t_Ri'* t_TE end of "raw" mode *t_TE* *'t_TE'* t_TI put terminal into "raw" mode *t_TI* *'t_TI'* - t_fd disable focus-event tracking *t_fd* *'t_fd'* - |xterm-focus-event| t_fe enable focus-event tracking *t_fe* *'t_fe'* |xterm-focus-event| + t_fd disable focus-event tracking *t_fd* *'t_fd'* + |xterm-focus-event| Some codes have a start, middle and end part. The start and end are defined by the termcap option, the middle part is text. diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index b46c44094e..2c20ceaa44 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -1,4 +1,4 @@ -*todo.txt* For Vim version 8.2. Last change: 2021 May 28 +*todo.txt* For Vim version 8.2. Last change: 2021 Jun 13 VIM REFERENCE MANUAL by Bram Moolenaar @@ -38,57 +38,30 @@ browser use: https://github.com/vim/vim/issues/1234 *known-bugs* -------------------- Known bugs and current work ----------------------- -Geen memory leak? - -Crash using outer var from nested lambda: - vim9script - def F(text: string): func(string): func(string): string - return (arg: string): func(string): string => ((sep: string): string => { - return text .. ' ' .. arg - }) - enddef - - echo F('hello')(' ')('there') - - - Vim9 - Make everything work: -- function returning nothing should return void instead of zero -- compile "expr" and "call" expression of a channel in channel_exe_cmd()? -- Need some solution for dict function. Can we implement part of classes? -- A lambda without {} does not require a return type, using { return x } does. - That's unexpected, since the arguments are not required to have a type. - alt 1: not require a return type, figure it out from the common type of all - the return statements found - alt 2: also require argument types -- Using "windo echo expr" does not accept a line break inside "expr" (in a - :def function and at script level in a not executed block). #7681 -- use CheckLegacyAndVim9Success(lines) in many more places +- Make debugging work - at least per function. + - How to evaluate the stack and variables on the stack? + - FIXME in test_debugger.vim - For builtin functions using tv_get_string*() use check_for_string() to be more strict about the argument type (not a bool). done: balloon_() - Check many more builtin function arguments at compile time. map() could check that the return type of the function argument matches the type of the list or dict member. (#8092) -- Allow for using an autoload function name without quotes. It is then loaded - (and compiled) right away. #8124 -- Test more expressions in legacy and Vim9 script, using - CheckLegacyAndVim9Success() + Same for other functions, such as searchpair(). +- use CheckLegacyAndVim9Success(lines) in many more places - Test try/catch and throw better, also nested. Test that return inside try/finally jumps to finally and then returns. - Test that a function defined inside a :def function is local to that function, g: functions can be defined and script-local functions cannot be defined. -- Make debugging work - at least per function. Need to recompile a function - to step through it line-by-line? Evaluate the stack and variables on the - stack? -- Reserve command for future use: :type, :class, :enum +- compile get_lambda_tv() in popup_add_timeout() Once Vim9 is stable: +- Add the "vim9script" feature, can use has('vim9script') - Change the help to prefer Vim9 syntax where appropriate - Add all the error numbers in a good place in documentation. - In the generic eval docs, point out the Vim9 syntax where it differs. -- Add the "vim9script" feature, can use has('vim9script') - Use Vim9 for runtime files. PR #7497 for autoload/ccomplete.vim @@ -100,13 +73,12 @@ Further Vim9 improvements, possibly after launch: Give an error if compilation fails. (#7625) Use the location where the option was set for deciding whether it's to be evaluated in Vim9 script context. -- implement :type, import type declaration. -- implement enum, import enum. -- Future work: See |vim9-classes| +- implement :type, "import type" +- implement enum, "import enum". +- implement class and interface: See |vim9-classes| - For range: make table of first ASCII character with flag to quickly check if it can be a Vim9 command. E.g. "+" can, but "." can't. -- compile get_lambda_tv() in popup_add_timeout() -- inline call to map() and filter() +- Inline call to map() and filter(), better type checking. - Make accessing varargs faster: arg[expr] EVAL expr LOADVARARG (varargs idx) @@ -300,6 +272,9 @@ inconsistent with the documentation. Making breakat support multibyte characters (Yasuhiro Matsumoto, #6598) Scroll doesn't work correctly, why? +glob() and globfile() do not always honor 'wildignorecase'. #8350 +globpath() does not use 'wildignorecase' at all? + Add 'termguiattr' option, use "gui=" attributes in the terminal? Would work with 'termguicolors'. #1740 @@ -344,6 +319,9 @@ Should also work without any group: :echo matchstr('aaa bbb', '.\{-1,}\>\|.*') aaa bbb (should be aaa) +Should add a match/str/list/pos method that also returns the test and position +of submatches. #8355 + Check out PR #543 (Roland Puntaier). Patch for multibyte characters in langmap and applying a mapping on them. (Christian Brabandt, 2015 Jun 12, update July 25) @@ -380,6 +358,10 @@ work. Using "au!" after "filetype on" is a bit slow. Can the matching of autocommands be made faster? (#7056) +Append in Visual block mode inserts the wrong character. +Test_visual_block_mode() already has the proper check, which is commented out. +(#8288) + Add the <=> (spaceship) operator and "cond ?< expr ?= expr ?> expr" replace this: let left = GetLeftFunc() @@ -2263,9 +2245,6 @@ Win32: Improved Makefile for MSVC. (Leonardo Valeri Manera, 2010 Aug 18) Win32: Expanding 'path' runs into a maximum size limit. (bgold12, 2009 Nov 15) -Win32: Patch for enabling quick edit mode in console. (Craig Barkhouse, 2010 -Sep 1) - Win32: Patch for using .png files for icons. (Charles Peacech, 2012 Feb 5) Putting a Visual block while 'visualedit' is "all" does not leave the cursor diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 0d66d2bb67..09d5a39db7 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1,4 +1,4 @@ -*usr_41.txt* For Vim version 8.2. Last change: 2021 Apr 19 +*usr_41.txt* For Vim version 8.2. Last change: 2021 Jun 07 VIM USER MANUAL - by Bram Moolenaar diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt index 76a8f5d3cc..eb45922ccf 100644 --- a/runtime/doc/various.txt +++ b/runtime/doc/various.txt @@ -724,7 +724,7 @@ K Run a program to lookup the keyword under the feature} *:sl!* *:sleep!* -:[N]sl[eep]! [N] [m] Same as above, but hide the cursor. +:[N]sl[eep]! [N][m] Same as above, but hide the cursor. *:xrestore* *:xr* :xr[estore] [display] Reinitializes the connection to the X11 server. Useful diff --git a/runtime/doc/vim.1 b/runtime/doc/vim.1 index 5bf0d05030..d55c8b3e85 100644 --- a/runtime/doc/vim.1 +++ b/runtime/doc/vim.1 @@ -186,7 +186,7 @@ behave mostly like Vi, even though a .vimrc file exists. .TP \-d Start in diff mode. -There should be two, three or four file name arguments. +There should between two to eight file name arguments. .B Vim will open all the files and show differences between them. Works like vimdiff(1). diff --git a/runtime/doc/vim.man b/runtime/doc/vim.man index 91f29e14e5..dbfba53cea 100644 --- a/runtime/doc/vim.man +++ b/runtime/doc/vim.man @@ -135,9 +135,9 @@ OPTIONS Vim behave mostly like Vi, even though a .vimrc file ex‐ ists. - -d Start in diff mode. There should be two, three or four - file name arguments. Vim will open all the files and show - differences between them. Works like vimdiff(1). + -d Start in diff mode. There should between two to eight file + name arguments. Vim will open all the files and show dif‐ + ferences between them. Works like vimdiff(1). -d {device} Open {device} for use as a terminal. Only on the Amiga. Example: "-d con:20/30/600/150". diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 406aedcfee..6ca1d74a99 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -457,7 +457,8 @@ which is similar to JavaScript: > var Lambda = (arg) => expression No line break is allowed in the arguments of a lambda up to and including the -"=>". This is OK: > +"=>" (so that Vim can tell the difference between an expression in parenthesis +and lambda arguments). This is OK: > filter(list, (k, v) => v > 0) This does not work: > @@ -998,9 +999,14 @@ prefix if they do not exist at the time of compiling. Note that for command line completion of {func} you can prepend "s:" to find script-local functions. -:disa[ssemble]! {func} Like `:disassemble` but with the instructions used for +:disa[ssemble] profile {func} + Like `:disassemble` but with the instructions used for profiling. +:disa[ssemble] debug {func} + Like `:disassemble` but with the instructions used for + debugging. + Limitations ~ Local variables will not be visible to string evaluation. For example: > diff --git a/runtime/doc/vimdiff.1 b/runtime/doc/vimdiff.1 index bed2b32889..ddcb30f1ca 100644 --- a/runtime/doc/vimdiff.1 +++ b/runtime/doc/vimdiff.1 @@ -1,17 +1,17 @@ .TH VIMDIFF 1 "2001 March 30" .SH NAME -vimdiff \- edit two, three or four versions of a file with Vim and show differences +vimdiff \- edit between two and eight versions of a file with Vim and show differences .SH SYNOPSIS .br .B vimdiff -[options] file1 file2 [file3 [file4]] +[options] file1 file2 [file3 [file4 [file5 [file6 [file7 [file8]]]]]] .PP .B gvimdiff .SH DESCRIPTION .B Vimdiff starts .B Vim -on two (or three or four) files. +on two up to eight files. Each file gets its own window. The differences between the files are highlighted. This is a nice way to inspect changes and to move changes from one version diff --git a/runtime/doc/vimdiff.man b/runtime/doc/vimdiff.man index 913ac13847..a053e6a742 100644 --- a/runtime/doc/vimdiff.man +++ b/runtime/doc/vimdiff.man @@ -1,27 +1,28 @@ -VIMDIFF(1) VIMDIFF(1) +VIMDIFF(1) General Commands Manual VIMDIFF(1) NAME - vimdiff - edit two, three or four versions of a file with Vim and show - differences + vimdiff - edit between two and eight versions of a file with Vim and + show differences SYNOPSIS - vimdiff [options] file1 file2 [file3 [file4]] + vimdiff [options] file1 file2 [file3 [file4 [file5 [file6 [file7 + [file8]]]]]] gvimdiff DESCRIPTION - Vimdiff starts Vim on two (or three or four) files. Each file gets its - own window. The differences between the files are highlighted. This - is a nice way to inspect changes and to move changes from one version - to another version of the same file. + Vimdiff starts Vim on two up to eight files. Each file gets its own + window. The differences between the files are highlighted. This is a + nice way to inspect changes and to move changes from one version to an‐ + other version of the same file. See vim(1) for details about Vim itself. When started as gvimdiff the GUI will be started, if available. - In each window the 'diff' option will be set, which causes the differ- + In each window the 'diff' option will be set, which causes the differ‐ ences to be highlighted. The 'wrap' and 'scrollbind' options are set to make the text look good. The 'foldmethod' option is set to "diff", which puts ranges of lines diff --git a/runtime/filetype.vim b/runtime/filetype.vim index 0f06391de1..04e2001176 100644 --- a/runtime/filetype.vim +++ b/runtime/filetype.vim @@ -1,7 +1,7 @@ " Vim support file to detect file types " " Maintainer: Bram Moolenaar -" Last Change: 2021 Apr 17 +" Last Change: 2021 Jun 13 " Listen very carefully, I will say this only once if exists("did_load_filetypes") diff --git a/runtime/gvim.desktop b/runtime/gvim.desktop index 3132bc861d..8da62cac4e 100644 --- a/runtime/gvim.desktop +++ b/runtime/gvim.desktop @@ -112,6 +112,7 @@ Icon[de]=gvim Icon[eo]=gvim Icon[fr]=gvim Icon[ru]=gvim +Icon[sr]=gvim Icon=gvim Categories=Utility;TextEditor; StartupNotify=true diff --git a/runtime/indent/html.vim b/runtime/indent/html.vim index 7019bd4a82..d4b91f6421 100644 --- a/runtime/indent/html.vim +++ b/runtime/indent/html.vim @@ -1,7 +1,7 @@ " Vim indent script for HTML " Maintainer: Bram Moolenaar " Original Author: Andy Wokula -" Last Change: 2021 Jan 26 +" Last Change: 2021 Jun 13 " Version: 1.0 "{{{ " Description: HTML indent script with cached state for faster indenting on a " range of lines. @@ -62,7 +62,7 @@ let s:tagname = '\w\+\(-\w\+\)*' " Prefer using buffer-local settings over global settings, so that there can " be defaults for all HTML files and exceptions for specific types of HTML " files. -func! HtmlIndent_CheckUserSettings() +func HtmlIndent_CheckUserSettings() "{{{ let inctags = '' if exists("b:html_indent_inctags") @@ -178,7 +178,7 @@ let s:endtags = [0,0,0,0,0,0,0] " long enough for the highest index "}}} " Add a list of tag names for a pair of to "tags". -func! s:AddITags(tags, taglist) +func s:AddITags(tags, taglist) "{{{ for itag in a:taglist let a:tags[itag] = 1 @@ -187,7 +187,7 @@ func! s:AddITags(tags, taglist) endfunc "}}} " Take a list of tag name pairs that are not to be used as tag pairs. -func! s:RemoveITags(tags, taglist) +func s:RemoveITags(tags, taglist) "{{{ for itag in a:taglist let a:tags[itag] = 1 @@ -196,7 +196,7 @@ func! s:RemoveITags(tags, taglist) endfunc "}}} " Add a block tag, that is a tag with a different kind of indenting. -func! s:AddBlockTag(tag, id, ...) +func s:AddBlockTag(tag, id, ...) "{{{ if !(a:id >= 2 && a:id < len(s:endtags)) echoerr 'AddBlockTag ' . a:id @@ -255,7 +255,7 @@ call s:AddBlockTag('') " Return non-zero when "tagname" is an opening tag, not being a block tag, for " which there should be a closing tag. Can be used by scripts that include " HTML indenting. -func! HtmlIndent_IsOpenTag(tagname) +func HtmlIndent_IsOpenTag(tagname) "{{{ if get(s:indent_tags, a:tagname) == 1 return 1 @@ -264,7 +264,7 @@ func! HtmlIndent_IsOpenTag(tagname) endfunc "}}} " Get the value for "tagname", taking care of buffer-local tags. -func! s:get_tag(tagname) +func s:get_tag(tagname) "{{{ let i = get(s:indent_tags, a:tagname) if (i == 1 || i == -1) && get(b:hi_removed_tags, a:tagname) != 0 @@ -277,7 +277,7 @@ func! s:get_tag(tagname) endfunc "}}} " Count the number of start and end tags in "text". -func! s:CountITags(text) +func s:CountITags(text) "{{{ " Store the result in s:curind and s:nextrel. let s:curind = 0 " relative indent steps for current line [unit &sw]: @@ -289,7 +289,7 @@ func! s:CountITags(text) endfunc "}}} " Count the number of start and end tags in text. -func! s:CountTagsAndState(text) +func s:CountTagsAndState(text) "{{{ " Store the result in s:curind and s:nextrel. Update b:hi_newstate.block. let s:curind = 0 " relative indent steps for current line [unit &sw]: @@ -304,7 +304,7 @@ func! s:CountTagsAndState(text) endfunc "}}} " Used by s:CountITags() and s:CountTagsAndState(). -func! s:CheckTag(itag) +func s:CheckTag(itag) "{{{ " Returns an empty string or "SCRIPT". " a:itag can be "tag" or "/tag" or "" @@ -338,7 +338,7 @@ func! s:CheckTag(itag) endfunc "}}} " Used by s:CheckTag(). Returns an empty string or "SCRIPT". -func! s:CheckBlockTag(blocktag, ind) +func s:CheckBlockTag(blocktag, ind) "{{{ if a:ind > 0 " a block starts here @@ -366,7 +366,7 @@ func! s:CheckBlockTag(blocktag, ind) endfunc "}}} " Used by s:CheckTag(). -func! s:CheckCustomTag(ctag) +func s:CheckCustomTag(ctag) "{{{ " Returns 1 if ctag is the tag for a custom element, 0 otherwise. " a:ctag can be "tag" or "/tag" or "" @@ -396,7 +396,7 @@ func! s:CheckCustomTag(ctag) endfunc "}}} " Return the