ssh git@grit.deadkey.org man

Commit c0f4380 h

Pat Ambrosio · 26-08-27 12:40

List section entries as rows, in title case

Changes: 1 file +26 -5

Changes (Side-by-Side)

share/jenny/lib/components.sh +26 -5

render_index () {
246 # not ordered relative to each other -- they are addressed, not published. 246 # not ordered relative to each other -- they are addressed, not published.
247 # Whether one is versioned is a directory convention (pages/study/x/v2/), not 247 # Whether one is versioned is a directory convention (pages/study/x/v2/), not
248 # something jenny knows about. 248 # something jenny knows about.
249 # title_case <text>
250 # Capitalises each word. Used only for labels derived from a path segment --
251 # "migration driven development" is a slug read aloud, not something anyone
252 # wrote, so presenting it lowercase looks like a mistake.
253 #
254 # A page's own title is never passed through here: the author chose its casing
255 # and "Method, an Introduction" must not become "Method, An Introduction".
256 title_case() {
257 printf '%s' "$1" | "$AWK" '{
258 for (i = 1; i <= NF; i++)
259 $i = toupper(substr($i, 1, 1)) substr($i, 2)
260 print
261 }'
262 }
263
249 # generate_section_indexes <pages_dir> 264 # generate_section_indexes <pages_dir>
250 # Writes a listing page for every directory under pages/ that has no index.md 265 # Writes a listing page for every directory under pages/ that has no index.md
251 # of its own, so a breadcrumb segment always leads somewhere. 266 # of its own, so a breadcrumb segment always leads somewhere.
generate_section_indexes() {
279 294
280 rel=${dir#"$pages_dir"/} 295 rel=${dir#"$pages_dir"/}
281 name=$(basename "$dir") 296 name=$(basename "$dir")
282 title=$(printf '%s' "$name" | tr '-' ' ')
297 title=$(title_case "$(printf '%s' "$name" | tr '-' ' ')")
283 298
284 listing="" 299 listing=""
285 count=0 300 count=0
286 # Pages first, then subsections, each alphabetical. Two kinds of thing in 301 # Pages first, then subsections, each alphabetical. Two kinds of thing in
287 # one list, so they are grouped rather than interleaved by name. 302 # one list, so they are grouped rather than interleaved by name.
303 #
304 # One link per row, separated by a blank line: markdown joins adjacent
305 # lines into a single paragraph, so without the blank line every entry
306 # ran together on one row.
288 while IFS= read -r entry; do 307 while IFS= read -r entry; do
289 [ -n "$entry" ] || continue 308 [ -n "$entry" ] || continue
290 [ "$(basename "$entry")" = "index.md" ] && continue 309 [ "$(basename "$entry")" = "index.md" ] && continue
291 slug=$(basename "${entry%.md}") 310 slug=$(basename "${entry%.md}")
292 label=$(get_title "$entry") 311 label=$(get_title "$entry")
293 [ -n "$label" ] || label=$(printf '%s' "$slug" | tr '-' ' ')
294 listing="$listing- [$label](/$rel/$slug)
312 [ -n "$label" ] || label=$(title_case "$(printf '%s' "$slug" | tr '-' ' ')")
313 listing="$listing[$label](/$rel/$slug)
314
295 " 315 "
296 count=$((count + 1)) 316 count=$((count + 1))
297 done < <(find "$dir" -maxdepth 1 -type f -name '*.md' | LC_ALL=C sort) 317 done < <(find "$dir" -maxdepth 1 -type f -name '*.md' | LC_ALL=C sort)
generate_section_indexes() {
299 while IFS= read -r entry; do 319 while IFS= read -r entry; do
300 [ -n "$entry" ] || continue 320 [ -n "$entry" ] || continue
301 sub=$(basename "$entry") 321 sub=$(basename "$entry")
302 sublabel=$(printf '%s' "$sub" | tr '-' ' ')
303 listing="$listing- [$sublabel](/$rel/$sub/)
322 sublabel=$(title_case "$(printf '%s' "$sub" | tr '-' ' ')")
323 listing="$listing[$sublabel](/$rel/$sub/)
324
304 " 325 "
305 count=$((count + 1)) 326 count=$((count + 1))
306 done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d | LC_ALL=C sort) 327 done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d | LC_ALL=C sort)

Raw

commit c0f4380011ee673d41dc5275ed472e9c000fea9f
Author: Pat Ambrosio <cp.ambrosio@gmail.com>
Date:   Thu Aug 27 12:40:48 2026 +0800

    List section entries as rows, in title case
    
    The generated listing used a bullet list and lowercase labels taken
    straight from the path. Bullets are for a list of things in prose; this is
    a directory of pages, so each gets its own row.
    
    The blank line between entries is load-bearing: markdown joins adjacent
    lines into one paragraph, so without it every link ran together on a
    single row.
    
    Labels derived from a path segment are title cased -- "migration driven
    development" is a slug read aloud, not something anyone wrote, and
    presenting it lowercase looks like a mistake. A page's own title is never
    re-cased: the author chose it, and "Method, an Introduction" must not
    become "Method, An Introduction".
    
    Tests cover both halves of that distinction, and that entries render as
    separate rows rather than as list items or one run-together line.
    
    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01WnSAstgnDYdKPwLGv1YZE5

diff --git a/share/jenny/lib/components.sh b/share/jenny/lib/components.sh
index 479c000..9733ea2 100644
--- a/share/jenny/lib/components.sh
+++ b/share/jenny/lib/components.sh
@@ -246,6 +246,21 @@ render_index () {
 # not ordered relative to each other -- they are addressed, not published.
 # Whether one is versioned is a directory convention (pages/study/x/v2/), not
 # something jenny knows about.
+# title_case <text>
+# Capitalises each word. Used only for labels derived from a path segment --
+# "migration driven development" is a slug read aloud, not something anyone
+# wrote, so presenting it lowercase looks like a mistake.
+#
+# A page's own title is never passed through here: the author chose its casing
+# and "Method, an Introduction" must not become "Method, An Introduction".
+title_case() {
+  printf '%s' "$1" | "$AWK" '{
+    for (i = 1; i <= NF; i++)
+      $i = toupper(substr($i, 1, 1)) substr($i, 2)
+    print
+  }'
+}
+
 # generate_section_indexes <pages_dir>
 # Writes a listing page for every directory under pages/ that has no index.md
 # of its own, so a breadcrumb segment always leads somewhere.
@@ -279,19 +294,24 @@ generate_section_indexes() {
 
     rel=${dir#"$pages_dir"/}
     name=$(basename "$dir")
-    title=$(printf '%s' "$name" | tr '-' ' ')
+    title=$(title_case "$(printf '%s' "$name" | tr '-' ' ')")
 
     listing=""
     count=0
     # Pages first, then subsections, each alphabetical. Two kinds of thing in
     # one list, so they are grouped rather than interleaved by name.
+    #
+    # One link per row, separated by a blank line: markdown joins adjacent
+    # lines into a single paragraph, so without the blank line every entry
+    # ran together on one row.
     while IFS= read -r entry; do
       [ -n "$entry" ] || continue
       [ "$(basename "$entry")" = "index.md" ] && continue
       slug=$(basename "${entry%.md}")
       label=$(get_title "$entry")
-      [ -n "$label" ] || label=$(printf '%s' "$slug" | tr '-' ' ')
-      listing="$listing- [$label](/$rel/$slug)
+      [ -n "$label" ] || label=$(title_case "$(printf '%s' "$slug" | tr '-' ' ')")
+      listing="$listing[$label](/$rel/$slug)
+
 "
       count=$((count + 1))
     done < <(find "$dir" -maxdepth 1 -type f -name '*.md' | LC_ALL=C sort)
@@ -299,8 +319,9 @@ generate_section_indexes() {
     while IFS= read -r entry; do
       [ -n "$entry" ] || continue
       sub=$(basename "$entry")
-      sublabel=$(printf '%s' "$sub" | tr '-' ' ')
-      listing="$listing- [$sublabel](/$rel/$sub/)
+      sublabel=$(title_case "$(printf '%s' "$sub" | tr '-' ' ')")
+      listing="$listing[$sublabel](/$rel/$sub/)
+
 "
       count=$((count + 1))
     done < <(find "$dir" -mindepth 1 -maxdepth 1 -type d | LC_ALL=C sort)