Skip to content

Commit

Permalink
Make the REPL banner resize to avoid wrapping
Browse files Browse the repository at this point in the history
We also spritz it up a bit using the new StyledStrings library, namely:
- colouring the Help and Pkg key prompts
- making the docs link a terminal link, and Pkg a link to the Pkg docs
- using box drawing characters for the dividing line
- making branch status more colourful
- making the official version text more subdued

With these change the four banners (from smallest to largest) are:
1. A one-liner, for extreme circumstances (new)
2. The short banner
3. The large banner, with the description stacked vertically (new)
4. The large banner, with the description stacked horizontally
  • Loading branch information
tecosaur committed Feb 12, 2024
1 parent 0a89164 commit 75c6468
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 74 deletions.
15 changes: 7 additions & 8 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,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::Int, history_file::Bool, color_set::Bool)
fallback_repl = parse(Bool, get(ENV, "JULIA_FALLBACK_REPL", "false"))
if !fallback_repl && interactive
load_InteractiveUtils()
Expand All @@ -424,7 +424,7 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Symbol, history_f
invokelatest(REPL_MODULE_REF[]) do REPL
term_env = get(ENV, "TERM", @static Sys.iswindows() ? "" : "dumb")
term = REPL.Terminals.TTYTerminal(term_env, stdin, stdout, stderr)
banner == :no || REPL.banner(term, short=banner==:short)
banner > 0 && REPL.banner(term, banner)
if term.term_type == "dumb"
repl = REPL.BasicREPL(term)
quiet || @warn "Terminal not fully functional"
Expand Down Expand Up @@ -549,12 +549,11 @@ end
function repl_main(_)
opts = Base.JLOptions()
interactiveinput = isa(stdin, Base.TTY)
b = opts.banner
auto = b == -1
banner = b == 0 || (auto && !interactiveinput) ? :no :
b == 1 || (auto && interactiveinput) ? :yes :
:short # b == 2

banner = if opts.banner == -1
10 * Int(interactiveinput)
else
Int(opts.banner)
end
quiet = (opts.quiet != 0)
history_file = (opts.historyfile != 0)
color_set = (opts.color != 0) # --color!=auto
Expand Down
19 changes: 12 additions & 7 deletions src/jloptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ static const char opts[] =
// interactive options
" -i, --interactive Interactive mode; REPL runs and `isinteractive()` is true\n"
" -q, --quiet Quiet startup: no banner, suppress REPL warnings\n"
" --banner={yes|no|short|auto*}\n"
" Enable or disable startup banner\n"
" --banner={yes|no|0-10|auto*}\n"
" Enable or disable startup banner, optionally setting a maximum ordinal size\n"
" --color={yes|no|auto*} Enable or disable color text\n"
" --history-file={yes*|no} Load or save history\n\n"

Expand Down Expand Up @@ -439,15 +439,20 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
break;
case opt_banner: // banner
if (!strcmp(optarg, "yes"))
jl_options.banner = 1;
jl_options.banner = 10;
else if (!strcmp(optarg, "no"))
jl_options.banner = 0;
else if (!strcmp(optarg, "auto"))
jl_options.banner = -1;
else if (!strcmp(optarg, "short"))
jl_options.banner = 2;
else
jl_errorf("julia: invalid argument to --banner={yes|no|auto|short} (%s)", optarg);
else {
errno = 0;
int bval = strtol(optarg, NULL, 10);
if (errno == ERANGE)
jl_errorf("julia: invalid argument to --banner={yes|no|0-10|auto} (%s)", optarg);
else
jl_options.banner = bval;
break;
}
break;
case opt_sysimage_native_code:
if (!strcmp(optarg,"yes"))
Expand Down
121 changes: 68 additions & 53 deletions stdlib/REPL/src/REPL.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1480,11 +1480,23 @@ ends_with_semicolon(code::AbstractString) = ends_with_semicolon(String(code))
ends_with_semicolon(code::Union{String,SubString{String}}) =
contains(_rm_strings_and_comments(code), r";\s*$")

function banner(io::IO = stdout; short = false)
if Base.GIT_VERSION_INFO.tagged_commit
commit_string = Base.TAGGED_RELEASE_BANNER
"""
banner(io::IO = stdout, maxsize:Int = 10)
Print the "Julia" informative banner to `io`, using a size variant no larger
than `maxsize`, where `maxsize` is an ordinal value correspanding to a
particular banner size.
!!! warning
The particular banner selected by `maxsize` is liable to being changed
without warning. `1` is the smallest banner, with each following size larger
than the previous. Currently there are four sizes available.
"""
function banner(io::IO = stdout, maxsize::Int = 10)
commit_string = if Base.GIT_VERSION_INFO.tagged_commit
Base.AnnotatedString(TAGGED_RELEASE_BANNER, :face => :shadow)
elseif isempty(Base.GIT_VERSION_INFO.commit)
commit_string = ""
styled""
else
days = Int(floor((ccall(:jl_clock_now, Float64, ()) - Base.GIT_VERSION_INFO.fork_master_timestamp) / (60 * 60 * 24)))
days = max(0, days)
Expand All @@ -1493,60 +1505,63 @@ function banner(io::IO = stdout; short = false)
commit = Base.GIT_VERSION_INFO.commit_short

if distance == 0
commit_string = "Commit $(commit) ($(days) $(unit) old master)"
styled"""Commit {grey:$commit} \
({warning:⌛ {italic:$days $unit}} old master)"""
else
branch = Base.GIT_VERSION_INFO.branch
commit_string = "$(branch)/$(commit) (fork: $(distance) commits, $(days) $(unit))"
styled"""{emphasis:$branch}/{grey:$commit} \
({italic:{success:{bold,(slant=normal):↑} $distance commits}, \
{warning:{(slant=normal):⌛} $days $unit}})"""
end
end

commit_date = isempty(Base.GIT_VERSION_INFO.date_string) ? "" : " ($(split(Base.GIT_VERSION_INFO.date_string)[1]))"

if get(io, :color, false)::Bool
c = Base.text_colors
tx = c[:normal] # text
jl = c[:normal] # julia
d1 = c[:bold] * c[:blue] # first dot
d2 = c[:bold] * c[:red] # second dot
d3 = c[:bold] * c[:green] # third dot
d4 = c[:bold] * c[:magenta] # fourth dot

if short
print(io,"""
$(d3)o$(tx) | Version $(VERSION)$(commit_date)
$(d2)o$(tx) $(d4)o$(tx) | $(commit_string)
""")
else
print(io,""" $(d3)_$(tx)
$(d1)_$(tx) $(jl)_$(tx) $(d2)_$(d3)(_)$(d4)_$(tx) | Documentation: https://docs.julialang.org
$(d1)(_)$(jl) | $(d2)(_)$(tx) $(d4)(_)$(tx) |
$(jl)_ _ _| |_ __ _$(tx) | Type \"?\" for help, \"]?\" for Pkg help.
$(jl)| | | | | | |/ _` |$(tx) |
$(jl)| | |_| | | | (_| |$(tx) | Version $(VERSION)$(commit_date)
$(jl)_/ |\\__'_|_|_|\\__'_|$(tx) | $(commit_string)
$(jl)|__/$(tx) |
""")
end
else
if short
print(io,"""
o | Version $(VERSION)$(commit_date)
o o | $(commit_string)
""")
else
print(io,"""
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type \"?\" for help, \"]?\" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version $(VERSION)$(commit_date)
_/ |\\__'_|_|_|\\__'_| | $(commit_string)
|__/ |
""")
end
commit_date = isempty(Base.GIT_VERSION_INFO.date_string) ? "" : styled" {light:($(split(Base.GIT_VERSION_INFO.date_string)[1]))}"
doclink = styled"{bold:Documentation:} {(underline=grey),link={https://docs.julialang.org}:https://docs.julialang.org}"
help = styled"Type {repl_prompt_help:?} for help, {repl_prompt_pkg:]?} for {(underline=grey),link={https://pkgdocs.julialang.org/}:Pkg} help."

size = min(if all(displaysize(io) .>= (8, 70)); 4 # Full size
elseif all(displaysize(io) .>= (8, 45)); 3 # Narrower
elseif all(displaysize(io) .>= (3, 50)); 2 # Tiny
else 1 end,
max(0, maxsize))

if size == 4 # Full size
print(io, styled"""
{bold,green:_}
{bold,blue:_} _ {bold:{red:_}{green:(_)}{magenta:_}} {shadow:│} $doclink
{bold,blue:(_)} | {bold:{red:(_)} {magenta:(_)}} {shadow:│}
_ _ _| |_ __ _ {shadow:│} $help
| | | | | | |/ _` | {shadow:│}
| | |_| | | | (_| | {shadow:│} Version {bold:$VERSION}$commit_date
_/ |\\__'_|_|_|\\__'_| {shadow:│} $commit_string
|__/ {shadow:│}
\n""")
elseif size == 3 # Rotated
print(io, styled"""
{bold,green:_}
{bold,blue:_} _ {bold:{red:_}{green:(_)}{magenta:_}}
{bold,blue:(_)} | {bold:{red:(_)} {magenta:(_)}}
_ _ _| |_ __ _
| | | | | | |/ _` |
| | |_| | | | (_| |
_/ |\\__'_|_|_|\\__'_|
|__/
$doclink
$help
Version {bold:$VERSION}$commit_date
$commit_string
\n""")
elseif size == 2 # Tiny
print(io, styled"""
{bold,green:o} {shadow:│} Version {bold:$VERSION}$commit_date
{bold:{red:o} {magenta:o}} {shadow:│} $commit_string
""", ifelse(displaysize(io) > (4, 0), "\n", ""))
elseif size == 1 && Base.GIT_VERSION_INFO.tagged_commit # Text only
print(io, styled"""{bold:{blue:∴} {magenta:Julia} $VERSION}$commit_date\n""")
elseif size == 1 # Text only
print(io, styled"""{bold:{blue:∴} {magenta:Julia} $VERSION}$commit_date $commit_string\n""")
end
end

Expand Down
4 changes: 2 additions & 2 deletions stdlib/REPL/test/repl.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1766,9 +1766,9 @@ let io = IOBuffer()
seek(io, 0)
@test countlines(io) == 9
take!(io)
@test REPL.banner(io; short=true) === nothing
@test REPL.banner(io, 1) === nothing
seek(io, 0)
@test countlines(io) == 2
@test countlines(io) == 1
end

@testset "Docstrings" begin
Expand Down
9 changes: 5 additions & 4 deletions test/cmdlineargs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,16 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
@test read(`$exename -e $p`, String) == "(0, -1)"
@test read(`$exename -q -e $p`, String) == "(1, 0)"
@test read(`$exename --quiet -e $p`, String) == "(1, 0)"
@test read(`$exename --banner=auto -e $p`, String) == "(0, -1)"
@test read(`$exename --banner=no -e $p`, String) == "(0, 0)"
@test read(`$exename --banner=yes -e $p`, String) == "(0, 1)"
@test read(`$exename --banner=short -e $p`, String) == "(0, 2)"
@test read(`$exename --banner=yes -e $p`, String) == "(0, 10)"
@test read(`$exename --banner=4 -e $p`, String) == "(1, 4)"
@test read(`$exename -q --banner=no -e $p`, String) == "(1, 0)"
@test read(`$exename -q --banner=yes -e $p`, String) == "(1, 1)"
@test read(`$exename -q --banner=short -e $p`, String) == "(1, 2)"
@test read(`$exename -q --banner=4 -e $p`, String) == "(1, 4)"
@test read(`$exename --banner=no -q -e $p`, String) == "(1, 0)"
@test read(`$exename --banner=yes -q -e $p`, String) == "(1, 1)"
@test read(`$exename --banner=short -q -e $p`, String) == "(1, 2)"
@test read(`$exename --banner=4 -q -e $p`, String) == "(1, 4)"
end

# --home
Expand Down
1 change: 1 addition & 0 deletions test/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ precompile_test_harness(false) do dir
Dict(Base.PkgId(Base.root_module(Base, :StyledStrings)) => Base.module_build_id(Base.root_module(Base, :StyledStrings))),
# and their dependencies
Dict(Base.PkgId(Base.root_module(Base, :Base64)) => Base.module_build_id(Base.root_module(Base, :Base64))),
Dict(Base.PkgId(Base.root_module(Base, :StyledStrings)) => Base.module_build_id(Base.root_module(Base, :StyledStrings))),
)
@test Dict(modules) == modules_ok

Expand Down

0 comments on commit 75c6468

Please sign in to comment.