Add tests and refactor config
This commit is contained in:
1
.shellcheckrc
Normal file
1
.shellcheckrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
disable=SC2034,SC2154
|
||||||
8
Makefile
8
Makefile
@@ -20,4 +20,10 @@ uninstall:
|
|||||||
clean:
|
clean:
|
||||||
rm -f kewt
|
rm -f kewt
|
||||||
|
|
||||||
.PHONY: all install uninstall clean
|
test:
|
||||||
|
sh tests/test_runner.sh
|
||||||
|
|
||||||
|
shellcheck:
|
||||||
|
shellcheck kewt.sh markdown.sh lib/*.sh
|
||||||
|
|
||||||
|
.PHONY: all install uninstall clean test shellcheck
|
||||||
|
|||||||
119
awk/reference_links.awk
Normal file
119
awk/reference_links.awk
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
{
|
||||||
|
lines[NR] = $0
|
||||||
|
total = NR
|
||||||
|
|
||||||
|
if (/^\[[^\]]+\]: */) {
|
||||||
|
line = $0
|
||||||
|
sub(/^\[/, "", line)
|
||||||
|
ref_id = line
|
||||||
|
sub(/\].*/, "", ref_id)
|
||||||
|
|
||||||
|
line = $0
|
||||||
|
sub(/^\[[^\]]+\]: */, "", line)
|
||||||
|
ref_url = line
|
||||||
|
sub(/[ \t].*/, "", ref_url)
|
||||||
|
|
||||||
|
ref_title = $0
|
||||||
|
sub(/^\[[^\]]+\]: *[^\t ]*[ \t]*/, "", ref_title)
|
||||||
|
sub(/^"/, "", ref_title)
|
||||||
|
sub(/"$/, "", ref_title)
|
||||||
|
gsub(/\|/, "!", ref_title)
|
||||||
|
|
||||||
|
refs[ref_id] = ref_url
|
||||||
|
if (ref_title != "") titles[ref_id] = ref_title
|
||||||
|
is_ref[NR] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve_image_ref(alt, id, url, title) {
|
||||||
|
url = refs[id]
|
||||||
|
title = (id in titles) ? titles[id] : ""
|
||||||
|
if (url == "") return "![" alt "][" id "]"
|
||||||
|
return "<img src=\"" url "\" title=\"" title "\" alt=\"" alt "\" />"
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolve_link_ref(text, id, url, title) {
|
||||||
|
url = refs[id]
|
||||||
|
title = (id in titles) ? titles[id] : ""
|
||||||
|
if (url == "") return "[" text "][" id "]"
|
||||||
|
return "<a href=\"" url "\" title=\"" title "\">" text "</a>"
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_refs(line, result, i, len, ch, j, k, depth, bracket_content, ref_id) {
|
||||||
|
result = ""
|
||||||
|
len = length(line)
|
||||||
|
i = 1
|
||||||
|
|
||||||
|
while (i <= len) {
|
||||||
|
ch = substr(line, i, 1)
|
||||||
|
|
||||||
|
if (ch == "!" && i < len && substr(line, i + 1, 1) == "[") {
|
||||||
|
bracket_content = ""
|
||||||
|
j = i + 2
|
||||||
|
while (j <= len && substr(line, j, 1) != "]") {
|
||||||
|
bracket_content = bracket_content substr(line, j, 1)
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if (j <= len && j < len && substr(line, j + 1, 1) == "[") {
|
||||||
|
k = j + 2
|
||||||
|
ref_id = ""
|
||||||
|
while (k <= len && substr(line, k, 1) != "]") {
|
||||||
|
ref_id = ref_id substr(line, k, 1)
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
if (k <= len) {
|
||||||
|
if (ref_id == "") ref_id = bracket_content
|
||||||
|
if (ref_id in refs) {
|
||||||
|
result = result resolve_image_ref(bracket_content, ref_id)
|
||||||
|
i = k + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = result substr(line, i, 1)
|
||||||
|
i++
|
||||||
|
} else if (ch == "[") {
|
||||||
|
bracket_content = ""
|
||||||
|
j = i + 1
|
||||||
|
depth = 1
|
||||||
|
while (j <= len && depth > 0) {
|
||||||
|
if (substr(line, j, 1) == "[") depth++
|
||||||
|
if (substr(line, j, 1) == "]") {
|
||||||
|
depth--
|
||||||
|
if (depth == 0) break
|
||||||
|
}
|
||||||
|
if (depth > 0) bracket_content = bracket_content substr(line, j, 1)
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if (j <= len && j < len && substr(line, j + 1, 1) == "[") {
|
||||||
|
k = j + 2
|
||||||
|
ref_id = ""
|
||||||
|
while (k <= len && substr(line, k, 1) != "]") {
|
||||||
|
ref_id = ref_id substr(line, k, 1)
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
if (k <= len) {
|
||||||
|
if (ref_id == "") ref_id = bracket_content
|
||||||
|
if (ref_id in refs) {
|
||||||
|
result = result resolve_link_ref(bracket_content, ref_id)
|
||||||
|
i = k + 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = result substr(line, i, 1)
|
||||||
|
i++
|
||||||
|
} else {
|
||||||
|
result = result ch
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
END {
|
||||||
|
for (n = 1; n <= total; n++) {
|
||||||
|
if (is_ref[n]) continue
|
||||||
|
print process_refs(lines[n])
|
||||||
|
}
|
||||||
|
}
|
||||||
449
lib/builder.sh
449
lib/builder.sh
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
# shellcheck disable=SC2129
|
||||||
|
|
||||||
needs_rebuild() {
|
needs_rebuild() {
|
||||||
src_file="$1"
|
src_file="$1"
|
||||||
@@ -29,90 +30,12 @@ write_content_warning_outputs() {
|
|||||||
generate_content_warning_page "$fm_title" "$fm_content_warning" "$_content_rel_url" "$_target_url" "$_landing_out_file" "false"
|
generate_content_warning_page "$fm_title" "$fm_content_warning" "$_content_rel_url" "$_target_url" "$_landing_out_file" "false"
|
||||||
}
|
}
|
||||||
|
|
||||||
build_site() {
|
build_dir_entries_list() {
|
||||||
echo "Building site from '$src' to '$out'..."
|
_bde_dir="$1"
|
||||||
|
_bde_rel_dir="$2"
|
||||||
|
_bde_entries_file="$3"
|
||||||
|
|
||||||
build_markdown_manifest
|
find "$_bde_dir" ! -name "$(basename "$_bde_dir")" -prune ! -name ".*" -print | while read -r entry; do
|
||||||
build_full_nav
|
|
||||||
|
|
||||||
eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while read -r dir; do
|
|
||||||
rel_dir="${dir#"$src"}"
|
|
||||||
rel_dir="${rel_dir#/}"
|
|
||||||
[ -z "$rel_dir" ] && rel_dir="."
|
|
||||||
out_dir="$out/$rel_dir"
|
|
||||||
mkdir -p "$out_dir"
|
|
||||||
|
|
||||||
if [ -f "$dir/styles.css" ]; then
|
|
||||||
if needs_rebuild "$dir/styles.css" "$out_dir/styles.css"; then
|
|
||||||
copy_style_with_resolved_vars "$dir/styles.css" "$out_dir/styles.css"
|
|
||||||
fi
|
|
||||||
elif [ -f "$dir/style.css" ]; then
|
|
||||||
if needs_rebuild "$dir/style.css" "$out_dir/styles.css"; then
|
|
||||||
copy_style_with_resolved_vars "$dir/style.css" "$out_dir/styles.css"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ "$dir_indexes" != "true" ] && continue
|
|
||||||
|
|
||||||
has_custom_index="false"
|
|
||||||
has_list="false"
|
|
||||||
if [ -f "$dir/index.md" ]; then
|
|
||||||
has_custom_index="true"
|
|
||||||
if grep -q '^[[:space:]]*{{LIST}}[[:space:]]*$' "$dir/index.md" 2>/dev/null; then
|
|
||||||
has_list="true"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$has_custom_index" = "false" ] || [ "$has_list" = "true" ]; then
|
|
||||||
is_posts_dir="false"
|
|
||||||
if is_posts_directory_rel "$rel_dir"; then
|
|
||||||
is_posts_dir="true"
|
|
||||||
fi
|
|
||||||
if [ "$single_file_index" = "true" ] && [ "$is_posts_dir" = "false" ] && [ "$has_list" = "false" ]; then
|
|
||||||
if load_manifest_dir_entry "$rel_dir" && [ "$dir_md_count" -eq 1 ]; then
|
|
||||||
md_file="$src/$dir_first_md"
|
|
||||||
is_home="false"; [ "$dir" = "$src" ] && is_home="true"
|
|
||||||
target_url=$(directory_index_url "$rel_dir")
|
|
||||||
if needs_rebuild "$md_file" "$out_dir/index.html"; then
|
|
||||||
parse_frontmatter "$md_file"
|
|
||||||
if [ -n "$fm_content_warning" ]; then
|
|
||||||
content_out_file="$out_dir/content.html"
|
|
||||||
if [ "$rel_dir" = "." ]; then
|
|
||||||
content_rel_url="/content.html"
|
|
||||||
else
|
|
||||||
content_rel_url="/$(encode_url_path "$rel_dir")/content.html"
|
|
||||||
fi
|
|
||||||
write_content_warning_outputs "$md_file" "$content_out_file" "$content_rel_url" "$target_url" "$out_dir/index.html" "$is_home"
|
|
||||||
else
|
|
||||||
render_markdown "$md_file" "$is_home" "$target_url" > "$out_dir/index.html"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
temp_index="$KEWT_TMPDIR/index.md"
|
|
||||||
temp_list="$KEWT_TMPDIR/list.md"
|
|
||||||
: > "$temp_list"
|
|
||||||
|
|
||||||
if [ "$has_custom_index" = "false" ]; then
|
|
||||||
display_dir="${rel_dir#.}"
|
|
||||||
[ -z "$display_dir" ] && display_dir="/"
|
|
||||||
echo "# Index of $display_dir" > "$temp_index"
|
|
||||||
echo "" >> "$temp_index"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
sort_args=""
|
|
||||||
# If this is the posts dir reverse
|
|
||||||
if is_posts_directory_rel "$rel_dir"; then
|
|
||||||
sort_args="-r"
|
|
||||||
fi
|
|
||||||
|
|
||||||
temp_entries="$KEWT_TMPDIR/entries_$$.txt"
|
|
||||||
: > "$temp_entries"
|
|
||||||
|
|
||||||
find "$dir" ! -name "$(basename "$dir")" -prune ! -name ".*" -print | while read -r entry; do
|
|
||||||
name="${entry##*/}"
|
name="${entry##*/}"
|
||||||
case "$name" in
|
case "$name" in
|
||||||
template.html|site.conf|style.css|styles.root.css|index.md) continue ;;
|
template.html|site.conf|style.css|styles.root.css|index.md) continue ;;
|
||||||
@@ -121,7 +44,7 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
entry_rel_dir="${entry#"$src"/}"
|
entry_rel_dir="${entry#"$src"/}"
|
||||||
manifest_dir_hidden_by_draft_index "$entry_rel_dir" && continue
|
manifest_dir_hidden_by_draft_index "$entry_rel_dir" && continue
|
||||||
dir_url="$(encode_url_path "$name")/index.html"
|
dir_url="$(encode_url_path "$name")/index.html"
|
||||||
echo "${name}|- [${name}/](${dir_url})" >> "$temp_entries"
|
echo "${name}|- [${name}/](${dir_url})" >> "$_bde_entries_file"
|
||||||
elif [ "${entry%.md}" != "$entry" ]; then
|
elif [ "${entry%.md}" != "$entry" ]; then
|
||||||
entry_rel_path="${entry#"$src"/}"
|
entry_rel_path="${entry#"$src"/}"
|
||||||
load_manifest_entry "$entry_rel_path" || continue
|
load_manifest_entry "$entry_rel_path" || continue
|
||||||
@@ -131,7 +54,7 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
post_h="$manifest_title"
|
post_h="$manifest_title"
|
||||||
|
|
||||||
is_post_entry="false"
|
is_post_entry="false"
|
||||||
if is_posts_directory_rel "$rel_dir"; then
|
if is_posts_directory_rel "$_bde_rel_dir"; then
|
||||||
is_post_entry="true"
|
is_post_entry="true"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -158,12 +81,76 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
sort_key="$name"
|
sort_key="$name"
|
||||||
fi
|
fi
|
||||||
entry_url=$(encode_url_path "${name%.md}.html")
|
entry_url=$(encode_url_path "${name%.md}.html")
|
||||||
echo "${sort_key}|- [$label](${entry_url})|$name|${entry_url}" >> "$temp_entries"
|
echo "${sort_key}|- [$label](${entry_url})|$name|${entry_url}" >> "$_bde_entries_file"
|
||||||
else
|
else
|
||||||
asset_url=$(encode_url_path "$name")
|
asset_url=$(encode_url_path "$name")
|
||||||
echo "${name}|- [$name]($asset_url)|$name|$asset_url" >> "$temp_entries"
|
echo "${name}|- [$name]($asset_url)|$name|$asset_url" >> "$_bde_entries_file"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
build_dir_index() {
|
||||||
|
_bdi_dir="$1"
|
||||||
|
_bdi_rel_dir="$2"
|
||||||
|
_bdi_out_dir="$3"
|
||||||
|
|
||||||
|
has_custom_index="false"
|
||||||
|
has_list="false"
|
||||||
|
if [ -f "$_bdi_dir/index.md" ]; then
|
||||||
|
has_custom_index="true"
|
||||||
|
if grep -q '^[[:space:]]*{{LIST}}[[:space:]]*$' "$_bdi_dir/index.md" 2>/dev/null; then
|
||||||
|
has_list="true"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$has_custom_index" = "false" ] || [ "$has_list" = "true" ]; then
|
||||||
|
is_posts_dir="false"
|
||||||
|
if is_posts_directory_rel "$_bdi_rel_dir"; then
|
||||||
|
is_posts_dir="true"
|
||||||
|
fi
|
||||||
|
if [ "$single_file_index" = "true" ] && [ "$is_posts_dir" = "false" ] && [ "$has_list" = "false" ]; then
|
||||||
|
if load_manifest_dir_entry "$_bdi_rel_dir" && [ "$dir_md_count" -eq 1 ]; then
|
||||||
|
md_file="$src/$dir_first_md"
|
||||||
|
is_home="false"; [ "$_bdi_dir" = "$src" ] && is_home="true"
|
||||||
|
target_url=$(directory_index_url "$_bdi_rel_dir")
|
||||||
|
if needs_rebuild "$md_file" "$_bdi_out_dir/index.html"; then
|
||||||
|
parse_frontmatter "$md_file"
|
||||||
|
if [ -n "$fm_content_warning" ]; then
|
||||||
|
content_out_file="$_bdi_out_dir/content.html"
|
||||||
|
if [ "$_bdi_rel_dir" = "." ]; then
|
||||||
|
content_rel_url="/content.html"
|
||||||
|
else
|
||||||
|
content_rel_url="/$(encode_url_path "$_bdi_rel_dir")/content.html"
|
||||||
|
fi
|
||||||
|
write_content_warning_outputs "$md_file" "$content_out_file" "$content_rel_url" "$target_url" "$_bdi_out_dir/index.html" "$is_home"
|
||||||
|
else
|
||||||
|
render_markdown "$md_file" "$is_home" "$target_url" > "$_bdi_out_dir/index.html"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
temp_index="$KEWT_TMPDIR/index.md"
|
||||||
|
temp_list="$KEWT_TMPDIR/list.md"
|
||||||
|
: > "$temp_list"
|
||||||
|
|
||||||
|
if [ "$has_custom_index" = "false" ]; then
|
||||||
|
display_dir="${_bdi_rel_dir#.}"
|
||||||
|
[ -z "$display_dir" ] && display_dir="/"
|
||||||
|
echo "# Index of $display_dir" > "$temp_index"
|
||||||
|
echo "" >> "$temp_index"
|
||||||
|
fi
|
||||||
|
|
||||||
|
sort_args=""
|
||||||
|
if is_posts_directory_rel "$_bdi_rel_dir"; then
|
||||||
|
sort_args="-r"
|
||||||
|
fi
|
||||||
|
|
||||||
|
temp_entries="$KEWT_TMPDIR/entries_$$.txt"
|
||||||
|
: > "$temp_entries"
|
||||||
|
|
||||||
|
build_dir_entries_list "$_bdi_dir" "$_bdi_rel_dir" "$temp_entries"
|
||||||
|
|
||||||
if [ "$is_posts_dir" = "true" ]; then
|
if [ "$is_posts_dir" = "true" ]; then
|
||||||
LC_ALL=C sort $sort_args "$temp_entries" > "$KEWT_TMPDIR/sorted_entries_$$.txt"
|
LC_ALL=C sort $sort_args "$temp_entries" > "$KEWT_TMPDIR/sorted_entries_$$.txt"
|
||||||
@@ -197,19 +184,35 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
fi
|
fi
|
||||||
rm -f "$temp_entries"
|
rm -f "$temp_entries"
|
||||||
|
|
||||||
is_home="false"; [ "$dir" = "$src" ] && is_home="true"
|
is_home="false"; [ "$_bdi_dir" = "$src" ] && is_home="true"
|
||||||
target_url=$(directory_index_url "$rel_dir")
|
target_url=$(directory_index_url "$_bdi_rel_dir")
|
||||||
|
|
||||||
num_items=$(wc -l < "$temp_list")
|
render_paginated_index "$_bdi_dir" "$_bdi_rel_dir" "$_bdi_out_dir" "$temp_index" "$temp_list" "$target_url" "$is_home" "$has_custom_index" "$is_posts_dir"
|
||||||
if [ "$is_posts_dir" = "true" ] && [ -n "$posts_per_page" ] && [ "$posts_per_page" -gt 0 ] && [ "$num_items" -gt "$posts_per_page" ]; then
|
rm -f "$temp_index" "$temp_list"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
render_paginated_index() {
|
||||||
|
_rpi_dir="$1"
|
||||||
|
_rpi_rel_dir="$2"
|
||||||
|
_rpi_out_dir="$3"
|
||||||
|
_rpi_temp_index="$4"
|
||||||
|
_rpi_temp_list="$5"
|
||||||
|
_rpi_target_url="$6"
|
||||||
|
_rpi_is_home="$7"
|
||||||
|
_rpi_has_custom_index="$8"
|
||||||
|
_rpi_is_posts_dir="$9"
|
||||||
|
|
||||||
|
num_items=$(wc -l < "$_rpi_temp_list")
|
||||||
|
if [ "$_rpi_is_posts_dir" = "true" ] && [ -n "$posts_per_page" ] && [ "$posts_per_page" -gt 0 ] && [ "$num_items" -gt "$posts_per_page" ]; then
|
||||||
num_pages=$(( (num_items + posts_per_page - 1) / posts_per_page ))
|
num_pages=$(( (num_items + posts_per_page - 1) / posts_per_page ))
|
||||||
p=1
|
p=1
|
||||||
while [ "$p" -le "$num_pages" ]; do
|
while [ "$p" -le "$num_pages" ]; do
|
||||||
chunk_list="$KEWT_TMPDIR/chunk.md"
|
chunk_list="$KEWT_TMPDIR/chunk.md"
|
||||||
start_line=$(( (p - 1) * posts_per_page + 1 ))
|
start_line=$(( (p - 1) * posts_per_page + 1 ))
|
||||||
tail -n +$start_line "$temp_list" | head -n "$posts_per_page" > "$chunk_list"
|
tail -n +$start_line "$_rpi_temp_list" | head -n "$posts_per_page" > "$chunk_list"
|
||||||
|
|
||||||
base_url_dir="$(dirname "$target_url")"
|
base_url_dir="$(dirname "$_rpi_target_url")"
|
||||||
[ "$base_url_dir" = "/" ] && base_url_dir=""
|
[ "$base_url_dir" = "/" ] && base_url_dir=""
|
||||||
|
|
||||||
nav_html="<div class=\"pagination\">"
|
nav_html="<div class=\"pagination\">"
|
||||||
@@ -230,8 +233,8 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
echo "$nav_html" >> "$chunk_list"
|
echo "$nav_html" >> "$chunk_list"
|
||||||
|
|
||||||
temp_index_p="$KEWT_TMPDIR/index_p$p.md"
|
temp_index_p="$KEWT_TMPDIR/index_p$p.md"
|
||||||
if [ "$has_custom_index" = "false" ]; then
|
if [ "$_rpi_has_custom_index" = "false" ]; then
|
||||||
display_dir="${rel_dir#.}"
|
display_dir="${_rpi_rel_dir#.}"
|
||||||
[ -z "$display_dir" ] && display_dir="/"
|
[ -z "$display_dir" ] && display_dir="/"
|
||||||
echo "# Index of $display_dir" > "$temp_index_p"
|
echo "# Index of $display_dir" > "$temp_index_p"
|
||||||
echo "" >> "$temp_index_p"
|
echo "" >> "$temp_index_p"
|
||||||
@@ -239,7 +242,7 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
: > "$temp_index_p"
|
: > "$temp_index_p"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$has_custom_index" = "true" ]; then
|
if [ "$_rpi_has_custom_index" = "true" ]; then
|
||||||
awk '
|
awk '
|
||||||
/^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
|
/^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
|
||||||
while((getline line < "'"$chunk_list"'") > 0) print line
|
while((getline line < "'"$chunk_list"'") > 0) print line
|
||||||
@@ -247,46 +250,46 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
{ print }
|
{ print }
|
||||||
' "$dir/index.md" >> "$temp_index_p"
|
' "$_rpi_dir/index.md" >> "$temp_index_p"
|
||||||
else
|
else
|
||||||
cat "$chunk_list" >> "$temp_index_p"
|
cat "$chunk_list" >> "$temp_index_p"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$p" -eq 1 ]; then
|
if [ "$p" -eq 1 ]; then
|
||||||
out_file="$out_dir/index.html"
|
out_file="$_rpi_out_dir/index.html"
|
||||||
target_url_p="$target_url"
|
target_url_p="$_rpi_target_url"
|
||||||
else
|
else
|
||||||
out_file="$out_dir/page/$p/index.html"
|
out_file="$_rpi_out_dir/page/$p/index.html"
|
||||||
target_url_p="$base_url_dir/page/$p/index.html"
|
target_url_p="$base_url_dir/page/$p/index.html"
|
||||||
mkdir -p "$(dirname "$out_file")"
|
mkdir -p "$(dirname "$out_file")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
render_markdown "$temp_index_p" "$is_home" "$target_url_p" > "$out_file"
|
render_markdown "$temp_index_p" "$_rpi_is_home" "$target_url_p" > "$out_file"
|
||||||
rm -f "$temp_index_p" "$chunk_list"
|
rm -f "$temp_index_p" "$chunk_list"
|
||||||
p=$((p + 1))
|
p=$((p + 1))
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
if [ "$has_custom_index" = "true" ]; then
|
if [ "$_rpi_has_custom_index" = "true" ]; then
|
||||||
awk '
|
awk '
|
||||||
/^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
|
/^[[:space:]]*\{\{LIST\}\}[[:space:]]*$/ {
|
||||||
while((getline line < "'"$temp_list"'") > 0) print line
|
while((getline line < "'"$_rpi_temp_list"'") > 0) print line
|
||||||
close("'"$temp_list"'")
|
close("'"$_rpi_temp_list"'")
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
{ print }
|
{ print }
|
||||||
' "$dir/index.md" > "$temp_index"
|
' "$_rpi_dir/index.md" > "$_rpi_temp_index"
|
||||||
else
|
else
|
||||||
cat "$temp_list" >> "$temp_index"
|
cat "$_rpi_temp_list" >> "$_rpi_temp_index"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
do_rebuild="false"
|
do_rebuild="false"
|
||||||
needs_rebuild "$dir" "$out_dir/index.html" && do_rebuild="true"
|
needs_rebuild "$_rpi_dir" "$_rpi_out_dir/index.html" && do_rebuild="true"
|
||||||
[ "$has_custom_index" = "true" ] && needs_rebuild "$dir/index.md" "$out_dir/index.html" && do_rebuild="true"
|
[ "$_rpi_has_custom_index" = "true" ] && needs_rebuild "$_rpi_dir/index.md" "$_rpi_out_dir/index.html" && do_rebuild="true"
|
||||||
|
|
||||||
if [ "$do_rebuild" = "false" ] && [ -f "$out_dir/index.html" ]; then
|
if [ "$do_rebuild" = "false" ] && [ -f "$_rpi_out_dir/index.html" ]; then
|
||||||
for _child in "$dir"/*; do
|
for _child in "$_rpi_dir"/*; do
|
||||||
[ -e "$_child" ] || continue
|
[ -e "$_child" ] || continue
|
||||||
if [ "$_child" -nt "$out_dir/index.html" ]; then
|
if [ "$_child" -nt "$_rpi_out_dir/index.html" ]; then
|
||||||
do_rebuild="true"
|
do_rebuild="true"
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
@@ -294,49 +297,53 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$do_rebuild" = "true" ]; then
|
if [ "$do_rebuild" = "true" ]; then
|
||||||
if [ "$has_custom_index" = "true" ]; then
|
if [ "$_rpi_has_custom_index" = "true" ]; then
|
||||||
parse_frontmatter "$dir/index.md"
|
parse_frontmatter "$_rpi_dir/index.md"
|
||||||
else
|
else
|
||||||
fm_content_warning=""
|
fm_content_warning=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$fm_content_warning" ]; then
|
if [ -n "$fm_content_warning" ]; then
|
||||||
content_out_file="$out_dir/content.html"
|
content_out_file="$_rpi_out_dir/content.html"
|
||||||
if [ "$rel_dir" = "." ]; then
|
if [ "$_rpi_rel_dir" = "." ]; then
|
||||||
content_rel_url="/content.html"
|
content_rel_url="/content.html"
|
||||||
else
|
else
|
||||||
content_rel_url="/$(encode_url_path "$rel_dir")/content.html"
|
content_rel_url="/$(encode_url_path "$_rpi_rel_dir")/content.html"
|
||||||
fi
|
fi
|
||||||
write_content_warning_outputs "$temp_index" "$content_out_file" "$content_rel_url" "$target_url" "$out_dir/index.html" "$is_home"
|
write_content_warning_outputs "$_rpi_temp_index" "$content_out_file" "$content_rel_url" "$_rpi_target_url" "$_rpi_out_dir/index.html" "$_rpi_is_home"
|
||||||
else
|
else
|
||||||
render_markdown "$temp_index" "$is_home" "$target_url" > "$out_dir/index.html"
|
render_markdown "$_rpi_temp_index" "$_rpi_is_home" "$_rpi_target_url" > "$_rpi_out_dir/index.html"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
rm -f "$temp_index" "$temp_list"
|
}
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ ! -f "$src/styles.css" ] && [ ! -f "$src/style.css" ]; then
|
build_directories() {
|
||||||
if [ -f "$src/styles.root.css" ]; then
|
eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type d -print" | sort | while read -r dir; do
|
||||||
_base_css="$script_dir/styles/$style.css"
|
rel_dir="${dir#"$src"}"
|
||||||
[ ! -f "$_base_css" ] && _base_css="$script_dir/styles/kewt.css"
|
rel_dir="${rel_dir#/}"
|
||||||
if [ ! -f "$out/styles.css" ] || [ "$src/styles.root.css" -nt "$out/styles.css" ] || [ "$_base_css" -nt "$out/styles.css" ]; then
|
[ -z "$rel_dir" ] && rel_dir="."
|
||||||
merge_root_style "$src/styles.root.css" "$_base_css" "$out/styles.css"
|
out_dir="$out/$rel_dir"
|
||||||
fi
|
mkdir -p "$out_dir"
|
||||||
elif [ -f "$script_dir/styles/$style.css" ]; then
|
|
||||||
if needs_rebuild "$script_dir/styles/$style.css" "$out/styles.css"; then
|
|
||||||
copy_style_with_resolved_vars "$script_dir/styles/$style.css" "$out/styles.css"
|
|
||||||
fi
|
|
||||||
elif [ -f "$script_dir/styles/$style.root.css" ]; then
|
|
||||||
_base_css="$script_dir/styles/kewt.css"
|
|
||||||
if [ ! -f "$out/styles.css" ] || [ "$script_dir/styles/$style.root.css" -nt "$out/styles.css" ] || [ "$_base_css" -nt "$out/styles.css" ]; then
|
|
||||||
merge_root_style "$script_dir/styles/$style.root.css" "$_base_css" "$out/styles.css"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type f -print" | sort | while IFS= read -r file; do
|
if [ -f "$dir/styles.css" ]; then
|
||||||
|
if needs_rebuild "$dir/styles.css" "$out_dir/styles.css"; then
|
||||||
|
copy_style_with_resolved_vars "$dir/styles.css" "$out_dir/styles.css"
|
||||||
|
fi
|
||||||
|
elif [ -f "$dir/style.css" ]; then
|
||||||
|
if needs_rebuild "$dir/style.css" "$out_dir/styles.css"; then
|
||||||
|
copy_style_with_resolved_vars "$dir/style.css" "$out_dir/styles.css"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ "$dir_indexes" != "true" ] && continue
|
||||||
|
|
||||||
|
build_dir_index "$dir" "$rel_dir" "$out_dir"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
build_files() {
|
||||||
|
eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type f -print" | sort | while IFS= read -r file; do
|
||||||
rel_path="${file#"$src"}"
|
rel_path="${file#"$src"}"
|
||||||
rel_path="${rel_path#/}"
|
rel_path="${rel_path#/}"
|
||||||
dir_rel=$(dirname "$rel_path")
|
dir_rel=$(dirname "$rel_path")
|
||||||
@@ -386,18 +393,33 @@ eval "find \"$src\" \( $IGNORE_ARGS \) -prune -o -type f -print" | sort | while
|
|||||||
cp "$file" "$out/$rel_path"
|
cp "$file" "$out/$rel_path"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
}
|
||||||
|
|
||||||
if [ -n "$error_page" ] && [ ! -f "$out/$error_page" ]; then
|
build_root_style() {
|
||||||
temp_404="$KEWT_TMPDIR/404_gen.md"
|
if [ ! -f "$src/styles.css" ] && [ ! -f "$src/style.css" ]; then
|
||||||
echo "# 404 - Not Found" > "$temp_404"
|
if [ -f "$src/styles.root.css" ]; then
|
||||||
echo "" >> "$temp_404"
|
_base_css="$script_dir/styles/$style.css"
|
||||||
echo "The requested page could not be found." >> "$temp_404"
|
[ ! -f "$_base_css" ] && _base_css="$script_dir/styles/kewt.css"
|
||||||
render_markdown "$temp_404" "false" "/$error_page" > "$out/$error_page"
|
if [ ! -f "$out/styles.css" ] || [ "$src/styles.root.css" -nt "$out/styles.css" ] || [ "$_base_css" -nt "$out/styles.css" ]; then
|
||||||
rm -f "$temp_404"
|
merge_root_style "$src/styles.root.css" "$_base_css" "$out/styles.css"
|
||||||
fi
|
fi
|
||||||
|
elif [ -f "$script_dir/styles/$style.css" ]; then
|
||||||
|
if needs_rebuild "$script_dir/styles/$style.css" "$out/styles.css"; then
|
||||||
|
copy_style_with_resolved_vars "$script_dir/styles/$style.css" "$out/styles.css"
|
||||||
|
fi
|
||||||
|
elif [ -f "$script_dir/styles/$style.root.css" ]; then
|
||||||
|
_base_css="$script_dir/styles/kewt.css"
|
||||||
|
if [ ! -f "$out/styles.css" ] || [ "$script_dir/styles/$style.root.css" -nt "$out/styles.css" ] || [ "$_base_css" -nt "$out/styles.css" ]; then
|
||||||
|
merge_root_style "$script_dir/styles/$style.root.css" "$_base_css" "$out/styles.css"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_sitemap() {
|
||||||
|
[ -n "$base_url" ] || return
|
||||||
|
|
||||||
if [ -n "$base_url" ]; then
|
|
||||||
sitemap_file="$out/sitemap.xml"
|
sitemap_file="$out/sitemap.xml"
|
||||||
base_url="${base_url%/}"
|
base_url="${base_url%/}"
|
||||||
today=$(date +%Y-%m-%d)
|
today=$(date +%Y-%m-%d)
|
||||||
@@ -407,35 +429,24 @@ if [ -n "$base_url" ]; then
|
|||||||
|
|
||||||
find "$out" -type f -name "*.html" -print | sort | while IFS= read -r html_file; do
|
find "$out" -type f -name "*.html" -print | sort | while IFS= read -r html_file; do
|
||||||
rel_url="${html_file#"$out"}"
|
rel_url="${html_file#"$out"}"
|
||||||
|
|
||||||
# Don't include 404 in the sitemap (duh)
|
|
||||||
[ "${rel_url#/}" = "$error_page" ] && continue
|
[ "${rel_url#/}" = "$error_page" ] && continue
|
||||||
|
|
||||||
{
|
printf ' <url>\n <loc>%s%s</loc>\n <lastmod>%s</lastmod>\n </url>\n' "$base_url" "$rel_url" "$today" >> "$sitemap_file"
|
||||||
printf ' <url>\n'
|
|
||||||
printf ' <loc>%s%s</loc>\n' "$base_url" "$rel_url"
|
|
||||||
printf ' <lastmod>%s</lastmod>\n' "$today"
|
|
||||||
printf ' </url>\n'
|
|
||||||
} >> "$sitemap_file"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
printf '</urlset>\n' >> "$sitemap_file"
|
printf '</urlset>\n' >> "$sitemap_file"
|
||||||
fi
|
}
|
||||||
|
|
||||||
|
build_feed() {
|
||||||
|
[ "$generate_feed" = "true" ] && [ -n "$base_url" ] || return
|
||||||
|
|
||||||
if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then
|
|
||||||
feed_path="$out/$feed_file"
|
feed_path="$out/$feed_file"
|
||||||
base_url_feed="${base_url%/}"
|
base_url_feed="${base_url%/}"
|
||||||
build_date=$(date -u '+%a, %d %b %Y %H:%M:%S +0000')
|
build_date=$(date -u '+%a, %d %b %Y %H:%M:%S +0000')
|
||||||
|
|
||||||
printf '<?xml version="1.0" encoding="UTF-8"?>\n' > "$feed_path"
|
printf '<?xml version="1.0" encoding="UTF-8"?>\n' > "$feed_path"
|
||||||
{
|
printf '<rss version="2.0">\n <channel>\n <title>%s</title>\n <link>%s</link>\n <description>%s</description>\n <lastBuildDate>%s</lastBuildDate>\n' \
|
||||||
printf '<rss version="2.0">\n'
|
"$title" "$base_url_feed" "$title" "$build_date" >> "$feed_path"
|
||||||
printf ' <channel>\n'
|
|
||||||
printf ' <title>%s</title>\n' "$title"
|
|
||||||
printf ' <link>%s</link>\n' "$base_url_feed"
|
|
||||||
printf ' <description>%s</description>\n' "$title"
|
|
||||||
printf ' <lastBuildDate>%s</lastBuildDate>\n' "$build_date"
|
|
||||||
} >> "$feed_path"
|
|
||||||
|
|
||||||
temp_feed_files="$KEWT_TMPDIR/feed_files_$$.txt"
|
temp_feed_files="$KEWT_TMPDIR/feed_files_$$.txt"
|
||||||
: > "$temp_feed_files"
|
: > "$temp_feed_files"
|
||||||
@@ -462,32 +473,19 @@ if [ "$generate_feed" = "true" ] && [ -n "$base_url" ]; then
|
|||||||
post_heading=$(echo "$post_slug" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)}1')
|
post_heading=$(echo "$post_slug" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) substr($i,2)}1')
|
||||||
fi
|
fi
|
||||||
feed_post_title="$post_heading - $post_date $post_time"
|
feed_post_title="$post_heading - $post_date $post_time"
|
||||||
|
|
||||||
post_url="$base_url_feed$manifest_url"
|
post_url="$base_url_feed$manifest_url"
|
||||||
|
|
||||||
pub_date=$(format_rfc2822_utc "$post_date" "$post_time")
|
pub_date=$(format_rfc2822_utc "$post_date" "$post_time")
|
||||||
|
|
||||||
{
|
printf ' <item>\n <title>%s</title>\n <link>%s</link>\n <guid>%s</guid>\n <pubDate>%s</pubDate>\n </item>\n' \
|
||||||
printf ' <item>\n'
|
"$feed_post_title" "$post_url" "$post_url" "$pub_date" >> "$feed_path"
|
||||||
printf ' <title>%s</title>\n' "$feed_post_title"
|
|
||||||
printf ' <link>%s</link>\n' "$post_url"
|
|
||||||
printf ' <guid>%s</guid>\n' "$post_url"
|
|
||||||
printf ' <pubDate>%s</pubDate>\n' "$pub_date"
|
|
||||||
printf ' </item>\n'
|
|
||||||
} >> "$feed_path"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
printf ' </channel>\n' >> "$feed_path"
|
printf ' </channel>\n</rss>\n' >> "$feed_path"
|
||||||
printf '</rss>\n' >> "$feed_path"
|
}
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then
|
build_search_index() {
|
||||||
if [ "$generate_search" = "true" ]; then
|
|
||||||
printf '[\n' > "$out/search.json"
|
printf '[\n' > "$out/search.json"
|
||||||
fi
|
|
||||||
first_search_item="true"
|
first_search_item="true"
|
||||||
temp_tags="$KEWT_TMPDIR/tags_$$.txt"
|
|
||||||
: > "$temp_tags"
|
|
||||||
|
|
||||||
while IFS= read -r rel_path; do
|
while IFS= read -r rel_path; do
|
||||||
load_manifest_entry "$rel_path" || continue
|
load_manifest_entry "$rel_path" || continue
|
||||||
@@ -529,7 +527,6 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then
|
|||||||
[ "$manifest_draft" = "true" ] && continue
|
[ "$manifest_draft" = "true" ] && continue
|
||||||
md_heading="$manifest_title"
|
md_heading="$manifest_title"
|
||||||
|
|
||||||
if [ "$generate_search" = "true" ]; then
|
|
||||||
if [ -z "$manifest_content_warning" ] || [ "$include_cw_pages_in_search" = "true" ]; then
|
if [ -z "$manifest_content_warning" ] || [ "$include_cw_pages_in_search" = "true" ]; then
|
||||||
md_content="$manifest_search_content"
|
md_content="$manifest_search_content"
|
||||||
if [ "$first_search_item" = "false" ]; then
|
if [ "$first_search_item" = "false" ]; then
|
||||||
@@ -538,23 +535,9 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then
|
|||||||
printf ' {"url": "%s", "title": "%s", "content": "%s"}' "$md_url" "$md_heading" "$md_content" >> "$out/search.json"
|
printf ' {"url": "%s", "title": "%s", "content": "%s"}' "$md_url" "$md_heading" "$md_content" >> "$out/search.json"
|
||||||
first_search_item="false"
|
first_search_item="false"
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$generate_tags" = "true" ] && [ -n "$manifest_tags" ]; then
|
|
||||||
old_ifs=$IFS
|
|
||||||
IFS=','
|
|
||||||
for tag in $manifest_tags; do
|
|
||||||
tag=$(echo "$tag" | sed 's/^[ \t]*//;s/[ \t]*$//')
|
|
||||||
[ -z "$tag" ] && continue
|
|
||||||
printf '%s|%s|%s\n' "$tag" "$md_url" "$md_heading" >> "$temp_tags"
|
|
||||||
done
|
|
||||||
IFS=$old_ifs
|
|
||||||
fi
|
|
||||||
done < "$manifest_visible_list"
|
done < "$manifest_visible_list"
|
||||||
|
|
||||||
if [ "$generate_search" = "true" ]; then
|
|
||||||
printf '\n]\n' >> "$out/search.json"
|
printf '\n]\n' >> "$out/search.json"
|
||||||
|
|
||||||
cp "$script_dir/lib/search.js" "$out/search.js"
|
cp "$script_dir/lib/search.js" "$out/search.js"
|
||||||
|
|
||||||
search_md="$KEWT_TMPDIR/search_$$.md"
|
search_md="$KEWT_TMPDIR/search_$$.md"
|
||||||
@@ -569,9 +552,29 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then
|
|||||||
'<script src="/search.js"></script>' > "$search_md"
|
'<script src="/search.js"></script>' > "$search_md"
|
||||||
render_markdown "$search_md" "false" "/search.html" > "$out/search.html"
|
render_markdown "$search_md" "false" "/search.html" > "$out/search.html"
|
||||||
rm -f "$search_md"
|
rm -f "$search_md"
|
||||||
fi
|
}
|
||||||
|
|
||||||
|
build_tags() {
|
||||||
|
temp_tags="$KEWT_TMPDIR/tags_$$.txt"
|
||||||
|
: > "$temp_tags"
|
||||||
|
|
||||||
|
while IFS= read -r rel_path; do
|
||||||
|
load_manifest_entry "$rel_path" || continue
|
||||||
|
[ "$manifest_draft" = "true" ] && continue
|
||||||
|
md_heading="$manifest_title"
|
||||||
|
|
||||||
|
if [ -n "$manifest_tags" ]; then
|
||||||
|
old_ifs=$IFS
|
||||||
|
IFS=','
|
||||||
|
for tag in $manifest_tags; do
|
||||||
|
tag=$(echo "$tag" | sed 's/^[ \t]*//;s/[ \t]*$//')
|
||||||
|
[ -z "$tag" ] && continue
|
||||||
|
printf '%s|%s|%s\n' "$tag" "$manifest_url" "$md_heading" >> "$temp_tags"
|
||||||
|
done
|
||||||
|
IFS=$old_ifs
|
||||||
|
fi
|
||||||
|
done < "$manifest_visible_list"
|
||||||
|
|
||||||
if [ "$generate_tags" = "true" ]; then
|
|
||||||
tags_out_dir="$out/$tags_dir"
|
tags_out_dir="$out/$tags_dir"
|
||||||
mkdir -p "$tags_out_dir"
|
mkdir -p "$tags_out_dir"
|
||||||
|
|
||||||
@@ -599,10 +602,38 @@ if [ "$generate_search" = "true" ] || [ "$generate_tags" = "true" ]; then
|
|||||||
done
|
done
|
||||||
|
|
||||||
render_markdown "$tags_index_md" "false" "/$tags_dir/index.html" > "$tags_out_dir/index.html"
|
render_markdown "$tags_index_md" "false" "/$tags_dir/index.html" > "$tags_out_dir/index.html"
|
||||||
rm -f "$tags_index_md"
|
rm -f "$tags_index_md" "$temp_tags"
|
||||||
fi
|
}
|
||||||
rm -f "$temp_tags"
|
|
||||||
fi
|
build_error_page() {
|
||||||
|
[ -n "$error_page" ] && [ ! -f "$out/$error_page" ] || return
|
||||||
echo "Build complete."
|
|
||||||
|
temp_404="$KEWT_TMPDIR/404_gen.md"
|
||||||
|
printf '# 404 - Not Found\n\nThe requested page could not be found.\n' > "$temp_404"
|
||||||
|
render_markdown "$temp_404" "false" "/$error_page" > "$out/$error_page"
|
||||||
|
rm -f "$temp_404"
|
||||||
|
}
|
||||||
|
|
||||||
|
build_site() {
|
||||||
|
echo "Building site from '$src' to '$out'..."
|
||||||
|
|
||||||
|
build_markdown_manifest
|
||||||
|
build_full_nav
|
||||||
|
|
||||||
|
build_directories
|
||||||
|
build_root_style
|
||||||
|
build_files
|
||||||
|
build_error_page
|
||||||
|
build_sitemap
|
||||||
|
build_feed
|
||||||
|
|
||||||
|
if [ "$generate_search" = "true" ]; then
|
||||||
|
build_search_index
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$generate_tags" = "true" ]; then
|
||||||
|
build_tags
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Build complete."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
# shellcheck disable=SC2153
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
invoked_as=$(basename "${KEWT_INVOKED_AS:-$0}")
|
invoked_as=$(basename "${KEWT_INVOKED_AS:-$0}")
|
||||||
@@ -97,11 +98,9 @@ update_site() {
|
|||||||
target_conf="$update_dir/site.conf"
|
target_conf="$update_dir/site.conf"
|
||||||
target_tmpl="$update_dir/template.html"
|
target_tmpl="$update_dir/template.html"
|
||||||
|
|
||||||
# Generate default site.conf
|
|
||||||
default_conf="$KEWT_TMPDIR/default_site.conf"
|
default_conf="$KEWT_TMPDIR/default_site.conf"
|
||||||
printf '%s\n' "$DEFAULT_CONF" > "$default_conf"
|
printf '%s\n' "$DEFAULT_CONF" > "$default_conf"
|
||||||
|
|
||||||
# Update site.conf
|
|
||||||
if [ ! -f "$target_conf" ]; then
|
if [ ! -f "$target_conf" ]; then
|
||||||
echo "No site.conf found in '$update_dir'; nothing to update."
|
echo "No site.conf found in '$update_dir'; nothing to update."
|
||||||
else
|
else
|
||||||
@@ -126,7 +125,6 @@ update_site() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update template.html
|
|
||||||
if [ -f "$target_tmpl" ]; then
|
if [ -f "$target_tmpl" ]; then
|
||||||
default_tmpl="$KEWT_TMPDIR/default_template.html"
|
default_tmpl="$KEWT_TMPDIR/default_template.html"
|
||||||
printf '%s\n' "$DEFAULT_TMPL" > "$default_tmpl"
|
printf '%s\n' "$DEFAULT_TMPL" > "$default_tmpl"
|
||||||
|
|||||||
172
lib/config.sh
172
lib/config.sh
@@ -62,106 +62,88 @@ DEFAULT_TMPL='<!doctype html>
|
|||||||
</body>
|
</body>
|
||||||
</html>'
|
</html>'
|
||||||
|
|
||||||
|
_parse_conf_val() {
|
||||||
|
_pv_val="$1"
|
||||||
|
case "$_pv_val" in
|
||||||
|
\"*\")
|
||||||
|
_pv_val=${_pv_val#\"}
|
||||||
|
_pv_val=${_pv_val%\"}
|
||||||
|
printf '%s' "$_pv_val" | sed 's/\\"/\"/g; s/\\\\/\\/g'
|
||||||
|
;;
|
||||||
|
\'*\')
|
||||||
|
_pv_val=${_pv_val#\'}
|
||||||
|
_pv_val=${_pv_val%\'}
|
||||||
|
printf '%s' "$_pv_val" | sed "s/\\\\'/'/g; s/\\\\/\\/g"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf '%s' "$_pv_val"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_load_conf_line() {
|
||||||
|
case "$1" in
|
||||||
|
''|'#'*) return ;;
|
||||||
|
*=*) ;;
|
||||||
|
*) return ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
_lc_key=${1%%=*}
|
||||||
|
_lc_val=${1#*=}
|
||||||
|
_lc_key=$(printf '%s' "$_lc_key" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
|
||||||
|
_lc_val=$(_parse_conf_val "$(printf '%s' "$_lc_val" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')")
|
||||||
|
|
||||||
|
case "$_lc_key" in
|
||||||
|
title) title="$_lc_val" ;;
|
||||||
|
style) style="${_lc_val#/}" ;;
|
||||||
|
dir_indexes) dir_indexes="$_lc_val" ;;
|
||||||
|
single_file_index) single_file_index="$_lc_val" ;;
|
||||||
|
flatten) flatten="$_lc_val" ;;
|
||||||
|
order) order="$_lc_val" ;;
|
||||||
|
home_name) home_name="$_lc_val" ;;
|
||||||
|
show_home_in_nav) show_home_in_nav="$_lc_val" ;;
|
||||||
|
nav_links) nav_links="$_lc_val" ;;
|
||||||
|
nav_extra) nav_extra="$_lc_val" ;;
|
||||||
|
footer) footer="$_lc_val" ;;
|
||||||
|
logo) logo="${_lc_val#/}" ;;
|
||||||
|
display_logo) display_logo="$_lc_val" ;;
|
||||||
|
display_title) display_title="$_lc_val" ;;
|
||||||
|
logo_as_favicon) logo_as_favicon="$_lc_val" ;;
|
||||||
|
favicon) favicon="${_lc_val#/}" ;;
|
||||||
|
generate_page_title) generate_page_title="$_lc_val" ;;
|
||||||
|
error_page) error_page="${_lc_val#/}" ;;
|
||||||
|
versioning) versioning="$_lc_val" ;;
|
||||||
|
enable_header_links) enable_header_links="$_lc_val" ;;
|
||||||
|
base_url) base_url="$_lc_val" ;;
|
||||||
|
generate_feed) generate_feed="$_lc_val" ;;
|
||||||
|
feed_file) feed_file="${_lc_val#/}" ;;
|
||||||
|
posts_dir) posts_dir="${_lc_val#/}" ;;
|
||||||
|
posts_per_page) posts_per_page="$_lc_val" ;;
|
||||||
|
custom_admonitions) custom_admonitions="$_lc_val" ;;
|
||||||
|
cw_hide_url) cw_hide_url="$_lc_val" ;;
|
||||||
|
lang) lang="$_lc_val" ;;
|
||||||
|
draft_by_default) draft_by_default="$_lc_val" ;;
|
||||||
|
generate_tags) generate_tags="$_lc_val" ;;
|
||||||
|
tags_dir) tags_dir="${_lc_val#/}" ;;
|
||||||
|
generate_search) generate_search="$_lc_val" ;;
|
||||||
|
search_in_footer) search_in_footer="$_lc_val" ;;
|
||||||
|
search_in_header) search_in_header="$_lc_val" ;;
|
||||||
|
include_cw_pages_in_search) include_cw_pages_in_search="$_lc_val" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
reset_config() {
|
reset_config() {
|
||||||
title="kewt"
|
while IFS= read -r _rc_line; do
|
||||||
style="kewt"
|
_load_conf_line "$_rc_line"
|
||||||
lang="en"
|
done <<EOF
|
||||||
draft_by_default="false"
|
$DEFAULT_CONF
|
||||||
dir_indexes="true"
|
EOF
|
||||||
single_file_index="true"
|
|
||||||
flatten="false"
|
|
||||||
order=""
|
|
||||||
home_name="Home"
|
|
||||||
show_home_in_nav="true"
|
|
||||||
nav_links=""
|
|
||||||
nav_extra=""
|
|
||||||
footer="made with <a href=\"https://kewt.krzak.org\">kewt</a>"
|
|
||||||
logo=""
|
|
||||||
display_logo="false"
|
|
||||||
display_title="true"
|
|
||||||
logo_as_favicon="true"
|
|
||||||
favicon=""
|
|
||||||
generate_page_title="true"
|
|
||||||
error_page="not_found.html"
|
|
||||||
versioning="false"
|
|
||||||
enable_header_links="true"
|
|
||||||
base_url=""
|
|
||||||
generate_feed="false"
|
|
||||||
feed_file="rss.xml"
|
|
||||||
posts_dir=""
|
|
||||||
posts_per_page="12"
|
|
||||||
custom_admonitions=""
|
|
||||||
cw_hide_url="true"
|
|
||||||
generate_tags="false"
|
|
||||||
tags_dir="tags"
|
|
||||||
generate_search="false"
|
|
||||||
search_in_footer="false"
|
|
||||||
search_in_header="false"
|
|
||||||
include_cw_pages_in_search="false"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
load_config() {
|
load_config() {
|
||||||
[ -f "$1" ] || return
|
[ -f "$1" ] || return
|
||||||
while IFS= read -r line || [ -n "$line" ]; do
|
while IFS= read -r _lc_line || [ -n "$_lc_line" ]; do
|
||||||
case "$line" in
|
_load_conf_line "$_lc_line"
|
||||||
''|'#'*) continue ;;
|
|
||||||
*=*) ;;
|
|
||||||
*) continue ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
key=${line%%=*}
|
|
||||||
val=${line#*=}
|
|
||||||
|
|
||||||
key=$(printf '%s' "$key" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
|
|
||||||
val=$(printf '%s' "$val" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')
|
|
||||||
case "$val" in
|
|
||||||
\"*\")
|
|
||||||
val=${val#\"}; val=${val%\"}
|
|
||||||
val=$(printf '%s' "$val" | sed 's/\\"/\"/g; s/\\\\/\\/g')
|
|
||||||
;;
|
|
||||||
\'*\')
|
|
||||||
val=${val#\'}; val=${val%\'}
|
|
||||||
val=$(printf '%s' "$val" | sed "s/\\\\'/'/g; s/\\\\/\\/g")
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
case "$key" in
|
|
||||||
title) title="$val" ;;
|
|
||||||
style) style="${val#/}" ;;
|
|
||||||
dir_indexes) dir_indexes="$val" ;;
|
|
||||||
single_file_index) single_file_index="$val" ;;
|
|
||||||
flatten) flatten="$val" ;;
|
|
||||||
order) order="$val" ;;
|
|
||||||
home_name) home_name="$val" ;;
|
|
||||||
show_home_in_nav) show_home_in_nav="$val" ;;
|
|
||||||
nav_links) nav_links="$val" ;;
|
|
||||||
nav_extra) nav_extra="$val" ;;
|
|
||||||
footer) footer="$val" ;;
|
|
||||||
logo) logo="${val#/}" ;;
|
|
||||||
display_logo) display_logo="$val" ;;
|
|
||||||
display_title) display_title="$val" ;;
|
|
||||||
logo_as_favicon) logo_as_favicon="$val" ;;
|
|
||||||
favicon) favicon="${val#/}" ;;
|
|
||||||
generate_page_title) generate_page_title="$val" ;;
|
|
||||||
error_page) error_page="${val#/}" ;;
|
|
||||||
versioning) versioning="$val" ;;
|
|
||||||
enable_header_links) enable_header_links="$val" ;;
|
|
||||||
base_url) base_url="$val" ;;
|
|
||||||
generate_feed) generate_feed="$val" ;;
|
|
||||||
feed_file) feed_file="${val#/}" ;;
|
|
||||||
posts_dir) posts_dir="${val#/}" ;;
|
|
||||||
posts_per_page) posts_per_page="$val" ;;
|
|
||||||
custom_admonitions) custom_admonitions="$val" ;;
|
|
||||||
cw_hide_url) cw_hide_url="$val" ;;
|
|
||||||
lang) lang="$val" ;;
|
|
||||||
draft_by_default) draft_by_default="$val" ;;
|
|
||||||
generate_tags) generate_tags="$val" ;;
|
|
||||||
tags_dir) tags_dir="${val#/}" ;;
|
|
||||||
generate_search) generate_search="$val" ;;
|
|
||||||
search_in_footer) search_in_footer="$val" ;;
|
|
||||||
search_in_header) search_in_header="$val" ;;
|
|
||||||
include_cw_pages_in_search) include_cw_pages_in_search="$val" ;;
|
|
||||||
esac
|
|
||||||
done < "$1"
|
done < "$1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
269
lib/generator.sh
269
lib/generator.sh
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
|
||||||
SEARCH_FORM_FOOTER='<form class="kewt-search-footer" action="/search.html" method="get"><input type="text" name="q" placeholder="Search..." required><button type="submit">Go</button></form>'
|
SEARCH_FORM_FOOTER='<form class="kewt-search-footer" action="/search.html" method="get"><input type="text" name="q" placeholder="Search..." required><button type="submit">Go</button></form>'
|
||||||
SEARCH_FORM_HEADER='<form class="kewt-search-header" action="/search.html" method="get"><input type="text" name="q" placeholder="Search..." required><button type="submit">Go</button></form>'
|
SEARCH_FORM_HEADER='<form class="kewt-search-header" action="/search.html" method="get"><input type="text" name="q" placeholder="Search..." required><button type="submit">Go</button></form>'
|
||||||
@@ -37,12 +38,14 @@ generate_nav() {
|
|||||||
|
|
||||||
sort -u "$nav_input" | AWK_SRC="$1" AWK_SINGLE_FILE_INDEX="$single_file_index" AWK_FLATTEN="$flatten" AWK_ORDER="$order" AWK_HOME_NAME="$home_name" AWK_SHOW_HOME_IN_NAV="$show_home_in_nav" AWK_DINFO="$dinfo" awk -f "$awk_dir/generate_sidebar.awk"
|
sort -u "$nav_input" | AWK_SRC="$1" AWK_SINGLE_FILE_INDEX="$single_file_index" AWK_FLATTEN="$flatten" AWK_ORDER="$order" AWK_HOME_NAME="$home_name" AWK_SHOW_HOME_IN_NAV="$show_home_in_nav" AWK_DINFO="$dinfo" awk -f "$awk_dir/generate_sidebar.awk"
|
||||||
}
|
}
|
||||||
|
|
||||||
escape_html_text() {
|
escape_html_text() {
|
||||||
printf '%s' "$1" | sed \
|
printf '%s' "$1" | sed \
|
||||||
-e 's/&/\&/g' \
|
-e 's/&/\&/g' \
|
||||||
-e 's/</\</g' \
|
-e 's/</\</g' \
|
||||||
-e 's/>/\>/g'
|
-e 's/>/\>/g'
|
||||||
}
|
}
|
||||||
|
|
||||||
escape_html_attr() {
|
escape_html_attr() {
|
||||||
printf '%s' "$1" | sed \
|
printf '%s' "$1" | sed \
|
||||||
-e 's/&/\&/g' \
|
-e 's/&/\&/g' \
|
||||||
@@ -50,13 +53,13 @@ escape_html_attr() {
|
|||||||
-e 's/</\</g' \
|
-e 's/</\</g' \
|
||||||
-e 's/>/\>/g'
|
-e 's/>/\>/g'
|
||||||
}
|
}
|
||||||
|
|
||||||
nav_links_html() {
|
nav_links_html() {
|
||||||
[ -n "$nav_links" ] || return
|
[ -n "$nav_links" ] || return
|
||||||
|
|
||||||
old_ifs=$IFS
|
old_ifs=$IFS
|
||||||
set -f
|
set -f
|
||||||
IFS=','
|
IFS=','
|
||||||
# shellcheck disable=SC2086
|
|
||||||
set -- $nav_links
|
set -- $nav_links
|
||||||
IFS=$old_ifs
|
IFS=$old_ifs
|
||||||
set +f
|
set +f
|
||||||
@@ -93,6 +96,7 @@ nav_links_html() {
|
|||||||
done
|
done
|
||||||
printf '</ul>'
|
printf '</ul>'
|
||||||
}
|
}
|
||||||
|
|
||||||
find_closest() {
|
find_closest() {
|
||||||
target="$1"
|
target="$1"
|
||||||
start_dir="$2"
|
start_dir="$2"
|
||||||
@@ -108,11 +112,13 @@ find_closest() {
|
|||||||
echo "$src/$target"
|
echo "$src/$target"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
copy_style_with_resolved_vars() {
|
copy_style_with_resolved_vars() {
|
||||||
src_style="$1"
|
src_style="$1"
|
||||||
out_style="$2"
|
out_style="$2"
|
||||||
awk -f "$awk_dir/replace_variables.awk" "$src_style" > "$out_style"
|
awk -f "$awk_dir/replace_variables.awk" "$src_style" > "$out_style"
|
||||||
}
|
}
|
||||||
|
|
||||||
merge_root_style() {
|
merge_root_style() {
|
||||||
root_file="$1"
|
root_file="$1"
|
||||||
base_css="$2"
|
base_css="$2"
|
||||||
@@ -134,19 +140,135 @@ merge_root_style() {
|
|||||||
' "$base_css"
|
' "$base_css"
|
||||||
} | awk -f "$awk_dir/replace_variables.awk" > "$out_file"
|
} | awk -f "$awk_dir/replace_variables.awk" > "$out_file"
|
||||||
}
|
}
|
||||||
render_markdown() {
|
|
||||||
file="$1"
|
|
||||||
is_home="$2"
|
|
||||||
url_override="$3"
|
|
||||||
|
|
||||||
if [ -n "$url_override" ]; then
|
resolve_render_template() {
|
||||||
current_url="$url_override"
|
local_template=$(find_closest "template.html" "$(dirname "$1")")
|
||||||
|
[ -z "$local_template" ] && local_template="$template"
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_render_style_path() {
|
||||||
|
closest_style_src=$(find_closest "styles.css" "$(dirname "$1")")
|
||||||
|
[ -z "$closest_style_src" ] && closest_style_src=$(find_closest "style.css" "$(dirname "$1")")
|
||||||
|
if [ -n "$closest_style_src" ]; then
|
||||||
|
style_rel_to_src="${closest_style_src#"$src"/}"
|
||||||
|
case "$closest_style_src" in
|
||||||
|
"$src/styles.css") style_rel_to_src="styles.css" ;;
|
||||||
|
"$src/style.css") style_rel_to_src="style.css" ;;
|
||||||
|
esac
|
||||||
|
style_path="/$(encode_url_path "${style_rel_to_src%styles.css}")"
|
||||||
|
style_path="${style_path%style.css}styles.css"
|
||||||
else
|
else
|
||||||
rel_path="${file#"$src"}"
|
style_path="/styles.css"
|
||||||
rel_path="${rel_path#/}"
|
fi
|
||||||
current_url=$(markdown_file_url "$rel_path")
|
}
|
||||||
|
|
||||||
|
build_header_brand_html() {
|
||||||
|
logo_html=""
|
||||||
|
if [ "$display_logo" = "true" ] && [ -n "$logo" ]; then
|
||||||
|
logo_html="<img class=\"site-logo\" src=\"$logo\" alt=\"$title\" />"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
brand_text=""
|
||||||
|
if [ "$display_title" = "true" ]; then
|
||||||
|
brand_text="$title"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$logo_html" ] && [ -n "$brand_text" ]; then
|
||||||
|
header_brand="<a href=\"/index.html\">$logo_html $brand_text</a>"
|
||||||
|
elif [ -n "$logo_html" ]; then
|
||||||
|
header_brand="<a href=\"/index.html\">$logo_html</a>"
|
||||||
|
elif [ -n "$brand_text" ]; then
|
||||||
|
header_brand="<a href=\"/index.html\">$brand_text</a>"
|
||||||
|
else
|
||||||
|
header_brand="<a href=\"/index.html\">$title</a>"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_favicon_head() {
|
||||||
|
favicon_src=""
|
||||||
|
if [ "$logo_as_favicon" = "true" ] && [ -n "$logo" ]; then
|
||||||
|
favicon_src="$logo"
|
||||||
|
elif [ -n "$favicon" ]; then
|
||||||
|
favicon_src="$favicon"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$favicon_src" ]; then
|
||||||
|
case "$favicon_src" in
|
||||||
|
http*|/*) head_extra="<link rel=\"icon\" href=\"$favicon_src\" />" ;;
|
||||||
|
*) head_extra="<link rel=\"icon\" href=\"/$favicon_src\" />" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
head_extra=""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_page_title() {
|
||||||
|
page_title="$title"
|
||||||
|
if [ -n "$fm_title" ]; then
|
||||||
|
page_title="$fm_title - $title"
|
||||||
|
elif [ "$generate_page_title" = "true" ] && [ -n "$file" ] && [ -f "$file" ]; then
|
||||||
|
if [ "$is_home" = "true" ] && [ -n "$home_name" ]; then
|
||||||
|
page_title="$home_name - $title"
|
||||||
|
else
|
||||||
|
first_heading=$(first_heading_from_markdown "$file")
|
||||||
|
if [ -n "$first_heading" ]; then
|
||||||
|
first_heading=$(strip_markdown_text "$first_heading")
|
||||||
|
page_title="$first_heading - $title"
|
||||||
|
else
|
||||||
|
basename_no_ext=$(basename "$file" .md)
|
||||||
|
if [ "$basename_no_ext" != "index" ] && [ "$basename_no_ext" != "404_gen" ]; then
|
||||||
|
cap_basename=$(echo "$basename_no_ext" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')
|
||||||
|
page_title="$cap_basename - $title"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_og_tags() {
|
||||||
|
head_extra_og="<meta property=\"og:title\" content=\"$(escape_html_attr "$page_title")\" />"
|
||||||
|
if [ -n "$fm_description" ]; then
|
||||||
|
head_extra_og="$head_extra_og
|
||||||
|
<meta property=\"og:description\" content=\"$(escape_html_attr "$fm_description")\" />"
|
||||||
|
fi
|
||||||
|
og_url="${base_url%/}${current_url}"
|
||||||
|
head_extra_og="$head_extra_og
|
||||||
|
<meta property=\"og:url\" content=\"$(escape_html_attr "$og_url")\" />"
|
||||||
|
|
||||||
|
if [ -n "$head_extra" ]; then
|
||||||
|
head_extra="$head_extra
|
||||||
|
$head_extra_og"
|
||||||
|
else
|
||||||
|
head_extra="$head_extra_og"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_cw_url_hide() {
|
||||||
|
if [ "$is_cw_content_page" = "true" ] && [ "$cw_hide_url" = "true" ]; then
|
||||||
|
head_extra="$head_extra
|
||||||
|
<script>window.history.replaceState(null, '', '$current_url');</script>"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_composed_footer() {
|
||||||
|
final_footer="$footer"
|
||||||
|
if [ "$search_in_footer" = "true" ]; then
|
||||||
|
final_footer="$footer $SEARCH_FORM_FOOTER"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
build_composed_nav() {
|
||||||
|
final_nav="$nav"
|
||||||
|
final_header_brand="$header_brand"
|
||||||
|
final_header_search=""
|
||||||
|
if [ "$search_in_header" = "true" ]; then
|
||||||
|
final_header_search="$SEARCH_FORM_HEADER"
|
||||||
|
final_nav="$SEARCH_FORM_NAV
|
||||||
|
$nav"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prepare_post_content() {
|
||||||
content_file="$file"
|
content_file="$file"
|
||||||
if [ -n "$posts_dir" ] && [ "$file" != "$src/$posts_dir/index.md" ]; then
|
if [ -n "$posts_dir" ] && [ "$file" != "$src/$posts_dir/index.md" ]; then
|
||||||
rel_dir_of_url=$(dirname "$current_url")
|
rel_dir_of_url=$(dirname "$current_url")
|
||||||
@@ -173,121 +295,36 @@ render_markdown() {
|
|||||||
content_file="$temp_post_with_backlink"
|
content_file="$temp_post_with_backlink"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
local_template=$(find_closest "template.html" "$(dirname "$file")")
|
render_markdown() {
|
||||||
[ -z "$local_template" ] && local_template="$template"
|
file="$1"
|
||||||
|
is_home="$2"
|
||||||
|
url_override="$3"
|
||||||
|
|
||||||
closest_style_src=$(find_closest "styles.css" "$(dirname "$file")")
|
if [ -n "$url_override" ]; then
|
||||||
[ -z "$closest_style_src" ] && closest_style_src=$(find_closest "style.css" "$(dirname "$file")")
|
current_url="$url_override"
|
||||||
if [ -n "$closest_style_src" ]; then
|
|
||||||
style_rel_to_src="${closest_style_src#"$src"/}"
|
|
||||||
case "$closest_style_src" in
|
|
||||||
"$src/styles.css") style_rel_to_src="styles.css" ;;
|
|
||||||
"$src/style.css") style_rel_to_src="style.css" ;;
|
|
||||||
esac
|
|
||||||
style_path="/$(encode_url_path "${style_rel_to_src%styles.css}")"
|
|
||||||
style_path="${style_path%style.css}styles.css"
|
|
||||||
else
|
else
|
||||||
style_path="/styles.css"
|
rel_path="${file#"$src"}"
|
||||||
fi
|
rel_path="${rel_path#/}"
|
||||||
|
current_url=$(markdown_file_url "$rel_path")
|
||||||
logo_html=""
|
|
||||||
if [ "$display_logo" = "true" ] && [ -n "$logo" ]; then
|
|
||||||
logo_html="<img class=\"site-logo\" src=\"$logo\" alt=\"$title\" />"
|
|
||||||
fi
|
|
||||||
|
|
||||||
brand_text=""
|
|
||||||
if [ "$display_title" = "true" ]; then
|
|
||||||
brand_text="$title"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$logo_html" ] && [ -n "$brand_text" ]; then
|
|
||||||
header_brand="<a href=\"/index.html\">$logo_html $brand_text</a>"
|
|
||||||
elif [ -n "$logo_html" ]; then
|
|
||||||
header_brand="<a href=\"/index.html\">$logo_html</a>"
|
|
||||||
elif [ -n "$brand_text" ]; then
|
|
||||||
header_brand="<a href=\"/index.html\">$brand_text</a>"
|
|
||||||
else
|
|
||||||
header_brand="<a href=\"/index.html\">$title</a>"
|
|
||||||
fi
|
|
||||||
|
|
||||||
favicon_src=""
|
|
||||||
if [ "$logo_as_favicon" = "true" ] && [ -n "$logo" ]; then
|
|
||||||
favicon_src="$logo"
|
|
||||||
elif [ -n "$favicon" ]; then
|
|
||||||
favicon_src="$favicon"
|
|
||||||
fi
|
|
||||||
head_extra=""
|
|
||||||
if [ -n "$favicon_src" ]; then
|
|
||||||
if echo "$favicon_src" | grep -q "^http"; then
|
|
||||||
head_extra="<link rel=\"icon\" href=\"$favicon_src\" />"
|
|
||||||
elif echo "$favicon_src" | grep -q "^/"; then
|
|
||||||
head_extra="<link rel=\"icon\" href=\"$favicon_src\" />"
|
|
||||||
else
|
|
||||||
head_extra="<link rel=\"icon\" href=\"/$favicon_src\" />"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
prepare_post_content
|
||||||
|
resolve_render_template "$file"
|
||||||
|
resolve_render_style_path "$file"
|
||||||
|
build_header_brand_html
|
||||||
|
build_favicon_head
|
||||||
parse_frontmatter "$file"
|
parse_frontmatter "$file"
|
||||||
|
build_page_title
|
||||||
page_title="$title"
|
build_og_tags
|
||||||
if [ -n "$fm_title" ]; then
|
build_cw_url_hide
|
||||||
page_title="$fm_title - $title"
|
build_composed_footer
|
||||||
elif [ "$generate_page_title" = "true" ] && [ -n "$file" ] && [ -f "$file" ]; then
|
build_composed_nav
|
||||||
if [ "$is_home" = "true" ] && [ -n "$home_name" ]; then
|
|
||||||
page_title="$home_name - $title"
|
|
||||||
else
|
|
||||||
first_heading=$(first_heading_from_markdown "$file")
|
|
||||||
if [ -n "$first_heading" ]; then
|
|
||||||
first_heading=$(strip_markdown_text "$first_heading")
|
|
||||||
page_title="$first_heading - $title"
|
|
||||||
else
|
|
||||||
basename_no_ext=$(basename "$file" .md)
|
|
||||||
if [ "$basename_no_ext" != "index" ] && [ "$basename_no_ext" != "404_gen" ]; then
|
|
||||||
cap_basename=$(echo "$basename_no_ext" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')
|
|
||||||
page_title="$cap_basename - $title"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
head_extra_og="<meta property=\"og:title\" content=\"$(escape_html_attr "$page_title")\" />"
|
|
||||||
if [ -n "$fm_description" ]; then
|
|
||||||
head_extra_og="$head_extra_og
|
|
||||||
<meta property=\"og:description\" content=\"$(escape_html_attr "$fm_description")\" />"
|
|
||||||
fi
|
|
||||||
og_url="${base_url%/}${current_url}"
|
|
||||||
head_extra_og="$head_extra_og
|
|
||||||
<meta property=\"og:url\" content=\"$(escape_html_attr "$og_url")\" />"
|
|
||||||
|
|
||||||
if [ -n "$head_extra" ]; then
|
|
||||||
head_extra="$head_extra
|
|
||||||
$head_extra_og"
|
|
||||||
else
|
|
||||||
head_extra="$head_extra_og"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$is_cw_content_page" = "true" ] && [ "$cw_hide_url" = "true" ]; then
|
|
||||||
head_extra="$head_extra
|
|
||||||
<script>window.history.replaceState(null, '', '$current_url');</script>"
|
|
||||||
fi
|
|
||||||
|
|
||||||
final_footer="$footer"
|
|
||||||
if [ "$search_in_footer" = "true" ]; then
|
|
||||||
final_footer="$footer $SEARCH_FORM_FOOTER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
final_nav="$nav"
|
|
||||||
final_header_brand="$header_brand"
|
|
||||||
final_header_search=""
|
|
||||||
if [ "$search_in_header" = "true" ]; then
|
|
||||||
final_header_search="$SEARCH_FORM_HEADER"
|
|
||||||
final_nav="$SEARCH_FORM_NAV
|
|
||||||
$nav"
|
|
||||||
fi
|
|
||||||
|
|
||||||
ENABLE_HEADER_LINKS="$enable_header_links" CUSTOM_ADMONITIONS="$custom_admonitions" MARKDOWN_SITE_ROOT="$src" MARKDOWN_FALLBACK_FILE="$script_dir/styles/$style.css" sh "$script_dir/markdown.sh" "$content_file" | AWK_LANG="$lang" AWK_CURRENT_URL="$current_url" AWK_TITLE="$page_title" AWK_NAV="$final_nav" AWK_FOOTER="$final_footer" AWK_STYLE_PATH="${style_path}" AWK_HEADER_BRAND="$final_header_brand" AWK_HEADER_SEARCH="$final_header_search" AWK_HEAD_EXTRA="$head_extra" AWK_VERSION="$asset_version" AWK_CONTENT_WARNING="$fm_content_warning" awk -f "$awk_dir/render_template.awk" "$local_template"
|
ENABLE_HEADER_LINKS="$enable_header_links" CUSTOM_ADMONITIONS="$custom_admonitions" MARKDOWN_SITE_ROOT="$src" MARKDOWN_FALLBACK_FILE="$script_dir/styles/$style.css" sh "$script_dir/markdown.sh" "$content_file" | AWK_LANG="$lang" AWK_CURRENT_URL="$current_url" AWK_TITLE="$page_title" AWK_NAV="$final_nav" AWK_FOOTER="$final_footer" AWK_STYLE_PATH="${style_path}" AWK_HEADER_BRAND="$final_header_brand" AWK_HEADER_SEARCH="$final_header_search" AWK_HEAD_EXTRA="$head_extra" AWK_VERSION="$asset_version" AWK_CONTENT_WARNING="$fm_content_warning" awk -f "$awk_dir/render_template.awk" "$local_template"
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_content_warning_page() {
|
generate_content_warning_page() {
|
||||||
_fm_title="$1"
|
_fm_title="$1"
|
||||||
_fm_content_warning="$2"
|
_fm_content_warning="$2"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
# shellcheck disable=SC2016,SC2030,SC2031
|
||||||
|
|
||||||
shell_quote() {
|
shell_quote() {
|
||||||
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
|
printf "'%s'" "$(printf '%s' "$1" | sed "s/'/'\\\\''/g")"
|
||||||
|
|||||||
79
markdown.sh
79
markdown.sh
@@ -3,14 +3,11 @@
|
|||||||
script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd)
|
script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd)
|
||||||
awk_dir="$script_dir/awk"
|
awk_dir="$script_dir/awk"
|
||||||
|
|
||||||
sed_inplace() {
|
run_awk() {
|
||||||
script="$1"
|
_ra_awk_file="$1"
|
||||||
file="$2"
|
shift
|
||||||
tmp="${file}.tmp.$$"
|
if ! awk -f "$_ra_awk_file" "$@"; then
|
||||||
if sed "$script" "$file" > "$tmp" && mv "$tmp" "$file"; then
|
echo "Error: AWK failed: $_ra_awk_file" >&2
|
||||||
return 0
|
|
||||||
else
|
|
||||||
rm -f "$tmp"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -21,36 +18,20 @@ cat "$@" > "$temp_file"
|
|||||||
|
|
||||||
trap 'rm -f "$temp_file" "$temp_file.tmp" "$temp_file.fm"' EXIT INT TERM
|
trap 'rm -f "$temp_file" "$temp_file.tmp" "$temp_file.fm"' EXIT INT TERM
|
||||||
|
|
||||||
# Frontmatter
|
|
||||||
fm_file="$temp_file.fm"
|
fm_file="$temp_file.fm"
|
||||||
: > "$fm_file"
|
: > "$fm_file"
|
||||||
awk -v fm_out="$fm_file" -f "$awk_dir/frontmatter.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
|
|
||||||
# Mask
|
run_awk "$awk_dir/frontmatter.awk" -v fm_out="$fm_file" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
awk -f "$awk_dir/mask_inline_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
awk -f "$awk_dir/mask_plain.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
|
|
||||||
# Reference links
|
run_awk "$awk_dir/mask_inline_code.awk" "$temp_file" \
|
||||||
refs=$(awk '/^\[[^\]]+\]: */' "$temp_file")
|
| run_awk "$awk_dir/mask_plain.awk" \
|
||||||
IFS='
|
| run_awk "$awk_dir/reference_links.awk" \
|
||||||
'
|
> "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
for ref in $refs; do
|
|
||||||
ref_id=$(echo "$ref" | sed 's/^\[\(.*\)\]: .*/\1/')
|
|
||||||
ref_url=$(echo "$ref" | sed 's/^\[.*\]: \([^ ]*\).*/\1/')
|
|
||||||
ref_title=$(echo "$ref" | sed -n 's/^\[.*\]: [^ ]* "\(.*\)"/\1/p' | sed 's@|@!@g')
|
|
||||||
sed_inplace "s|!\[\([^]]*\)\]\[$ref_id\]|<img src=\"$ref_url\" title=\"$ref_title\" alt=\"\1\" />|g" "$temp_file"
|
|
||||||
sed_inplace "s|\[\([^]]*\)\]\[$ref_id\]|<a href=\"$ref_url\" title=\"$ref_title\">\1</a>|g" "$temp_file"
|
|
||||||
sed_inplace "s|!\[$ref_id\]\[\]|<img src=\"$ref_url\" title=\"$ref_title\" alt=\"$ref_id\" />|g" "$temp_file"
|
|
||||||
sed_inplace "s|\[$ref_id\]\[\]|<a href=\"$ref_url\" title=\"$ref_title\">$ref_id</a>|g" "$temp_file"
|
|
||||||
done
|
|
||||||
sed_inplace "/^\[[^\]]*\]: */d" "$temp_file"
|
|
||||||
|
|
||||||
# Blocks
|
|
||||||
|
|
||||||
loop_count=0
|
loop_count=0
|
||||||
max_iterations=100
|
max_iterations=100
|
||||||
while grep '^>' "$temp_file" >/dev/null; do
|
while grep -q '^>' "$temp_file"; do
|
||||||
awk -f "$awk_dir/blockquote.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
run_awk "$awk_dir/blockquote.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
||||||
loop_count=$((loop_count + 1))
|
loop_count=$((loop_count + 1))
|
||||||
if [ "$loop_count" -gt "$max_iterations" ]; then
|
if [ "$loop_count" -gt "$max_iterations" ]; then
|
||||||
echo "Warning: Blockquote processing exceeded $max_iterations iterations on $1. Breaking to prevent infinite loop." >&2
|
echo "Warning: Blockquote processing exceeded $max_iterations iterations on $1. Breaking to prevent infinite loop." >&2
|
||||||
@@ -58,25 +39,19 @@ while grep '^>' "$temp_file" >/dev/null; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
awk -v custom_admonitions="$CUSTOM_ADMONITIONS" -f "$awk_dir/blockquote_to_admonition.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
run_awk "$awk_dir/blockquote_to_admonition.awk" -v custom_admonitions="$CUSTOM_ADMONITIONS" "$temp_file" \
|
||||||
awk -f "$awk_dir/fenced_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
| run_awk "$awk_dir/fenced_code.awk" \
|
||||||
awk -f "$awk_dir/indented_code.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
| run_awk "$awk_dir/indented_code.awk" \
|
||||||
awk -f "$awk_dir/pipe_tables.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
| run_awk "$awk_dir/pipe_tables.awk" \
|
||||||
awk -f "$awk_dir/definition_lists.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
| run_awk "$awk_dir/definition_lists.awk" \
|
||||||
awk -f "$awk_dir/lists.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
| run_awk "$awk_dir/lists.awk" \
|
||||||
|
| run_awk "$awk_dir/toc.awk" \
|
||||||
|
| run_awk "$awk_dir/footnotes.awk" \
|
||||||
|
| run_awk "$awk_dir/breaks.awk" \
|
||||||
|
| run_awk "$awk_dir/paragraphs.awk" \
|
||||||
|
| run_awk "$awk_dir/emoji.awk" -v emoji_file="$awk_dir/emoji.tsv" \
|
||||||
|
| run_awk "$awk_dir/markdown_inline.awk" \
|
||||||
|
| run_awk "$awk_dir/headers.awk" -v enable_header_links="$ENABLE_HEADER_LINKS" \
|
||||||
|
| run_awk "$awk_dir/markdown_embed.awk" -v input_file="$1" -v site_root="$MARKDOWN_SITE_ROOT" -v fallback_file="$MARKDOWN_FALLBACK_FILE" -v script_dir="$script_dir"
|
||||||
|
|
||||||
# TOC
|
rm -f "$temp_file"
|
||||||
awk -f "$awk_dir/toc.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
# Footnotes
|
|
||||||
awk -f "$awk_dir/footnotes.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
|
|
||||||
# Spacing
|
|
||||||
awk -f "$awk_dir/breaks.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
awk -f "$awk_dir/paragraphs.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
|
|
||||||
# Inline styles
|
|
||||||
awk -v emoji_file="$awk_dir/emoji.tsv" -f "$awk_dir/emoji.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
awk -f "$awk_dir/markdown_inline.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
awk -v enable_header_links="$ENABLE_HEADER_LINKS" -f "$awk_dir/headers.awk" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file"
|
|
||||||
awk -v input_file="$1" -v site_root="$MARKDOWN_SITE_ROOT" -v fallback_file="$MARKDOWN_FALLBACK_FILE" -v script_dir="$script_dir" -f "$awk_dir/markdown_embed.awk" "$temp_file"
|
|
||||||
rm "$temp_file"
|
|
||||||
|
|||||||
106
tests/test_config.sh
Executable file
106
tests/test_config.sh
Executable file
@@ -0,0 +1,106 @@
|
|||||||
|
test_config_defaults() {
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
|
||||||
|
assert_eq "kewt" "$title" "default title"
|
||||||
|
assert_eq "kewt" "$style" "default style"
|
||||||
|
assert_eq "en" "$lang" "default lang"
|
||||||
|
assert_eq "false" "$draft_by_default" "default draft_by_default"
|
||||||
|
assert_eq "true" "$dir_indexes" "default dir_indexes"
|
||||||
|
assert_eq "true" "$single_file_index" "default single_file_index"
|
||||||
|
assert_eq "false" "$flatten" "default flatten"
|
||||||
|
assert_eq "Home" "$home_name" "default home_name"
|
||||||
|
assert_eq "true" "$show_home_in_nav" "default show_home_in_nav"
|
||||||
|
assert_eq "false" "$generate_feed" "default generate_feed"
|
||||||
|
assert_eq "rss.xml" "$feed_file" "default feed_file"
|
||||||
|
assert_eq "12" "$posts_per_page" "default posts_per_page"
|
||||||
|
assert_eq "false" "$generate_tags" "default generate_tags"
|
||||||
|
assert_eq "tags" "$tags_dir" "default tags_dir"
|
||||||
|
assert_eq "false" "$generate_search" "default generate_search"
|
||||||
|
assert_eq "true" "$enable_header_links" "default enable_header_links"
|
||||||
|
assert_eq "true" "$cw_hide_url" "default cw_hide_url"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_config_reset() {
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
title="custom"
|
||||||
|
style="nord"
|
||||||
|
generate_feed="true"
|
||||||
|
reset_config
|
||||||
|
|
||||||
|
assert_eq "kewt" "$title" "reset title"
|
||||||
|
assert_eq "kewt" "$style" "reset style"
|
||||||
|
assert_eq "false" "$generate_feed" "reset generate_feed"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_config_load() {
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
|
||||||
|
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
|
||||||
|
mkdir -p "$tmpdir"
|
||||||
|
cat > "$tmpdir/test.conf" <<EOF
|
||||||
|
title = "My Site"
|
||||||
|
style = "nord"
|
||||||
|
generate_feed = true
|
||||||
|
base_url = "https://example.com"
|
||||||
|
posts_per_page = 5
|
||||||
|
EOF
|
||||||
|
|
||||||
|
reset_config
|
||||||
|
load_config "$tmpdir/test.conf"
|
||||||
|
|
||||||
|
assert_eq "My Site" "$title" "load title"
|
||||||
|
assert_eq "nord" "$style" "load style"
|
||||||
|
assert_eq "true" "$generate_feed" "load generate_feed"
|
||||||
|
assert_eq "https://example.com" "$base_url" "load base_url"
|
||||||
|
assert_eq "5" "$posts_per_page" "load posts_per_page"
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_config_load_quoted() {
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
|
||||||
|
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
|
||||||
|
mkdir -p "$tmpdir"
|
||||||
|
cat > "$tmpdir/test.conf" <<'EOF'
|
||||||
|
footer = "made with <a href=\"https://kewt.krzak.org\">kewt</a>"
|
||||||
|
nav_links = "[Docs](/docs), [About](/about)"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
reset_config
|
||||||
|
load_config "$tmpdir/test.conf"
|
||||||
|
|
||||||
|
assert_eq 'made with <a href="https://kewt.krzak.org">kewt</a>' "$footer" "load quoted footer"
|
||||||
|
assert_eq "[Docs](/docs), [About](/about)" "$nav_links" "load quoted nav_links"
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_config_load_skips_comments() {
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
|
||||||
|
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
|
||||||
|
mkdir -p "$tmpdir"
|
||||||
|
cat > "$tmpdir/test.conf" <<EOF
|
||||||
|
# This is a comment
|
||||||
|
title = "Test Site"
|
||||||
|
# Another comment
|
||||||
|
style = "kewt"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
reset_config
|
||||||
|
load_config "$tmpdir/test.conf"
|
||||||
|
|
||||||
|
assert_eq "Test Site" "$title" "load with comments title"
|
||||||
|
assert_eq "kewt" "$style" "load with comments style"
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_config_load_missing_file() {
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
reset_config
|
||||||
|
load_config "/nonexistent/path/site.conf"
|
||||||
|
|
||||||
|
assert_eq "kewt" "$title" "missing file keeps defaults"
|
||||||
|
}
|
||||||
92
tests/test_metadata.sh
Executable file
92
tests/test_metadata.sh
Executable file
@@ -0,0 +1,92 @@
|
|||||||
|
test_strip_markdown_bold() {
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
result=$(strip_markdown_text "**bold text**")
|
||||||
|
assert_eq "bold text" "$result" "strip bold"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_strip_markdown_italic() {
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
result=$(strip_markdown_text "*italic text*")
|
||||||
|
assert_eq "italic text" "$result" "strip italic"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_strip_markdown_link() {
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
result=$(strip_markdown_text "[link](http://example.com)")
|
||||||
|
assert_eq "link" "$result" "strip link"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_strip_markdown_code() {
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
result=$(strip_markdown_text "\`code\`")
|
||||||
|
assert_eq "code" "$result" "strip code"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_first_heading() {
|
||||||
|
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
|
||||||
|
mkdir -p "$tmpdir"
|
||||||
|
printf '# Hello World\n\nSome content\n' > "$tmpdir/test.md"
|
||||||
|
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
result=$(first_heading_from_markdown "$tmpdir/test.md")
|
||||||
|
assert_eq "Hello World" "$result" "first heading"
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_first_heading_no_heading() {
|
||||||
|
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
|
||||||
|
mkdir -p "$tmpdir"
|
||||||
|
printf 'Random content\n' > "$tmpdir/test.md"
|
||||||
|
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
result=$(first_heading_from_markdown "$tmpdir/test.md")
|
||||||
|
assert_eq "" "$result" "no heading returns empty"
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_parse_frontmatter() {
|
||||||
|
tmpdir="${TMPDIR:-/tmp}/kewt_test.$$"
|
||||||
|
mkdir -p "$tmpdir"
|
||||||
|
cat > "$tmpdir/test.md" <<'EOF'
|
||||||
|
---
|
||||||
|
title = "My Post"
|
||||||
|
date = "2026-05-20 10:00"
|
||||||
|
draft = false
|
||||||
|
description = "A test post"
|
||||||
|
tags = "test, example"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Content
|
||||||
|
EOF
|
||||||
|
|
||||||
|
export KEWT_TMPDIR="$tmpdir"
|
||||||
|
export awk_dir="$project_dir/awk"
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
. "$project_dir/lib/config.sh"
|
||||||
|
|
||||||
|
parse_frontmatter "$tmpdir/test.md"
|
||||||
|
|
||||||
|
assert_eq "My Post" "$fm_title" "parse title"
|
||||||
|
assert_eq "2026-05-20 10:00" "$fm_date" "parse date"
|
||||||
|
assert_eq "false" "$fm_draft" "parse draft"
|
||||||
|
assert_eq "A test post" "$fm_description" "parse description"
|
||||||
|
assert_eq "test, example" "$fm_tags" "parse tags"
|
||||||
|
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_set_post_datetime_from_date() {
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
set_post_datetime "2026-05-20 14:30" "fallback"
|
||||||
|
assert_eq "2026-05-20" "$post_date" "post date from date field"
|
||||||
|
assert_eq "14:30" "$post_time" "post time from date field"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_set_post_datetime_from_filename() {
|
||||||
|
. "$project_dir/lib/metadata.sh"
|
||||||
|
set_post_datetime "" "2026-05-20-14-30-slug"
|
||||||
|
assert_eq "2026-05-20" "$post_date" "post date from filename"
|
||||||
|
assert_eq "14:30" "$post_time" "post time from filename"
|
||||||
|
}
|
||||||
93
tests/test_runner.sh
Executable file
93
tests/test_runner.sh
Executable file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
script_dir=$(CDPATH="" cd -- "$(dirname -- "$0")" && pwd)
|
||||||
|
project_dir=$(CDPATH="" cd -- "$script_dir/.." && pwd)
|
||||||
|
|
||||||
|
passed=0
|
||||||
|
failed=0
|
||||||
|
total=0
|
||||||
|
|
||||||
|
assert_eq() {
|
||||||
|
total=$((total + 1))
|
||||||
|
expected="$1"
|
||||||
|
actual="$2"
|
||||||
|
label="$3"
|
||||||
|
|
||||||
|
if [ "$expected" = "$actual" ]; then
|
||||||
|
passed=$((passed + 1))
|
||||||
|
printf " PASS: %s\n" "$label"
|
||||||
|
else
|
||||||
|
failed=$((failed + 1))
|
||||||
|
printf " FAIL: %s\n" "$label"
|
||||||
|
printf " expected: %s\n" "$expected"
|
||||||
|
printf " actual: %s\n" "$actual"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_contains() {
|
||||||
|
total=$((total + 1))
|
||||||
|
needle="$1"
|
||||||
|
haystack="$2"
|
||||||
|
label="$3"
|
||||||
|
|
||||||
|
case "$haystack" in
|
||||||
|
*"$needle"*)
|
||||||
|
passed=$((passed + 1))
|
||||||
|
printf " PASS: %s\n" "$label"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
failed=$((failed + 1))
|
||||||
|
printf " FAIL: %s\n" "$label"
|
||||||
|
printf " expected to contain: %s\n" "$needle"
|
||||||
|
printf " actual: %s\n" "$haystack"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_file_exists() {
|
||||||
|
total=$((total + 1))
|
||||||
|
path="$1"
|
||||||
|
label="$2"
|
||||||
|
|
||||||
|
if [ -f "$path" ]; then
|
||||||
|
passed=$((passed + 1))
|
||||||
|
printf " PASS: %s\n" "$label"
|
||||||
|
else
|
||||||
|
failed=$((failed + 1))
|
||||||
|
printf " FAIL: %s\n" "$label"
|
||||||
|
printf " file not found: %s\n" "$path"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_test_file() {
|
||||||
|
test_file="$1"
|
||||||
|
test_name=$(basename "$test_file" .sh)
|
||||||
|
printf "\n== %s ==\n" "$test_name"
|
||||||
|
|
||||||
|
saved_total=$total
|
||||||
|
saved_passed=$passed
|
||||||
|
saved_failed=$failed
|
||||||
|
|
||||||
|
. "$test_file"
|
||||||
|
|
||||||
|
for func in $(grep '^test_' "$test_file" | sed 's/().*//' | sort -u); do
|
||||||
|
$func
|
||||||
|
done
|
||||||
|
|
||||||
|
file_total=$((total - saved_total))
|
||||||
|
file_passed=$((passed - saved_passed))
|
||||||
|
file_failed=$((failed - saved_failed))
|
||||||
|
if [ "$file_total" -eq 0 ]; then
|
||||||
|
printf " (no tests found)\n"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for test_file in "$script_dir"/test_*.sh; do
|
||||||
|
[ "$(basename "$test_file")" = "test_runner.sh" ] && continue
|
||||||
|
run_test_file "$test_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "\n== Results ==\n"
|
||||||
|
printf " %d passed, %d failed, %d total\n" "$passed" "$failed" "$total"
|
||||||
|
|
||||||
|
[ "$failed" -eq 0 ] && exit 0 || exit 1
|
||||||
71
tests/test_runtime.sh
Executable file
71
tests/test_runtime.sh
Executable file
@@ -0,0 +1,71 @@
|
|||||||
|
test_url_encode_spaces() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(encode_url_path "hello world")
|
||||||
|
assert_eq "hello%20world" "$result" "encode spaces"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_url_encode_hash() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(encode_url_path "file#section")
|
||||||
|
assert_eq "file%23section" "$result" "encode hash"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_url_encode_question() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(encode_url_path "search?q=test")
|
||||||
|
assert_eq "search%3Fq=test" "$result" "encode question mark"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_url_encode_percent() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(encode_url_path "100%")
|
||||||
|
assert_eq "100%25" "$result" "encode percent"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_markdown_file_url() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(markdown_file_url "docs/readme.md")
|
||||||
|
assert_eq "/docs/readme.html" "$result" "markdown file url"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_directory_index_url_root() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(directory_index_url "")
|
||||||
|
assert_eq "/index.html" "$result" "root index url"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_directory_index_url_subdir() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(directory_index_url "docs")
|
||||||
|
assert_eq "/docs/index.html" "$result" "subdir index url"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_directory_index_url_dot() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(directory_index_url ".")
|
||||||
|
assert_eq "/index.html" "$result" "dot index url"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_format_rfc2822_utc() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(format_rfc2822_utc "2026-05-20" "14:30")
|
||||||
|
assert_eq "Wed, 20 May 2026 14:30:00 +0000" "$result" "rfc2822 format"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_format_rfc2822_utc_default_time() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(format_rfc2822_utc "2026-01-01")
|
||||||
|
assert_eq "Thu, 01 Jan 2026 00:00:00 +0000" "$result" "rfc2822 default time"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_trim_whitespace() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(trim_whitespace " hello ")
|
||||||
|
assert_eq "hello" "$result" "trim whitespace"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_trim_whitespace_tabs() {
|
||||||
|
. "$project_dir/lib/runtime.sh"
|
||||||
|
result=$(trim_whitespace " world ")
|
||||||
|
assert_eq "world" "$result" "trim tabs"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user