Patch 8.0.1505
Problem: Debugger can't break on a condition. (Charles Campbell)
Solution: Add ":breakadd expr". (Christian Brabandt, closes #859)
Files: runtime/doc/repeat.txt, src/eval.c, src/evalfunc.c,
src/userfunc.c, src/ex_cmds2.c, src/ex_docmd.c,
src/proto/eval.pro, src/proto/ex_cmds2.pro, src/structs.h
*** ../vim-8.0.1504/runtime/doc/repeat.txt 2017-06-10 14:29:26.766871128
+0200
--- runtime/doc/repeat.txt 2018-02-11 18:28:19.817645767 +0100
***************
*** 802,807 ****
--- 806,824 ----
< Note that this only works for commands that are executed when
sourcing the file, not for a function defined in that file.
+ :breaka[dd] expr {expression}
+ Sets a breakpoint, that will break whenever the {expression}
+ evaluates to a different value. Example: >
+ :breakadd expr g:lnum
+
+ < Will break, whenever the global variable lnum changes.
+ Note if you watch a |script-variable| this will break
+ when switching scripts, since the script variable is only
+ valid in the script where it has been defined and if that
+ script is called from several other scripts, this will stop
+ whenever that particular variable will become visible or
+ unaccessible again.
+
The [lnum] is the line number of the breakpoint. Vim will stop at or after
this line. When omitted line 1 is used.
*** ../vim-8.0.1504/src/eval.c 2018-02-10 18:45:21.044822330 +0100
--- src/eval.c 2018-02-11 18:44:34.598688909 +0100
***************
*** 3237,3258 ****
}
/*
- * types for expressions.
- */
- typedef enum
- {
- TYPE_UNKNOWN = 0
- , TYPE_EQUAL /* == */
- , TYPE_NEQUAL /* != */
- , TYPE_GREATER /* > */
- , TYPE_GEQUAL /* >= */
- , TYPE_SMALLER /* < */
- , TYPE_SEQUAL /* <= */
- , TYPE_MATCH /* =~ */
- , TYPE_NOMATCH /* !~ */
- } exptype_T;
-
- /*
* The "evaluate" argument: When FALSE, the argument is only parsed but not
* executed. The function may return OK, but the rettv will be of type
* VAR_UNKNOWN. The function still returns FAIL for a syntax error.
--- 3237,3242 ----
***************
*** 3531,3539 ****
exptype_T type = TYPE_UNKNOWN;
int type_is = FALSE; /* TRUE for "is" and "isnot" */
int len = 2;
- varnumber_T n1, n2;
- char_u *s1, *s2;
- char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
int ic;
/*
--- 3515,3520 ----
***************
*** 3615,3812 ****
clear_tv(rettv);
return FAIL;
}
!
! if (evaluate)
! {
! if (type_is && rettv->v_type != var2.v_type)
! {
! /* For "is" a different type always means FALSE, for "notis"
! * it means TRUE. */
! n1 = (type == TYPE_NEQUAL);
! }
! else if (rettv->v_type == VAR_LIST || var2.v_type == VAR_LIST)
! {
! if (type_is)
! {
! n1 = (rettv->v_type == var2.v_type
! && rettv->vval.v_list == var2.vval.v_list);
! if (type == TYPE_NEQUAL)
! n1 = !n1;
! }
! else if (rettv->v_type != var2.v_type
! || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
! {
! if (rettv->v_type != var2.v_type)
! EMSG(_("E691: Can only compare List with List"));
! else
! EMSG(_("E692: Invalid operation for List"));
! clear_tv(rettv);
! clear_tv(&var2);
! return FAIL;
! }
! else
! {
! /* Compare two Lists for being equal or unequal. */
! n1 = list_equal(rettv->vval.v_list, var2.vval.v_list,
! ic, FALSE);
! if (type == TYPE_NEQUAL)
! n1 = !n1;
! }
! }
!
! else if (rettv->v_type == VAR_DICT || var2.v_type == VAR_DICT)
! {
! if (type_is)
! {
! n1 = (rettv->v_type == var2.v_type
! && rettv->vval.v_dict == var2.vval.v_dict);
! if (type == TYPE_NEQUAL)
! n1 = !n1;
! }
! else if (rettv->v_type != var2.v_type
! || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
! {
! if (rettv->v_type != var2.v_type)
! EMSG(_("E735: Can only compare Dictionary with
Dictionary"));
! else
! EMSG(_("E736: Invalid operation for Dictionary"));
! clear_tv(rettv);
! clear_tv(&var2);
! return FAIL;
! }
! else
! {
! /* Compare two Dictionaries for being equal or unequal. */
! n1 = dict_equal(rettv->vval.v_dict, var2.vval.v_dict,
! ic, FALSE);
! if (type == TYPE_NEQUAL)
! n1 = !n1;
! }
! }
!
! else if (rettv->v_type == VAR_FUNC || var2.v_type == VAR_FUNC
! || rettv->v_type == VAR_PARTIAL || var2.v_type == VAR_PARTIAL)
! {
! if (type != TYPE_EQUAL && type != TYPE_NEQUAL)
! {
! EMSG(_("E694: Invalid operation for Funcrefs"));
! clear_tv(rettv);
! clear_tv(&var2);
! return FAIL;
! }
! if ((rettv->v_type == VAR_PARTIAL
! && rettv->vval.v_partial == NULL)
! || (var2.v_type == VAR_PARTIAL
! && var2.vval.v_partial == NULL))
! /* when a partial is NULL assume not equal */
! n1 = FALSE;
! else if (type_is)
! {
! if (rettv->v_type == VAR_FUNC && var2.v_type == VAR_FUNC)
! /* strings are considered the same if their value is
! * the same */
! n1 = tv_equal(rettv, &var2, ic, FALSE);
! else if (rettv->v_type == VAR_PARTIAL
! && var2.v_type == VAR_PARTIAL)
! n1 = (rettv->vval.v_partial == var2.vval.v_partial);
! else
! n1 = FALSE;
! }
! else
! n1 = tv_equal(rettv, &var2, ic, FALSE);
! if (type == TYPE_NEQUAL)
! n1 = !n1;
! }
!
! #ifdef FEAT_FLOAT
! /*
! * If one of the two variables is a float, compare as a float.
! * When using "=~" or "!~", always compare as string.
! */
! else if ((rettv->v_type == VAR_FLOAT || var2.v_type == VAR_FLOAT)
! && type != TYPE_MATCH && type != TYPE_NOMATCH)
! {
! float_T f1, f2;
!
! if (rettv->v_type == VAR_FLOAT)
! f1 = rettv->vval.v_float;
! else
! f1 = get_tv_number(rettv);
! if (var2.v_type == VAR_FLOAT)
! f2 = var2.vval.v_float;
! else
! f2 = get_tv_number(&var2);
! n1 = FALSE;
! switch (type)
! {
! case TYPE_EQUAL: n1 = (f1 == f2); break;
! case TYPE_NEQUAL: n1 = (f1 != f2); break;
! case TYPE_GREATER: n1 = (f1 > f2); break;
! case TYPE_GEQUAL: n1 = (f1 >= f2); break;
! case TYPE_SMALLER: n1 = (f1 < f2); break;
! case TYPE_SEQUAL: n1 = (f1 <= f2); break;
! case TYPE_UNKNOWN:
! case TYPE_MATCH:
! case TYPE_NOMATCH: break; /* avoid gcc warning */
! }
! }
! #endif
!
! /*
! * If one of the two variables is a number, compare as a number.
! * When using "=~" or "!~", always compare as string.
! */
! else if ((rettv->v_type == VAR_NUMBER || var2.v_type == VAR_NUMBER)
! && type != TYPE_MATCH && type != TYPE_NOMATCH)
! {
! n1 = get_tv_number(rettv);
! n2 = get_tv_number(&var2);
! switch (type)
! {
! case TYPE_EQUAL: n1 = (n1 == n2); break;
! case TYPE_NEQUAL: n1 = (n1 != n2); break;
! case TYPE_GREATER: n1 = (n1 > n2); break;
! case TYPE_GEQUAL: n1 = (n1 >= n2); break;
! case TYPE_SMALLER: n1 = (n1 < n2); break;
! case TYPE_SEQUAL: n1 = (n1 <= n2); break;
! case TYPE_UNKNOWN:
! case TYPE_MATCH:
! case TYPE_NOMATCH: break; /* avoid gcc warning */
! }
! }
! else
! {
! s1 = get_tv_string_buf(rettv, buf1);
! s2 = get_tv_string_buf(&var2, buf2);
! if (type != TYPE_MATCH && type != TYPE_NOMATCH)
! i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
! else
! i = 0;
! n1 = FALSE;
! switch (type)
! {
! case TYPE_EQUAL: n1 = (i == 0); break;
! case TYPE_NEQUAL: n1 = (i != 0); break;
! case TYPE_GREATER: n1 = (i > 0); break;
! case TYPE_GEQUAL: n1 = (i >= 0); break;
! case TYPE_SMALLER: n1 = (i < 0); break;
! case TYPE_SEQUAL: n1 = (i <= 0); break;
!
! case TYPE_MATCH:
! case TYPE_NOMATCH:
! n1 = pattern_match(s2, s1, ic);
! if (type == TYPE_NOMATCH)
! n1 = !n1;
! break;
!
! case TYPE_UNKNOWN: break; /* avoid gcc warning */
! }
! }
! clear_tv(rettv);
! clear_tv(&var2);
! rettv->v_type = VAR_NUMBER;
! rettv->vval.v_number = n1;
! }
}
return OK;
--- 3596,3602 ----
clear_tv(rettv);
return FAIL;
}
! return typval_compare(rettv, &var2, type, type_is, ic, evaluate);
}
return OK;
***************
*** 6840,6846 ****
/*
* Get the value of internal variable "name".
! * Return OK or FAIL.
*/
int
get_var_tv(
--- 6630,6636 ----
/*
* Get the value of internal variable "name".
! * Return OK or FAIL. If OK is returned "rettv" must be cleared.
*/
int
get_var_tv(
***************
*** 8419,8425 ****
win_T *
find_win_by_nr(
typval_T *vp,
! tabpage_T *tp UNUSED) /* NULL for current tab page */
{
win_T *wp;
int nr;
--- 8209,8215 ----
win_T *
find_win_by_nr(
typval_T *vp,
! tabpage_T *tp) /* NULL for current tab page */
{
win_T *wp;
int nr;
***************
*** 9279,9284 ****
--- 9069,9345 ----
}
+ int
+ typval_compare(
+ typval_T *typ1, /* first operand */
+ typval_T *typ2, /* second operand */
+ exptype_T type, /* operator */
+ int type_is, /* TRUE for "is" and "isnot" */
+ int ic, /* ignore case */
+ int evaluate)
+ {
+ int i;
+ varnumber_T n1, n2;
+ char_u *s1, *s2;
+ char_u buf1[NUMBUFLEN], buf2[NUMBUFLEN];
+
+ if (evaluate)
+ {
+ if (type_is && typ1->v_type != typ2->v_type)
+ {
+ /* For "is" a different type always means FALSE, for "notis"
+ * it means TRUE. */
+ n1 = (type == TYPE_NEQUAL);
+ }
+ else if (typ1->v_type == VAR_LIST || typ2->v_type == VAR_LIST)
+ {
+ if (type_is)
+ {
+ n1 = (typ1->v_type == typ2->v_type
+ && typ1->vval.v_list == typ2->vval.v_list);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ else if (typ1->v_type != typ2->v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (typ1->v_type != typ2->v_type)
+ EMSG(_("E691: Can only compare List with List"));
+ else
+ EMSG(_("E692: Invalid operation for List"));
+ clear_tv(typ1);
+ clear_tv(typ2);
+ return FAIL;
+ }
+ else
+ {
+ /* Compare two Lists for being equal or unequal. */
+ n1 = list_equal(typ1->vval.v_list, typ2->vval.v_list,
+ ic, FALSE);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+
+ else if (typ1->v_type == VAR_DICT || typ2->v_type == VAR_DICT)
+ {
+ if (type_is)
+ {
+ n1 = (typ1->v_type == typ2->v_type
+ && typ1->vval.v_dict == typ2->vval.v_dict);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ else if (typ1->v_type != typ2->v_type
+ || (type != TYPE_EQUAL && type != TYPE_NEQUAL))
+ {
+ if (typ1->v_type != typ2->v_type)
+ EMSG(_("E735: Can only compare Dictionary with
Dictionary"));
+ else
+ EMSG(_("E736: Invalid operation for Dictionary"));
+ clear_tv(typ1);
+ clear_tv(typ2);
+ return FAIL;
+ }
+ else
+ {
+ /* Compare two Dictionaries for being equal or unequal. */
+ n1 = dict_equal(typ1->vval.v_dict, typ2->vval.v_dict,
+ ic, FALSE);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+ }
+
+ else if (typ1->v_type == VAR_FUNC || typ2->v_type == VAR_FUNC
+ || typ1->v_type == VAR_PARTIAL || typ2->v_type == VAR_PARTIAL)
+ {
+ if (type != TYPE_EQUAL && type != TYPE_NEQUAL)
+ {
+ EMSG(_("E694: Invalid operation for Funcrefs"));
+ clear_tv(typ1);
+ clear_tv(typ2);
+ return FAIL;
+ }
+ if ((typ1->v_type == VAR_PARTIAL
+ && typ1->vval.v_partial == NULL)
+ || (typ2->v_type == VAR_PARTIAL
+ && typ2->vval.v_partial == NULL))
+ /* when a partial is NULL assume not equal */
+ n1 = FALSE;
+ else if (type_is)
+ {
+ if (typ1->v_type == VAR_FUNC && typ2->v_type == VAR_FUNC)
+ /* strings are considered the same if their value is
+ * the same */
+ n1 = tv_equal(typ1, typ2, ic, FALSE);
+ else if (typ1->v_type == VAR_PARTIAL
+ && typ2->v_type == VAR_PARTIAL)
+ n1 = (typ1->vval.v_partial == typ2->vval.v_partial);
+ else
+ n1 = FALSE;
+ }
+ else
+ n1 = tv_equal(typ1, typ2, ic, FALSE);
+ if (type == TYPE_NEQUAL)
+ n1 = !n1;
+ }
+
+ #ifdef FEAT_FLOAT
+ /*
+ * If one of the two variables is a float, compare as a float.
+ * When using "=~" or "!~", always compare as string.
+ */
+ else if ((typ1->v_type == VAR_FLOAT || typ2->v_type == VAR_FLOAT)
+ && type != TYPE_MATCH && type != TYPE_NOMATCH)
+ {
+ float_T f1, f2;
+
+ if (typ1->v_type == VAR_FLOAT)
+ f1 = typ1->vval.v_float;
+ else
+ f1 = get_tv_number(typ1);
+ if (typ2->v_type == VAR_FLOAT)
+ f2 = typ2->vval.v_float;
+ else
+ f2 = get_tv_number(typ2);
+ n1 = FALSE;
+ switch (type)
+ {
+ case TYPE_EQUAL: n1 = (f1 == f2); break;
+ case TYPE_NEQUAL: n1 = (f1 != f2); break;
+ case TYPE_GREATER: n1 = (f1 > f2); break;
+ case TYPE_GEQUAL: n1 = (f1 >= f2); break;
+ case TYPE_SMALLER: n1 = (f1 < f2); break;
+ case TYPE_SEQUAL: n1 = (f1 <= f2); break;
+ case TYPE_UNKNOWN:
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: break; /* avoid gcc warning */
+ }
+ }
+ #endif
+
+ /*
+ * If one of the two variables is a number, compare as a number.
+ * When using "=~" or "!~", always compare as string.
+ */
+ else if ((typ1->v_type == VAR_NUMBER || typ2->v_type == VAR_NUMBER)
+ && type != TYPE_MATCH && type != TYPE_NOMATCH)
+ {
+ n1 = get_tv_number(typ1);
+ n2 = get_tv_number(typ2);
+ switch (type)
+ {
+ case TYPE_EQUAL: n1 = (n1 == n2); break;
+ case TYPE_NEQUAL: n1 = (n1 != n2); break;
+ case TYPE_GREATER: n1 = (n1 > n2); break;
+ case TYPE_GEQUAL: n1 = (n1 >= n2); break;
+ case TYPE_SMALLER: n1 = (n1 < n2); break;
+ case TYPE_SEQUAL: n1 = (n1 <= n2); break;
+ case TYPE_UNKNOWN:
+ case TYPE_MATCH:
+ case TYPE_NOMATCH: break; /* avoid gcc warning */
+ }
+ }
+ else
+ {
+ s1 = get_tv_string_buf(typ1, buf1);
+ s2 = get_tv_string_buf(typ2, buf2);
+ if (type != TYPE_MATCH && type != TYPE_NOMATCH)
+ i = ic ? MB_STRICMP(s1, s2) : STRCMP(s1, s2);
+ else
+ i = 0;
+ n1 = FALSE;
+ switch (type)
+ {
+ case TYPE_EQUAL: n1 = (i == 0); break;
+ case TYPE_NEQUAL: n1 = (i != 0); break;
+ case TYPE_GREATER: n1 = (i > 0); break;
+ case TYPE_GEQUAL: n1 = (i >= 0); break;
+ case TYPE_SMALLER: n1 = (i < 0); break;
+ case TYPE_SEQUAL: n1 = (i <= 0); break;
+
+ case TYPE_MATCH:
+ case TYPE_NOMATCH:
+ n1 = pattern_match(s2, s1, ic);
+ if (type == TYPE_NOMATCH)
+ n1 = !n1;
+ break;
+
+ case TYPE_UNKNOWN: break; /* avoid gcc warning */
+ }
+ }
+ clear_tv(typ1);
+ clear_tv(typ2);
+ typ1->v_type = VAR_NUMBER;
+ typ1->vval.v_number = n1;
+ }
+ return OK;
+ }
+
+ int
+ typval_copy(typ1, typ2)
+ typval_T *typ1;
+ typval_T *typ2;
+ {
+ if (typ2 == NULL)
+ rettv_list_alloc(typ2);
+
+ if (typ1 != NULL && typ2 != NULL)
+ return item_copy(typ1, typ2, TRUE, 0);
+
+ return FAIL;
+ }
+
+ char_u *
+ typval_tostring(arg)
+ typval_T *arg;
+ {
+ char_u *tofree;
+ char_u numbuf[NUMBUFLEN];
+ char_u *ret = NULL;
+
+ if (arg == NULL)
+ return vim_strsave((char_u *)"(does not exist)");
+ ret = tv2string(arg, &tofree, numbuf, 0);
+ /* Make a copy if we have a value but it's not in allocated memory. */
+ if (ret != NULL && tofree == NULL)
+ ret = vim_strsave(ret);
+ return ret;
+ }
+
+ int
+ var_exists(char_u *var)
+ {
+ char_u *name;
+ char_u *tofree;
+ typval_T tv;
+ int len = 0;
+ int n = FALSE;
+
+ /* get_name_len() takes care of expanding curly braces */
+ name = var;
+ len = get_name_len(&var, &tofree, TRUE, FALSE);
+ if (len > 0)
+ {
+ if (tofree != NULL)
+ name = tofree;
+ n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
+ if (n)
+ {
+ /* handle d.key, l[idx], f(expr) */
+ n = (handle_subscript(&var, &tv, TRUE, FALSE) == OK);
+ if (n)
+ clear_tv(&tv);
+ }
+ }
+ if (*var != NUL)
+ n = FALSE;
+
+ vim_free(tofree);
+ return n;
+ }
+
#endif /* FEAT_EVAL */
*** ../vim-8.0.1504/src/evalfunc.c 2018-02-11 14:29:45.372349161 +0100
--- src/evalfunc.c 2018-02-11 18:39:17.376950755 +0100
***************
*** 2991,2999 ****
f_exists(typval_T *argvars, typval_T *rettv)
{
char_u *p;
- char_u *name;
int n = FALSE;
- int len = 0;
p = get_tv_string(&argvars[0]);
if (*p == '$') /* environment variable */
--- 2991,2997 ----
***************
*** 3035,3063 ****
}
else /* internal variable */
{
! char_u *tofree;
! typval_T tv;
!
! /* get_name_len() takes care of expanding curly braces */
! name = p;
! len = get_name_len(&p, &tofree, TRUE, FALSE);
! if (len > 0)
! {
! if (tofree != NULL)
! name = tofree;
! n = (get_var_tv(name, len, &tv, NULL, FALSE, TRUE) == OK);
! if (n)
! {
! /* handle d.key, l[idx], f(expr) */
! n = (handle_subscript(&p, &tv, TRUE, FALSE) == OK);
! if (n)
! clear_tv(&tv);
! }
! }
! if (*p != NUL)
! n = FALSE;
!
! vim_free(tofree);
}
rettv->vval.v_number = n;
--- 3033,3039 ----
}
else /* internal variable */
{
! n = var_exists(p);
}
rettv->vval.v_number = n;
*** ../vim-8.0.1504/src/userfunc.c 2018-02-10 18:45:21.096821957 +0100
--- src/userfunc.c 2018-02-11 18:30:01.808923584 +0100
***************
*** 3085,3090 ****
--- 3085,3092 ----
failed = TRUE;
break;
}
+ if (has_watchexpr())
+ dbg_check_breakpoint(eap);
/* Handle a function returning a Funcref, Dictionary or List. */
if (handle_subscript(&arg, &rettv, !eap->skip, TRUE) == FAIL)
*** ../vim-8.0.1504/src/ex_cmds2.c 2018-02-10 18:45:21.052822273 +0100
--- src/ex_cmds2.c 2018-02-11 19:01:13.319595875 +0100
***************
*** 73,78 ****
--- 73,88 ----
static void do_checkbacktracelevel(void);
static void do_showbacktrace(char_u *cmd);
+ static char_u *debug_oldval = NULL; /* old and newval for debug expressions
*/
+ static char_u *debug_newval = NULL;
+ static int debug_expr = 0; /* use debug_expr */
+
+ int
+ has_watchexpr(void)
+ {
+ return debug_expr;
+ }
+
/*
* do_debug(): Debug mode.
* Repeatedly get Ex commands, until told to continue normal execution.
***************
*** 135,147 ****
if (!debug_did_msg)
MSG(_("Entering Debug mode. Type \"cont\" to continue."));
if (sourcing_name != NULL)
msg(sourcing_name);
if (sourcing_lnum != 0)
smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
else
smsg((char_u *)_("cmd: %s"), cmd);
-
/*
* Repeat getting a command and executing it.
*/
--- 145,168 ----
if (!debug_did_msg)
MSG(_("Entering Debug mode. Type \"cont\" to continue."));
+ if (debug_oldval != NULL)
+ {
+ smsg((char_u *)_("Oldval = \"%s\""), debug_oldval);
+ vim_free(debug_oldval);
+ debug_oldval = NULL;
+ }
+ if (debug_newval != NULL)
+ {
+ smsg((char_u *)_("Newval = \"%s\""), debug_newval);
+ vim_free(debug_newval);
+ debug_newval = NULL;
+ }
if (sourcing_name != NULL)
msg(sourcing_name);
if (sourcing_lnum != 0)
smsg((char_u *)_("line %ld: %s"), (long)sourcing_lnum, cmd);
else
smsg((char_u *)_("cmd: %s"), cmd);
/*
* Repeat getting a command and executing it.
*/
***************
*** 528,538 ****
struct debuggy
{
int dbg_nr; /* breakpoint number */
! int dbg_type; /* DBG_FUNC or DBG_FILE */
! char_u *dbg_name; /* function or file name */
regprog_T *dbg_prog; /* regexp program */
linenr_T dbg_lnum; /* line number in function or file */
int dbg_forceit; /* ! used */
};
static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
--- 549,563 ----
struct debuggy
{
int dbg_nr; /* breakpoint number */
! int dbg_type; /* DBG_FUNC, 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 */
+ #ifdef FEAT_EVAL
+ typval_T *dbg_val; /* last result of watchexpression */
+ #endif
+ int dbg_level; /* stored nested level for expr */
};
static garray_T dbg_breakp = {0, 0, sizeof(struct debuggy), 4, NULL};
***************
*** 546,551 ****
--- 571,577 ----
#endif
#define DBG_FUNC 1
#define DBG_FILE 2
+ #define DBG_EXPR 3
static int dbg_parsearg(char_u *arg, garray_T *gap);
static linenr_T debuggy_find(int file,char_u *fname, linenr_T after, garray_T
*gap, int *fp);
***************
*** 589,594 ****
--- 615,626 ----
bp->dbg_type = DBG_FILE;
here = TRUE;
}
+ else if (
+ #ifdef FEAT_PROFILE
+ gap != &prof_ga &&
+ #endif
+ STRNCMP(p, "expr", 4) == 0)
+ bp->dbg_type = DBG_EXPR;
else
{
EMSG2(_(e_invarg2), p);
***************
*** 624,629 ****
--- 656,667 ----
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);
+ if (bp->dbg_name != NULL)
+ bp->dbg_val = eval_expr(bp->dbg_name, NULL);
+ }
else
{
/* Expand the file name in the same way as do_source(). This means
***************
*** 671,696 ****
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);
! vim_free(pat);
! }
! if (pat == NULL || bp->dbg_prog == NULL)
! vim_free(bp->dbg_name);
! else
{
! if (bp->dbg_lnum == 0) /* default line number is 1 */
! bp->dbg_lnum = 1;
#ifdef FEAT_PROFILE
! if (eap->cmdidx != CMD_profile)
#endif
! {
! DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
! ++debug_tick;
}
! ++gap->ga_len;
}
}
}
--- 709,743 ----
bp = &DEBUGGY(gap, gap->ga_len);
bp->dbg_forceit = eap->forceit;
! if (bp->dbg_type != DBG_EXPR)
{
! 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);
! vim_free(pat);
! }
! if (pat == NULL || bp->dbg_prog == NULL)
! vim_free(bp->dbg_name);
! else
! {
! if (bp->dbg_lnum == 0) /* default line number is 1 */
! bp->dbg_lnum = 1;
#ifdef FEAT_PROFILE
! if (eap->cmdidx != CMD_profile)
#endif
! {
! DEBUGGY(gap, gap->ga_len).dbg_nr = ++last_breakp;
! ++debug_tick;
! }
! ++gap->ga_len;
}
! }
! else
! {
! /* DBG_EXPR */
! DEBUGGY(gap, gap->ga_len++).dbg_nr = ++last_breakp;
! ++debug_tick;
}
}
}
***************
*** 750,756 ****
}
else
{
! /* ":breakdel {func|file} [lnum] {name}" */
if (dbg_parsearg(eap->arg, gap) == FAIL)
return;
bp = &DEBUGGY(gap, gap->ga_len);
--- 797,803 ----
}
else
{
! /* ":breakdel {func|file|expr} [lnum] {name}" */
if (dbg_parsearg(eap->arg, gap) == FAIL)
return;
bp = &DEBUGGY(gap, gap->ga_len);
***************
*** 778,783 ****
--- 825,835 ----
while (gap->ga_len > 0)
{
vim_free(DEBUGGY(gap, todel).dbg_name);
+ #ifdef FEAT_EVAL
+ if (DEBUGGY(gap, todel).dbg_type == DBG_EXPR
+ && DEBUGGY(gap, todel).dbg_val != NULL)
+ free_tv(DEBUGGY(gap, todel).dbg_val);
+ #endif
vim_regfree(DEBUGGY(gap, todel).dbg_prog);
--gap->ga_len;
if (todel < gap->ga_len)
***************
*** 814,824 ****
bp = &BREAKP(i);
if (bp->dbg_type == DBG_FILE)
home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
! smsg((char_u *)_("%3d %s %s line %ld"),
bp->dbg_nr,
bp->dbg_type == DBG_FUNC ? "func" : "file",
bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
(long)bp->dbg_lnum);
}
}
--- 866,880 ----
bp = &BREAKP(i);
if (bp->dbg_type == DBG_FILE)
home_replace(NULL, bp->dbg_name, NameBuff, MAXPATHL, TRUE);
! if (bp->dbg_type != DBG_EXPR)
! smsg((char_u *)_("%3d %s %s line %ld"),
bp->dbg_nr,
bp->dbg_type == DBG_FUNC ? "func" : "file",
bp->dbg_type == DBG_FUNC ? bp->dbg_name : NameBuff,
(long)bp->dbg_lnum);
+ else
+ smsg((char_u *)_("%3d expr %s"),
+ bp->dbg_nr, bp->dbg_name);
}
}
***************
*** 889,895 ****
/* Skip entries that are not useful or are for a line that is beyond
* an already found breakpoint. */
bp = &DEBUGGY(gap, i);
! if (((bp->dbg_type == DBG_FILE) == file && (
#ifdef FEAT_PROFILE
gap == &prof_ga ||
#endif
--- 945,952 ----
/* Skip entries that are not useful or are for a line that is beyond
* an already found breakpoint. */
bp = &DEBUGGY(gap, i);
! if (((bp->dbg_type == DBG_FILE) == file &&
! bp->dbg_type != DBG_EXPR && (
#ifdef FEAT_PROFILE
gap == &prof_ga ||
#endif
***************
*** 910,915 ****
--- 967,1032 ----
}
got_int |= prev_got_int;
}
+ #ifdef FEAT_EVAL
+ else if (bp->dbg_type == DBG_EXPR)
+ {
+ typval_T *tv;
+ int line = FALSE;
+
+ prev_got_int = got_int;
+ got_int = FALSE;
+
+ tv = eval_expr(bp->dbg_name, NULL);
+ 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
+ {
+ typval_T val3;
+
+ if (typval_copy(bp->dbg_val, &val3) == OK)
+ {
+ if (typval_compare(tv, &val3, TYPE_EQUAL,
+ TRUE, FALSE, TRUE) == OK
+ && tv->vval.v_number == FALSE)
+ {
+ typval_T *v;
+
+ line = TRUE;
+ debug_oldval = typval_tostring(bp->dbg_val);
+ v = eval_expr(bp->dbg_name, NULL);
+ debug_newval = typval_tostring(v);
+ free_tv(bp->dbg_val);
+ bp->dbg_val = v;
+ }
+ }
+ free_tv(tv);
+ }
+ }
+ else if (bp->dbg_val != NULL)
+ {
+ debug_oldval = typval_tostring(bp->dbg_val);
+ debug_newval = typval_tostring(NULL);
+ free_tv(bp->dbg_val);
+ bp->dbg_val = NULL;
+ line = TRUE;
+ }
+
+ if (line)
+ {
+ lnum = after > 0 ? after : 1;
+ break;
+ }
+
+ got_int |= prev_got_int;
+ }
+ #endif
}
if (name != fname)
vim_free(name);
*** ../vim-8.0.1504/src/ex_docmd.c 2018-02-10 18:45:21.056822244 +0100
--- src/ex_docmd.c 2018-02-11 18:16:14.746787486 +0100
***************
*** 1174,1179 ****
--- 1174,1186 ----
}
}
+ /* Check for the next breakpoint after a watchexpression */
+ if (breakpoint != NULL && has_watchexpr())
+ {
+ *breakpoint = dbg_find_breakpoint(FALSE, fname, sourcing_lnum);
+ *dbg_tick = debug_tick;
+ }
+
/*
* When not inside any ":while" loop, clear remembered lines.
*/
*** ../vim-8.0.1504/src/proto/eval.pro 2017-12-16 18:26:56.626992497 +0100
--- src/proto/eval.pro 2018-02-11 18:45:02.854487787 +0100
***************
*** 64,70 ****
varnumber_T get_vim_var_nr(int idx);
char_u *get_vim_var_str(int idx);
list_T *get_vim_var_list(int idx);
! dict_T * get_vim_var_dict(int idx);
void set_vim_var_char(int c);
void set_vcount(long count, long count1, int set_prevcount);
void set_vim_var_string(int idx, char_u *val, int len);
--- 64,70 ----
varnumber_T get_vim_var_nr(int idx);
char_u *get_vim_var_str(int idx);
list_T *get_vim_var_list(int idx);
! dict_T *get_vim_var_dict(int idx);
void set_vim_var_char(int c);
void set_vcount(long count, long count1, int set_prevcount);
void set_vim_var_string(int idx, char_u *val, int len);
***************
*** 129,134 ****
--- 129,138 ----
void assert_exception(typval_T *argvars);
void assert_fails(typval_T *argvars);
void fill_assert_error(garray_T *gap, typval_T *opt_msg_tv, char_u *exp_str,
typval_T *exp_tv, typval_T *got_tv, assert_type_T atype);
+ int typval_compare(typval_T *typ1, typval_T *typ2, exptype_T type, int
type_is, int ic, int evaluate);
+ int typval_copy(typval_T *typ1, typval_T *typ2);
+ char_u *typval_tostring(typval_T *arg);
+ int var_exists(char_u *var);
int modify_fname(char_u *src, int *usedlen, char_u **fnamep, char_u **bufp,
int *fnamelen);
char_u *do_string_sub(char_u *str, char_u *pat, char_u *sub, typval_T *expr,
char_u *flags);
void filter_map(typval_T *argvars, typval_T *rettv, int map);
*** ../vim-8.0.1504/src/proto/ex_cmds2.pro 2017-08-03 14:29:09.895896191
+0200
--- src/proto/ex_cmds2.pro 2018-02-11 18:16:14.746787486 +0100
***************
*** 1,4 ****
--- 1,5 ----
/* ex_cmds2.c */
+ int has_watchexpr (void);
void do_debug(char_u *cmd);
void ex_debug(exarg_T *eap);
void dbg_check_breakpoint(exarg_T *eap);
*** ../vim-8.0.1504/src/structs.h 2018-02-10 18:15:00.754098808 +0100
--- src/structs.h 2018-02-11 18:16:14.746787486 +0100
***************
*** 3263,3268 ****
--- 3263,3284 ----
} context_sha256_T;
/*
+ * types for expressions.
+ */
+ typedef enum
+ {
+ TYPE_UNKNOWN = 0
+ , TYPE_EQUAL /* == */
+ , TYPE_NEQUAL /* != */
+ , TYPE_GREATER /* > */
+ , TYPE_GEQUAL /* >= */
+ , TYPE_SMALLER /* < */
+ , TYPE_SEQUAL /* <= */
+ , TYPE_MATCH /* =~ */
+ , TYPE_NOMATCH /* !~ */
+ } exptype_T;
+
+ /*
* Structure used for reading in json_decode().
*/
struct js_reader
*** ../vim-8.0.1504/src/version.c 2018-02-11 16:40:13.439759211 +0100
--- src/version.c 2018-02-11 19:05:22.425829110 +0100
***************
*** 773,774 ****
--- 773,776 ----
{ /* Add new patch number below this line */
+ /**/
+ 1505,
/**/
--
ARTHUR: Be quiet!
DENNIS: --but by a two-thirds majority in the case of more--
ARTHUR: Be quiet! I order you to be quiet!
WOMAN: Order, eh -- who does he think he is?
ARTHUR: I am your king!
The Quest for the Holy Grail (Monty Python)
/// Bram Moolenaar -- [email protected] -- 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 ///
--
--
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].
For more options, visit https://groups.google.com/d/optout.