diff options
Diffstat (limited to 'src/nvim/ex_cmds2.c')
-rw-r--r-- | src/nvim/ex_cmds2.c | 122 |
1 files changed, 98 insertions, 24 deletions
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index cc0ec71627..e394edb032 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -120,6 +120,9 @@ struct source_cookie { /// batch mode debugging: don't save and restore typeahead. static bool debug_greedy = false; +static char *debug_oldval = NULL; // old and newval for debug expressions +static char *debug_newval = NULL; + /// Debug mode. Repeatedly get Ex commands, until told to continue normal /// execution. void do_debug(char_u *cmd) @@ -166,6 +169,16 @@ void do_debug(char_u *cmd) if (!debug_did_msg) { MSG(_("Entering Debug mode. Type \"cont\" to continue.")); } + if (debug_oldval != NULL) { + smsg(_("Oldval = \"%s\""), debug_oldval); + xfree(debug_oldval); + debug_oldval = NULL; + } + if (debug_newval != NULL) { + smsg(_("Newval = \"%s\""), debug_newval); + xfree(debug_newval); + debug_newval = NULL; + } if (sourcing_name != NULL) { msg(sourcing_name); } @@ -174,7 +187,6 @@ void do_debug(char_u *cmd) } else { smsg(_("cmd: %s"), cmd); } - // Repeat getting a command and executing it. for (;; ) { msg_scroll = true; @@ -514,11 +526,13 @@ bool dbg_check_skipped(exarg_T *eap) /// This is a grow-array of structs. struct debuggy { int dbg_nr; ///< breakpoint number - int dbg_type; ///< DBG_FUNC or DBG_FILE - char_u *dbg_name; ///< function or file name + int dbg_type; ///< DBG_FUNC or DBG_FILE or DBG_EXPR + char_u *dbg_name; ///< function, expression or file name regprog_T *dbg_prog; ///< regexp program linenr_T dbg_lnum; ///< line number in function or file int dbg_forceit; ///< ! used + typval_T *dbg_val; ///< last result of watchexpression + int dbg_level; ///< stored nested level for expr }; static garray_T dbg_breakp = { 0, 0, sizeof(struct debuggy), 4, NULL }; @@ -530,6 +544,7 @@ static int last_breakp = 0; // nr of last defined breakpoint static garray_T prof_ga = { 0, 0, sizeof(struct debuggy), 4, NULL }; #define DBG_FUNC 1 #define DBG_FILE 2 +#define DBG_EXPR 3 /// Parse the arguments of ":profile", ":breakadd" or ":breakdel" and put them @@ -562,6 +577,8 @@ static int dbg_parsearg(char_u *arg, garray_T *gap) } bp->dbg_type = DBG_FILE; here = true; + } else if (gap != &prof_ga && STRNCMP(p, "expr", 4) == 0) { + bp->dbg_type = DBG_EXPR; } else { EMSG2(_(e_invarg2), p); return FAIL; @@ -590,6 +607,9 @@ static int dbg_parsearg(char_u *arg, garray_T *gap) bp->dbg_name = vim_strsave(p); } else if (here) { bp->dbg_name = vim_strsave(curbuf->b_ffname); + } else if (bp->dbg_type == DBG_EXPR) { + bp->dbg_name = vim_strsave(p); + bp->dbg_val = eval_expr(bp->dbg_name); } else { // Expand the file name in the same way as do_source(). This means // doing it twice, so that $DIR/file gets expanded when $DIR is @@ -621,7 +641,6 @@ static int dbg_parsearg(char_u *arg, garray_T *gap) void ex_breakadd(exarg_T *eap) { struct debuggy *bp; - char_u *pat; garray_T *gap; gap = &dbg_breakp; @@ -633,22 +652,28 @@ void ex_breakadd(exarg_T *eap) bp = &DEBUGGY(gap, gap->ga_len); bp->dbg_forceit = eap->forceit; - pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); - if (pat != NULL) { - bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); - xfree(pat); - } - if (pat == NULL || bp->dbg_prog == NULL) { - xfree(bp->dbg_name); - } else { - if (bp->dbg_lnum == 0) { // default line number is 1 - bp->dbg_lnum = 1; + if (bp->dbg_type != DBG_EXPR) { + char_u *pat = file_pat_to_reg_pat(bp->dbg_name, NULL, NULL, false); + if (pat != NULL) { + bp->dbg_prog = vim_regcomp(pat, RE_MAGIC + RE_STRING); + xfree(pat); } - if (eap->cmdidx != CMD_profile) { - DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; - debug_tick++; + if (pat == NULL || bp->dbg_prog == NULL) { + xfree(bp->dbg_name); + } else { + if (bp->dbg_lnum == 0) { // default line number is 1 + bp->dbg_lnum = 1; + } + if (eap->cmdidx != CMD_profile) { + DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp; + debug_tick++; + } + gap->ga_len++; } - gap->ga_len++; + } else { + // DBG_EXPR + DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp; + debug_tick++; } } } @@ -691,7 +716,7 @@ void ex_breakdel(exarg_T *eap) todel = 0; del_all = true; } else { - // ":breakdel {func|file} [lnum] {name}" + // ":breakdel {func|file|expr} [lnum] {name}" if (dbg_parsearg(eap->arg, gap) == FAIL) { return; } @@ -716,6 +741,10 @@ void ex_breakdel(exarg_T *eap) } else { while (!GA_EMPTY(gap)) { xfree(DEBUGGY(gap, todel).dbg_name); + if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR + && DEBUGGY(gap, todel).dbg_val != NULL) { + tv_free(DEBUGGY(gap, todel).dbg_val); + } vim_regfree(DEBUGGY(gap, todel).dbg_prog); gap->ga_len--; if (todel < gap->ga_len) { @@ -750,11 +779,15 @@ void ex_breaklist(exarg_T *eap) if (bp->dbg_type == DBG_FILE) { home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, true); } - smsg(_("%3d %s %s line %" PRId64), - bp->dbg_nr, - bp->dbg_type == DBG_FUNC ? "func" : "file", - bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, - (int64_t)bp->dbg_lnum); + if (bp->dbg_type != DBG_EXPR) { + smsg(_("%3d %s %s line %" PRId64), + bp->dbg_nr, + bp->dbg_type == DBG_FUNC ? "func" : "file", + bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff, + (int64_t)bp->dbg_lnum); + } else { + smsg(_("%3d expr %s"), bp->dbg_nr, bp->dbg_name); + } } } } @@ -814,6 +847,7 @@ debuggy_find( // an already found breakpoint. bp = &DEBUGGY(gap, i); if ((bp->dbg_type == DBG_FILE) == file + && bp->dbg_type != DBG_EXPR && (gap == &prof_ga || (bp->dbg_lnum > after && (lnum == 0 || bp->dbg_lnum < lnum)))) { // Save the value of got_int and reset it. We don't want a @@ -828,6 +862,46 @@ debuggy_find( } } got_int |= prev_got_int; + } else if (bp->dbg_type == DBG_EXPR) { + bool line = false; + + prev_got_int = got_int; + got_int = false; + + typval_T *tv = eval_expr(bp->dbg_name); + if (tv != NULL) { + if (bp->dbg_val == NULL) { + debug_oldval = typval_tostring(NULL); + bp->dbg_val = tv; + debug_newval = typval_tostring(bp->dbg_val); + line = true; + } else { + if (typval_compare(tv, bp->dbg_val, TYPE_EQUAL, true, false) == OK + && tv->vval.v_number == false) { + line = true; + debug_oldval = typval_tostring(bp->dbg_val); + // Need to evaluate again, typval_compare() overwrites "tv". + typval_T *v = eval_expr(bp->dbg_name); + debug_newval = typval_tostring(v); + tv_free(bp->dbg_val); + bp->dbg_val = v; + } + tv_free(tv); + } + } else if (bp->dbg_val != NULL) { + debug_oldval = typval_tostring(bp->dbg_val); + debug_newval = typval_tostring(NULL); + tv_free(bp->dbg_val); + bp->dbg_val = NULL; + line = true; + } + + if (line) { + lnum = after > 0 ? after : 1; + break; + } + + got_int |= prev_got_int; } } if (name != fname) { |