diff --git a/base/REPL.jl b/base/REPL.jl index a6c6880f828aa..6716c80fd0292 100644 --- a/base/REPL.jl +++ b/base/REPL.jl @@ -112,14 +112,12 @@ end function display_error(io::IO, er, bt) print_with_color(Base.error_color(), io, "ERROR: "; bold = true) - Base.with_output_color(Base.error_color(), io) do io - # remove REPL-related frames from interactive printing - eval_ind = findlast(addr->ip_matches_func(addr, :eval), bt) - if eval_ind != 0 - bt = bt[1:eval_ind-1] - end - Base.showerror(IOContext(io, :limit => true), er, bt) + # remove REPL-related frames from interactive printing + eval_ind = findlast(addr->Base.REPL.ip_matches_func(addr, :eval), bt) + if eval_ind != 0 + bt = bt[1:eval_ind-1] end + showerror(IOContext(io, :limit => true), er, bt) end immutable REPLDisplay{R<:AbstractREPL} <: Display @@ -167,6 +165,8 @@ function print_response(errio::IO, val::ANY, bt, show_value::Bool, have_color::B catch err if bt !== nothing println(errio, "SYSTEM: show(lasterr) caused an error") + println(errio, err) + Base.show_backtrace(errio, bt) break end val = err diff --git a/base/array.jl b/base/array.jl index f4f507b92dfb6..2946e6022ad0b 100644 --- a/base/array.jl +++ b/base/array.jl @@ -737,7 +737,8 @@ julia> deleteat!([6, 5, 4, 3, 2, 1], 1:2:5) julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2)) ERROR: ArgumentError: indices must be unique and sorted - in deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:753 +Stacktrace: + [1] deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:748 ``` """ function deleteat!(a::Vector, inds) diff --git a/base/client.jl b/base/client.jl index 5b1e35fcb1e5b..1789cba0dc5fe 100644 --- a/base/client.jl +++ b/base/client.jl @@ -22,18 +22,19 @@ const text_colors = AnyDict( :normal => "\033[0m", :default => "\033[39m", :bold => "\033[1m", + :nothing => "", ) +for i in 0:255 + text_colors[i] = "\033[38;5;$(i)m" +end + const disable_text_style = AnyDict( :bold => "\033[22m", :normal => "", :default => "", ) -for i in 0:255 - text_colors[i] = "\033[38;5;$(i)m" -end - # Create a docstring with an automatically generated list # of colors. available_text_colors = collect(Iterators.filter(x -> !isa(x, Integer), keys(text_colors))) @@ -52,6 +53,7 @@ Available colors are: $available_text_colors_docstring as well as the integers 0 The color `:default` will print text in the default color while the color `:normal` will print text with all text properties (like boldness) reset. +Printing with the color `:nothing` will print the string without modifications. """ text_colors @@ -83,6 +85,9 @@ info_color() = repl_color("JULIA_INFO_COLOR" , default_color_info) input_color() = text_colors[:bold] * text_colors[repl_color("JULIA_INPUT_COLOR", default_color_input)] answer_color() = text_colors[:bold] * text_colors[repl_color("JULIA_ANSWER_COLOR", default_color_answer)] +stackframe_lineinfo_color() = repl_color("JULIA_STACKFRAME_LINEINFO_COLOR", :bold) +stackframe_function_color() = repl_color("JULIA_STACKFRAME_FUNCTION_COLOR", :bold) + function repl_cmd(cmd, out) shell = shell_split(get(ENV,"JULIA_SHELL",get(ENV,"SHELL","/bin/sh"))) # Note that we can't support the fish shell due to its lack of subshells diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index b4ed27eebfb55..d1205cd4e09bc 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -450,7 +450,8 @@ If `T` is not a bitstype, an error is thrown. ```jldoctest julia> sizeof(Base.LinAlg.LU) ERROR: argument is an abstract type; size is indeterminate - in sizeof(::Type{T}) at ./essentials.jl:99 +Stacktrace: + [1] sizeof(::Type{T}) at ./essentials.jl:99 ``` """ sizeof(::Type) @@ -2531,7 +2532,8 @@ julia> convert(Int, 3.0) julia> convert(Int, 3.5) ERROR: InexactError() - in convert(::Type{Int64}, ::Float64) at ./float.jl:656 +Stacktrace: + [1] convert(::Type{Int64}, ::Float64) at ./float.jl:656 ``` If `T` is a `AbstractFloat` or `Rational` type, diff --git a/base/linalg/eigen.jl b/base/linalg/eigen.jl index 1a91f491a6943..31a97f7f6ffe9 100644 --- a/base/linalg/eigen.jl +++ b/base/linalg/eigen.jl @@ -208,8 +208,9 @@ julia> A = [0 im; -1 0] julia> eigmax(A) ERROR: DomainError: - in #eigmax#36(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:218 - in eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:216 +Stacktrace: + [1] #eigmax#30(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:219 + [2] eigmax(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:217 ``` """ function eigmax(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true) @@ -249,8 +250,9 @@ julia> A = [0 im; -1 0] julia> eigmin(A) ERROR: DomainError: - in #eigmin#37(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:259 - in eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:257 +Stacktrace: + [1] #eigmin#31(::Bool, ::Bool, ::Function, ::Array{Complex{Int64},2}) at ./linalg/eigen.jl:261 + [2] eigmin(::Array{Complex{Int64},2}) at ./linalg/eigen.jl:259 ``` """ function eigmin(A::Union{Number, StridedMatrix}; permute::Bool=true, scale::Bool=true) diff --git a/base/nullable.jl b/base/nullable.jl index 3b333d2612de9..0122dfa4755ff 100644 --- a/base/nullable.jl +++ b/base/nullable.jl @@ -111,7 +111,8 @@ Nullable{String}() julia> unsafe_get(x) ERROR: UndefRefError: access to undefined reference - in unsafe_get(::Nullable{String}) at ./nullable.jl:123 +Stacktrace: + [1] unsafe_get(::Nullable{String}) at ./nullable.jl:124 julia> x = 1 1 diff --git a/base/replutil.jl b/base/replutil.jl index 19354e3b66faa..4f9c49687c899 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -194,7 +194,9 @@ end function showerror(io::IO, ex, bt; backtrace=true) try - showerror(io, ex) + with_output_color(have_color ? error_color() : :nothing, io) do io + showerror(io, ex) + end finally backtrace && show_backtrace(io, bt) end @@ -577,15 +579,21 @@ function show_method_candidates(io::IO, ex::MethodError, kwargs::Vector=Any[]) end end -function show_trace_entry(io, frame, n) +function show_trace_entry(io, frame, n; prefix = " in ") print(io, "\n") - show(io, frame, full_path=true) + show(io, frame, full_path=true; prefix = prefix) n > 1 && print(io, " (repeats ", n, " times)") end function show_backtrace(io::IO, t::Vector) - process_entry(last_frame, n) = - show_trace_entry(io, last_frame, n) + n_frames = 0 + frame_counter = 0 + process_backtrace((a,b) -> n_frames += 1, t) + n_frames != 0 && print(io, "\nStacktrace:") + process_entry = (last_frame, n) -> begin + frame_counter += 1 + show_trace_entry(io, last_frame, n, prefix = string(" [", frame_counter, "] ")) + end process_backtrace(process_entry, t) end diff --git a/base/show.jl b/base/show.jl index 58e7e7e0d33e1..72d876dfef735 100644 --- a/base/show.jl +++ b/base/show.jl @@ -1031,31 +1031,37 @@ end function show_lambda_types(io::IO, li::Core.MethodInstance) # print a method signature tuple for a lambda definition - if li.specTypes === Tuple - print(io, li.def.name, "(...)") - return - end - - sig = li.specTypes.parameters - ft = sig[1] - if ft <: Function && isempty(ft.parameters) && - isdefined(ft.name.module, ft.name.mt.name) && - ft == typeof(getfield(ft.name.module, ft.name.mt.name)) - print(io, ft.name.mt.name) - elseif isa(ft, DataType) && ft.name === Type.name && isleaftype(ft) - f = ft.parameters[1] - print(io, f) - else - print(io, "(::", ft, ")") + local sig + returned_from_do = false + Base.with_output_color(have_color ? stackframe_function_color() : :nothing, io) do io + if li.specTypes === Tuple + print(io, li.def.name, "(...)") + returned_from_do = true + return + end + sig = li.specTypes.parameters + ft = sig[1] + if ft <: Function && isempty(ft.parameters) && + isdefined(ft.name.module, ft.name.mt.name) && + ft == typeof(getfield(ft.name.module, ft.name.mt.name)) + print(io, ft.name.mt.name) + elseif isa(ft, DataType) && ft.name === Type.name && isleaftype(ft) + f = ft.parameters[1] + print(io, f) + else + print(io, "(::", ft, ")") + end end + returned_from_do && return first = true - print(io, '(') + print_style = have_color ? :bold : :nothing + print_with_color(print_style, io, "(") for i = 2:length(sig) # fixme (iter): `eachindex` with offset? first || print(io, ", ") first = false print(io, "::", sig[i]) end - print(io, ')') + print_with_color(print_style, io, ")") nothing end diff --git a/base/stacktraces.jl b/base/stacktraces.jl index 7f92db5995b0b..e22b6bfd9742f 100644 --- a/base/stacktraces.jl +++ b/base/stacktraces.jl @@ -188,7 +188,7 @@ function show_spec_linfo(io::IO, frame::StackFrame) if frame.func === empty_sym @printf(io, "ip:%#x", frame.pointer) else - print(io, frame.func) + print_with_color(Base.have_color ? Base.stackframe_function_color() : :nothing, io, string(frame.func)) end else linfo = get(frame.linfo) @@ -200,16 +200,20 @@ function show_spec_linfo(io::IO, frame::StackFrame) end end -function show(io::IO, frame::StackFrame; full_path::Bool=false) - print(io, " in ") +function show(io::IO, frame::StackFrame; full_path::Bool=false, + prefix = " in ") + print(io, prefix) show_spec_linfo(io, frame) if frame.file !== empty_sym file_info = full_path ? string(frame.file) : basename(string(frame.file)) - print(io, " at ", file_info, ":") - if frame.line >= 0 - print(io, frame.line) - else - print(io, "?") + print(io, " at ") + Base.with_output_color(Base.have_color ? Base.stackframe_lineinfo_color() : :nothing, io) do io + print(io, file_info, ":") + if frame.line >= 0 + print(io, frame.line) + else + print(io, "?") + end end end if frame.inlined diff --git a/base/test.jl b/base/test.jl index 194ce11e7a937..f6b24705a06de 100644 --- a/base/test.jl +++ b/base/test.jl @@ -972,7 +972,8 @@ Body: julia> @inferred f(1,2,3) ERROR: return type Int64 does not match inferred return type Union{Float64,Int64} - in error(::String) at ./error.jl:21 +Stacktrace: + [1] error(::String) at ./error.jl:21 julia> @inferred max(1,2) 2 diff --git a/base/util.jl b/base/util.jl index ba4c421b81df0..dcebe7e72c51a 100644 --- a/base/util.jl +++ b/base/util.jl @@ -309,7 +309,7 @@ function with_output_color(f::Function, color::Union{Int, Symbol}, io::IO, args. have_color && print(buf, get(text_colors, color, color_normal)) try f(IOContext(buf, io), args...) finally - have_color && print(buf, get(disable_text_style, color, text_colors[:default])) + have_color && color != :nothing && print(buf, get(disable_text_style, color, text_colors[:default])) have_color && (bold || color == :bold) && print(buf, disable_text_style[:bold]) print(io, String(take!(buf))) end diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index e9ff1817036cc..3d0844cfa0f9a 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -366,12 +366,12 @@ end for precomp in ("yes", "no") bt = readstring(pipeline(ignorestatus(`$(Base.julia_cmd()) --startup-file=no --precompiled=$precomp -E 'include("____nonexistent_file")'`), stderr=catcmd)) - @test contains(bt, "in include_from_node1") + @test contains(bt, "include_from_node1") if is_windows() && Sys.WORD_SIZE == 32 && precomp == "yes" # fixme, issue #17251 - @test_broken contains(bt, "in include_from_node1(::String) at $(joinpath(".","loading.jl"))") + @test_broken contains(bt, "include_from_node1(::String) at $(joinpath(".","loading.jl"))") else - @test contains(bt, "in include_from_node1(::String) at $(joinpath(".","loading.jl"))") + @test contains(bt, "include_from_node1(::String) at $(joinpath(".","loading.jl"))") end lno = match(r"at \.[\/\\]loading\.jl:(\d+)", bt) @test length(lno.captures) == 1 diff --git a/test/compile.jl b/test/compile.jl index 5057190db4e33..fd7be47f004b0 100644 --- a/test/compile.jl +++ b/test/compile.jl @@ -217,7 +217,7 @@ try end """) - t = redirected_stderr("ERROR: LoadError: Declaring __precompile__(false) is not allowed in files that are being precompiled.\n in __precompile__") + t = redirected_stderr("ERROR: LoadError: Declaring __precompile__(false) is not allowed in files that are being precompiled.\nStacktrace:\n [1] __precompile__") try Base.compilecache("Baz") # from __precompile__(false) error("__precompile__ disabled test failed") @@ -314,7 +314,7 @@ try error("break me") end """) - t = redirected_stderr("ERROR: LoadError: break me\n in error") + t = redirected_stderr("ERROR: LoadError: break me\nStacktrace:\n [1] error") try Base.require(:FooBar) error("\"LoadError: break me\" test failed")