Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make testing more robust on wide term size #114

Merged
merged 10 commits into from
Jun 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions docs/src/layout/grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ The idea is simple: take a bunch of renderables and make a grid out of them:
import Term: Panel
import Term.Layout: grid

p = Panel(height=6, width=12)
panels = repeat([p], 8)
panels = repeat([Panel(height=6, width=12)], 8)

grid(panels)
```
Expand All @@ -34,16 +33,28 @@ But you can hide it too:
grid(panels; aspect=1, show_placeholder=true)
```

One can use complex expressions for layouts, and use and underscore `_` to specify empty elements in the layout:
You can use `layout` to more directly specify the number of rows and columns in the grid:
```@example grid
grid(panels; layout=(3, 4), show_placeholder=true)
```

Leaving a `nothing` argument will auto-magically compute the remaining `rows` or `cols` of the layout:
You can use `layout` to more directly specify the number of rows and columns in the grid:
```@example grid
grid(panels; layout=(3, nothing), show_placeholder=true)
```

One can use complex expressions for layouts, using an underscore `_` to specify empty elements in the layout:
```@example grid
grid(panels[1:6]; layout=:((a * _ * b) / (_ * _ * c * d) / (_ * e * f)))
```

Finally you can use `layout` to more directly specify the number of rows and columns in the grid:
Repeating elements is supported:
```@example grid
grid(panels; layout=(3, 4), show_placeholder=true)
grid(panels[1:2]; layout=:((α * _ * α) / (_ * _ * β * β)))
```


!!! note
Note that grid uses `vstack` and `hstack` to combine the renderables into the layout you requested. As such, it returns a single renderable, you don't have access to the individual renderables that went into making the grid any longer. This also means that the grid can be stack with other content to create a larger layout.

Expand Down
10 changes: 6 additions & 4 deletions src/__text_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -331,15 +331,17 @@ function fillin(text; bg = nothing)::String
end

"""
truncate(text::AbstractString, width::Int)
str_trunc(text::AbstractString, width::Int)

Shorten a string of text to a target width
"""
function truncate(text::AbstractString, width::Int; trailing_dots = "...")
# occursin('\n', text) && do_by_line(ln -> truncate(ln, width; trailing_dots=trailing_dots), text)
function str_trunc(text::AbstractString, width::Int; trailing_dots = "...")
# occursin('\n', text) && do_by_line(ln -> str_trunc(ln, width; trailing_dots=trailing_dots), text)
width < 0 && return text
textlen(text) ≤ width && return text

trunc = reshape_text(text, width - 3)
return split_lines(trunc)[1] * trailing_dots
out = first(split_lines(trunc)) * trailing_dots
# @assert textlen(out) ≤ width - 3
return out
end
4 changes: 2 additions & 2 deletions src/_progress.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ function update!(col::ElapsedColumn, args...)::String
string(round(elapsedtime / (60 * 1000); digits = 2), "min")
end

msg = lpad(truncate(msg, col.padwidth), col.padwidth)
msg = lpad(str_trunc(msg, col.padwidth), col.padwidth)
return apply_style("elapsed: $(msg)", col.style)
end

Expand Down Expand Up @@ -195,7 +195,7 @@ function update!(col::ETAColumn, args...)::String
string(round(remaining / (60 * 1000); digits = 2), "min")
end

msg = lpad(truncate(msg, col.padwidth), col.padwidth)
msg = lpad(str_trunc(msg, col.padwidth), col.padwidth)

return apply_style("remaining: $(msg)", col.style)
end
Expand Down
4 changes: 2 additions & 2 deletions src/_repr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ function repr_get_obj_fields_display(obj)

values = []
for val in _values
val = truncate(string(val), 45)
val = str_trunc(string(val), 45)
push!(values, RenderableText.(val; style = theme.repr_values_style))
end

Expand Down Expand Up @@ -73,7 +73,7 @@ function repr_panel(
end

function vec_elems2renderables(v::Union{Tuple,AbstractVector}, N, max_w)
shortsting(x) = x isa AbstractRenderable ? info(x) : truncate(string(x), max_w)
shortsting(x) = x isa AbstractRenderable ? info(x) : str_trunc(string(x), max_w)
out = highlight.(shortsting.(v[1:N]))

length(v) > N && push!(out, "⋮";)
Expand Down
4 changes: 2 additions & 2 deletions src/boxes.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Boxes

import Term: rint, chars, join_lines, loop_last, textlen, get_lr_widths, truncate
import Term: rint, chars, join_lines, loop_last, textlen, get_lr_widths, str_trunc

import ..Style: apply_style
import ..Segments: Segment
Expand Down Expand Up @@ -179,7 +179,7 @@ function get_title_row(
return Segment(get_row(box, width, row), style)
else
title = apply_style(title)
title = textlen(title) < width - 8 ? title : truncate(title, width - 8)
title = textlen(title) < width - 8 ? title : str_trunc(title, width - 8)
end

# compose title line
Expand Down
8 changes: 3 additions & 5 deletions src/colors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,9 @@ function get_color(string; bg = false)::AbstractColor

if is_named_color(string)
return if string ∈ COLORS_16b
idx = findfirst((c) -> c == string, COLORS_16b)[1]
BitColor(COLORS_16b[idx])
else
idx = findfirst((c) -> c == string, NAMED_COLORS)[1]
NamedColor(NAMED_COLORS[idx])
BitColor(COLORS_16b[findfirst(c -> c == string, COLORS_16b)])
elseif string ∈ NAMED_COLORS
NamedColor(NAMED_COLORS[findfirst(c -> c == string, NAMED_COLORS)])
end
elseif is_rgb_color(string)
return RGBColor(string)
Expand Down
8 changes: 4 additions & 4 deletions src/dendograms.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Dendograms

import Term: fint, rint, cint, truncate, loop_firstlast, highlight, textlen
import Term: fint, rint, cint, str_trunc, loop_firstlast, highlight, textlen

import ..Renderables: AbstractRenderable
import ..Boxes: get_rrow, get_lrow, get_row, SQUARE
Expand Down Expand Up @@ -44,7 +44,7 @@ function Leaf(leaf)
# get a string representation of the appropriate length
leaf = string(leaf)
leaf = if textlen(leaf) > CELLWIDTH
truncate(leaf, CELLWIDTH)
str_trunc(leaf, CELLWIDTH)
else
pad(leaf, CELLWIDTH + 1, :center)
end
Expand Down Expand Up @@ -125,7 +125,7 @@ function Dendogram(head, args::Vector; first_arg = nothing, pretitle = nothing)
segments,
[
Segment(
" " * pad(truncate(pretitle, CELLWIDTH), width - 1, :center),
" " * pad(str_trunc(pretitle, CELLWIDTH), width - 1, :center),
PRETITLE_STYLE,
),
Segment(" " * pad("⋀", width - 1, :center), "green bold"),
Expand Down Expand Up @@ -244,7 +244,7 @@ function link(dendos...; title = "", shifttitle = false, pretitle = nothing)::De

# add 'pretitle' lines (for expressions only)
if !isnothing(pretitle)
pretitle = truncate(pretitle, CELLWIDTH)
pretitle = str_trunc(pretitle, CELLWIDTH)
l(txt) = fint(midpoint - textwidth(txt) / 2) + length(space)
r(txt) = cint((width - midpoint - textwidth(txt) / 2))
prepend!(
Expand Down
6 changes: 3 additions & 3 deletions src/errors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Base: show_method_candidates, ExceptionStack, InterpreterIP

import Term:
highlight,
truncate,
str_trunc,
reshape_text,
load_code_and_highlight,
DEFAULT_WIDTH,
Expand Down Expand Up @@ -95,7 +95,7 @@ end
# ! KeyError
function error_message(er::KeyError)
# @info "err KeyError" er fieldnames(KeyError)
key = truncate(er.key, 40)
key = str_trunc(er.key, 40)
msg = "Key `$(key)` not found!"
return msg, ""
end
Expand Down Expand Up @@ -150,7 +150,7 @@ function error_message(er::MethodError; kwargs...)
_args = join(
map(
a ->
" {dim bold}($(a[1])){/dim bold} $(truncate(highlight("::"*string(typeof(a[2]))), 30))",
" {dim bold}($(a[1])){/dim bold} $(str_trunc(highlight("::"*string(typeof(a[2]))), 30))",
enumerate(er.args),
),
"\n",
Expand Down
92 changes: 53 additions & 39 deletions src/grid.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Author(s): T Bltg (github.com/t-bltg)
"""
module Grid

import ..Renderables: Renderable, AbstractRenderable
Expand All @@ -11,71 +14,82 @@ export grid

include("_compositor.jl")

# ---------------------------------------------------------------------------- #
# GRID #
# ---------------------------------------------------------------------------- #

"""
grid(
rens::Union{Nothing,AbstractVector{<:AbstractRenderable}} = nothing;
placeholder::Union{Nothing,AbstractRenderable} = nothing,
aspect::Union{Nothing,Number,NTuple} = nothing,
layout::Union{Nothing,Tuple} = nothing,
layout::Union{Nothing,Tuple,Expr} = nothing,
pad::Union{Tuple,Integer} = 0,
)

Construct a grid from a `AbstractVector` of `AbstractRenderable`s.

Lays out the renderables to createa a grid with the desired aspect ratio or
layout (number of rows, number of columns). If no renderables are passed it
creates placeholders.
Lays out the renderables to create a grid with the desired aspect ratio or
layout (number of rows, number of columns, or one left free with `nothing`).
Complex layout is supported using compositor expressions.
"""
function grid(
rens::Union{Nothing,AbstractVector{<:AbstractRenderable}} = nothing;
rens::Union{AbstractVector{<:AbstractRenderable},NamedTuple};
placeholder::Union{Nothing,AbstractRenderable} = nothing,
aspect::Union{Nothing,Number,NTuple} = nothing,
layout::Union{Nothing,Tuple,Expr} = nothing,
show_placeholder::Bool = false,
pad::Union{Tuple,Integer} = 0,
)
(isnothing(layout) && isnothing(rens)) && error("Grid: layout or aspect required")

style = show_placeholder ? "" : "hidden"

if !isnothing(rens) && layout isa Expr
n, kw = 0, Dict()
sizes = size.(rens)
sz = (minimum(first.(sizes)), minimum(last.(sizes)))
for (i, e) in enumerate(get_elements_and_sizes(layout; placeholder_size = sz))
nm = e.args[1]
kw[nm] = if nm === :_
compositor_placeholder(nm, sz..., style)
ph_style = show_placeholder ? "" : "hidden"

rens_seq = rens isa NamedTuple ? collect(values(rens)) : rens

if layout isa Expr
sizes = size.(rens_seq)
# arbitrary, taking the smallest `Renderable` size for placeholder
ph_size = (minimum(first.(sizes)), minimum(last.(sizes)))

kw = Dict{Symbol,Any}()
n = 0
for (i, e) in enumerate(get_elements_and_sizes(layout; placeholder_size = ph_size))
kw[nm] = if (nm = e.args[1]) === :_
compositor_placeholder(nm, ph_size..., ph_style)
elseif haskey(kw, nm)
kw[nm] # repeated element
elseif rens isa NamedTuple
rens[nm] # symbol mapping
else
haskey(kw, nm) ? kw[nm] : rens[n += 1]
rens[n += 1] # stream of `Renderable`s
end
end
compositor = Compositor(layout; placeholder_size = sz, check = false, pairs(kw)...)
compositor =
Compositor(layout; placeholder_size = ph_size, check = false, pairs(kw)...)
return Renderable(compositor)
end

nrows, ncols = isnothing(layout) ? calc_nrows_ncols(length(rens), aspect) : layout
if isnothing(rens)
isnothing(layout) &&
throw(ArgumentError("`layout` must be given as `Tuple` of `Integer`s"))
rens = fill(PlaceHolder(default_size()...), prod(layout))
else
if isnothing(nrows)
nrows, r = divrem(length(rens), ncols)
r == 0 || (nrows += 1)
elseif isnothing(ncols)
ncols, r = divrem(length(rens), nrows)
r == 0 || (ncols += 1)
end
fill_in =
(isnothing(placeholder) ? PlaceHolder(first(rens); style = style) : placeholder)
rens = vcat(rens, repeat([fill_in], nrows * ncols - length(rens)))
if isnothing(nrows)
nrows, r = divrem(length(rens), ncols)
r == 0 || (nrows += 1)
elseif isnothing(ncols)
ncols, r = divrem(length(rens), nrows)
r == 0 || (ncols += 1)
end
return grid(reshape(rens, nrows, ncols); pad = pad)
fill_in = something(placeholder, PlaceHolder(first(rens); style = ph_style))
rens_all = vcat(rens_seq, repeat([fill_in], nrows * ncols - length(rens)))
return grid(reshape(rens_all, nrows, ncols); pad = pad)
end

"""
grid(
rens::Nothing = nothing;
layout::Union{Nothing,Tuple,Expr} = nothing,
kw...
)

Construct a grid of `PlaceHolder`s, for a given layout.
"""
function grid(rens::Nothing = nothing; layout::Union{Nothing,Tuple,Expr} = nothing, kw...)
isnothing(layout) &&
throw(ArgumentError("`layout` must be given as `Tuple` of `Integer`s or `Expr`"))
return grid(fill(PlaceHolder(default_size()...), prod(layout)); kw...)
end

"""
Expand Down
6 changes: 3 additions & 3 deletions src/logs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Term:
rint,
highlight,
TERM_THEME,
truncate,
str_trunc,
ltrim_str

import ..Consoles: console_width, console_height, change_scroll_region, move_to_line
Expand Down Expand Up @@ -103,7 +103,7 @@ end
"""
handle_progress(logger::TermLogger, prog)

Handle progress information passed by `ProgressLogging`
Handle progress information passed by `ProgressLogging`.

It creates/adds/removes `ProgressJob`s to the logger's
`ProgressBar` to create progress visualizations.
Expand Down Expand Up @@ -227,7 +227,7 @@ function Logging.handle_message(
end

wpad = maximum(textlen.(_types)) + 2
ks = truncate.(string.(keys(kwargs)), 28)
ks = str_trunc.(string.(keys(kwargs)), 28)
namepad = maximum(textlen.(ks))

# print all kwargs
Expand Down
4 changes: 2 additions & 2 deletions src/panels.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Panels

import Term: reshape_text, join_lines, fillin, truncate, ltrim_str, DEFAULT_WIDTH
import Term: reshape_text, join_lines, fillin, str_trunc, ltrim_str, DEFAULT_WIDTH

import ..Renderables: AbstractRenderable, RenderablesUnion, Renderable, RenderableText
import ..Layout: pad, vstack, Padding, lvstack
Expand Down Expand Up @@ -421,7 +421,7 @@ function trim_renderable(ren::Union{AbstractString,AbstractRenderable}, width::I
else
texts = rstrip.(getfield.(ren.segments, :text))
segs = map(
s -> get_width(s) > width ? pad(truncate(s, width), width, :left) : s,
s -> get_width(s) > width ? pad(str_trunc(s, width), width, :left) : s,
texts,
)
lvstack(segs)
Expand Down
2 changes: 1 addition & 1 deletion src/progress.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ using Dates
import Parameters: @with_kw
import UUIDs: UUID

import Term: rint, textlen, truncate, loop_last, get_file_format, update!, DEFAULT_WIDTH
import Term: rint, textlen, loop_last, get_file_format, update!, str_trunc, DEFAULT_WIDTH
import ..Tprint: tprint, tprintln
import ..Style: apply_style
import ..Consoles:
Expand Down
4 changes: 2 additions & 2 deletions src/repr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Repr
using InteractiveUtils

import Term:
truncate,
str_trunc,
escape_brackets,
highlight,
do_by_line,
Expand Down Expand Up @@ -100,7 +100,7 @@ end
Show a dictionary's keys and values and their data types.
"""
function termshow(io::IO, obj::AbstractDict; kwargs...)
short_string(x) = truncate(string(x), 30)
short_string(x) = str_trunc(string(x), 30)
theme = TERM_THEME[]

# prepare text renderables
Expand Down
Loading