Skip to content

Commit

Permalink
Enable support for NO_COLOR and FORCE_COLOR environment variables (
Browse files Browse the repository at this point in the history
  • Loading branch information
omus authored and DilumAluthge committed Jun 3, 2024
1 parent f273f36 commit 30858f4
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 12 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ Command-line option changes

* The `-m/--module` flag can be passed to run the `main` function inside a package with a set of arguments.
This `main` function should be declared using `@main` to indicate that it is an entry point.
* Enabling or disabling color text in Julia can now be controlled with the
[`NO_COLOR`](https://no-color.org/) or [`FORCE_COLOR`](https://force-color.org/) environment
variables. ([#53742]).

Multi-threading changes
-----------------------
Expand Down
7 changes: 3 additions & 4 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ incomplete_tag(exc::Meta.ParseError) = incomplete_tag(exc.detail)
cmd_suppresses_program(cmd) = cmd in ('e', 'E')
function exec_options(opts)
startup = (opts.startupfile != 2)
global have_color = (opts.color != 0) ? (opts.color == 1) : nothing # --color=on
global have_color = colored_text(opts)
global is_interactive = (opts.isinteractive != 0)

# pre-process command line argument list
Expand Down Expand Up @@ -419,7 +419,7 @@ end
global active_repl

# run the requested sort of evaluation loop on stdio
function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_file::Bool, color_set::Bool)
function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_file::Bool)
fallback_repl = parse(Bool, get(ENV, "JULIA_FALLBACK_REPL", "false"))
if !fallback_repl && interactive
load_InteractiveUtils()
Expand Down Expand Up @@ -565,8 +565,7 @@ function repl_main(_)

quiet = (opts.quiet != 0)
history_file = (opts.historyfile != 0)
color_set = (opts.color != 0) # --color!=auto
return run_main_repl(interactiveinput, quiet, banner, history_file, color_set)
return run_main_repl(interactiveinput, quiet, banner, history_file)
end

"""
Expand Down
8 changes: 4 additions & 4 deletions base/libuv.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ function reinit_stdio()
global stdout = init_stdio(ccall(:jl_stdout_stream, Ptr{Cvoid}, ()))::IO
global stderr = init_stdio(ccall(:jl_stderr_stream, Ptr{Cvoid}, ()))::IO
opts = JLOptions()
if opts.color != 0
have_color = (opts.color == 1)
color = colored_text(opts)
if !isnothing(color)
if !isa(stdout, TTY)
global stdout = IOContext(stdout, :color => have_color)
global stdout = IOContext(stdout, :color => color::Bool)
end
if !isa(stderr, TTY)
global stderr = IOContext(stderr, :color => have_color)
global stderr = IOContext(stderr, :color => color::Bool)
end
end
nothing
Expand Down
12 changes: 12 additions & 0 deletions base/options.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ end

JLOptions() = unsafe_load(cglobal(:jl_options, JLOptions))

function colored_text(opts::JLOptions)
return if opts.color != 0
opts.color == 1
elseif !isempty(get(ENV, "FORCE_COLOR", ""))
true
elseif !isempty(get(ENV, "NO_COLOR", ""))
false
else
nothing
end
end

function show(io::IO, opt::JLOptions)
print(io, "JLOptions(")
fields = fieldnames(JLOptions)
Expand Down
15 changes: 14 additions & 1 deletion doc/src/manual/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ affinitized. Otherwise, Julia lets the operating system handle thread policy.
## REPL formatting

Environment variables that determine how REPL output should be formatted at the
terminal. Generally, these variables should be set to [ANSI terminal escape
terminal. The `JULIA_*_COLOR` variables should be set to [ANSI terminal escape
sequences](https://en.wikipedia.org/wiki/ANSI_escape_code). Julia provides
a high-level interface with much of the same functionality; see the section on
[The Julia REPL](@ref).
Expand Down Expand Up @@ -406,6 +406,19 @@ should have at the terminal.
The formatting `Base.answer_color()` (default: normal, `"\033[0m"`) that output
should have at the terminal.

### [`NO_COLOR`](@id NO_COLOR)

When this variable is present and not an empty string (regardless of its value) then colored
text will be disabled on the REPL. Can be overridden with the flag `--color=yes` or with the
environment variable [`FORCE_COLOR`](@ref FORCE_COLOR). This environment variable is
[commonly recognized by command-line applications](https://no-color.org/).

### [`FORCE_COLOR`](@id FORCE_COLOR)

When this variable is present and not an empty string (regardless of its value) then
colored text will be enabled on the REPL. Can be overridden with the flag `--color=no`. This
environment variable is [commonly recognized by command-line applications](https://force-color.org/).

## System and Package Image Building

### [`JULIA_CPU_TARGET`](@id JULIA_CPU_TARGET)
Expand Down
27 changes: 24 additions & 3 deletions test/cmdlineargs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,30 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
@test readchomp(`$exename -E "isinteractive()" -i`) == "true"

# --color
@test readchomp(`$exename --color=yes -E "Base.have_color"`) == "true"
@test readchomp(`$exename --color=no -E "Base.have_color"`) == "false"
@test errors_not_signals(`$exename --color=false`)
function color_cmd(; flag, no_color=nothing, force_color=nothing)
cmd = `$exename --color=$flag -E "Base.have_color"`
return addenv(cmd, "NO_COLOR" => no_color, "FORCE_COLOR" => force_color)
end

@test readchomp(color_cmd(flag="auto")) == "nothing"
@test readchomp(color_cmd(flag="no")) == "false"
@test readchomp(color_cmd(flag="yes")) == "true"
@test errors_not_signals(color_cmd(flag="false"))
@test errors_not_signals(color_cmd(flag="true"))

@test readchomp(color_cmd(flag="auto", no_color="")) == "nothing"
@test readchomp(color_cmd(flag="auto", no_color="1")) == "false"
@test readchomp(color_cmd(flag="no", no_color="1")) == "false"
@test readchomp(color_cmd(flag="yes", no_color="1")) == "true"

@test readchomp(color_cmd(flag="auto", force_color="")) == "nothing"
@test readchomp(color_cmd(flag="auto", force_color="1")) == "true"
@test readchomp(color_cmd(flag="no", force_color="1")) == "false"
@test readchomp(color_cmd(flag="yes", force_color="1")) == "true"

@test readchomp(color_cmd(flag="auto", no_color="1", force_color="1")) == "true"
@test readchomp(color_cmd(flag="no", no_color="1", force_color="1")) == "false"
@test readchomp(color_cmd(flag="yes", no_color="1", force_color="1")) == "true"

# --history-file
@test readchomp(`$exename -E "Bool(Base.JLOptions().historyfile)"
Expand Down

0 comments on commit 30858f4

Please sign in to comment.