diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/eval.c | 29 | ||||
| -rw-r--r-- | src/nvim/ex_cmds2.c | 137 | ||||
| -rw-r--r-- | src/nvim/globals.h | 9 | ||||
| -rw-r--r-- | src/nvim/version.c | 2 | 
4 files changed, 166 insertions, 11 deletions
| diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 712ee06b85..201a71facb 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -18123,6 +18123,25 @@ static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, in    return HI2DI(hi);  } +// Get function call environment based on backtrace debug level +static funccall_T *get_funccal(void) +{ +  funccall_T *funccal = current_funccal; +  if (debug_backtrace_level > 0) { +    for (int i = 0; i < debug_backtrace_level; i++) { +      funccall_T *temp_funccal = funccal->caller; +      if (temp_funccal) { +        funccal = temp_funccal; +      } else { +        // backtrace level overflow. reset to max +        debug_backtrace_level = i; +      } +    } +  } + +  return funccal; +} +  // Find the dict and hashtable used for a variable name.  Set "varname" to the  // start of name without ':'.  static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d) @@ -18147,7 +18166,11 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)        return &compat_hashtab;      } -    *d = current_funccal ? ¤t_funccal->l_vars : &globvardict; +    if (current_funccal == NULL) { +      *d = &globvardict; +    } else { +      *d = &get_funccal()->l_vars;  // l: variable +    }      goto end;    } @@ -18169,9 +18192,9 @@ static hashtab_T *find_var_ht_dict(char_u *name, uint8_t **varname, dict_T **d)    } else if (*name == 'v') {                    // v: variable      *d = &vimvardict;    } else if (*name == 'a' && current_funccal != NULL) {  // function argument -    *d = ¤t_funccal->l_avars; +    *d = &get_funccal()->l_avars;    } else if (*name == 'l' && current_funccal != NULL) {  // local variable -    *d = ¤t_funccal->l_vars; +    *d = &get_funccal()->l_vars;    } else if (*name == 's'                       // script variable        && current_SID > 0 && current_SID <= ga_scripts.ga_len) {      *d = &SCRIPT_SV(current_SID)->sv_dict; diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index df387f9a60..c323b7fb92 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -116,6 +116,11 @@ struct source_cookie {  static int debug_greedy = FALSE;        /* batch mode debugging: don't save                                             and restore typeahead. */ +static int get_maxbacktrace_level(void); +static void do_setdebugtracelevel(char_u *arg); +static void do_checkbacktracelevel(void); +static void do_showbacktrace(char_u *cmd); +  /*   * do_debug(): Debug mode.   * Repeatedly get Ex commands, until told to continue normal execution. @@ -144,6 +149,10 @@ void do_debug(char_u *cmd)  #define CMD_FINISH      4  #define CMD_QUIT        5  #define CMD_INTERRUPT   6 +#define CMD_BACKTRACE   7 +#define CMD_FRAME       8 +#define CMD_UP          9 +#define CMD_DOWN        10    ++RedrawingDisabled;          /* don't redisplay the window */ @@ -194,6 +203,7 @@ void do_debug(char_u *cmd)      ex_normal_busy = save_ex_normal_busy;      cmdline_row = msg_row; +    msg_starthere();      if (cmdline != NULL) {        /* If this is a debug command, set "last_cmd".         * If not, reset "last_cmd". @@ -210,8 +220,15 @@ void do_debug(char_u *cmd)          case 's': last_cmd = CMD_STEP;            tail = "tep";            break; -        case 'f': last_cmd = CMD_FINISH; -          tail = "inish"; +        case 'f': +          last_cmd = 0; +          if (p[1] == 'r') { +            last_cmd = CMD_FRAME; +            tail = "rame"; +          } else { +            last_cmd = CMD_FINISH; +            tail = "inish"; +          }            break;          case 'q': last_cmd = CMD_QUIT;            tail = "uit"; @@ -219,6 +236,26 @@ void do_debug(char_u *cmd)          case 'i': last_cmd = CMD_INTERRUPT;            tail = "nterrupt";            break; +        case 'b': +          last_cmd = CMD_BACKTRACE; +          if (p[1] == 't') { +            tail = "t"; +          } else { +            tail = "acktrace"; +          } +          break; +        case 'w': +          last_cmd = CMD_BACKTRACE; +          tail = "here"; +          break; +        case 'u': +          last_cmd = CMD_UP; +          tail = "p"; +          break; +        case 'd': +          last_cmd = CMD_DOWN; +          tail = "own"; +          break;          default: last_cmd = 0;          }          if (last_cmd != 0) { @@ -228,8 +265,9 @@ void do_debug(char_u *cmd)              ++p;              ++tail;            } -          if (ASCII_ISALPHA(*p)) +          if (ASCII_ISALPHA(*p) && last_cmd != CMD_FRAME) {              last_cmd = 0; +          }          }        } @@ -259,7 +297,28 @@ void do_debug(char_u *cmd)            /* Do not repeat ">interrupt" cmd, continue stepping. */            last_cmd = CMD_STEP;            break; +        case CMD_BACKTRACE: +          do_showbacktrace(cmd); +          continue; +        case CMD_FRAME: +          if (*p == NUL) { +            do_showbacktrace(cmd); +          } else { +            p = skipwhite(p); +            do_setdebugtracelevel(p); +          } +          continue; +        case CMD_UP: +          debug_backtrace_level++; +          do_checkbacktracelevel(); +          continue; +        case CMD_DOWN: +          debug_backtrace_level--; +          do_checkbacktracelevel(); +          continue;          } +        // Going out reset backtrace_level +        debug_backtrace_level = 0;          break;        } @@ -294,6 +353,78 @@ void do_debug(char_u *cmd)    debug_did_msg = TRUE;  } +static int get_maxbacktrace_level(void) +{ +  int maxbacktrace = 0; + +  if (sourcing_name != NULL) { +    char *p = (char *)sourcing_name; +    char *q; +    while ((q = strstr(p, "..")) != NULL) { +      p = q + 2; +      maxbacktrace++; +    } +  } +  return maxbacktrace; +} + +static void do_setdebugtracelevel(char_u *arg) +{ +  int level = atoi((char *)arg); +  if (*arg == '+' || level < 0) { +    debug_backtrace_level += level; +  } else { +    debug_backtrace_level = level; +  } + +  do_checkbacktracelevel(); +} + +static void do_checkbacktracelevel(void) +{ +  if (debug_backtrace_level < 0) { +    debug_backtrace_level = 0; +    MSG(_("frame is zero")); +  } else { +    int max = get_maxbacktrace_level(); +    if (debug_backtrace_level > max) { +      debug_backtrace_level = max; +      smsg(_("frame at highest level: %d"), max); +    } +  } +} + +static void do_showbacktrace(char_u *cmd) +{ +  if (sourcing_name != NULL) { +    int i = 0; +    int max = get_maxbacktrace_level(); +    char *cur = (char *)sourcing_name; +    while (!got_int) { +      char *next = strstr(cur, ".."); +      if (next != NULL) { +        *next = NUL; +      } +      if (i == max - debug_backtrace_level) { +        smsg("->%d %s", max - i, cur); +      } else { +        smsg("  %d %s", max - i, cur); +      } +      i++; +      if (next == NULL) { +        break; +      } +      *next = '.'; +      cur = next + 2; +    } +  } +  if (sourcing_lnum != 0) { +    smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd); +  } else { +    smsg(_("cmd: %s"), cmd); +  } +} +  /*   * ":debug".   */ diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 49d1de21d9..30fe97c8db 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -293,10 +293,11 @@ EXTERN int msg_no_more INIT(= FALSE);       /* don't use more prompt, truncate  EXTERN char_u   *sourcing_name INIT( = NULL); /* name of error message source */  EXTERN linenr_T sourcing_lnum INIT(= 0);    /* line number of the source file */ -EXTERN int ex_nesting_level INIT(= 0);          /* nesting level */ -EXTERN int debug_break_level INIT(= -1);        /* break below this level */ -EXTERN int debug_did_msg INIT(= FALSE);         /* did "debug mode" message */ -EXTERN int debug_tick INIT(= 0);                /* breakpoint change count */ +EXTERN int ex_nesting_level INIT(= 0);          // nesting level +EXTERN int debug_break_level INIT(= -1);        // break below this level +EXTERN int debug_did_msg INIT(= false);         // did "debug mode" message +EXTERN int debug_tick INIT(= 0);                // breakpoint change count +EXTERN int debug_backtrace_level INIT(= 0);     // breakpoint backtrace level  /* Values for "do_profiling". */  #define PROF_NONE       0       /* profiling not started */ diff --git a/src/nvim/version.c b/src/nvim/version.c index 7ee3b596de..b6dd017f8d 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -580,7 +580,7 @@ static int included_patches[] = {    1105,    // 1104 NA    // 1103 NA -  // 1102, +  1102,    1101,    // 1100 NA    // 1099 NA | 
