Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Ctrl+Q for stack traces #36344

Merged
merged 9 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions base/errorshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -699,8 +699,8 @@ function print_stackframe(io, i, frame, n, digit_align_width, modulecolor)

# Used by the REPL to make it possible to open
# the location of a stackframe/method in the editor.
if haskey(io, :LAST_SHOWN_LINE_INFOS)
push!(io[:LAST_SHOWN_LINE_INFOS], (string(frame.file), frame.line))
if haskey(io, :last_shown_line_infos)
push!(io[:last_shown_line_infos], (string(frame.file), frame.line))
end

inlined = getfield(frame, :inlined)
Expand Down Expand Up @@ -749,8 +749,8 @@ end


function show_backtrace(io::IO, t::Vector)
if haskey(io, :LAST_SHOWN_LINE_INFOS)
resize!(io[:LAST_SHOWN_LINE_INFOS], 0)
if haskey(io, :last_shown_line_infos)
empty!(io[:last_shown_line_infos])
end

# t is a pre-processed backtrace (ref #12856)
Expand Down
17 changes: 11 additions & 6 deletions base/methodshow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -240,17 +240,20 @@ function show_method_table(io::IO, ms::MethodList, max::Int=-1, header::Bool=tru
end
n = rest = 0
local last
LAST_SHOWN_LINE_INFOS = get(io, :LAST_SHOWN_LINE_INFOS, Tuple{String,Int}[])

resize!(LAST_SHOWN_LINE_INFOS, 0)
last_shown_line_infos = get(io, :last_shown_line_infos, nothing)
last_shown_line_infos === nothing || empty!(last_shown_line_infos)

for meth in ms
if max==-1 || n<max
n += 1
println(io)
print(io, "[$n] ")
show(io, meth)
file, line = updated_methodloc(meth)
push!(LAST_SHOWN_LINE_INFOS, (string(file), line))
if last_shown_line_infos !== nothing
push!(last_shown_line_infos, (string(file), line))
end
else
rest += 1
last = meth
Expand Down Expand Up @@ -374,16 +377,18 @@ show(io::IO, mime::MIME"text/html", mt::Core.MethodTable) = show(io, mime, Metho

# pretty-printing of AbstractVector{Method}
function show(io::IO, mime::MIME"text/plain", mt::AbstractVector{Method})
LAST_SHOWN_LINE_INFOS = get(io, :LAST_SHOWN_LINE_INFOS, Tuple{String,Int}[])
resize!(LAST_SHOWN_LINE_INFOS, 0)
last_shown_line_infos = get(io, :last_shown_line_infos, nothing)
last_shown_line_infos === nothing || empty!(last_shown_line_infos)
first = true
for (i, m) in enumerate(mt)
first || println(io)
first = false
print(io, "[$(i)] ")
show(io, m)
file, line = updated_methodloc(m)
push!(LAST_SHOWN_LINE_INFOS, (string(file), line))
if last_shown_line_infos !== nothing
push!(last_shown_line_infos, (string(file), line))
end
end
end

Expand Down
53 changes: 29 additions & 24 deletions stdlib/REPL/src/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,37 +204,26 @@ end
==(a::REPLDisplay, b::REPLDisplay) = a.repl === b.repl

function display(d::REPLDisplay, mime::MIME"text/plain", x)
io = outstream(d.repl)
get(io, :color, false) && write(io, answer_color(d.repl))
if isdefined(d.repl, :options) && isdefined(d.repl.options, :iocontext)
# this can override the :limit property set initially
io = foldl(IOContext, d.repl.options.iocontext,
init=IOContext(io, :limit => true, :module => Main))
end

infos = Tuple{String,Int}[]
io = IOContext(io, :LAST_SHOWN_LINE_INFOS => infos)

show(io, mime, x)
println(io)

if !isempty(infos)
d.repl.last_shown_line_infos = infos
println(
io,
"\nTo edit a specific method, type the corresponding number into the " *
"REPL and press Ctrl+Q",
)
with_methodtable_hint(d.repl) do io
get(io, :color, false) && write(io, answer_color(d.repl))
if isdefined(d.repl, :options) && isdefined(d.repl.options, :iocontext)
# this can override the :limit property set initially
io = foldl(IOContext, d.repl.options.iocontext,
init=IOContext(io, :limit => true, :module => Main))
end
show(io, mime, x)
println(io)
end

nothing
end
display(d::REPLDisplay, x) = display(d, MIME("text/plain"), x)

function print_response(repl::AbstractREPL, @nospecialize(response), show_value::Bool, have_color::Bool)
repl.waserror = response[2]
io = IOContext(outstream(repl), :module => Main)
print_response(io, response, show_value, have_color, specialdisplay(repl))
with_methodtable_hint(repl) do io
io = IOContext(io, :module => Main)
print_response(io, response, show_value, have_color, specialdisplay(repl))
end
nothing
end
function print_response(errio::IO, @nospecialize(response), show_value::Bool, have_color::Bool, specialdisplay=nothing)
Expand Down Expand Up @@ -495,6 +484,22 @@ function complete_line(c::LatexCompletions, s)
return unique!(map(completion_text, ret)), partial[range], should_complete
end

with_methodtable_hint(f, repl) = f(outstream(repl))
function with_methodtable_hint(f, repl::LineEditREPL)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I think this is a clean approach!

linfos = Tuple{String,Int}[]
io = IOContext(outstream(repl), :last_shown_line_infos => linfos)
f(io)
if !isempty(linfos)
repl.last_shown_line_infos = linfos
println(
io,
"\nTo edit a specific method, type the corresponding number into the " *
"REPL and press Ctrl+Q",
)
end
nothing
end

mutable struct REPLHistoryProvider <: HistoryProvider
history::Vector{String}
history_file::Union{Nothing,IO}
Expand Down
42 changes: 42 additions & 0 deletions stdlib/REPL/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1240,3 +1240,45 @@ frontend_task = @async begin
end
REPL.start_repl_backend(backend)
Base.wait(frontend_task)

macro throw_with_linenumbernode(err)
Expr(:block, LineNumberNode(42, Symbol("test.jl")), :(() -> throw($err)))
end

@testset "last shown line infos" begin
out_stream = IOBuffer()
term = REPL.TTYTerminal("dumb", IOBuffer(), out_stream, IOBuffer())
repl = REPL.LineEditREPL(term, false)
repl.specialdisplay = REPL.REPLDisplay(repl)

REPL.print_response(repl, (methods(+), false), true, false)
seekstart(out_stream)
@test count(
contains(
"To edit a specific method, type the corresponding number into the REPL and " *
"press Ctrl+Q"
),
eachline(out_stream),
) == 1
take!(out_stream)

err = ErrorException("Foo")
bt = try
@throw_with_linenumbernode(err)()
catch
Base.catch_stack()
end

repl.backendref = REPL.REPLBackendRef(Channel(1), Channel(1))
put!(repl.backendref.response_channel, (bt, true))

REPL.print_response(repl, (err, true), true, false)
seekstart(out_stream)
@test count(
contains(
"To edit a specific method, type the corresponding number into the REPL and " *
"press Ctrl+Q"
),
eachline(out_stream),
) == 1
end