Skip to content

Commit ef85796

Browse files
committed
Add support for section and inter-post links
1 parent 19881ca commit ef85796

File tree

8 files changed

+127
-41
lines changed

8 files changed

+127
-41
lines changed

blog/build.rkt

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,19 @@
1010
racket/promise
1111
racket/sequence
1212
racket/serialize
13+
scribble/core
1314
scribble/xref
1415
setup/xref
1516
threading
1617
(only-in xml write-xexpr)
1718

18-
"markdown/post.rkt"
19-
"paths.rkt"
2019
"build/metadata.rkt"
2120
"build/render/scribble.rkt"
2221
"build/render/feed.rkt"
23-
"build/render/page.rkt")
22+
"build/render/page.rkt"
23+
"lang/metadata.rkt"
24+
"markdown/post.rkt"
25+
"paths.rkt")
2426

2527
(define num-posts-per-page 10)
2628

@@ -39,9 +41,23 @@
3941
(path-replace-extension #".sxref")
4042
(build-path build-dir _)))
4143

44+
;; Functions like `other-doc` assume that each top-level document has the tag
45+
;; '(part "top") on its top-level section. This is only ensured by
46+
;; setup/scribble, which we are not using, so we have to add it manually.
47+
(define (ensure-top-tag main-part)
48+
(if (member '(part "top") (part-tags main-part))
49+
main-part
50+
(struct-copy part main-part
51+
[tags (cons '(part "top") (part-tags main-part))])))
52+
53+
(define (set-blog-tag-prefix main-part path-str)
54+
(struct-copy part main-part [tag-prefix (blog-post-path->tag-prefix path-str)]))
55+
4256
(define (markdown-post file-name)
4357
(define path (build-path posts-dir file-name))
44-
(define main-part-promise (delay (parse-markdown-post (file->string path) path)))
58+
(define main-part-promise (delay (~> (parse-markdown-post (file->string path) path)
59+
ensure-top-tag
60+
(set-blog-tag-prefix file-name))))
4561
(post-dep path main-part-promise))
4662

4763
(define all-post-deps
@@ -95,16 +111,21 @@
95111

96112
(define (render-scribble render% main-part out-path
97113
#:dest-dir [dest-dir (path-only out-path)]
114+
#:xrefs-in [xref-in-paths '()]
98115
#:xref-out [xref-out-path #f])
99116
(define main-parts (list main-part))
100117
(define out-paths (list out-path))
101118
(define renderer (new render% [dest-dir dest-dir]))
102119

103120
(define traverse-info (send renderer traverse main-parts out-paths))
104121
(define collect-info (send renderer collect main-parts out-paths traverse-info))
122+
123+
(for ([path (in-list xref-in-paths)])
124+
(define xref-in (call-with-input-file* path read))
125+
(send renderer deserialize-info xref-in collect-info))
105126
(xref-transfer-info renderer collect-info (load-collections-xref))
106-
(define resolve-info (send renderer resolve main-parts out-paths collect-info))
107127

128+
(define resolve-info (send renderer resolve main-parts out-paths collect-info))
108129
(match-define (list render-result)
109130
(send renderer render main-parts out-paths resolve-info))
110131

@@ -172,7 +193,8 @@
172193
(local-require (only-in "posts/about-me.scrbl" [doc main-part]))
173194
(render-scribble (blog-standalone-page-render% standalone-page)
174195
main-part
175-
(reroot-path site-path output-dir)))
196+
(reroot-path site-path output-dir)
197+
#:xrefs-in (map post-dep-xref-path all-post-deps)))
176198

177199
(define (build-sitemap posts)
178200
(define site-path "/sitemap.txt")

blog/build/render/scribble.rkt

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
(only-in xml write-xexpr xexpr/c)
2525

2626
"../../lang/post-language.rkt"
27+
"../../paths.rkt"
2728
"../metadata.rkt"
2829
"highlight/pygments.rkt"
2930
"util.rkt")
@@ -85,8 +86,10 @@
8586
(λ (tag) (tag->query-string tag)))))
8687

8788
; values associated with tags during the collect pass
88-
(struct blog-post (title path) #:prefab)
89-
(struct blog-post-anchor (title path anchor) #:prefab)
89+
(serializable-struct blog-page (title path) #:transparent
90+
#:guard (struct-guard/c content? site-path?))
91+
(serializable-struct blog-page-anchor (title path anchor) #:transparent
92+
#:guard (struct-guard/c content? site-path? string?))
9093

9194
(define header-depth->html-tag
9295
(match-lambda
@@ -151,7 +154,8 @@
151154
fns))
152155

153156
(define/overment (render-one part ri output-file)
154-
(parameterize ([current-output-file output-file])
157+
(parameterize ([current-output-file output-file]
158+
[current-top-part part])
155159
(inner/hijack render-one part ri output-file)))
156160

157161
(define/override (render-nested-flow i part ri starting-item?)
@@ -175,6 +179,12 @@
175179
(define/override (set-external-tag-path p)
176180
(set! external-tag-path (string->url p)))
177181

182+
;; Returns the (absolute) path portion of the URL for the page that contains
183+
;; the part currently being rendered.
184+
(define/public (get-current-site-path)
185+
(path->string (build-path "/" (find-relative-path (get-dest-directory)
186+
(current-output-file)))))
187+
178188
;; -------------------------------------------------------------------------
179189
;; collect
180190

@@ -183,8 +193,8 @@
183193
; racket doc reference; index 4 corresponds to `whole-page?`
184194
[(? vector? dest) (vector-ref dest 4)]
185195
; blog references
186-
[(? blog-post?) #t]
187-
[(? blog-post-anchor?) #f]))
196+
[(? blog-page?) #t]
197+
[(? blog-page-anchor?) #f]))
188198

189199
(define/public (current-part-whole-page? d)
190200
(eq? d (current-top-part)))
@@ -199,21 +209,21 @@
199209
(define/override (collect-part-tags d ci number)
200210
(for ([t (part-tags d)])
201211
(define key (generate-tag t ci))
202-
(define title (or (part-title-content d) '("???")))
212+
(define title (or (part-title-content d) "???"))
203213
(collect-put! ci key
204214
(if (current-part-whole-page? d)
205-
(blog-post title (current-output-file))
206-
(blog-post-anchor title
207-
(current-output-file)
215+
(blog-page title (get-current-site-path))
216+
(blog-page-anchor title
217+
(get-current-site-path)
208218
(tag->anchor-name (add-current-tag-prefix key)))))))
209219

210220
(define/override (collect-target-element i ci)
211221
(define key (generate-tag (target-element-tag i) ci))
212222
(when (redirect-target-element? i)
213223
(raise-arguments-error 'collect-target-element "redirect targets not supported"
214224
"element" i))
215-
(collect-put! ci key (blog-post-anchor #f
216-
(current-output-file)
225+
(collect-put! ci key (blog-page-anchor #f
226+
(get-current-site-path)
217227
(tag->anchor-name (add-current-tag-prefix key)))))
218228

219229
(define/override (resolve-content i d ri)
@@ -248,9 +258,14 @@
248258

249259
(define/override (render-part-content part ri)
250260
(define number (collected-info-number (part-collected-info part ri)))
261+
(define anchors (for/list ([tag (in-list (part-tags part))])
262+
`(a ([name ,(tag->anchor-name
263+
(add-current-tag-prefix
264+
(tag-key tag ri)))]))))
251265
(define title
252266
(when/list (not (part-style? part 'hidden))
253267
`(,(header-depth->html-tag (number-depth number))
268+
,@anchors
254269
,@(cond/list
255270
[(part-title-content part)
256271
=> (λ (title-content) (render-content title-content part ri))]))))
@@ -280,8 +295,9 @@
280295
(define title-content
281296
(match (resolve-get part ri tag)
282297
[(vector title _ ...) title]
283-
[(blog-post title _) title]
284-
[(blog-post-anchor title _ _) title]))
298+
[(blog-page title _) title]
299+
[(blog-page-anchor title _ _) title]
300+
[#f "???"]))
285301
(render-content title-content part ri))
286302

287303
(define/override (render-content elem part ri)
@@ -357,18 +373,13 @@
357373
(url-query external-tag-path)))
358374
(url->string (struct-copy url external-tag-path [query redirect-query]))]
359375

360-
[(blog-post _ path)
361-
(relative-path->relative-url-string
362-
(find-relative-path (get-dest-directory) path))]
376+
[(blog-page _ path)
377+
(site-path->url-string path)]
363378

364-
[(blog-post-anchor _ path anchor)
365-
(define file-path path)
366-
(define fragment (string-append "#" (uri-encode anchor)))
367-
(if (equal? file-path (current-output-file))
368-
fragment
369-
(string-append (relative-path->relative-url-string
370-
(find-relative-path (get-dest-directory) file-path))
371-
fragment))]))
379+
[(blog-page-anchor _ path anchor)
380+
(if (equal? path (get-current-site-path))
381+
(string-append "#" (uri-encode anchor))
382+
(site-path->url-string path #:fragment anchor))]))
372383

373384
(define attrs* (attributes-union (hasheq 'href href) attrs))
374385
(wrap-for-style #:attrs (hasheq) `[(a ,(attributes->list attrs*) ,@rendered)])]
@@ -501,6 +512,11 @@
501512
; files containing serialized `rendered-post` structures, instead.
502513
(define/override (get-suffix) #".info")
503514

515+
(define/override (get-current-site-path)
516+
(define part (current-top-part))
517+
(post-path (get-required-style-prop post-date? (style-properties (part-style part)))
518+
(content->string (strip-aux (part-title-content part)))))
519+
504520
(define/override (render-one part ri output-file)
505521
(define props (style-properties (part-style part)))
506522
(define title-str (content->string (strip-aux (part-title-content part)) this part ri))

blog/build/render/util.rkt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
(define tag->anchor-name
4343
(match-lambda
4444
[(literal-anchor anchor-name) anchor-name]
45+
[(cons 'part tag) (tag->anchor-name tag)]
4546
[(? list? elements)
4647
; This anchor naming scheme does not in any way create unique anchors, but
4748
; that should be okay for internal references in this use case, and having

blog/lang/metadata.rkt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
(struct-out post-tags)
1010
(contract-out
1111
[post-date->string (-> post-date? string?)]
12-
[post-date->strings (-> post-date? (list/c string? string? string?))]))
12+
[post-date->strings (-> post-date? (list/c string? string? string?))]
13+
[blog-post-path->tag-prefix (-> (and/c string? relative-path?) string?)]))
1314

1415
(serializable-struct post-date (year month day) #:transparent
1516
#:guard (struct-guard/c exact-integer? (integer-in 1 12) (integer-in 1 31)))
@@ -23,3 +24,6 @@
2324
(list (~a (post-date-year date))
2425
(~r #:min-width 2 #:pad-string "0" (post-date-month date))
2526
(~r #:min-width 2 #:pad-string "0" (post-date-day date))))
27+
28+
(define (blog-post-path->tag-prefix path)
29+
(~a `(blog ,path)))

blog/lang/post-language.rkt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
racket/contract
88
racket/match
99
racket/string
10+
(prefix-in scribble: scribble/base)
1011
scribble/base
1112
scribble/core
1213
scribble/decode
@@ -20,7 +21,16 @@
2021
infer-date
2122
(struct-out post-tags)
2223
define-footnote
23-
(contract-out [code (-> content? ... element?)]
24+
(contract-out [seclink (->* [string?]
25+
[#:doc (or/c module-path? #f)
26+
#:post (or/c string? #f)
27+
#:tag-prefixes (or/c (listof string?) #f)
28+
#:indirect? any/c]
29+
#:rest (listof pre-content?)
30+
element?)]
31+
[other-post (-> string? element?)]
32+
33+
[code (-> content? ... element?)]
2434
[code-block (-> content? ... block?)]
2535
(struct pygments-content ([source string?] [language string?]))
2636
[pygments (-> #:language string? string? ... element?)]
@@ -45,6 +55,24 @@
4555

4656
;; -----------------------------------------------------------------------------
4757

58+
(define (seclink tag
59+
#:doc [module-path #f]
60+
#:post [post-path #f]
61+
#:tag-prefixes [prefixes #f]
62+
#:indirect? [indirect? #f]
63+
. pre-content)
64+
(apply scribble:seclink tag pre-content
65+
#:doc module-path
66+
#:tag-prefixes (if post-path
67+
(cons (blog-post-path->tag-prefix post-path) (or prefixes '()))
68+
prefixes)
69+
#:indirect? indirect?))
70+
71+
(define (other-post post-path)
72+
(seclink "top" #:post post-path))
73+
74+
;; -----------------------------------------------------------------------------
75+
4876
(define (code . content)
4977
(element (style #f (list (alt-tag "code"))) content))
5078

blog/markdown/to-scribble.rkt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010
scribble/decode-struct
1111
scribble/html-properties
1212

13-
"../lang/post-language.rkt"
13+
(only-in "../lang/post-language.rkt"
14+
code
15+
code-block
16+
footnote-flow
17+
footnote-reference-element
18+
pygments-block)
1419
(prefix-in md: "parse.rkt"))
1520

1621
(provide (contract-out

blog/paths.rkt

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#lang racket/base
22

3-
(require racket/contract
3+
(require net/url
4+
racket/contract
45
racket/format
56
racket/runtime-path
67
racket/string
@@ -14,13 +15,15 @@
1415
[posts-dir path?]
1516

1617
[site-path? predicate/c]
18+
[site-path->url-string (->* [site-path?] [#:fragment (or/c string? #f)] string?)]
19+
[full-url (->* [site-path?] [#:fragment (or/c string? #f)] string?)]
20+
1721
[index-path (->* [] [exact-positive-integer?
1822
#:tag (or/c string? #f)
1923
#:file? any/c]
2024
site-path?)]
2125
[post-path (->* [post-date? string?] [#:file? any/c] site-path?)]
22-
[feed-path (->* [(or/c 'atom 'rss)] [#:tag (or/c string? #f)] site-path?)]
23-
[full-url (-> site-path? string?)]))
26+
[feed-path (->* [(or/c 'atom 'rss)] [#:tag (or/c string? #f)] site-path?)]))
2427

2528
(define-runtime-path build-dir-base "../build")
2629
(define-runtime-path output-dir-base "../output")
@@ -33,6 +36,18 @@
3336
(and (string? v)
3437
(absolute-path? v)))
3538

39+
(define (site-path->url-string path #:fragment [fragment #f])
40+
(url->string (struct-copy url (path->url path)
41+
[scheme #f]
42+
[host #f]
43+
[fragment fragment])))
44+
45+
(define (full-url path #:fragment [fragment #f])
46+
(url->string (struct-copy url (path->url path)
47+
[scheme "https"]
48+
[host "lexi-lambda.github.io"]
49+
[fragment #f])))
50+
3651
(define (index-path [page-number 1]
3752
#:tag [tag #f]
3853
#:file? [file? #f])
@@ -51,6 +66,3 @@
5166

5267
(define (feed-path format #:tag [tag #f])
5368
(~a "/feeds/" (if tag (to-slug tag) "all") "." format ".xml"))
54-
55-
(define (full-url path)
56-
(~a "https://lexi-lambda.github.io" path))

blog/posts/about-me.scrbl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#lang scribble/base
22
@(begin
33
(require racket/list
4-
scribble/core
5-
scribble/html-properties
64
threading
75
"../lang/post-language.rkt")
86

0 commit comments

Comments
 (0)