From 1b358801350ade5fbb96300c73886a8b8423292b Mon Sep 17 00:00:00 2001 From: Eric Berquist Date: Sat, 11 Nov 2023 12:34:37 -0500 Subject: [PATCH 1/2] Add `p [var]` commands to print all or just one frame local variable --- README.md | 3 +++ src/commands.jl | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 740f73c..8569792 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,9 @@ Querying: - `st`: show the "status" (current function, source code and current expression to run) - `bt`: show a backtrace - `fr [i::Int]`: show all variables in the current or `i`th frame +- `p` + - `p`: print all currently defined variables + - `p x` : print the value of the variable `x` Evaluation: - `w` diff --git a/src/commands.jl b/src/commands.jl index 95e524b..5cd1aa4 100644 --- a/src/commands.jl +++ b/src/commands.jl @@ -1,4 +1,3 @@ - function assert_allow_step(state) if state.broke_on_error printstyled(stderr, "Cannot step after breaking on error\n"; color=Base.error_color()) @@ -140,6 +139,26 @@ function execute_command(state::DebuggerState, v::Union{Val{:up}, Val{:down}}, c end return execute_command(state, Val(:f), string("f ", state.level + offset)) end + +function execute_command(state::DebuggerState, ::Val{:p}, cmd::AbstractString) + cmds = split(cmd, r" +") + io = Base.pipe_writer(state.terminal) + frame = active_frame(state) + if length(cmds) == 1 + print_locals(io, frame) + else + vars = JuliaInterpreter.locals(frame) + for requested_var in cmds[2:end] + for var in vars + if string(var.name) == requested_var + print_var(io, var) + end + end + end + end + return false +end + function execute_command(state::DebuggerState, ::Val{:w}, cmd::AbstractString) # TODO show some info messages? cmds = split(cmd, r" +") @@ -269,6 +288,9 @@ function execute_command(state::DebuggerState, ::Union{Val{:help}, Val{:?}}, cmd - `st`: show the "status" (current function, source code and current expression to run)\\ - `bt`: show a backtrace\\ - `fr [i::Int]`: show all variables in the current or `i`th frame\\ + - `p`\\ + - `p`: print all currently defined variables\\ + - `p x` : print the value of the variable `x`\\ Evaluation:\\ From 0c06b8e5439a03dcef95ccb3a6ea06c1c3823059 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sat, 18 Jul 2026 13:56:39 +0200 Subject: [PATCH 2/2] Polish `p` command: colored output stream, warn on unknown variable, add tests Builds on #339 by Eric Berquist. Uses output_stream(state) like other commands, prints an error for variables not present in the frame, and adds a testset. Co-Authored-By: Claude Fable 5 --- README.md | 4 ++-- src/commands.jl | 12 +++++++++--- test/misc.jl | 15 +++++++++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8569792..bccd14f 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,8 @@ Querying: - `bt`: show a backtrace - `fr [i::Int]`: show all variables in the current or `i`th frame - `p` - - `p`: print all currently defined variables - - `p x` : print the value of the variable `x` + - `p`: print all variables in the current frame (same as `fr`) + - `p x [y ...]`: print the value of the variable(s) `x` (and `y` ...) Evaluation: - `w` diff --git a/src/commands.jl b/src/commands.jl index 5cd1aa4..d4cb0bb 100644 --- a/src/commands.jl +++ b/src/commands.jl @@ -1,3 +1,4 @@ + function assert_allow_step(state) if state.broke_on_error printstyled(stderr, "Cannot step after breaking on error\n"; color=Base.error_color()) @@ -142,18 +143,23 @@ end function execute_command(state::DebuggerState, ::Val{:p}, cmd::AbstractString) cmds = split(cmd, r" +") - io = Base.pipe_writer(state.terminal) + io = output_stream(state) frame = active_frame(state) if length(cmds) == 1 print_locals(io, frame) else vars = JuliaInterpreter.locals(frame) for requested_var in cmds[2:end] + found = false for var in vars if string(var.name) == requested_var print_var(io, var) + found = true end end + if !found + printstyled(io, "no variable `$requested_var` in this frame\n"; color=Base.error_color()) + end end end return false @@ -289,8 +295,8 @@ function execute_command(state::DebuggerState, ::Union{Val{:help}, Val{:?}}, cmd - `bt`: show a backtrace\\ - `fr [i::Int]`: show all variables in the current or `i`th frame\\ - `p`\\ - - `p`: print all currently defined variables\\ - - `p x` : print the value of the variable `x`\\ + - `p`: print all variables in the current frame (same as `fr`)\\ + - `p x [y ...]`: print the value of the variable(s) `x` (and `y` ...)\\ Evaluation:\\ diff --git a/test/misc.jl b/test/misc.jl index 6665006..ac08773 100644 --- a/test/misc.jl +++ b/test/misc.jl @@ -251,3 +251,18 @@ end ret, _, _ = Debugger.completions(provider, "x", "x") @test "x" in ret end + +@testset "p command" begin + function command_output(frame, cmd) + buf = IOBuffer() + term = REPL.Terminals.TTYTerminal("dumb", stdin, buf, stderr) + state = Debugger.DebuggerState(; frame=frame, terminal=term) + execute_command(state, Val{Symbol(first(split(cmd)))}(), cmd) + return String(take!(buf)) + end + f_p_cmd(x) = (y = x + 1; y * 2) + frame = @make_frame f_p_cmd(3) + @test occursin("x::$Int = 3", command_output(frame, "p x")) + @test occursin("x::$Int = 3", command_output(frame, "p")) + @test occursin("no variable `nope` in this frame", command_output(frame, "p nope")) +end