Skip to content
Open
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
4 changes: 3 additions & 1 deletion ext/LinearAlgebraExt.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module LinearAlgebraExt

import Accessors: set, @set
import Accessors: set, @set, _shortstring
using LinearAlgebra: norm, normalize, diag, diagind

set(arr, ::typeof(normalize), val) = norm(arr) * val
Expand All @@ -11,4 +11,6 @@ end

set(A, ::typeof(diag), val) = @set A[diagind(A)] = val

_shortstring(prev, o::typeof(norm); is_compact) = is_compact ? "‖$(prev)‖" : "$o($prev)"

end
4 changes: 3 additions & 1 deletion ext/UnitfulExt.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
module UnitfulExt

import Accessors: set
import Accessors: set, _shortstring
using Unitful

# ustrip(unit, _) works automatically because Unitful defines inverse() for it
# inverse(ustrip) is impossible, so special set() handling is required
set(obj, ::typeof(ustrip), val) = val * unit(obj)

_shortstring(prev, o::Base.Fix1{typeof(ustrip)}; is_compact) = is_compact ? "$prev [$(o.x)]" : @invoke _shortstring(prev, o::Base.Fix1; is_compact)

end
32 changes: 23 additions & 9 deletions src/sugar.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,13 +495,25 @@ IndexLens(::Tuple{Elements}) = Elements()
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::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[∗ₚ]"
_shortstring(prev, o::PropertyLens{field}; is_compact) where {field} =
is_compact && prev == "_" ? "$field" :
"$prev.$field"
_shortstring(prev, o::IndexLens; is_compact) = "$prev[$(join(repr.(o.indices), ", "))]"
_shortstring(prev, o::Union{Function,Type}; is_compact) =
_isoperator(o) ? "$(_fT_repr(o))$prev" :
is_compact && prev == "_" ? _fT_repr(o) : "$(_fT_repr(o))($prev)"
_shortstring(prev, o::Base.Fix1; is_compact) = _isoperator(o.f) ? "$(o.x) $(_fT_repr(o.f)) $prev" : "$(_fT_repr(o.f))($(o.x), $prev)"
_shortstring(prev, o::Base.Fix2; is_compact) = _isoperator(o.f) ? "$prev $(_fT_repr(o.f)) $(o.x)" : "$(_fT_repr(o.f))($prev, $(o.x))"
_shortstring(prev, o::Elements; is_compact) = "$prev[∗]"
_shortstring(prev, o::Properties; is_compact) = "$prev[∗ₚ]"

_shortstring(prev, o::typeof(real); is_compact) = is_compact ? "Re($prev)" : "$o($prev)"
_shortstring(prev, o::typeof(imag); is_compact) = is_compact ? "Im($prev)" : "$o($prev)"
_shortstring(prev, o::typeof(abs); is_compact) = is_compact ? "|$prev|" : "$o($prev)"
_shortstring(prev, o::typeof(sqrt); is_compact) = "√$prev"
_shortstring(prev, o::typeof(log10); is_compact) = is_compact ? "log₁₀($prev)" : "$o($prev)"
_shortstring(prev, o::typeof(log); is_compact) = is_compact ? "ln($prev)" : "$o($prev)"
_shortstring(prev, o::Base.Splat; is_compact) = is_compact ? "$(o.f)($prev...)" : "$o($prev)"

# compact representation of functions and types
# most notably, it deals with the module name in a consistent way: doesn't show it
Expand All @@ -511,6 +523,7 @@ _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))
_isoperator(::typeof(sqrt)) = true
_isoperator(f) = false

# does o need parens when nested in another such o?
Expand All @@ -530,14 +543,15 @@ function show_optic(io, optic)
print(io, " ∘ ")
end
if !isempty(inner)
is_compact = get(io, :compact, false)
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)
_shortstring(prev, o; is_compact), _need_parens(o)
end |> first
if get(io, :compact, false)
if is_compact
print(io, shortstr)
else
print(io, "(@o ", shortstr, ")")
Expand Down
23 changes: 20 additions & 3 deletions test/test_core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ using Accessors: test_getset_laws, test_modify_law
using Accessors: compose, get_update_op
using ConstructionBase: ConstructionBase
using StaticNumbers: StaticNumbers, static
using LinearAlgebra
using Unitful

struct T
a
Expand Down Expand Up @@ -461,14 +463,29 @@ end
@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
@test sprint(show, (@optic √log(_.a[2])); context=:compact => true) == "√ln(a[2])"
@test sprint(show, (@optic √(log(_.a[2]) + 1)); context=:compact => true) == "√(ln(a[2]) + 1)"
@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"

# compact handling of specific functions
@test sprint(show, (@o splat(max)(_.a))) == "(@o splat(max)(_.a))"
@test sprint(show, (@o splat(max)(_.a)); context=:compact => true) == "max(a...)"
@test sprint(show, (@o abs(_.a))) == "(@o abs(_.a))"
@test sprint(show, (@o abs(_.a)); context=:compact => true) == "|a|"
@test sprint(show, (@o real(_.a))) == "(@o real(_.a))"
@test sprint(show, (@o real(_.a)); context=:compact => true) == "Re(a)"
@test sprint(show, (@o imag(_.a))) == "(@o imag(_.a))"
@test sprint(show, (@o imag(_.a)); context=:compact => true) == "Im(a)"
@test sprint(show, (@o norm(_.a))) == "(@o norm(_.a))"
@test sprint(show, (@o norm(_.a)); context=:compact => true) == "‖a‖"
@test sprint(show, (@o log10(ustrip(u"km", _.a)))) == "(@o log10(ustrip(km, _.a)))"
@test sprint(show, (@o log10(ustrip(u"km", _.a))); context=:compact => true) == "log₁₀(a [km])"
end

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