Skip to content

Commit

Permalink
v07 init (#443)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlienart authored Apr 13, 2020
1 parent 3972bfb commit 5eaac6e
Show file tree
Hide file tree
Showing 35 changed files with 735 additions and 261 deletions.
2 changes: 0 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ language: julia
os:
- linux
julia:
- 1.1
- 1.2
- 1.3
- 1.4
- nightly
Expand Down
63 changes: 59 additions & 4 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,67 @@
# NEWS

This document keeps track of breaking changes and what you can do if you update and things don't work anymore.

Notes are in reverse chronological order.
This document keeps track of **key new features**, **breaking changes** and what you can do if you update and things don't work anymore.

You can also check out [this issue](https://github.com/tlienart/Franklin.jl/issues/323) with a more granular list of things that are being worked on / have been fixed / added.

### v0.6+ (new functionalities)
## v0.7

### Breaking changes

* indented code blocks are now opt-in, prefer fenced code blocks with backticks `` ` ``. This helps avoid ambiguities in parsing. If you do want indented code blocks on a page use `@def indented_code = true`, if you want them everywhere, put that definition in your `config.md`.
* markers for comments now **must** be separated with a character distinct from `-` so `<!--_` is ok, `<!---` is not, `~-->` is ok, `--->` is not. Rule of thumb: use a whitespace.

**Note**: supported Julia versions: 1.3, **1.4**, 1.5.

### New stuff

The main new stuff are:

* you can unpack in template for loops `{{for (x, y, z) in iterator}}`,
* you can use `{{var}}` as a short for `{{fill var}}`, you can use `{{...}}` blocks directly in markdown,
* variable definitions (`@def`) can now be multi-line, the secondary lines **must** be indented,
* you can access page variables from other pages using `{{fill var path}}` where `path` is the relative path to the other file so for instance `{{fill var index}}` or `{{fill var blog/page1}}`, this can be combined with a for loop for instance:

```
@def paths = ["index", "blog/page1"]
{{for p in paths}}
{{fill var p}}
{{end}}
```

And maybe most importantly, the addition of a `utils.jl` file to complement the `config.md`. In that file you can define variables and functions that can be used elsewhere on your site; they are evaluated in a `Utils` module which is imported in all evaluated code blocks.

* if you define a variable `var = 5`, it will be accessible everywhere, taking priority over any other page variable (including global), you can call `{{fill var}}` or use it in an evaluated code block with `Utils.var`.
* if you define a function `foo() = print("hello")`, you can use it in an evaluated code block with `Utils.foo()`
* if you define a function `hfun_foo() = return "blah"`, you can use it as a template function `{{foo}}`, they have access to page variable names so this would also be valid:

```julia
function hfun_bar(vname) # vname is a vector of string here
val = locvar(vname[1])
return round(sqrt(val), digits=2)
end
```

which you can call with `{{bar var}}`.

* if you define a function `lx_baz` you can use `\baz{...}` and have the function directly act on the input string, the syntax to use must conform to the following example:

```julia
function lx_baz(com, _)
# keep this first line
brace_content = Franklin.content(com.braces[1]) # input string
# Now do whatever you want with the content:
return uppercase(brace_content)
end
```

which you can call with `\baz{some string}`.



---

## v0.6+

* addition of an `ignore` global page variable to ignore files and directories, addition of a `div_content` page variable to change the name of the main container div.
* Multiline markdown definitions are now allowed, the lines **must** be indented with four spaces e.g. this is ok:
Expand Down
18 changes: 9 additions & 9 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Franklin"
uuid = "713c75ef-9fc9-4b05-94a9-213340da978e"
authors = ["Thibaut Lienart <[email protected]>"]
version = "0.6.17"
version = "0.7.0"

This comment has been minimized.

Copy link
@tlienart

tlienart Apr 13, 2020

Author Owner

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand All @@ -19,14 +19,14 @@ Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[compat]
DocStringExtensions = "^0.8"
FranklinTemplates = "^0.5, 0.6"
HTTP = "^0.8"
Literate = "^2.2"
LiveServer = "^0.3"
NodeJS = "^0.6, ^1"
OrderedCollections = "^1.1"
julia = "^1.1"
DocStringExtensions = "0.8"
FranklinTemplates = "0.6"
HTTP = "0.8"
Literate = "2.2"
LiveServer = "0.3"
NodeJS = "0.6,1"
OrderedCollections = "1.1"
julia = "1.1"

[extras]
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ See [the docs](https://franklinjl.org) for more information and examples.

## Getting started

With Julia ≥ 1.1:
With Julia ≥ 1.3:

```julia
pkg> add Franklin
Expand Down
9 changes: 6 additions & 3 deletions src/Franklin.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module Franklin

using FranklinTemplates
using FranklinTemplates: filecmp

using Markdown
using Markdown: htmlesc
Expand Down Expand Up @@ -36,9 +37,10 @@ export jd2html # = fd2html
# CONSTANTS
#

# Obtained via `dig www...`; may change over time; see check_ping
# we check in sequence, one should work... this may need to be updated
# over time.
# These are common IP addresses that we can quickly ping to see if the
# user seems online. This is used in `verify_links`. The IPs were
# obtained via `dig www...`; they may change over time; see `check_ping`
# we check in sequence, one should work if the user is online...
const IP_CHECK = (
"172.217.21.132" => "Google", # google
"140.82.118.4" => "GitHub", # github
Expand Down Expand Up @@ -139,6 +141,7 @@ include("eval/literate.jl")
# > markdown
include("converter/markdown/blocks.jl")
include("converter/markdown/utils.jl")
include("converter/markdown/mddefs.jl")
include("converter/markdown/md.jl")
# > latex
include("converter/latex/latex.jl")
Expand Down
98 changes: 57 additions & 41 deletions src/converter/html/blocks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,56 +157,37 @@ end
"""
$SIGNATURES
Process a for block.
Process a for block (for a variable iterate).
"""
function process_html_for(hs::AS, qblocks::Vector{AbstractBlock},
i::Int)::Tuple{String,Int,Int}
# check that the iterable is known
β_open = qblocks[i]
vname = β_open.vname
iname = β_open.iname
if !haskey(LOCAL_VARS, iname)
vname = β_open.vname # x or (x, v)
iname = β_open.iname # var

if iname UTILS_NAMES && !haskey(LOCAL_VARS, iname)
throw(HTMLBlockError("The iterable '$iname' is not recognised. " *
"Please make sure it's defined."))
end

# try to close the for loop
if i == length(qblocks)
throw(HTMLBlockError("Could not close the conditional block " *
"starting with '$(qblocks[i].ss)'."))
end

init_idx = i
content = ""

# inbalance keeps track of whether we've managed to find a
# matching {{end}}. It increases if it sees other opening {{if..}}
# and decreases if it sees a {{end}}
inbalance = 1
while i < length(qblocks) && inbalance > 0
i += 1
inbalance += hbalance(qblocks[i])
end
# we've exhausted the candidate qblocks and not found an appropriate {{end}}
if inbalance > 0
throw(HTMLBlockError("Could not close the conditional block " *
"starting with '$(qblocks[init_idx].ss)'."))
if iname UTILS_NAMES # can only happen if Utils is defined.
iter = getfield(Main.Utils, Symbol(iname))
else
iter = locvar(iname)
end
# we've found the closing {{end}} and index `i`
β_close = qblocks[i]
i_close = i

isempty(locvar(iname)) && @goto final_step
i_close, β_close = get_for_body(i, qblocks)
isempty(iter) && @goto final_step

# is vname a single variable or multiple variables?
# --> {{for v in iterate}}
# --> {{for (v1, v2) in iterate }}
# --> {{for (v1, v2) in iterate }} (unpacking)
vnames = [vname]
if startswith(vname, "(")
vnames = strip.(split(vname[2:end-1], ","))
end
# check that the first element of the iterate has the same length
el1 = first(locvar(iname))
el1 = first(iter)
length(vnames) in (1, length(el1)) ||
throw(HTMLBlockError("In a {{for ...}}, the first element of" *
"the iterate has length $(length(el1)) but tried to unpack" *
Expand All @@ -222,22 +203,57 @@ function process_html_for(hs::AS, qblocks::Vector{AbstractBlock},
isempty(strip(inner)) && @goto final_step
content = ""
if length(vnames) == 1
for value in locvar(iname)
rx1 = Regex("{{\\s*fill\\s+$vname\\s*}}") # {{ fill v}}
rx2 = Regex("{{\\s*fill\\s+(\\S+)\\s+$vname\\s*}}") # {{ fill x v}}
for v in iter
# at the moment we only consider {{fill ...}}
content *= replace(inner,
Regex("({{\\s*fill\\s+$vname\\s*}})") => "$value")
tmp = replace(inner, rx1 => "$v")
tmp = replace(tmp, rx2 => SubstitutionString("{{fill \\1 $v}}"))
content *= tmp
end
else
for value in locvar(iname)
temp = inner
for (vname, value) in zip(vnames, value)
temp = replace(temp,
Regex("({{\\s*fill\\s+$vname\\s*}})") => "$value")
for values in iter # each element of the iter can be unpacked
tmp = inner
for (vname, v) in zip(vnames, values)
rx1 = Regex("{{\\s*fill\\s+$vname\\s*}}")
rx2 = Regex("{{\\s*fill\\s+(\\S+)\\s+$vname\\s*}}")
tmp = replace(tmp, rx1 => "$v")
tmp = replace(tmp, rx2 => SubstitutionString("{{fill \\1 $v}}"))
end
content *= temp
content *= tmp
end
end
@label final_step
head = nextind(hs, to(β_close))
return convert_html(content), head, i_close
end

"""
$SIGNATURES
Extract the body of a for loop, keeping track of balancing.
"""
function get_for_body(i::Int, qblocks::Vector{AbstractBlock})
# try to close the for loop
if i == length(qblocks)
throw(HTMLBlockError("Could not close the block starting with" *
"'$(qblocks[i].ss)'."))
end
init_idx = i
content = ""
# inbalance keeps track of whether we've managed to find a
# matching {{end}}. It increases if it sees other opening {{if..}}
# and decreases if it sees a {{end}}
inb = 1
while i < length(qblocks) && inb > 0
i += 1
inb += hbalance(qblocks[i])
end
# we've exhausted the candidate qblocks and not found a matching {{end}}
if inb > 0
throw(HTMLBlockError("Could not close the block starting with" *
"'$(qblocks[init_idx].ss)'."))
end
# we've found the closing {{end}} and index `i`
return i, qblocks[i]
end
59 changes: 38 additions & 21 deletions src/converter/html/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ Helper function to process an individual block when it's a `HFun` such as
`{{ fill author }}`. See also [`convert_html`](@ref).
"""
function convert_html_fblock::HFun)::String
# try to find a function `hfun_...`
fun = Symbol("hfun_" * lowercase.fname))
isdefined(Franklin, fun) && return eval(:($fun($β.params)))

# if zero parameters, see if can fill
if isempty.params) && !isnothing(locvar.fname))
ex = isempty.params) ? :($fun()) : :($fun($β.params))
# see if a hfun was defined in utils
if isdefined(Main, :Utils) && isdefined(Main.Utils, fun)
res = Core.eval(Main.Utils, ex)
return string(res)
end
# see if a hfun was defined internally
isdefined(Franklin, fun) && return eval(ex)
# if zero parameters, see if can fill (case: {{vname}})
if isempty.params) &&
(!isnothing(locvar.fname)) || β.fname in UTILS_NAMES)
return hfun_fill([β.fname])
end

# XXX Future
# XXX see if there's an externally defined hfun
# XXX isdefined(Utils, fun) && Utils.eval(:($fun($β.params)))

# if we get here, then the function name is unknown, warn and ignore
@warn "I found a function block '{{$(β.fname) ...}}' but I don't " *
"recognise the function name. Ignoring."
Expand All @@ -29,24 +30,40 @@ end
"""
$(SIGNATURES)
H-Function of the form `{{ fill vname }}` to plug in the content of a
franklin-var `vname` (assuming it can be represented as a string).
H-Function of the form `{{ fill vname }}` or `{{ fill vname rpath}}` to plug in
the content of a franklin-var `vname` (assuming it can be represented as a
string).
"""
function hfun_fill(params::Vector{String})::String
# check params
if length(params) != 1
throw(HTMLFunctionError("I found a {{fill ...}} with more than one parameter. Verify."))
if length(params) > 2 || isempty(params)
throw(HTMLFunctionError("{{fill ...}} should have one or two " *
"($(length(params)) given). Verify."))
end
# form the fill
repl = ""
vname = params[1]
if haskey(LOCAL_VARS, vname)
# retrieve the value stored
tmp_repl = locvar(vname)
isnothing(tmp_repl) || (repl = string(tmp_repl))
else
@warn "I found a '{{fill $vname}}' but I do not know the " *
"variable '$vname'. Ignoring."
if length(params) == 1
if vname in UTILS_NAMES
repl = string(getfield(Main.Utils, Symbol(vname)))
else
tmp_repl = locvar(vname)
if isnothing(tmp_repl)
@warn "I found a '{{fill $vname}}' but I do not know the " *
"variable '$vname'. Ignoring."
else
repl = string(tmp_repl)
end
end
else # two parameters, look in a path
rpath = params[2]
tmp_repl = pagevar(rpath, vname)
if isnothing(tmp_repl)
@warn "I found a '{{fill $vname $rpath}}' but I do not know the " *
"variable '$vname' or the path '$rpath'. Ignoring."
else
repl = string(tmp_repl)
end
end
return repl
end
Expand Down
1 change: 1 addition & 0 deletions src/converter/html/html.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ function fd2html_v(st::AS; internal::Bool=false,
dir::String="")::Tuple{String,Dict}
isempty(st) && return st
if !internal
empty!(ALL_PAGE_VARS)
FOLDER_PATH[] = isempty(dir) ? mktempdir() : dir
set_paths!()
def_GLOBAL_LXDEFS!()
Expand Down
2 changes: 1 addition & 1 deletion src/converter/latex/hyperrefs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function lx_label(lxc::LxCom, _)
end

function lx_biblabel(lxc::LxCom, _)::String
name = refstring(strip(content(lxc.braces[1])))
name = refstring(stent(lxc.braces[1]))
PAGE_BIBREFS[name] = content(lxc.braces[2])
return "<a id=\"$name\"></a>"
end
Expand Down
Loading

1 comment on commit 5eaac6e

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/12852

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v0.7.0 -m "<description of version>" 5eaac6ecf99535f8423147c6b6c336605afec40d
git push origin v0.7.0

Please sign in to comment.