blob: ad35f4c8ff7116aa3372d6151038513c88c508b9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
;;; Copyright © 2019 - 2020 Jakob L. Kreuze <zerodaysfordays@sdf.org>
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see
;;; <http://www.gnu.org/licenses/>.
(define-module (jakob utils)
#:use-module (haunt post)
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-19)
#:export (assq-map!
maybe-cons*
maybe-list
date->string*
intersperse
first-paragraph
description-from-post
elide-string))
(define (assq-map! alist key fn)
"Destructively apply FN to KEY in ALIST, if it exists"
(match (assq-ref alist key)
(#f alist)
(val (assq-set! alist key (fn val)))))
(define (maybe-list . args)
"Create a list of all ARGS that are neither #f nor unspecified."
(remove (lambda (element)
(or (not element) (unspecified? element)))
args))
(define (maybe-cons* . args)
"Cons all ARGS that are neither #f nor unspecified."
(apply cons* (apply maybe-list args)))
(define (date->string* date)
"Convert DATE to human readable string."
(date->string date "~a ~d ~B ~Y"))
(define (intersperse lst delim)
"Return the elements of LST delimited by DELIM, such that the resultant list
is of an odd length and every second element is DELIM."
(if (<= (length lst) 1)
lst
(cons* (car lst)
delim
(intersperse (cdr lst) delim))))
(define (remove-footnote-references content)
"Remove any <sup> elements from CONTENT."
(map (lambda (elt)
(if (list? elt)
(remove-footnote-references elt)
elt))
(remove (lambda (elt)
(and (list? elt) (eq? 'sup (car elt))))
content)))
(define (first-paragraph post)
(let loop ((sxml (post-sxml post)))
(match sxml
(((and ('p content ...) paragraph) . tail)
(remove-footnote-references paragraph))
((head . tail) (loop tail)))))
(define (description-from-post post)
(define (first-elem sxml)
(if (and (list? sxml) (positive? (length sxml)))
(if (symbol? (first sxml))
sxml
(let ((reduced (remove null? (map first-elem sxml))))
(if (positive? (length reduced))
(first reduced)
'())))
'()))
(define (collect-strings elt res)
(cond ((null? elt) res)
((string? (car elt)) (collect-strings (cdr elt) (cons (car elt) res)))
((list? (car elt)) (if (and (positive? (length (car elt)))
(not (eq? '@ (caar elt))))
(let ((nested (collect-strings (car elt) (list))))
(collect-strings (cdr elt) (append nested res)))
(collect-strings (cdr elt) res)))
(else (collect-strings (cdr elt) res))))
(let* ((sxml (first-paragraph post))
(extracted (collect-strings (first-elem sxml) (list))))
(string-join (map string-trim-both (reverse extracted)) " ")))
(define (elide-string s len)
"Return S elided to be at most LEN characters"
(when (< len 3) (error "LEN cannot be smaller than 3"))
(if (<= (string-length s) len)
s
(string-append (string-take s (floor/ (- len 3) 2))
"..."
(string-take-right s (ceiling/ (- len 3) 2)))))
|