Patch 8.2.2842
Problem: Vim9: skip argument to searchpair() is not compiled.
Solution: Add VAR_INSTR.
Files: src/structs.h, src/vim9.h, src/vim9compile.c, src/vim9execute.c,
src/proto/
vim9execute.pro, src/eval.c, src/evalfunc.c, src/vim.h,
src/evalvars.c, src/typval.c, src/vim9type.c, src/testing.c,
src/viminfo.c, src/if_py_both.h, src/json.c,
src/testdir/test_vim9_disassemble.vim,
src/testdir/test_vim9_builtin.vim
*** ../vim-8.2.2841/src/structs.h 2021-04-24 14:15:03.680264471 +0200
--- src/structs.h 2021-05-07 15:33:39.708802153 +0200
***************
*** 1371,1376 ****
--- 1371,1377 ----
typedef struct channel_S channel_T;
typedef struct cctx_S cctx_T;
typedef struct ectx_S ectx_T;
+ typedef struct instr_S instr_T;
typedef enum
{
***************
*** 1389,1394 ****
--- 1390,1396 ----
VAR_DICT, // "v_dict" is used
VAR_JOB, // "v_job" is used
VAR_CHANNEL, // "v_channel" is used
+ VAR_INSTR, // "v_instr" is used
} vartype_T;
// A type specification.
***************
*** 1429,1434 ****
--- 1431,1437 ----
channel_T *v_channel; // channel value (can be NULL!)
#endif
blob_T *v_blob; // blob value (can be NULL!)
+ instr_T *v_instr; // instructions to execute
} vval;
} typval_T;
*** ../vim-8.2.2841/src/vim9.h 2021-05-05 21:31:36.068018579 +0200
--- src/vim9.h 2021-05-07 16:52:30.209276710 +0200
***************
*** 20,25 ****
--- 20,26 ----
ISN_ECHOERR, // echo Ex commands isn_arg.number items on top of stack
ISN_RANGE, // compute range from isn_arg.string, push to stack
ISN_SUBSTITUTE, // :s command with expression
+ ISN_INSTR, // instructions compiled from expression
// get and set variables
ISN_LOAD, // push local variable isn_arg.number
***************
*** 411,416 ****
--- 412,418 ----
isn_outer_T outer;
subs_T subs;
cexpr_T cexpr;
+ isn_T *instr;
} isn_arg;
};
*** ../vim-8.2.2841/src/vim9compile.c 2021-05-06 21:04:51.514534033 +0200
--- src/vim9compile.c 2021-05-07 16:54:08.825005973 +0200
***************
*** 615,620 ****
--- 615,621 ----
case VAR_DICT:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
to_string_error((*type)->tt_type);
return FAIL;
}
***************
*** 3097,3112 ****
return res;
}
/*
* Compile the argument expressions.
* "arg" points to just after the "(" and is advanced to after the ")"
*/
static int
! compile_arguments(char_u **arg, cctx_T *cctx, int *argcount)
{
char_u *p = *arg;
char_u *whitep = *arg;
int must_end = FALSE;
for (;;)
{
--- 3098,3169 ----
return res;
}
+ static void
+ clear_instr_ga(garray_T *gap)
+ {
+ int idx;
+
+ for (idx = 0; idx < gap->ga_len; ++idx)
+ delete_instr(((isn_T *)gap->ga_data) + idx);
+ ga_clear(gap);
+ }
+
+ /*
+ * Compile a string in a ISN_PUSHS instruction into an ISN_INSTR.
+ * Returns FAIL if compilation fails.
+ */
+ static int
+ compile_string(isn_T *isn, cctx_T *cctx)
+ {
+ char_u *s = isn->isn_arg.string;
+ garray_T save_ga = cctx->ctx_instr;
+ int expr_res;
+ int trailing_error;
+ int instr_count;
+ isn_T *instr = NULL;
+
+ // Temporarily reset the list of instructions so that the jump labels are
+ // correct.
+ cctx->ctx_instr.ga_len = 0;
+ cctx->ctx_instr.ga_maxlen = 0;
+ cctx->ctx_instr.ga_data = NULL;
+ expr_res = compile_expr0(&s, cctx);
+ s = skipwhite(s);
+ trailing_error = *s != NUL;
+
+ if (expr_res == FAIL || trailing_error)
+ {
+ if (trailing_error)
+ semsg(_(e_trailing_arg), s);
+ clear_instr_ga(&cctx->ctx_instr);
+ cctx->ctx_instr = save_ga;
+ return FAIL;
+ }
+
+ // Move the generated instructions into the ISN_INSTR instruction, then
+ // restore the list of instructions.
+ instr_count = cctx->ctx_instr.ga_len;
+ instr = cctx->ctx_instr.ga_data;
+ instr[instr_count].isn_type = ISN_FINISH;
+
+ cctx->ctx_instr = save_ga;
+ vim_free(isn->isn_arg.string);
+ isn->isn_type = ISN_INSTR;
+ isn->isn_arg.instr = instr;
+ return OK;
+ }
+
/*
* Compile the argument expressions.
* "arg" points to just after the "(" and is advanced to after the ")"
*/
static int
! compile_arguments(char_u **arg, cctx_T *cctx, int *argcount, int is_searchpair)
{
char_u *p = *arg;
char_u *whitep = *arg;
int must_end = FALSE;
+ int instr_count;
for (;;)
{
***************
*** 3123,3132 ****
--- 3180,3200 ----
return FAIL;
}
+ instr_count = cctx->ctx_instr.ga_len;
if (compile_expr0(&p, cctx) == FAIL)
return FAIL;
++*argcount;
+ if (is_searchpair && *argcount == 5
+ && cctx->ctx_instr.ga_len == instr_count + 1)
+ {
+ isn_T *isn = ((isn_T *)cctx->ctx_instr.ga_data) + instr_count;
+
+ // {skip} argument of searchpair() can be compiled if not empty
+ if (isn->isn_type == ISN_PUSHS && *isn->isn_arg.string != NUL)
+ compile_string(isn, cctx);
+ }
+
if (*p != ',' && *skipwhite(p) == ',')
{
semsg(_(e_no_white_space_allowed_before_str_str), ",", p);
***************
*** 3175,3180 ****
--- 3243,3249 ----
ufunc_T *ufunc = NULL;
int res = FAIL;
int is_autoload;
+ int is_searchpair;
// we can evaluate "has('name')" at compile time
if (varlen == 3 && STRNCMP(*arg, "has", 3) == 0)
***************
*** 3216,3223 ****
vim_strncpy(namebuf, *arg, varlen);
name = fname_trans_sid(namebuf, fname_buf, &tofree, &error);
*arg = skipwhite(*arg + varlen + 1);
! if (compile_arguments(arg, cctx, &argcount) == FAIL)
goto theend;
is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
--- 3285,3295 ----
vim_strncpy(namebuf, *arg, varlen);
name = fname_trans_sid(namebuf, fname_buf, &tofree, &error);
+ // we handle the "skip" argument of searchpair() differently
+ is_searchpair = (varlen == 10 && STRNCMP(*arg, "searchpair", 10) == 0);
+
*arg = skipwhite(*arg + varlen + 1);
! if (compile_arguments(arg, cctx, &argcount, is_searchpair) == FAIL)
goto theend;
is_autoload = vim_strchr(name, AUTOLOAD_CHAR) != NULL;
***************
*** 4027,4033 ****
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
*arg = skipwhite(p + 1);
! if (compile_arguments(arg, cctx, &argcount) == FAIL)
return FAIL;
if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
return FAIL;
--- 4099,4105 ----
type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
*arg = skipwhite(p + 1);
! if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
return FAIL;
if (generate_PCALL(cctx, argcount, name_start, type, TRUE) == FAIL)
return FAIL;
***************
*** 4080,4086 ****
return FAIL;
}
*arg = skipwhite(*arg + 1);
! if (compile_arguments(arg, cctx, &argcount) == FAIL)
return FAIL;
// Move the instructions for the arguments to before the
--- 4152,4158 ----
return FAIL;
}
*arg = skipwhite(*arg + 1);
! if (compile_arguments(arg, cctx, &argcount, FALSE) == FAIL)
return FAIL;
// Move the instructions for the arguments to before the
***************
*** 6728,6733 ****
--- 6800,6806 ----
case VAR_ANY:
case VAR_PARTIAL:
case VAR_VOID:
+ case VAR_INSTR:
case VAR_SPECIAL: // cannot happen
generate_PUSHNR(cctx, 0);
break;
***************
*** 8536,8551 ****
}
- static void
- clear_instr_ga(garray_T *gap)
- {
- int idx;
-
- for (idx = 0; idx < gap->ga_len; ++idx)
- delete_instr(((isn_T *)gap->ga_data) + idx);
- ga_clear(gap);
- }
-
/*
* :s/pat/repl/
*/
--- 8609,8614 ----
***************
*** 8568,8580 ****
int expr_res;
int trailing_error;
int instr_count;
! isn_T *instr = NULL;
isn_T *isn;
cmd += 3;
end = skip_substitute(cmd, delimiter);
! // Temporarily reset the list of instructions so that the jumps
// labels are correct.
cctx->ctx_instr.ga_len = 0;
cctx->ctx_instr.ga_maxlen = 0;
--- 8631,8643 ----
int expr_res;
int trailing_error;
int instr_count;
! isn_T *instr;
isn_T *isn;
cmd += 3;
end = skip_substitute(cmd, delimiter);
! // Temporarily reset the list of instructions so that the jump
// labels are correct.
cctx->ctx_instr.ga_len = 0;
cctx->ctx_instr.ga_maxlen = 0;
***************
*** 8592,8598 ****
semsg(_(e_trailing_arg), cmd);
clear_instr_ga(&cctx->ctx_instr);
cctx->ctx_instr = save_ga;
- vim_free(instr);
return NULL;
}
--- 8655,8660 ----
***************
*** 9552,9557 ****
--- 9614,9630 ----
for (idx = 0; list[idx].isn_type != ISN_FINISH; ++idx)
delete_instr(list + idx);
vim_free(list);
+ }
+ break;
+
+ case ISN_INSTR:
+ {
+ int idx;
+ isn_T *list = isn->isn_arg.instr;
+
+ for (idx = 0; list[idx].isn_type != ISN_FINISH; ++idx)
+ delete_instr(list + idx);
+ vim_free(list);
}
break;
*** ../vim-8.2.2841/src/vim9execute.c 2021-05-05 22:51:35.631336525 +0200
--- src/vim9execute.c 2021-05-07 16:57:49.448411700 +0200
***************
*** 1259,1264 ****
--- 1259,1270 ----
return OK;
}
+ // used for v_instr of typval of VAR_INSTR
+ struct instr_S {
+ ectx_T *instr_ectx;
+ isn_T *instr_instr;
+ };
+
// used for substitute_instr
typedef struct subs_expr_S {
ectx_T *subs_ectx;
***************
*** 1379,1384 ****
--- 1385,1407 ----
}
break;
+ // push typeval VAR_INSTR with instructions to be executed
+ case ISN_INSTR:
+ {
+ if (GA_GROW(&ectx->ec_stack, 1) == FAIL)
+ return FAIL;
+ tv = STACK_TV_BOT(0);
+ tv->vval.v_instr = ALLOC_ONE(instr_T);
+ if (tv->vval.v_instr == NULL)
+ goto on_error;
+ ++ectx->ec_stack.ga_len;
+
+ tv->v_type = VAR_INSTR;
+ tv->vval.v_instr->instr_ectx = ectx;
+ tv->vval.v_instr->instr_instr = iptr->isn_arg.instr;
+ }
+ break;
+
// execute :substitute with an expression
case ISN_SUBSTITUTE:
{
***************
*** 3997,4002 ****
--- 4020,4052 ----
}
/*
+ * Execute the instructions from a VAR_INSTR typeval and put the result in
+ * "rettv".
+ * Return OK or FAIL.
+ */
+ int
+ exe_typval_instr(typval_T *tv, typval_T *rettv)
+ {
+ ectx_T *ectx = tv->vval.v_instr->instr_ectx;
+ isn_T *save_instr = ectx->ec_instr;
+ int save_iidx = ectx->ec_iidx;
+ int res;
+
+ ectx->ec_instr = tv->vval.v_instr->instr_instr;
+ res = exec_instructions(ectx);
+ if (res == OK)
+ {
+ *rettv = *STACK_TV_BOT(-1);
+ --ectx->ec_stack.ga_len;
+ }
+
+ ectx->ec_instr = save_instr;
+ ectx->ec_iidx = save_iidx;
+
+ return res;
+ }
+
+ /*
* Execute the instructions from an ISN_SUBSTITUTE command, which are in
* "substitute_instr".
*/
***************
*** 4436,4441 ****
--- 4486,4499 ----
}
#endif
break;
+ case ISN_INSTR:
+ {
+ smsg("%s%4d INSTR", pfx, current);
+ list_instructions(" ", iptr->isn_arg.instr,
+ INT_MAX, NULL);
+ msg(" -------------");
+ }
+ break;
case ISN_SUBSTITUTE:
{
subs_T *subs = &iptr->isn_arg.subs;
***************
*** 5225,5230 ****
--- 5283,5289 ----
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
+ case VAR_INSTR:
break;
}
return FALSE;
*** ../vim-8.2.2841/src/proto/
vim9execute.pro 2021-04-19 16:48:44.431055514 +0200
--- src/proto/
vim9execute.pro 2021-05-07 16:02:15.324738264 +0200
***************
*** 4,9 ****
--- 4,10 ----
char_u *char_from_string(char_u *str, varnumber_T index);
char_u *string_slice(char_u *str, varnumber_T first, varnumber_T last, int exclusive);
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 ex_disassemble(exarg_T *eap);
*** ../vim-8.2.2841/src/eval.c 2021-04-28 20:00:35.014355562 +0200
--- src/eval.c 2021-05-07 16:49:04.853854664 +0200
***************
*** 309,314 ****
--- 309,318 ----
return FAIL;
}
}
+ else if (expr->v_type == VAR_INSTR)
+ {
+ return exe_typval_instr(expr, rettv);
+ }
else
{
s = tv_get_string_buf_chk(expr, buf);
***************
*** 1510,1515 ****
--- 1514,1520 ----
case VAR_SPECIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
break;
case VAR_BLOB:
***************
*** 4084,4089 ****
--- 4089,4095 ----
case VAR_SPECIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
if (verbose)
emsg(_(e_cannot_index_special_variable));
return FAIL;
***************
*** 4177,4182 ****
--- 4183,4189 ----
case VAR_SPECIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
break; // not evaluating, skipping over subscript
case VAR_NUMBER:
***************
*** 5067,5072 ****
--- 5074,5084 ----
}
break;
+ case VAR_INSTR:
+ *tofree = NULL;
+ r = (char_u *)"instructions";
+ break;
+
case VAR_FLOAT:
#ifdef FEAT_FLOAT
*tofree = NULL;
***************
*** 5987,5992 ****
--- 5999,6005 ----
case VAR_SPECIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
copy_tv(from, to);
break;
case VAR_LIST:
*** ../vim-8.2.2841/src/evalfunc.c 2021-04-02 18:55:52.058322772 +0200
--- src/evalfunc.c 2021-05-07 16:50:29.513613937 +0200
***************
*** 2989,2994 ****
--- 2989,2995 ----
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
+ case VAR_INSTR:
internal_error_no_abort("f_empty(UNKNOWN)");
n = TRUE;
break;
***************
*** 6303,6308 ****
--- 6304,6310 ----
case VAR_PARTIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
emsg(_("E701: Invalid type for len()"));
break;
}
***************
*** 10215,10220 ****
--- 10217,10223 ----
case VAR_JOB: n = VAR_TYPE_JOB; break;
case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
case VAR_BLOB: n = VAR_TYPE_BLOB; break;
+ case VAR_INSTR: n = VAR_TYPE_INSTR; break;
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
*** ../vim-8.2.2841/src/vim.h 2021-04-26 21:14:12.713924760 +0200
--- src/vim.h 2021-05-07 16:50:40.873581896 +0200
***************
*** 2030,2035 ****
--- 2030,2036 ----
#define VAR_TYPE_JOB 8
#define VAR_TYPE_CHANNEL 9
#define VAR_TYPE_BLOB 10
+ #define VAR_TYPE_INSTR 11
#define DICT_MAXNEST 100 // maximum nesting of lists and dicts
*** ../vim-8.2.2841/src/evalvars.c 2021-04-19 20:49:58.156857538 +0200
--- src/evalvars.c 2021-05-07 16:37:44.703664554 +0200
***************
*** 1912,1917 ****
--- 1912,1918 ----
case VAR_SPECIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
break;
case VAR_BLOB:
*** ../vim-8.2.2841/src/typval.c 2021-04-10 21:45:42.938892687 +0200
--- src/typval.c 2021-05-07 16:43:08.430865423 +0200
***************
*** 91,96 ****
--- 91,97 ----
case VAR_VOID:
case VAR_BOOL:
case VAR_SPECIAL:
+ case VAR_INSTR:
break;
}
vim_free(varp);
***************
*** 153,158 ****
--- 154,160 ----
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
+ case VAR_INSTR:
break;
}
varp->v_lock = 0;
***************
*** 236,241 ****
--- 238,244 ----
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
+ case VAR_INSTR:
internal_error_no_abort("tv_get_number(UNKNOWN)");
break;
}
***************
*** 333,338 ****
--- 336,342 ----
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
+ case VAR_INSTR:
internal_error_no_abort("tv_get_float(UNKNOWN)");
break;
}
***************
*** 514,519 ****
--- 518,524 ----
case VAR_UNKNOWN:
case VAR_ANY:
case VAR_VOID:
+ case VAR_INSTR:
emsg(_(e_inval_string));
break;
}
***************
*** 614,619 ****
--- 619,628 ----
++to->vval.v_channel->ch_refcount;
break;
#endif
+ case VAR_INSTR:
+ to->vval.v_instr = from->vval.v_instr;
+ break;
+
case VAR_STRING:
case VAR_FUNC:
if (from->vval.v_string == NULL)
***************
*** 1116,1121 ****
--- 1125,1132 ----
#ifdef FEAT_JOB_CHANNEL
return tv1->vval.v_channel == tv2->vval.v_channel;
#endif
+ case VAR_INSTR:
+ return tv1->vval.v_instr == tv2->vval.v_instr;
case VAR_PARTIAL:
return tv1->vval.v_partial == tv2->vval.v_partial;
*** ../vim-8.2.2841/src/vim9type.c 2021-04-13 20:53:09.846201149 +0200
--- src/vim9type.c 2021-05-07 16:58:51.892245751 +0200
***************
*** 950,955 ****
--- 950,956 ----
case VAR_BLOB:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
break; // not composite is always OK
case VAR_LIST:
case VAR_DICT:
***************
*** 1097,1102 ****
--- 1098,1104 ----
case VAR_CHANNEL: return "channel";
case VAR_LIST: return "list";
case VAR_DICT: return "dict";
+ case VAR_INSTR: return "instr";
case VAR_FUNC:
case VAR_PARTIAL: return "func";
*** ../vim-8.2.2841/src/testing.c 2021-04-02 18:55:52.058322772 +0200
--- src/testing.c 2021-05-07 16:51:01.009525276 +0200
***************
*** 1023,1028 ****
--- 1023,1029 ----
case VAR_FLOAT:
case VAR_SPECIAL:
case VAR_STRING:
+ case VAR_INSTR:
break;
case VAR_JOB:
#ifdef FEAT_JOB_CHANNEL
*** ../vim-8.2.2841/src/viminfo.c 2021-02-10 19:22:12.132400451 +0100
--- src/viminfo.c 2021-05-07 16:59:07.928203253 +0200
***************
*** 1376,1381 ****
--- 1376,1382 ----
case VAR_PARTIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
continue;
}
fprintf(fp, "!%s\t%s\t", this_var->di_key, s);
*** ../vim-8.2.2841/src/if_py_both.h 2021-02-21 19:12:43.018019657 +0100
--- src/if_py_both.h 2021-05-07 16:59:37.992123722 +0200
***************
*** 6425,6430 ****
--- 6425,6431 ----
case VAR_VOID:
case VAR_CHANNEL:
case VAR_JOB:
+ case VAR_INSTR:
Py_INCREF(Py_None);
return Py_None;
case VAR_BOOL:
*** ../vim-8.2.2841/src/json.c 2021-02-08 21:53:05.592963320 +0100
--- src/json.c 2021-05-07 17:00:01.392061945 +0200
***************
*** 230,235 ****
--- 230,236 ----
case VAR_PARTIAL:
case VAR_JOB:
case VAR_CHANNEL:
+ case VAR_INSTR:
semsg(_(e_cannot_json_encode_str), vartype_name(val->v_type));
return FAIL;
*** ../vim-8.2.2841/src/testdir/test_vim9_disassemble.vim 2021-05-05 21:31:36.068018579 +0200
--- src/testdir/test_vim9_disassemble.vim 2021-05-07 17:44:36.216903993 +0200
***************
*** 140,145 ****
--- 140,174 ----
res)
enddef
+
+ def s:SearchPair()
+ var col = 8
+ searchpair("{", "", "}", "", "col('.') > col")
+ enddef
+
+ def Test_disassemble_seachpair()
+ var res = execute('disass s:SearchPair')
+ assert_match('<SNR>\d*_SearchPair.*' ..
+ ' var col = 8\_s*' ..
+ '\d STORE 8 in $0\_s*' ..
+ ' searchpair("{", "", "}", "", "col(''.'') > col")\_s*' ..
+ '\d PUSHS "{"\_s*' ..
+ '\d PUSHS ""\_s*' ..
+ '\d PUSHS "}"\_s*' ..
+ '\d PUSHS ""\_s*' ..
+ '\d INSTR\_s*' ..
+ ' 0 PUSHS "."\_s*' ..
+ ' 1 BCALL col(argc 1)\_s*' ..
+ ' 2 LOAD $0\_s*' ..
+ ' 3 COMPARENR >\_s*' ..
+ ' -------------\_s*' ..
+ '\d BCALL searchpair(argc 5)\_s*' ..
+ '\d DROP\_s*' ..
+ '\d RETURN 0',
+ res)
+ enddef
+
+
def s:RedirVar()
var result: string
redir =>> result
*** ../vim-8.2.2841/src/testdir/test_vim9_builtin.vim 2021-05-03 21:40:05.011799095 +0200
--- src/testdir/test_vim9_builtin.vim 2021-05-07 17:52:35.119650127 +0200
***************
*** 974,979 ****
--- 974,993 ----
bwipe!
enddef
+ def Test_searchpair()
+ new
+ setline(1, "here { and } there")
+ normal f{
+ var col = 15
+ assert_equal(1, searchpair('{', '', '}', '', 'col(".") > col'))
+ assert_equal(12, col('.'))
+ col = 8
+ normal 0f{
+ assert_equal(0, searchpair('{', '', '}', '', 'col(".") > col'))
+ assert_equal(6, col('.'))
+ bwipe!
+ enddef
+
def Test_set_get_bufline()
# similar to Test_setbufline_getbufline()
var lines =<< trim END
*** ../vim-8.2.2841/src/version.c 2021-05-07 15:00:14.197520296 +0200
--- src/version.c 2021-05-07 17:55:06.431598365 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2842,
/**/
--
A man is incomplete until he's married ... and then he's finished!
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///