# Escaping Primitives
This is a regression test for components upon which HTL is constructed,
the design centers around `EscapeProxy` which escapes content printed to
it. There are several wrappers which drive special proxy handling.
using HypertextLiteral: EscapeProxy, Bypass, Reprint, Render
## EscapeProxy
This utility class acts wraps an `IO` stream to provide HTML escaping.
io_buffer = IOBuffer()
io = IOContext(io_buffer, :hello => "world")
ep = EscapeProxy(io)
macro echo(expr)
:($expr; print(String(take!(io_buffer))))
end
The result of this proxy is that regular content printed to it is passed
along to the wrapped `IO`, after escaping the ampersand (`&`), less-than
(`<`), single-quote (`'`), and double-quote (`"`).
@echo print(ep, "(&'<\")")
#-> (&'<")
Any [IO context properties](https://docs.julialang.org/en/v1/base/io-network/#Base.IOContext-Tuple{IO,%20Pair}) will be reflected by the `EscapeProxy`:
@echo print(ep, get(ep, :hello, "oops"))
#-> world
## Bypass
This wrapper simply prints its content.
print(Bypass(""))
#->
Printed content wrapped with `Bypass` is not subject to escaping.
@echo print(ep, Bypass(""), "", Bypass(""))
#-> <A&B>
## Reprint
This wrapper holds a closure that prints to an `io`.
print(Reprint(io::IO -> print(io, "Hello World")))
#-> Hello World
Reprinted content is still subject to escaping.
@echo print(ep, Reprint(io -> print(io, "(&'<\")")))
#-> (&'<")
## Render
This wrapper prints text/html display of an object.
struct Custom
content
end
Base.show(io::IO, m::MIME"text/html", c::Custom) =
print(io, c.content)
print(Render(Custom("")))
#->
The printed content is not subject to escaping.
@echo print(ep, Render(Custom("")))
#->
It's an error if the wrapped object isn't showable to `"text/html"`.
print(Render("This is an error!"))
#-> ERROR: MethodError: … show(… ::MIME{Symbol("text/html")}⋮