Defining HTML functions and LaTeX commands with code
Overview
Along with the config.md
file, the utils.jl
file allows you to define functions and objects that may be useful throughout your website and, also, to define special functions that you can call on pages.
In utils.jl
you can:
- define objects and functions that can be accessed from any code cell via the
Utils
module, - define your own
html_show(obj::SomeType)
for objects ofSomeType
which should be shown in a specific way when returned by executed cells, - define functions with specific signatures to power custom commands, environments or html functions.
The first two are pretty simple and explained in the two short subpoints below. The last point is a bit more involved and is discussed with examples in the custom functions section below.
Definining objects and functions in the Utils
module
The code in utils.jl
is made available via a Utils
module that can be accessed from any code cell.
For instance, in the utils.jl
of the present website, we have the code
struct Baz
z::Int
end
newbaz(z) = Baz(z)
This can be accessed on the current page (or any other page) via the Utils
module:
b = Utils.Baz(1)
@show b.z
b2 = Utils.newbaz(3)
@show b2.z
b.z = 1
b2.z = 3
Custom show method
When showing the output of a code cell, a custom show method can be defined in Utils
to be called for specific objects.
The signature of that method must be html_show(obj::SomeType)
.
For instance, in the utils.jl
we have:
struct Foo
x::Int
end
html_show(f::Foo) = "<strong>Foo: $(f.x)</strong>"
the custom show gets called when the resulting object of an executed code block
is of the type (here Foo
):
Utils.Foo(1)
see also this point for more information on custom show methods.
Custom functions
Functions defined in utils with a name that start with lx_fname
, env_fname
or hfun_fname
can be called on pages respectively with \fname{...}
, \begin{fname}...\end{fname}
and {{fname ...}}
.
This allows you to essentially have arbitrary logic executed at page-build time.
Before clarifying how these functions should be defined and called, it is useful to remember the order in which such commands will be resolved:
lx*
andenv*
functions will be resolved on first pass, as soon as they're seen by Franklin. The context that is available to these functions, correspondingly, is whatever was processed before them. These functions are expected to return "intermediate" HTML (i.e. possibly containing{{...}}
) and will be further processed in a second pass.hfun*
functions will be resolved on second pass, as such they have access to the full page context, and are expected to produce "final" HTML.
In many cases, the differences are irrelevant, and users can use whichever they prefer.
Custom hfuns
The signature of a valid "hfun" is:
function hfun_fname(p::Vector{String})::String
# logic
return "..."
end
Of course you don't have to add the explicit typing, but we added it here to indicate that these functions map a vector of strings (arguments) to a string output to be inserted.
Once such a function is defined, it can be called on any page (including layout
pages) with {{fname ...}}
.
Here are three simple examples:
function hfun_ex_hfun_1()
return "<span style=\"color:red; font-weight: 500;\">Hello!</span>"
end
function hfun_ex_hfun_2(p)
return "<span style=\"color:red; font-weight: 500;\">$(strip(p[1], '\"'))</span>"
end
function hfun_ex_hfun_args(p)
io = IOBuffer()
for (i, p_i) in p
println(io, "* argument $i: \"$(p_i)\"")
end
return html(String(take!(io)))
end
The first one (hfun_ex_hfun_1
) doesn't have arguments and just prints a coloured span:
The second one (hfun_ex_hfun_2
) assumes there's one argument and prints it:
The last one (hfun_ex_hfun_args
) is meant to illustrate how the argument splitting works:
At this point you probably already have the intution for the argument splitting: the arguments
are assumed to be separated by one or more spaces unless they are grouped with quotes.
Any quotes are passed to the function and, depending on your use case, you may want to strip them
with strip(p[k], '\"')
as we did in hfun_ex_hfun_2
.
When defining a "hfun", you can interact with the state of the website through a few functions that are available in the Utils module, see Utils tools.
Custom lxfuns
The signature of a valid "lxfun" is
function lx_fname(p::Vector{String})::String
# logic
return "..."
end
where fname
can be switched for anything command name you want and where the
argument (p
here) is a list of strings corresponding to each of the brace that will
be given to the command.
It can be left empty in the definition if the user desires to have an argument-less command.
Here's an example:
function lx_exlx(p::Vector{String})
return "<i>$(uppercase(p[1]))</i> <b>$(uppercasefirst(p[2]))</b>"
end
and if we call \exlx{hello}{reader}
, we get: HELLO Reader.
Here's another example without arguments:
function lx_exlx2()
return "<s>hello</s>"
end
and if we call \exlx2
we get: hello.
As indicated earlier, the output of an lxfun gets process_file_from_triggered
at the second pass, so
for instance:
function lx_exlx3()
# fill the local variable header
return "<span style='color:blue'>{{header}}</span>"
end
and if we call \exlx3
we get: hello from a global variable!.
Custom envfuns
Utils tools
When defining any function in utils, you can make use of a set of useful functions available by default, and which allow you to interact with the state of the website generation process.
function | description |
---|---|
html(s) ,
html(s, lc) |
convert a markdown string s (optionally specifying the LocalContext object in which this should happen) |
html2(s) ,
html2(s, lc) |
convert an intermediate HTML string (essentially: finds and processes {{...}} ) |
cur_gc() |
return the current GlobalContext object |
cur_lc() |
return the current LocalContext object |
path(s) |
return the absolute path associated with symbol s for instance path(:folder) will return the path to the website folder, path(:site) the path to the output folder. |
getlvar(s) |
value of the local var with symbol s |
getgvar(s) |
value of the global var with symbol s |
getvarfrom(s, rp) |
value of the local var with symbol s expected to be defined on page with relative path rp |
setlvar!(s, v) |
set the value of a local var with symbol s to v |
setgvar!(s, v) |
set the value of a global var with symbol s to v |
get_page_tags(rp) |
get all the tags defined on the current page or, if rp is specified, on the page corresponding to rp |
get_all_tags() |
get the dictionary of all tags on all pages |
get_rpath() |
get the relative path to the current page |
attach(rp) |
attach a file at rp to the current page (see below) |
Attaching a file
The attach
tool is necessary to indicate that a page depends on another file (e.g. a script, data, ...) which, if changed, should trigger a re-build of the page.
To give a concrete example: this is used for the built-in handling of Literate files. If a page depends on a Literate file, then any change on that Literate file should trigger a re-build of that page.