Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: PATCH: evaluation depth in prompts



On Tue, 26 Aug 2014 18:10:55 +0100
Peter Stephenson <p.stephenson@xxxxxxxxxxx> wrote:
> On Tue, 26 Aug 2014 17:40:29 +0100
> Peter Stephenson <p.stephenson@xxxxxxxxxxx> wrote:
> > A better solution might be for a prompt escape that tracks the
> > nesting level (which is trivial apart from picking a new letter).
> 
> %e for evaluation depth (%E is taken but %e isn't).

In case anyone's still following, here's the original script updated.
This now gives reliable tracing of who's calling whom, even for
functions calling themselves recursively, which I think was pretty much
impossible to automate reliably before by means of prompt tracing ---
you could hack it up or alternatively use debug traps and the functrace
stuff.

pws


# Trivial function to trace the strcture of zsh function calls
# with xtrace output using a PS4 containing %N and %i (see prompt_match
# below).
#
# Input is stderr from a shell with xtrace active and a suitable PS4.
# The completion system's ^X? binding can produce such output.
#
# For shells with %e (added in 5.0.7(?)): using PS4="+%e:%N:%i> "
# allows better tracing by outputting the execution depth of the
# construct being executed.
#
# If that's not available, the default PS4="+%N:%i> " is assumed. In
# this case, because we can't be sure a change in execution is a new
# call or a return to a previous function, we always assume the latter
# where the names match.  This is the normal case but may be wrong for
# certain recursive structures.

emulate -L zsh
setopt extendedglob

# Match lines for PS4="+%e:%N:%i> ".  Adapt as appropriate.
# With %e for evaluation depth.
local eprompt_match="+(#b)([0-9]##):([^>]##):([0-9]##)> *"
integer edepth_match=1
integer efunc_match=2
integer elineno_match=3

# Match lines for PS4="+%N:%i> ".  Adapt as appropriate.
# No evaluation depth.
local prompt_match="+(#b)([^>]##):([0-9]##)> *"
# Function name in $match[1]
integer func_match=1
# Line number in $match[2]
integer lineno_match=2
# Padding to indent a line
local pad="  "

local line func indent last_line
integer lineno depth last_depth=-1 diff
local -a match mbegin mend funcs

while read line; do
  if [[ $line = ${~eprompt_match} ]]; then
    depth=$match[$edepth_match]
    func=$match[$efunc_match]
    lineno=$match[$elineno_match]

    if (( last_depth == -1 )); then
      print -r -- ${func}:${lineno}
    elif (( depth < last_depth )); then
      (( diff = last_depth - depth ))
      while (( diff-- )); do
	indent=${indent%%$pad}
      done
    elif (( depth > last_depth )); then
      (( diff = depth - last_depth ))
      while (( diff-- )); do
	indent+=$pad
      done
      print -r -- "$indent$last_line -> $func"
    fi

    last_depth=$depth
    last_line=${func}:${lineno}
  elif [[ $line = ${~prompt_match} ]]; then
    depth=$match[$depth_match]
    func=$match[$func_match]
    lineno=$match[$lineno_match]

    if (( ${#funcs} == 0 )); then
      print -r -- ${func}:${lineno}
      funcs+=($func)
    elif [[ $func != ${funcs[-1]} ]]; then
      if [[ $func = ${funcs[-2]} ]]; then
	funcs=(${funcs[1,-2]})
	indent=${indent%%$pad}
      else
	indent+=$pad
	print -r -- "$indent$last_line -> $func"
	funcs+=($func)
      fi
    fi

    last_line=${func}:${lineno}
  fi
done <${1:-/dev/stdin}



Messages sorted by: Reverse Date, Date, Thread, Author