To: vim_dev@googlegroups.com Subject: Patch 8.2.1800 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1900 Problem: Vim9: command modifiers do not work. Solution: Make most command modifiers work. Files: src/vim9.h, src/vim9compile.c, src/vim9execute.c, src/usercmd.c, src/proto/usercmd.pro, src/scriptfile.c, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.1899/src/vim9.h 2020-10-23 18:02:28.707453763 +0200 --- src/vim9.h 2020-10-24 21:37:25.489883302 +0200 *************** *** 142,149 **** ISN_PUT, // ":put", uses isn_arg.put ! ISN_SILENT, // set msg_silent or emsg_silent if arg_number is non-zero ! ISN_UNSILENT, // undo ISN_SILENT ISN_SHUFFLE, // move item on stack up or down ISN_DROP // pop stack and discard value --- 142,149 ---- ISN_PUT, // ":put", uses isn_arg.put ! ISN_CMDMOD, // set cmdmod ! ISN_CMDMOD_REV, // undo ISN_CMDMOD ISN_SHUFFLE, // move item on stack up or down ISN_DROP // pop stack and discard value *************** *** 278,283 **** --- 278,288 ---- linenr_T put_lnum; // line number to put below } put_T; + // arguments to ISN_CMDMOD + typedef struct { + cmdmod_T *cf_cmdmod; // allocated + } cmod_T; + /* * Instruction */ *************** *** 314,319 **** --- 319,325 ---- checklen_T checklen; shuffle_T shuffle; put_T put; + cmod_T cmdmod; } isn_arg; }; *** ../vim-8.2.1899/src/vim9compile.c 2020-10-24 20:49:37.502683026 +0200 --- src/vim9compile.c 2020-10-24 22:05:17.881470884 +0200 *************** *** 142,148 **** garray_T ctx_type_stack; // type of each item on the stack garray_T *ctx_type_list; // list of pointers to allocated types ! int ctx_silent; // set when ISN_SILENT was generated }; static void delete_def_function_contents(dfunc_T *dfunc); --- 142,148 ---- garray_T ctx_type_stack; // type of each item on the stack garray_T *ctx_type_list; // list of pointers to allocated types ! int ctx_has_cmdmod; // ISN_CMDMOD was generated }; static void delete_def_function_contents(dfunc_T *dfunc); *************** *** 1823,1858 **** } /* ! * Generate any instructions for side effects of "cmdmod". */ static int generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod) { isn_T *isn; ! // TODO: use more modifiers in the command ! if (cmod->cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT)) { ! if ((isn = generate_instr(cctx, ISN_SILENT)) == NULL) return FAIL; ! isn->isn_arg.number = (cmod->cmod_flags & CMOD_ERRSILENT) != 0; ! cctx->ctx_silent = (cmod->cmod_flags & CMOD_ERRSILENT) ? 2 : 1; } return OK; } static int ! generate_restore_cmdmods(cctx_T *cctx) { isn_T *isn; ! if (cctx->ctx_silent > 0) { ! if ((isn = generate_instr(cctx, ISN_UNSILENT)) == NULL) return FAIL; - isn->isn_arg.number = cctx->ctx_silent == 2; - cctx->ctx_silent = 0; } return OK; } --- 1823,1867 ---- } /* ! * Generate an instruction for any command modifiers. */ static int generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod) { isn_T *isn; ! if (cmod->cmod_flags != 0 ! || cmod->cmod_split != 0 ! || cmod->cmod_verbose != 0 ! || cmod->cmod_tab != 0 ! || cmod->cmod_filter_regmatch.regprog != NULL) { ! cctx->ctx_has_cmdmod = TRUE; ! ! if ((isn = generate_instr(cctx, ISN_CMDMOD)) == NULL) ! return FAIL; ! isn->isn_arg.cmdmod.cf_cmdmod = ALLOC_ONE(cmdmod_T); ! if (isn->isn_arg.cmdmod.cf_cmdmod == NULL) return FAIL; ! mch_memmove(isn->isn_arg.cmdmod.cf_cmdmod, cmod, sizeof(cmdmod_T)); ! // filter progam now belongs to the instruction ! cmod->cmod_filter_regmatch.regprog = NULL; } + return OK; } static int ! generate_undo_cmdmods(cctx_T *cctx) { isn_T *isn; ! if (cctx->ctx_has_cmdmod) { ! if ((isn = generate_instr(cctx, ISN_CMDMOD_REV)) == NULL) return FAIL; } + return OK; } *************** *** 7092,7100 **** for (;;) { exarg_T ea; - cmdmod_T local_cmdmod; int starts_with_colon = FALSE; char_u *cmd; // Bail out on the first error to avoid a flood of errors and report // the right line number when inside try/catch. --- 7101,7109 ---- for (;;) { exarg_T ea; int starts_with_colon = FALSE; char_u *cmd; + cmdmod_T local_cmdmod; // Bail out on the first error to avoid a flood of errors and report // the right line number when inside try/catch. *************** *** 7175,7181 **** /* * COMMAND MODIFIERS */ ! CLEAR_FIELD(local_cmdmod); if (parse_command_modifiers(&ea, &errormsg, &local_cmdmod, FALSE) == FAIL) { --- 7184,7190 ---- /* * COMMAND MODIFIERS */ ! cctx.ctx_has_cmdmod = FALSE; if (parse_command_modifiers(&ea, &errormsg, &local_cmdmod, FALSE) == FAIL) { *************** *** 7497,7503 **** line = skipwhite(line); // Undo any command modifiers. ! generate_restore_cmdmods(&cctx); if (cctx.ctx_type_stack.ga_len < 0) { --- 7506,7512 ---- line = skipwhite(line); // Undo any command modifiers. ! generate_undo_cmdmods(&cctx); if (cctx.ctx_type_stack.ga_len < 0) { *************** *** 7742,7747 **** --- 7751,7762 ---- free_type(isn->isn_arg.type.ct_type); break; + case ISN_CMDMOD: + vim_regfree(isn->isn_arg.cmdmod.cf_cmdmod + ->cmod_filter_regmatch.regprog); + vim_free(isn->isn_arg.cmdmod.cf_cmdmod); + break; + case ISN_2BOOL: case ISN_2STRING: case ISN_2STRING_ANY: *************** *** 7754,7759 **** --- 7769,7775 ---- case ISN_CATCH: case ISN_CHECKLEN: case ISN_CHECKNR: + case ISN_CMDMOD_REV: case ISN_COMPAREANY: case ISN_COMPAREBLOB: case ISN_COMPAREBOOL: *************** *** 7805,7811 **** case ISN_PUT: case ISN_RETURN: case ISN_SHUFFLE: - case ISN_SILENT: case ISN_SLICE: case ISN_STORE: case ISN_STOREDICT: --- 7821,7826 ---- *************** *** 7819,7825 **** case ISN_STRSLICE: case ISN_THROW: case ISN_TRY: - case ISN_UNSILENT: // nothing allocated break; } --- 7834,7839 ---- *** ../vim-8.2.1899/src/vim9execute.c 2020-10-23 18:02:28.711453754 +0200 --- src/vim9execute.c 2020-10-24 22:32:19.873366315 +0200 *************** *** 832,839 **** int save_suppress_errthrow = suppress_errthrow; msglist_T **saved_msg_list = NULL; msglist_T *private_msg_list = NULL; ! int save_msg_silent = -1; ! int save_emsg_silent = -1; // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) --- 832,839 ---- int save_suppress_errthrow = suppress_errthrow; msglist_T **saved_msg_list = NULL; msglist_T *private_msg_list = NULL; ! cmdmod_T save_cmdmod; ! int restore_cmdmod = FALSE; // Get pointer to item in the stack. #define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx) *************** *** 2816,2837 **** } break; ! case ISN_SILENT: ! if (save_msg_silent == -1) ! save_msg_silent = msg_silent; ! ++msg_silent; ! if (iptr->isn_arg.number) ! { ! if (save_emsg_silent == -1) ! save_emsg_silent = emsg_silent; ! ++emsg_silent; ! } break; ! case ISN_UNSILENT: ! --msg_silent; ! if (iptr->isn_arg.number) ! --emsg_silent; break; case ISN_SHUFFLE: --- 2816,2834 ---- } break; ! case ISN_CMDMOD: ! save_cmdmod = cmdmod; ! restore_cmdmod = TRUE; ! cmdmod = *iptr->isn_arg.cmdmod.cf_cmdmod; ! apply_cmdmod(&cmdmod); break; ! case ISN_CMDMOD_REV: ! // filter regprog is owned by the instruction, don't free it ! cmdmod.cmod_filter_regmatch.regprog = NULL; ! undo_cmdmod(&cmdmod); ! cmdmod = save_cmdmod; ! restore_cmdmod = FALSE; break; case ISN_SHUFFLE: *************** *** 2905,2914 **** } msg_list = saved_msg_list; ! if (save_msg_silent != -1) ! msg_silent = save_msg_silent; ! if (save_emsg_silent != -1) ! emsg_silent = save_emsg_silent; failed_early: // Free all local variables, but not arguments. --- 2902,2913 ---- } msg_list = saved_msg_list; ! if (restore_cmdmod) ! { ! cmdmod.cmod_filter_regmatch.regprog = NULL; ! undo_cmdmod(&cmdmod); ! cmdmod = save_cmdmod; ! } failed_early: // Free all local variables, but not arguments. *************** *** 3527,3536 **** (long)iptr->isn_arg.put.put_lnum); break; ! case ISN_SILENT: smsg("%4d SILENT%s", current, ! iptr->isn_arg.number ? "!" : ""); break; ! case ISN_UNSILENT: smsg("%4d UNSILENT%s", current, ! iptr->isn_arg.number ? "!" : ""); break; case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current, iptr->isn_arg.shuffle.shfl_item, --- 3526,3549 ---- (long)iptr->isn_arg.put.put_lnum); break; ! // TODO: summarize modifiers ! case ISN_CMDMOD: ! { ! char_u *buf; ! int len = produce_cmdmods( ! NULL, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); ! ! buf = alloc(len + 1); ! if (buf != NULL) ! { ! (void)produce_cmdmods( ! buf, iptr->isn_arg.cmdmod.cf_cmdmod, FALSE); ! smsg("%4d CMDMOD %s", current, buf); ! vim_free(buf); ! } ! break; ! } ! case ISN_CMDMOD_REV: smsg("%4d CMDMOD_REV", current); break; case ISN_SHUFFLE: smsg("%4d SHUFFLE %d up %d", current, iptr->isn_arg.shuffle.shfl_item, *** ../vim-8.2.1899/src/usercmd.c 2020-10-24 20:49:37.502683026 +0200 --- src/usercmd.c 2020-10-24 22:27:14.546124437 +0200 *************** *** 1235,1271 **** } /* ! * Add modifiers from "cmdmod.cmod_split" to "buf". Set "multi_mods" when one * was added. Return the number of bytes added. */ size_t ! add_win_cmd_modifers(char_u *buf, int *multi_mods) { size_t result = 0; // :aboveleft and :leftabove ! if (cmdmod.cmod_split & WSP_ABOVE) result += add_cmd_modifier(buf, "aboveleft", multi_mods); // :belowright and :rightbelow ! if (cmdmod.cmod_split & WSP_BELOW) result += add_cmd_modifier(buf, "belowright", multi_mods); // :botright ! if (cmdmod.cmod_split & WSP_BOT) result += add_cmd_modifier(buf, "botright", multi_mods); // :tab ! if (cmdmod.cmod_tab > 0) result += add_cmd_modifier(buf, "tab", multi_mods); // :topleft ! if (cmdmod.cmod_split & WSP_TOP) result += add_cmd_modifier(buf, "topleft", multi_mods); // :vertical ! if (cmdmod.cmod_split & WSP_VERT) result += add_cmd_modifier(buf, "vertical", multi_mods); return result; } /* * Check for a <> code in a user command. * "code" points to the '<'. "len" the length of the <> (inclusive). * "buf" is where the result is to be added. --- 1235,1338 ---- } /* ! * Add modifiers from "cmod->cmod_split" to "buf". Set "multi_mods" when one * was added. Return the number of bytes added. */ size_t ! add_win_cmd_modifers(char_u *buf, cmdmod_T *cmod, int *multi_mods) { size_t result = 0; // :aboveleft and :leftabove ! if (cmod->cmod_split & WSP_ABOVE) result += add_cmd_modifier(buf, "aboveleft", multi_mods); // :belowright and :rightbelow ! if (cmod->cmod_split & WSP_BELOW) result += add_cmd_modifier(buf, "belowright", multi_mods); // :botright ! if (cmod->cmod_split & WSP_BOT) result += add_cmd_modifier(buf, "botright", multi_mods); // :tab ! if (cmod->cmod_tab > 0) result += add_cmd_modifier(buf, "tab", multi_mods); // :topleft ! if (cmod->cmod_split & WSP_TOP) result += add_cmd_modifier(buf, "topleft", multi_mods); // :vertical ! if (cmod->cmod_split & WSP_VERT) result += add_cmd_modifier(buf, "vertical", multi_mods); return result; } /* + * Generate text for the "cmod" command modifiers. + * If "buf" is NULL just return the length. + */ + int + produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote) + { + int result = 0; + int multi_mods = 0; + int i; + typedef struct { + int flag; + char *name; + } mod_entry_T; + static mod_entry_T mod_entries[] = { + #ifdef FEAT_BROWSE_CMD + {CMOD_BROWSE, "browse"}, + #endif + #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) + {CMOD_CONFIRM, "confirm"}, + #endif + {CMOD_HIDE, "hide"}, + {CMOD_KEEPALT, "keepalt"}, + {CMOD_KEEPJUMPS, "keepjumps"}, + {CMOD_KEEPMARKS, "keepmarks"}, + {CMOD_KEEPPATTERNS, "keeppatterns"}, + {CMOD_LOCKMARKS, "lockmarks"}, + {CMOD_NOSWAPFILE, "noswapfile"}, + {CMOD_UNSILENT, "unsilent"}, + {CMOD_NOAUTOCMD, "noautocmd"}, + #ifdef HAVE_SANDBOX + {CMOD_SANDBOX, "sandbox"}, + #endif + {0, NULL} + }; + + result = quote ? 2 : 0; + if (buf != NULL) + { + if (quote) + *buf++ = '"'; + *buf = '\0'; + } + + // the modifiers that are simple flags + for (i = 0; mod_entries[i].name != NULL; ++i) + if (cmod->cmod_flags & mod_entries[i].flag) + result += add_cmd_modifier(buf, mod_entries[i].name, &multi_mods); + + // :silent + if (cmod->cmod_flags & CMOD_SILENT) + result += add_cmd_modifier(buf, + (cmod->cmod_flags & CMOD_ERRSILENT) ? "silent!" + : "silent", &multi_mods); + // :verbose + if (p_verbose > 0) + result += add_cmd_modifier(buf, "verbose", &multi_mods); + // flags from cmod->cmod_split + result += add_win_cmd_modifers(buf, cmod, &multi_mods); + if (quote && buf != NULL) + { + buf += result - 2; + *buf = '"'; + } + return result; + } + + /* * Check for a <> code in a user command. * "code" points to the '<'. "len" the length of the <> (inclusive). * "buf" is where the result is to be added. *************** *** 1452,1513 **** case ct_MODS: { ! int multi_mods = 0; ! typedef struct { ! int flag; ! char *name; ! } mod_entry_T; ! static mod_entry_T mod_entries[] = { ! #ifdef FEAT_BROWSE_CMD ! {CMOD_BROWSE, "browse"}, ! #endif ! #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) ! {CMOD_CONFIRM, "confirm"}, ! #endif ! {CMOD_HIDE, "hide"}, ! {CMOD_KEEPALT, "keepalt"}, ! {CMOD_KEEPJUMPS, "keepjumps"}, ! {CMOD_KEEPMARKS, "keepmarks"}, ! {CMOD_KEEPPATTERNS, "keeppatterns"}, ! {CMOD_LOCKMARKS, "lockmarks"}, ! {CMOD_NOSWAPFILE, "noswapfile"}, ! {0, NULL} ! }; ! int i; ! ! result = quote ? 2 : 0; ! if (buf != NULL) ! { ! if (quote) ! *buf++ = '"'; ! *buf = '\0'; ! } ! ! // the modifiers that are simple flags ! for (i = 0; mod_entries[i].name != NULL; ++i) ! if (cmdmod.cmod_flags & mod_entries[i].flag) ! result += add_cmd_modifier(buf, mod_entries[i].name, ! &multi_mods); ! ! // TODO: How to support :noautocmd? ! #ifdef HAVE_SANDBOX ! // TODO: How to support :sandbox? ! #endif ! // :silent ! if (msg_silent > 0) ! result += add_cmd_modifier(buf, ! emsg_silent > 0 ? "silent!" : "silent", &multi_mods); ! // TODO: How to support :unsilent? ! // :verbose ! if (p_verbose > 0) ! result += add_cmd_modifier(buf, "verbose", &multi_mods); ! // flags from cmdmod.cmod_split ! result += add_win_cmd_modifers(buf, &multi_mods); ! if (quote && buf != NULL) ! { ! buf += result - 2; ! *buf = '"'; ! } break; } --- 1519,1525 ---- case ct_MODS: { ! result = produce_cmdmods(buf, &cmdmod, quote); break; } *** ../vim-8.2.1899/src/proto/usercmd.pro 2020-04-13 21:16:18.039292270 +0200 --- src/proto/usercmd.pro 2020-10-24 22:27:17.942115967 +0200 *************** *** 14,19 **** void ex_comclear(exarg_T *eap); void uc_clear(garray_T *gap); void ex_delcommand(exarg_T *eap); ! size_t add_win_cmd_modifers(char_u *buf, int *multi_mods); void do_ucmd(exarg_T *eap); /* vim: set ft=c : */ --- 14,20 ---- void ex_comclear(exarg_T *eap); void uc_clear(garray_T *gap); void ex_delcommand(exarg_T *eap); ! size_t add_win_cmd_modifers(char_u *buf, cmdmod_T *cmod, int *multi_mods); ! int produce_cmdmods(char_u *buf, cmdmod_T *cmod, int quote); void do_ucmd(exarg_T *eap); /* vim: set ft=c : */ *** ../vim-8.2.1899/src/scriptfile.c 2020-10-24 20:49:37.502683026 +0200 --- src/scriptfile.c 2020-10-24 22:25:13.686426083 +0200 *************** *** 1009,1015 **** int multi_mods = 0; buf[0] = NUL; ! (void)add_win_cmd_modifers(buf, &multi_mods); vim_setenv((char_u *)"OPTWIN_CMD", buf); cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); --- 1009,1015 ---- int multi_mods = 0; buf[0] = NUL; ! (void)add_win_cmd_modifers(buf, &cmdmod, &multi_mods); vim_setenv((char_u *)"OPTWIN_CMD", buf); cmd_source((char_u *)SYS_OPTWIN_FILE, NULL); *** ../vim-8.2.1899/src/testdir/test_vim9_disassemble.vim 2020-10-23 18:02:28.711453754 +0200 --- src/testdir/test_vim9_disassemble.vim 2020-10-24 22:33:12.893235083 +0200 *************** *** 1627,1641 **** var res = execute('disass s:SilentMessage') assert_match('\d*_SilentMessage\_s*' .. 'silent echomsg "text"\_s*' .. ! '\d SILENT\_s*' .. '\d PUSHS "text"\_s*' .. '\d ECHOMSG 1\_s*' .. ! '\d UNSILENT\_s*' .. 'silent! echoerr "error"\_s*' .. ! '\d SILENT!\_s*' .. '\d PUSHS "error"\_s*' .. '\d ECHOERR 1\_s*' .. ! '\d UNSILENT!\_s*' .. '\d PUSHNR 0\_s*' .. '\d RETURN', res) --- 1627,1641 ---- var res = execute('disass s:SilentMessage') assert_match('\d*_SilentMessage\_s*' .. 'silent echomsg "text"\_s*' .. ! '\d CMDMOD silent\_s*' .. '\d PUSHS "text"\_s*' .. '\d ECHOMSG 1\_s*' .. ! '\d CMDMOD_REV\_s*' .. 'silent! echoerr "error"\_s*' .. ! '\d CMDMOD silent!\_s*' .. '\d PUSHS "error"\_s*' .. '\d ECHOERR 1\_s*' .. ! '\d CMDMOD_REV\_s*' .. '\d PUSHNR 0\_s*' .. '\d RETURN', res) *** ../vim-8.2.1899/src/version.c 2020-10-24 20:58:02.533121768 +0200 --- src/version.c 2020-10-24 23:06:40.563791658 +0200 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 1900, /**/ -- I have a watch cat! Just break in and she'll watch. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///