diff --git a/NEWS.md b/NEWS.md index b319100a3e07a..7aeb6f927804d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -70,6 +70,8 @@ Language changes * The line number of function definitions is now added by the parser as an additional `LineNumberNode` at the start of each function body ([#35138]). +* Color now defaults to on when stdout and stderr are TTYs ([#34347]) + Multi-threading changes ----------------------- diff --git a/base/Base.jl b/base/Base.jl index cb4271067fdf2..ba8ff108c73dc 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -241,6 +241,7 @@ include("filesystem.jl") using .Filesystem include("cmd.jl") include("process.jl") +include("ttyhascolor.jl") include("grisu/grisu.jl") include("secretbuffer.jl") diff --git a/base/client.jl b/base/client.jl index 2d069ce84de8d..8985a5fdc825c 100644 --- a/base/client.jl +++ b/base/client.jl @@ -3,7 +3,7 @@ ## client.jl - frontend handling command line options, environment setup, ## and REPL -have_color = false +have_color = nothing default_color_warn = :yellow default_color_error = :light_red default_color_info = :cyan @@ -109,6 +109,7 @@ display_error(er, bt=nothing) = display_error(stderr, er, bt) function eval_user_input(errio, @nospecialize(ast), show_value::Bool) errcount = 0 lasterr = nothing + have_color = get(stdout, :color, false) while true try if have_color @@ -220,7 +221,7 @@ function exec_options(opts) startup = (opts.startupfile != 2) history_file = (opts.historyfile != 0) color_set = (opts.color != 0) # --color!=auto - global have_color = (opts.color == 1) # --color=on + global have_color = color_set ? (opts.color == 1) : nothing # --color=on global is_interactive = (opts.isinteractive != 0) # pre-process command line argument list @@ -492,7 +493,7 @@ function _start() invokelatest(display_error, catch_stack()) exit(1) end - if is_interactive && have_color + if is_interactive && have_color === true print(color_normal) end end diff --git a/base/loading.jl b/base/loading.jl index baa4514b6a64d..edcfded90f0e4 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1169,10 +1169,11 @@ function create_expr_cache(input::String, output::String, concrete_deps::typeof( eval(Meta.parse(code)) end """ + io = open(pipeline(`$(julia_cmd()) -O0 --output-ji $output --output-incremental=yes --startup-file=no --history-file=no --warn-overwrite=yes - --color=$(have_color ? "yes" : "no") + --color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no") --eval $code_object`, stderr=stderr), "w", stdout) in = io.in diff --git a/base/stream.jl b/base/stream.jl index 7932f4fe69628..5368b2eb9359b 100644 --- a/base/stream.jl +++ b/base/stream.jl @@ -485,11 +485,6 @@ function displaysize(io::TTY) return h, w end -in(key_value::Pair{Symbol,Bool}, ::TTY) = key_value.first === :color && key_value.second === have_color -haskey(::TTY, key::Symbol) = key === :color -getindex(::TTY, key::Symbol) = key === :color ? have_color : throw(KeyError(key)) -get(::TTY, key::Symbol, default) = key === :color ? have_color : default - ### Libuv callbacks ### ## BUFFER ## diff --git a/base/ttyhascolor.jl b/base/ttyhascolor.jl new file mode 100644 index 0000000000000..c852bd5feb62f --- /dev/null +++ b/base/ttyhascolor.jl @@ -0,0 +1,25 @@ +if Sys.iswindows() + ttyhascolor(term_type = nothing) = true +else + function ttyhascolor(term_type = get(ENV, "TERM", "")) + startswith(term_type, "xterm") && return true + try + @static if Sys.KERNEL === :FreeBSD + return success(`tput AF 0`) + else + return success(`tput setaf 0`) + end + catch e + return false + end + end +end +function get_have_color() + global have_color + have_color === nothing && (have_color = ttyhascolor()) + return have_color::Bool +end +in(key_value::Pair{Symbol,Bool}, ::TTY) = key_value.first === :color && key_value.second === get_have_color() +haskey(::TTY, key::Symbol) = key === :color +getindex(::TTY, key::Symbol) = key === :color ? get_have_color() : throw(KeyError(key)) +get(::TTY, key::Symbol, default) = key === :color ? get_have_color() : default \ No newline at end of file diff --git a/deps/checksums/Pkg-23da050ea368fade2ff801daf69c928b11ef61ef.tar.gz/md5 b/deps/checksums/Pkg-23da050ea368fade2ff801daf69c928b11ef61ef.tar.gz/md5 new file mode 100644 index 0000000000000..c2d8876ba3112 --- /dev/null +++ b/deps/checksums/Pkg-23da050ea368fade2ff801daf69c928b11ef61ef.tar.gz/md5 @@ -0,0 +1 @@ +4db13f3b0038a93c2c899af142181533 diff --git a/deps/checksums/Pkg-23da050ea368fade2ff801daf69c928b11ef61ef.tar.gz/sha512 b/deps/checksums/Pkg-23da050ea368fade2ff801daf69c928b11ef61ef.tar.gz/sha512 new file mode 100644 index 0000000000000..0fec2dbaf4c32 --- /dev/null +++ b/deps/checksums/Pkg-23da050ea368fade2ff801daf69c928b11ef61ef.tar.gz/sha512 @@ -0,0 +1 @@ +20f562ed1c9b86424ead9b6556ea4be2ab116bfe11922a0123418b522cd32dd81b04904f06cb1f28712f125410254f20253c3a5cc58b84622f1c6441daa2b665 diff --git a/deps/checksums/Pkg-8c415b01924eb4452cb7be8438c2bbc0978d1152.tar.gz/md5 b/deps/checksums/Pkg-8c415b01924eb4452cb7be8438c2bbc0978d1152.tar.gz/md5 deleted file mode 100644 index 44252542ea573..0000000000000 --- a/deps/checksums/Pkg-8c415b01924eb4452cb7be8438c2bbc0978d1152.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -a5478592cc9eede8065202b23aee79a7 diff --git a/deps/checksums/Pkg-8c415b01924eb4452cb7be8438c2bbc0978d1152.tar.gz/sha512 b/deps/checksums/Pkg-8c415b01924eb4452cb7be8438c2bbc0978d1152.tar.gz/sha512 deleted file mode 100644 index 20b5185e8f37a..0000000000000 --- a/deps/checksums/Pkg-8c415b01924eb4452cb7be8438c2bbc0978d1152.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -576ad34eed41d4749fc4a2b263bf6a75d2224d8ac0672b5e3f52666e9fa5c4c9a3565498402f9b611543376c2a1f37cb8a1414095e6e9a76ba9331ef52483fe1 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index 123dc8e6d11df..dd34aad170546 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,2 +1,2 @@ PKG_BRANCH = master -PKG_SHA1 = 8c415b01924eb4452cb7be8438c2bbc0978d1152 +PKG_SHA1 = 23da050ea368fade2ff801daf69c928b11ef61ef diff --git a/stdlib/REPL/src/REPL.jl b/stdlib/REPL/src/REPL.jl index 657b2ca4c9e33..a79ece12ca27a 100644 --- a/stdlib/REPL/src/REPL.jl +++ b/stdlib/REPL/src/REPL.jl @@ -304,6 +304,7 @@ mutable struct BasicREPL <: AbstractREPL end outstream(r::BasicREPL) = r.terminal +hascolor(r::BasicREPL) = hascolor(r.terminal) function run_frontend(repl::BasicREPL, backend::REPLBackendRef) d = REPLDisplay(repl) @@ -430,13 +431,14 @@ mutable struct LineEditREPL <: AbstractREPL interface::ModalInterface backendref::REPLBackendRef LineEditREPL(t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell,in_help,envcolors) = - new(t,true,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell, + new(t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell, in_help,envcolors,false,nothing, Options(), nothing) end outstream(r::LineEditREPL) = r.t specialdisplay(r::LineEditREPL) = r.specialdisplay specialdisplay(r::AbstractREPL) = nothing terminal(r::LineEditREPL) = r.t +hascolor(r::LineEditREPL) = r.hascolor LineEditREPL(t::TextTerminal, hascolor::Bool, envcolors::Bool=false) = LineEditREPL(t, hascolor, @@ -815,7 +817,7 @@ function respond(f, repl, main; pass_empty = false, suppress_on_semicolon = true response = (catch_stack(), true) end hide_output = suppress_on_semicolon && ends_with_semicolon(line) - print_response(repl, response, !hide_output, Base.have_color) + print_response(repl, response, !hide_output, hascolor(repl)) end prepare_next(repl) reset_state(s) @@ -957,7 +959,7 @@ function setup_interface( end hist_from_file(hp, f, hist_path) catch - print_response(repl, (catch_stack(),true), true, Base.have_color) + print_response(repl, (catch_stack(),true), true, hascolor(repl)) println(outstream(repl)) @info "Disabling history file for this session" repl.history_file = false @@ -1157,6 +1159,7 @@ StreamREPL(stream::IO) = StreamREPL(stream, Base.text_colors[:green], Base.input run_repl(stream::IO) = run_repl(StreamREPL(stream)) outstream(s::StreamREPL) = s.stream +hascolor(s::StreamREPL) = get(s.stream, :color, false) answer_color(r::LineEditREPL) = r.envcolors ? Base.answer_color() : r.answer_color answer_color(r::StreamREPL) = r.answer_color @@ -1215,7 +1218,7 @@ function ends_with_semicolon(line::AbstractString) end function run_frontend(repl::StreamREPL, backend::REPLBackendRef) - have_color = Base.have_color + have_color = hascolor(repl) Base.banner(repl.stream) d = REPLDisplay(repl) dopushdisplay = !in(d,Base.Multimedia.displays) diff --git a/stdlib/REPL/src/Terminals.jl b/stdlib/REPL/src/Terminals.jl index c8135bb6f2879..15fa3836041b9 100644 --- a/stdlib/REPL/src/Terminals.jl +++ b/stdlib/REPL/src/Terminals.jl @@ -152,22 +152,7 @@ beep(t::UnixTerminal) = write(t.err_stream,"\x7") Base.displaysize(t::UnixTerminal) = displaysize(t.out_stream) -if Sys.iswindows() - hascolor(t::TTYTerminal) = true -else - function hascolor(t::TTYTerminal) - startswith(t.term_type, "xterm") && return true - try - @static if Sys.KERNEL === :FreeBSD - return success(`tput AF 0`) - else - return success(`tput setaf 0`) - end - catch - return false - end - end -end +hascolor(t::TTYTerminal) = Base.ttyhascolor(t.term_type) # use cached value of have_color Base.in(key_value::Pair, t::TTYTerminal) = in(key_value, pipe_writer(t)) diff --git a/stdlib/REPL/test/repl.jl b/stdlib/REPL/test/repl.jl index 3af23e146e51b..e543b99ee3953 100644 --- a/stdlib/REPL/test/repl.jl +++ b/stdlib/REPL/test/repl.jl @@ -47,7 +47,7 @@ function fake_repl(@nospecialize(f); options::REPL.Options=REPL.Options(confirm_ Base.link_pipe!(output, reader_supports_async=true, writer_supports_async=true) Base.link_pipe!(err, reader_supports_async=true, writer_supports_async=true) - repl = REPL.LineEditREPL(FakeTerminal(input.out, output.in, err.in), true) + repl = REPL.LineEditREPL(FakeTerminal(input.out, output.in, err.in, options.hascolor), options.hascolor) repl.options = options hard_kill = kill_timer(900) # Your debugging session starts now. You have 15 minutes. Go. @@ -90,7 +90,7 @@ end # in the mix. If verification needs to be done, keep it to the bare minimum. Basically # this should make sure nothing crashes without depending on how exactly the control # characters are being used. -fake_repl() do stdin_write, stdout_read, repl +fake_repl(options = REPL.Options(confirm_exit=false,hascolor=false)) do stdin_write, stdout_read, repl repl.specialdisplay = REPL.REPLDisplay(repl) repl.history_file = false