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

Optics show improvements #186

Merged
merged 3 commits into from
Dec 24, 2024
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
35 changes: 22 additions & 13 deletions src/sugar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -493,12 +493,17 @@ IndexLens(::Tuple{Properties}) = Properties()
### nice show() for optics
_shortstring(prev, o::PropertyLens{field}) where {field} = "$prev.$field"
_shortstring(prev, o::IndexLens) ="$prev[$(join(repr.(o.indices), ", "))]"
_shortstring(prev, o::Function) = _isoperator(o) ? "$o$prev" : "$o($prev)"
_shortstring(prev, o::Base.Fix1) = _isoperator(o.f) ? "$(o.x) $(o.f) $prev" : "$(o.f)($(o.x), $prev)"
_shortstring(prev, o::Base.Fix2) = _isoperator(o.f) ? "$prev $(o.f) $(o.x)" : "$(o.f)($prev, $(o.x))"
_shortstring(prev, o::Union{Function,Type}) = _isoperator(o) ? "$(_fT_repr(o))$prev" : "$(_fT_repr(o))($prev)"
_shortstring(prev, o::Base.Fix1) = _isoperator(o.f) ? "$(o.x) $(_fT_repr(o.f)) $prev" : "$(_fT_repr(o.f))($(o.x), $prev)"
_shortstring(prev, o::Base.Fix2) = _isoperator(o.f) ? "$prev $(_fT_repr(o.f)) $(o.x)" : "$(_fT_repr(o.f))($prev, $(o.x))"
_shortstring(prev, o::Elements) = "$prev[∗]"
_shortstring(prev, o::Properties) = "$prev[∗ₚ]"

# compact representation of functions and types
# most notably, it deals with the module name in a consistent way: doesn't show it
# by default, it's not shown for functions but shown for types, see https://github.com/JuliaLang/julia/issues/56790
_fT_repr(o) = repr(o; context=:compact => true)

# can f be stringfied using the operator (infix) syntax?
# otherwise uses regular function call syntax
_isoperator(f::Function) = Base.isoperator(nameof(f))
Expand All @@ -516,19 +521,23 @@ function show_optic(io, optic)
outer = Iterators.dropwhile(x -> applicable(_shortstring, "", x), opts)
if !isempty(outer)
show(io, opcompose(outer...))
end
if !isempty(inner) && !isempty(outer)
print(io, " ∘ ")
end
shortstr = reduce(inner; init=("_", false)) do (prev, need_parens_prev), o
# if _need_parens is true for this o and the one before, wrap the previous one in parentheses
if need_parens_prev && _need_parens(o)
prev = "($prev)"
if !isempty(inner)
shortstr = reduce(inner; init=("_", false)) do (prev, need_parens_prev), o
# if _need_parens is true for this o and the one before, wrap the previous one in parentheses
if need_parens_prev && _need_parens(o)
prev = "($prev)"
end
_shortstring(prev, o), _need_parens(o)
end |> first
if get(io, :compact, false)
print(io, shortstr)
else
print(io, "(@o ", shortstr, ")")
end
_shortstring(prev, o), _need_parens(o)
end |> first
if get(io, :compact, false)
print(io, shortstr)
else
print(io, "(@o ", shortstr, ")")
end
end

Expand Down
8 changes: 8 additions & 0 deletions test/test_core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,16 @@ end
@test sprint(show, (@optic (_.a + 1) * 2)) == "(@o (_.a + 1) * 2)"
@test sprint(show, (@optic (_.a * 2) + 1)) == "(@o (_.a * 2) + 1)"
@test sprint(show, (@optic log(_.a[2]))) == "(@o log(_.a[2]))"
@test sprint(show, (@optic Tuple(_.a[2]))) == "(@o Tuple(_.a[2]))"
@test sprint(show, (@optic log(_).a[2])) == "(@o _.a[2]) ∘ log" # could be shorter, but difficult to dispatch correctly without piracy
@test sprint(show, (@optic log(_.a[2])); context=:compact => true) == "log(_.a[2])"
@test sprint(show, (@optic Base.tail(_.a[2])); context=:compact => true) == "tail(_.a[2])" # non-exported function
@test sprint(show, (@optic Base.Fix2(_.a[2])); context=:compact => true) == "Fix2(_.a[2])" # non-exported type

# show_optic is reasonable even for types without special show_optic handling:
o = Recursive(x->true, Properties())
@test sprint(Accessors.show_optic, o) == "$o"
@test sprint(Accessors.show_optic, (@o _.a) ∘ o) == "(@o _.a) ∘ $o"
end

@testset "text/plain show" begin
Expand Down
Loading