Patch 8.2.2834
Problem: Vim9: :cexpr does not work with local variables.
Solution: Compile :cexpr.
Files: src/vim9compile.c, src/vim9.h, src/vim9execute.c, src/quickfix.c,
src/proto/quickfix.pro, src/testdir/test_quickfix.vim,
src/testdir/test_vim9_disassemble.vim
*** ../vim-8.2.2833/src/vim9compile.c 2021-04-25 13:54:38.988836743 +0200
--- src/vim9compile.c 2021-05-05 21:22:00.713708961 +0200
***************
*** 8704,8709 ****
--- 8704,8737 ----
return compile_exec(line, eap, cctx);
}
+ static char_u *
+ compile_cexpr(char_u *line, exarg_T *eap, cctx_T *cctx)
+ {
+ isn_T *isn;
+ char_u *p;
+
+ isn = generate_instr(cctx, ISN_CEXPR_AUCMD);
+ if (isn == NULL)
+ return NULL;
+ isn->isn_arg.number = eap->cmdidx;
+
+ p = eap->arg;
+ if (compile_expr0(&p, cctx) == FAIL)
+ return NULL;
+
+ isn = generate_instr(cctx, ISN_CEXPR_CORE);
+ if (isn == NULL)
+ return NULL;
+ isn->isn_arg.cexpr.cexpr_ref = ALLOC_ONE(cexprref_T);
+ if (isn->isn_arg.cexpr.cexpr_ref == NULL)
+ return NULL;
+ isn->isn_arg.cexpr.cexpr_ref->cer_cmdidx = eap->cmdidx;
+ isn->isn_arg.cexpr.cexpr_ref->cer_forceit = eap->forceit;
+ isn->isn_arg.cexpr.cexpr_ref->cer_cmdline = vim_strsave(skipwhite(line));
+
+ return p;
+ }
+
/*
* Add a function to the list of :def functions.
* This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
***************
*** 9262,9267 ****
--- 9290,9305 ----
line = compile_redir(line, &ea, &cctx);
break;
+ case CMD_cexpr:
+ case CMD_lexpr:
+ case CMD_caddexpr:
+ case CMD_laddexpr:
+ case CMD_cgetexpr:
+ case CMD_lgetexpr:
+ ea.arg = p;
+ line = compile_cexpr(line, &ea, &cctx);
+ break;
+
// TODO: any other commands with an expression argument?
case CMD_append:
***************
*** 9602,9607 ****
--- 9640,9649 ----
vim_free(isn->isn_arg.try.try_ref);
break;
+ case ISN_CEXPR_CORE:
+ vim_free(isn->isn_arg.cexpr.cexpr_ref);
+ break;
+
case ISN_2BOOL:
case ISN_2STRING:
case ISN_2STRING_ANY:
***************
*** 9614,9619 ****
--- 9656,9662 ----
case ISN_BLOBINDEX:
case ISN_BLOBSLICE:
case ISN_CATCH:
+ case ISN_CEXPR_AUCMD:
case ISN_CHECKLEN:
case ISN_CHECKNR:
case ISN_CMDMOD_REV:
*** ../vim-8.2.2833/src/vim9.h 2021-04-26 20:32:54.918399234 +0200
--- src/vim9.h 2021-05-05 21:08:23.319561182 +0200
***************
*** 172,177 ****
--- 172,180 ----
ISN_REDIRSTART, // :redir =>
ISN_REDIREND, // :redir END, isn_arg.number == 1 for append
+ ISN_CEXPR_AUCMD, // first part of :cexpr isn_arg.number is cmdidx
+ ISN_CEXPR_CORE, // second part of :cexpr, uses isn_arg.cexpr
+
ISN_FINISH // end marker in list of instructions
} isntype_T;
***************
*** 352,357 ****
--- 355,372 ----
isn_T *subs_instr; // sequence of instructions
} subs_T;
+ // indirect arguments to ISN_TRY
+ typedef struct {
+ int cer_cmdidx;
+ char_u *cer_cmdline;
+ int cer_forceit;
+ } cexprref_T;
+
+ // arguments to ISN_CEXPR_CORE
+ typedef struct {
+ cexprref_T *cexpr_ref;
+ } cexpr_T;
+
/*
* Instruction
*/
***************
*** 395,400 ****
--- 410,416 ----
unpack_T unpack;
isn_outer_T outer;
subs_T subs;
+ cexpr_T cexpr;
} isn_arg;
};
*** ../vim-8.2.2833/src/vim9execute.c 2021-04-26 21:34:43.708519638 +0200
--- src/vim9execute.c 2021-05-05 21:19:31.250055070 +0200
***************
*** 1442,1447 ****
--- 1442,1470 ----
}
break;
+ case ISN_CEXPR_AUCMD:
+ if (trigger_cexpr_autocmd(iptr->isn_arg.number) == FAIL)
+ goto on_error;
+ break;
+
+ case ISN_CEXPR_CORE:
+ {
+ exarg_T ea;
+ int res;
+
+ CLEAR_FIELD(ea);
+ ea.cmdidx = iptr->isn_arg.cexpr.cexpr_ref->cer_cmdidx;
+ ea.forceit = iptr->isn_arg.cexpr.cexpr_ref->cer_forceit;
+ ea.cmdlinep = &iptr->isn_arg.cexpr.cexpr_ref->cer_cmdline;
+ --ectx->ec_stack.ga_len;
+ tv = STACK_TV_BOT(0);
+ res = cexpr_core(&ea, tv);
+ clear_tv(tv);
+ if (res == FAIL)
+ goto on_error;
+ }
+ break;
+
// execute Ex command from pieces on the stack
case ISN_EXECCONCAT:
{
***************
*** 4391,4396 ****
--- 4414,4433 ----
smsg("%s%4d REDIR END%s", pfx, current,
iptr->isn_arg.number ? " append" : "");
break;
+ case ISN_CEXPR_AUCMD:
+ smsg("%s%4d CEXPR pre %s", pfx, current,
+ cexpr_get_auname(iptr->isn_arg.number));
+ break;
+ case ISN_CEXPR_CORE:
+ {
+ cexprref_T *cer = iptr->isn_arg.cexpr.cexpr_ref;
+
+ smsg("%s%4d CEXPR core %s%s \"%s\"", pfx, current,
+ cexpr_get_auname(cer->cer_cmdidx),
+ cer->cer_forceit ? "!" : "",
+ cer->cer_cmdline);
+ }
+ break;
case ISN_SUBSTITUTE:
{
subs_T *subs = &iptr->isn_arg.subs;
*** ../vim-8.2.2833/src/quickfix.c 2021-05-03 18:57:02.392070898 +0200
--- src/quickfix.c 2021-05-05 21:16:02.518534404 +0200
***************
*** 7864,7870 ****
/*
* Return the autocmd name for the :cexpr Ex commands.
*/
! static char_u *
cexpr_get_auname(cmdidx_T cmdidx)
{
switch (cmdidx)
--- 7864,7870 ----
/*
* Return the autocmd name for the :cexpr Ex commands.
*/
! char_u *
cexpr_get_auname(cmdidx_T cmdidx)
{
switch (cmdidx)
***************
*** 7879,7910 ****
}
}
! /*
! * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
! * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
! */
! void
! ex_cexpr(exarg_T *eap)
{
! typval_T *tv;
! qf_info_T *qi;
! char_u *au_name = NULL;
! int res;
! int_u save_qfid;
! win_T *wp = NULL;
- au_name = cexpr_get_auname(eap->cmdidx);
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
curbuf->b_fname, TRUE, curbuf))
{
- #ifdef FEAT_EVAL
if (aborting())
! return;
! #endif
}
qi = qf_cmd_get_or_alloc_stack(eap, &wp);
if (qi == NULL)
return;
// Evaluate the expression. When the result is a string or a list we can
--- 7879,7961 ----
}
}
! int
! trigger_cexpr_autocmd(int cmdidx)
{
! char_u *au_name = cexpr_get_auname(cmdidx);
if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
curbuf->b_fname, TRUE, curbuf))
{
if (aborting())
! return FAIL;
}
+ return OK;
+ }
+
+ int
+ cexpr_core(exarg_T *eap, typval_T *tv)
+ {
+ qf_info_T *qi;
+ win_T *wp = NULL;
qi = qf_cmd_get_or_alloc_stack(eap, &wp);
if (qi == NULL)
+ return FAIL;
+
+ if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
+ || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
+ {
+ int res;
+ int_u save_qfid;
+ char_u *au_name = cexpr_get_auname(eap->cmdidx);
+
+ incr_quickfix_busy();
+ res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
+ (eap->cmdidx != CMD_caddexpr
+ && eap->cmdidx != CMD_laddexpr),
+ (linenr_T)0, (linenr_T)0,
+ qf_cmdtitle(*eap->cmdlinep), NULL);
+ if (qf_stack_empty(qi))
+ {
+ decr_quickfix_busy();
+ return FAIL;
+ }
+ if (res >= 0)
+ qf_list_changed(qf_get_curlist(qi));
+
+ // Remember the current quickfix list identifier, so that we can
+ // check for autocommands changing the current quickfix list.
+ save_qfid = qf_get_curlist(qi)->qf_id;
+ if (au_name != NULL)
+ apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
+ curbuf->b_fname, TRUE, curbuf);
+
+ // Jump to the first error for a new list and if autocmds didn't
+ // free the list.
+ if (res > 0 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)
+ && qflist_valid(wp, save_qfid))
+ // display the first error
+ qf_jump_first(qi, save_qfid, eap->forceit);
+ decr_quickfix_busy();
+ return OK;
+ }
+
+ emsg(_("E777: String or List expected"));
+ return FAIL;
+ }
+
+ /*
+ * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
+ * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
+ * Also: ":caddexpr", ":cgetexpr", "laddexpr" and "laddexpr".
+ */
+ void
+ ex_cexpr(exarg_T *eap)
+ {
+ typval_T *tv;
+
+ if (trigger_cexpr_autocmd(eap->cmdidx) == FAIL)
return;
// Evaluate the expression. When the result is a string or a list we can
***************
*** 7912,7953 ****
tv = eval_expr(eap->arg, eap);
if (tv != NULL)
{
! if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
! || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
! {
! incr_quickfix_busy();
! res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
! (eap->cmdidx != CMD_caddexpr
! && eap->cmdidx != CMD_laddexpr),
! (linenr_T)0, (linenr_T)0,
! qf_cmdtitle(*eap->cmdlinep), NULL);
! if (qf_stack_empty(qi))
! {
! decr_quickfix_busy();
! goto cleanup;
! }
! if (res >= 0)
! qf_list_changed(qf_get_curlist(qi));
!
! // Remember the current quickfix list identifier, so that we can
! // check for autocommands changing the current quickfix list.
! save_qfid = qf_get_curlist(qi)->qf_id;
! if (au_name != NULL)
! apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
! curbuf->b_fname, TRUE, curbuf);
!
! // Jump to the first error for a new list and if autocmds didn't
! // free the list.
! if (res > 0 && (eap->cmdidx == CMD_cexpr
! || eap->cmdidx == CMD_lexpr)
! && qflist_valid(wp, save_qfid))
! // display the first error
! qf_jump_first(qi, save_qfid, eap->forceit);
! decr_quickfix_busy();
! }
! else
! emsg(_("E777: String or List expected"));
! cleanup:
free_tv(tv);
}
}
--- 7963,7969 ----
tv = eval_expr(eap->arg, eap);
if (tv != NULL)
{
! (void)cexpr_core(eap, tv);
free_tv(tv);
}
}
*** ../vim-8.2.2833/src/proto/quickfix.pro 2020-07-20 21:31:01.268823457
+0200
--- src/proto/quickfix.pro 2021-05-05 21:16:06.846524534 +0200
***************
*** 30,35 ****
--- 30,38 ----
int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, dict_T
*what);
int set_ref_in_quickfix(int copyID);
void ex_cbuffer(exarg_T *eap);
+ char_u *cexpr_get_auname(cmdidx_T cmdidx);
+ int trigger_cexpr_autocmd(int cmdidx);
+ int cexpr_core(exarg_T *eap, typval_T *tv);
void ex_cexpr(exarg_T *eap);
void ex_helpgrep(exarg_T *eap);
void f_getloclist(typval_T *argvars, typval_T *rettv);
*** ../vim-8.2.2833/src/testdir/test_quickfix.vim 2021-04-26
21:14:12.713924760 +0200
--- src/testdir/test_quickfix.vim 2021-05-05 21:25:42.969191409 +0200
***************
*** 722,727 ****
--- 722,743 ----
helpclose
enddef
+ def Test_vim9_cexpr()
+ var text = 'somefile:95:error'
+ cexpr text
+ var l = getqflist()
+ assert_equal(1, l->len())
+ assert_equal(95, l[0].lnum)
+ assert_equal('error', l[0].text)
+
+ text = 'somefile:77:warning'
+ caddexpr text
+ l = getqflist()
+ assert_equal(2, l->len())
+ assert_equal(77, l[1].lnum)
+ assert_equal('warning', l[1].text)
+ enddef
+
func Test_errortitle()
augroup QfBufWinEnter
au!
*** ../vim-8.2.2833/src/testdir/test_vim9_disassemble.vim 2021-04-20
22:16:35.355248931 +0200
--- src/testdir/test_vim9_disassemble.vim 2021-05-05 21:29:49.304542273
+0200
***************
*** 167,172 ****
--- 167,191 ----
res)
enddef
+ def s:Cexpr()
+ var errors = "list of errors"
+ cexpr errors
+ enddef
+
+ def Test_disassemble_cexpr()
+ var res = execute('disass s:Cexpr')
+ assert_match('<SNR>\d*_Cexpr.*' ..
+ ' var errors = "list of errors"\_s*' ..
+ '\d PUSHS "list of errors"\_s*' ..
+ '\d STORE $0\_s*' ..
+ ' cexpr errors\_s*' ..
+ '\d CEXPR pre cexpr\_s*' ..
+ '\d LOAD $0\_s*' ..
+ '\d CEXPR core cexpr "cexpr errors"\_s*' ..
+ '\d RETURN 0',
+ res)
+ enddef
+
def s:YankRange()
norm! m[jjm]
:'[,']yank
*** ../vim-8.2.2833/src/version.c 2021-05-05 19:58:12.921605195 +0200
--- src/version.c 2021-05-05 21:30:47.388251203 +0200
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2834,
/**/
--
The term "free software" is defined by Richard M. Stallman as
being software that isn't necessarily for free. Confusing?
Let's call it "Stallman software" then!
-- Bram Moolenaar
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// \\\
\\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202105051932.145JWDln885076%40masaka.moolenaar.net.