mirror of
https://git.sakamoto.pl/laudom/http.sh.git
synced 2025-08-04 12:53:32 +02:00
Compare commits
3 commits
93271da824
...
c6311cf4c1
Author | SHA1 | Date | |
---|---|---|---|
|
c6311cf4c1 | ||
|
e9018284f5 | ||
|
e809c0be6b |
5 changed files with 123 additions and 18 deletions
|
@ -10,7 +10,7 @@ declare -A str
|
||||||
str[title]="Hello, world!"
|
str[title]="Hello, world!"
|
||||||
str[test]="meow"
|
str[test]="meow"
|
||||||
|
|
||||||
render str "${cfg[namespace]}/templates/main.htm"
|
render str "templates/main.htm"
|
||||||
```
|
```
|
||||||
|
|
||||||
`render` is the core of the templating engine; it takes an assoc array, iterates over it, applies
|
`render` is the core of the templating engine; it takes an assoc array, iterates over it, applies
|
||||||
|
@ -18,7 +18,10 @@ additional magic and outputs the response directly to stdout. It is likely the f
|
||||||
to run in your script.
|
to run in your script.
|
||||||
|
|
||||||
The script above has referenced an HTML file; For this example, we put it under
|
The script above has referenced an HTML file; For this example, we put it under
|
||||||
`app/templates/main.htm`, but you're free to use any directory structure for this.
|
`app/templates/main.htm`, but you're free to use any directory structure for this. An observant
|
||||||
|
reader might have noticed the relative path; All paths are treated as relative to the namespace's
|
||||||
|
directory. This behavior can be modified by setting `template_relative_paths`, which is described
|
||||||
|
in greater detail by the [main template documentation](./template.md).
|
||||||
|
|
||||||
```
|
```
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
@ -100,7 +103,7 @@ done
|
||||||
# once we have a full list of elements, assign it to the array passed to render
|
# once we have a full list of elements, assign it to the array passed to render
|
||||||
str[_list]=list
|
str[_list]=list
|
||||||
|
|
||||||
render str "${cfg[namespace]}/templates/main.htm"
|
render str "templates/main.htm"
|
||||||
```
|
```
|
||||||
|
|
||||||
And the template...
|
And the template...
|
||||||
|
@ -182,7 +185,7 @@ declare -A str
|
||||||
str[title]="time pretty-print"
|
str[title]="time pretty-print"
|
||||||
str[+time]="$EPOCHSECONDS"
|
str[+time]="$EPOCHSECONDS"
|
||||||
|
|
||||||
render str "${cfg[namespace]}/templates/main.htm"
|
render str "templates/main.htm"
|
||||||
```
|
```
|
||||||
|
|
||||||

|

|
||||||
|
|
|
@ -23,8 +23,34 @@ For practical examples, see the [template examples](template-examples.md) page.
|
||||||
`render <assoc_array> <file> [recurse]`
|
`render <assoc_array> <file> [recurse]`
|
||||||
|
|
||||||
The first param points to an associative array containing the replacement data. Second one points
|
The first param points to an associative array containing the replacement data. Second one points
|
||||||
to a file containing the template itself. Third is optional, and controls whether `render` will
|
to a file containing the template itself (see section below for special usage). Third is optional,
|
||||||
recurse or not. This is mostly used internally, you likely won't ever need to set it.
|
and controls whether `render` will recurse or not (this is mostly used internally, you likely
|
||||||
|
won't ever need to set it).
|
||||||
|
|
||||||
|
### File paths
|
||||||
|
|
||||||
|
Starting with HTTP.sh 0.97.1 (2025-05-18), paths in calls to `render` and include tags are
|
||||||
|
relative to the namespace directory (usually `app/`). This behavior can be changed by defining
|
||||||
|
an array called `template_relative_paths`:
|
||||||
|
|
||||||
|
```
|
||||||
|
template_relative_paths=(
|
||||||
|
"${cfg[namespace]}/templates/neue_theme/"
|
||||||
|
"${cfg[namespace]}/templates/default/"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The templating engine will check all the files in order and pick the first one that exists. This
|
||||||
|
can be used to implement basic inheritance.
|
||||||
|
|
||||||
|
Before 0.97.1, paths were relative to the main HTTP.sh directory. Take care when upgrading, either
|
||||||
|
fix the paths, or set `template_relative_paths="./"` to emulate the previous behavior.
|
||||||
|
|
||||||
|
### Inline templates
|
||||||
|
|
||||||
|
For some purposes, it may be beneficial to store the template within the script file itself.
|
||||||
|
This can be done either through passing `/dev/stdin` as a file name, or through inlining
|
||||||
|
a file substitution, such as `<(echo ...)`.
|
||||||
|
|
||||||
## Simple replace
|
## Simple replace
|
||||||
|
|
||||||
|
@ -58,9 +84,8 @@ output (for filling out hidden form values, etc.)
|
||||||
Template includes are special, in that you don't have to define them in the array.
|
Template includes are special, in that you don't have to define them in the array.
|
||||||
They get processed first to "glue together" one singular template.
|
They get processed first to "glue together" one singular template.
|
||||||
|
|
||||||
Currently, the path starts at the root of HTTPsh's directory. We don't support expanding variables
|
The path starts at the root of your namespace (usually `app/`). This behavior can be changed,
|
||||||
inside the include tag, so for now you'll need to hardcode `{{#app/templates/...}}`. This will
|
see section "File paths" above.
|
||||||
likely get changed in a future release, starting the path in your namespace.
|
|
||||||
|
|
||||||
**Warning**: No recursion is supported within included templates; This means that you can't have
|
**Warning**: No recursion is supported within included templates; This means that you can't have
|
||||||
an "include chain". Furthermore, some interactions between included templates and loops/ifs are
|
an "include chain". Furthermore, some interactions between included templates and loops/ifs are
|
||||||
|
|
|
@ -6,11 +6,18 @@
|
||||||
function render() {
|
function render() {
|
||||||
local _tpl_newline=$'\01'
|
local _tpl_newline=$'\01'
|
||||||
local _tpl_ctrl=$'\02'
|
local _tpl_ctrl=$'\02'
|
||||||
|
local tplfile
|
||||||
|
|
||||||
|
_template_find_absolute_path "$2"
|
||||||
|
|
||||||
|
if [[ ! "$tplfile" ]]; then
|
||||||
|
exit 1 # fail hard
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ "$3" != true ]]; then
|
if [[ "$3" != true ]]; then
|
||||||
local template="$(tr -d "${_tpl_newline}${_tpl_ctrl}" < "$2" | sed 's/\&/<2F>UwU<77>/g')"
|
local template="$(tr -d "${_tpl_newline}${_tpl_ctrl}" < "$tplfile" | sed 's/\&/<2F>UwU<77>/g')"
|
||||||
else
|
else
|
||||||
local template="$(tr -d "${_tpl_ctrl}" < "$2" | sed -E 's/\\/\\\\/g')"
|
local template="$(tr -d "${_tpl_ctrl}" < "$tplfile" | sed -E 's/\\/\\\\/g')"
|
||||||
fi
|
fi
|
||||||
local buf=
|
local buf=
|
||||||
local garbage="$template"$'\n'
|
local garbage="$template"$'\n'
|
||||||
|
@ -24,14 +31,19 @@ function render() {
|
||||||
# below check prevents the loop loading itself as a template.
|
# below check prevents the loop loading itself as a template.
|
||||||
# this is possibly not enough to prevent all recursions, but
|
# this is possibly not enough to prevent all recursions, but
|
||||||
# i see it as a last-ditch measure. so it'll do here.
|
# i see it as a last-ditch measure. so it'll do here.
|
||||||
if [[ "$file" == "$2" ]]; then
|
if [[ "$file" == "$tplfile" ]]; then
|
||||||
subtemplate+="s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}I cowardly refuse to endlessly recurse\!${_tpl_ctrl}g;"
|
subtemplate+="s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}I cowardly refuse to endlessly recurse\!${_tpl_ctrl}g;"
|
||||||
elif [[ -f "$key" ]]; then
|
# elif [[ -f "$key" ]]; then
|
||||||
local input="$(tr -d "${_tpl_ctrl}${_tpl_newline}" < "$key" | sed 's/\&/<2F>UwU<77>/g')"
|
else
|
||||||
|
local i
|
||||||
|
local IFS=''
|
||||||
|
|
||||||
|
_template_find_absolute_path "$key"
|
||||||
|
local input="$(tr -d "${_tpl_ctrl}${_tpl_newline}" < "$tplfile" | sed 's/\&/<2F>UwU<77>/g')"
|
||||||
garbage+="$input"$'\n'
|
garbage+="$input"$'\n'
|
||||||
input="$(tr $'\n' "${_tpl_newline}" <<< "$input")" # for another hack
|
input="$(tr $'\n' "${_tpl_newline}" <<< "$input")" # for another hack
|
||||||
subtemplate+="s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}${input}${_tpl_ctrl};"
|
subtemplate+="s${_tpl_ctrl}\{\{\#$key\}\}${_tpl_ctrl}${input}${_tpl_ctrl};"
|
||||||
_template_find_special_uri "$(cat "$key")"
|
_template_find_special_uri "$(cat "$tplfile")"
|
||||||
fi
|
fi
|
||||||
done <<< "$(grep -Poh '{{#\K(.*?)(?=}})' <<< "$template")"
|
done <<< "$(grep -Poh '{{#\K(.*?)(?=}})' <<< "$template")"
|
||||||
|
|
||||||
|
@ -118,6 +130,27 @@ function render() {
|
||||||
[[ "$3" != true ]] && _template_uri_list=()
|
[[ "$3" != true ]] && _template_uri_list=()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# internal function that looks for the current template. uses path relative to
|
||||||
|
# the namespace, unless overriden with ${template_relative_paths[@]}
|
||||||
|
#
|
||||||
|
# - /dev/stdin is a special value, which gets passed literally.
|
||||||
|
# - /dev/fd/* allows file substitutions `<(echo ...)` to be used.
|
||||||
|
#
|
||||||
|
# _template_find_absolute_path(name) -> $tplfile
|
||||||
|
_template_find_absolute_path() {
|
||||||
|
if [[ ! "${template_relative_paths}" || "$1" == /dev/stdin || "$1" == "/dev/fd/"* ]]; then
|
||||||
|
tplfile="$1"
|
||||||
|
else
|
||||||
|
for (( i=0; i<${#template_relative_paths[@]}; i++ )); do
|
||||||
|
if [[ -f "${template_relative_paths[i]}/$1" ]]; then
|
||||||
|
tplfile="${template_relative_paths[i]}/$1"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
_template_uri_list=()
|
_template_uri_list=()
|
||||||
# internal function that finds all occurences of the special `{{-uri-N}}` tag.
|
# internal function that finds all occurences of the special `{{-uri-N}}` tag.
|
||||||
# here to also make it run on subtemplates
|
# here to also make it run on subtemplates
|
||||||
|
@ -168,8 +201,9 @@ function nested_add() {
|
||||||
ref+=("$nested_id")
|
ref+=("$nested_id")
|
||||||
}
|
}
|
||||||
|
|
||||||
# nested_get(ref, i)
|
# nested_get(ref, i, [res])
|
||||||
function nested_get() {
|
function nested_get() {
|
||||||
local -n ref=$1
|
local -n ref=$1
|
||||||
declare -g -n res=_${ref["$2"]}
|
local name=${3:-res}
|
||||||
|
declare -g -n $name=_${ref["$2"]}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
HTTPSH_VERSION=0.97
|
HTTPSH_VERSION=0.97.1
|
||||||
|
|
|
@ -51,6 +51,45 @@ tpl_date_invalid() {
|
||||||
match="value: 1970-01-01 01:00:00"
|
match="value: 1970-01-01 01:00:00"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tpl_path_custom() {
|
||||||
|
prepare() {
|
||||||
|
declare -ga template_relative_paths=("/tmp/")
|
||||||
|
|
||||||
|
tempfile="$(mktemp)" || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
tst() {
|
||||||
|
declare -A meow
|
||||||
|
render meow "$(basename "$tempfile")"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl_path_inheritance() {
|
||||||
|
prepare() {
|
||||||
|
tempdir="$(mktemp -d)" || return 1
|
||||||
|
declare -ga template_relative_paths=(
|
||||||
|
"$tempdir"
|
||||||
|
"/tmp/"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl_path_include() {
|
||||||
|
prepare() {
|
||||||
|
another_tempfile="$(mktemp)"
|
||||||
|
echo "meow?" > "$another_tempfile"
|
||||||
|
echo "{{#$(basename "$another_tempfile")}}" > "$tempfile"
|
||||||
|
}
|
||||||
|
|
||||||
|
match="meow?"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -R "$tempdir"
|
||||||
|
rm "$tempfile" "$another_tempfile"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
subtest_list=(
|
subtest_list=(
|
||||||
tpl_basic
|
tpl_basic
|
||||||
tpl_basic_specialchars
|
tpl_basic_specialchars
|
||||||
|
@ -59,4 +98,8 @@ subtest_list=(
|
||||||
tpl_date
|
tpl_date
|
||||||
tpl_date_empty
|
tpl_date_empty
|
||||||
tpl_date_invalid
|
tpl_date_invalid
|
||||||
|
|
||||||
|
tpl_path_custom
|
||||||
|
tpl_path_inheritance
|
||||||
|
tpl_path_include
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue