Skip to content

Commit 0bf392e

Browse files
authored
Enable support for NO_COLOR and FORCE_COLOR environment variables (#53742)
1 parent 196dec6 commit 0bf392e

File tree

6 files changed

+60
-12
lines changed

6 files changed

+60
-12
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ Command-line option changes
3636

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

4043
Multi-threading changes
4144
-----------------------

base/client.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ incomplete_tag(exc::Meta.ParseError) = incomplete_tag(exc.detail)
229229
cmd_suppresses_program(cmd) = cmd in ('e', 'E')
230230
function exec_options(opts)
231231
startup = (opts.startupfile != 2)
232-
global have_color = (opts.color != 0) ? (opts.color == 1) : nothing # --color=on
232+
global have_color = colored_text(opts)
233233
global is_interactive = (opts.isinteractive != 0)
234234

235235
# pre-process command line argument list
@@ -419,7 +419,7 @@ end
419419
global active_repl
420420

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

566566
quiet = (opts.quiet != 0)
567567
history_file = (opts.historyfile != 0)
568-
color_set = (opts.color != 0) # --color!=auto
569-
return run_main_repl(interactiveinput, quiet, banner, history_file, color_set)
568+
return run_main_repl(interactiveinput, quiet, banner, history_file)
570569
end
571570

572571
"""

base/libuv.jl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,13 @@ function reinit_stdio()
138138
global stdout = init_stdio(ccall(:jl_stdout_stream, Ptr{Cvoid}, ()))::IO
139139
global stderr = init_stdio(ccall(:jl_stderr_stream, Ptr{Cvoid}, ()))::IO
140140
opts = JLOptions()
141-
if opts.color != 0
142-
have_color = (opts.color == 1)
141+
color = colored_text(opts)
142+
if !isnothing(color)
143143
if !isa(stdout, TTY)
144-
global stdout = IOContext(stdout, :color => have_color)
144+
global stdout = IOContext(stdout, :color => color::Bool)
145145
end
146146
if !isa(stderr, TTY)
147-
global stderr = IOContext(stderr, :color => have_color)
147+
global stderr = IOContext(stderr, :color => color::Bool)
148148
end
149149
end
150150
nothing

base/options.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ end
6767

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

70+
function colored_text(opts::JLOptions)
71+
return if opts.color != 0
72+
opts.color == 1
73+
elseif !isempty(get(ENV, "FORCE_COLOR", ""))
74+
true
75+
elseif !isempty(get(ENV, "NO_COLOR", ""))
76+
false
77+
else
78+
nothing
79+
end
80+
end
81+
7082
function show(io::IO, opt::JLOptions)
7183
print(io, "JLOptions(")
7284
fields = fieldnames(JLOptions)

doc/src/manual/environment-variables.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ affinitized. Otherwise, Julia lets the operating system handle thread policy.
376376
## REPL formatting
377377

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

409+
### [`NO_COLOR`](@id NO_COLOR)
410+
411+
When this variable is present and not an empty string (regardless of its value) then colored
412+
text will be disabled on the REPL. Can be overridden with the flag `--color=yes` or with the
413+
environment variable [`FORCE_COLOR`](@ref FORCE_COLOR). This environment variable is
414+
[commonly recognized by command-line applications](https://no-color.org/).
415+
416+
### [`FORCE_COLOR`](@id FORCE_COLOR)
417+
418+
When this variable is present and not an empty string (regardless of its value) then
419+
colored text will be enabled on the REPL. Can be overridden with the flag `--color=no`. This
420+
environment variable is [commonly recognized by command-line applications](https://force-color.org/).
421+
409422
## System and Package Image Building
410423

411424
### [`JULIA_CPU_TARGET`](@id JULIA_CPU_TARGET)

test/cmdlineargs.jl

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,9 +429,30 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
429429
@test readchomp(`$exename -E "isinteractive()" -i`) == "true"
430430

431431
# --color
432-
@test readchomp(`$exename --color=yes -E "Base.have_color"`) == "true"
433-
@test readchomp(`$exename --color=no -E "Base.have_color"`) == "false"
434-
@test errors_not_signals(`$exename --color=false`)
432+
function color_cmd(; flag, no_color=nothing, force_color=nothing)
433+
cmd = `$exename --color=$flag -E "Base.have_color"`
434+
return addenv(cmd, "NO_COLOR" => no_color, "FORCE_COLOR" => force_color)
435+
end
436+
437+
@test readchomp(color_cmd(flag="auto")) == "nothing"
438+
@test readchomp(color_cmd(flag="no")) == "false"
439+
@test readchomp(color_cmd(flag="yes")) == "true"
440+
@test errors_not_signals(color_cmd(flag="false"))
441+
@test errors_not_signals(color_cmd(flag="true"))
442+
443+
@test readchomp(color_cmd(flag="auto", no_color="")) == "nothing"
444+
@test readchomp(color_cmd(flag="auto", no_color="1")) == "false"
445+
@test readchomp(color_cmd(flag="no", no_color="1")) == "false"
446+
@test readchomp(color_cmd(flag="yes", no_color="1")) == "true"
447+
448+
@test readchomp(color_cmd(flag="auto", force_color="")) == "nothing"
449+
@test readchomp(color_cmd(flag="auto", force_color="1")) == "true"
450+
@test readchomp(color_cmd(flag="no", force_color="1")) == "false"
451+
@test readchomp(color_cmd(flag="yes", force_color="1")) == "true"
452+
453+
@test readchomp(color_cmd(flag="auto", no_color="1", force_color="1")) == "true"
454+
@test readchomp(color_cmd(flag="no", no_color="1", force_color="1")) == "false"
455+
@test readchomp(color_cmd(flag="yes", no_color="1", force_color="1")) == "true"
435456

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

0 commit comments

Comments
 (0)