aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_cmds2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/ex_cmds2.c')
-rw-r--r--src/nvim/ex_cmds2.c122
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) {