;; schini, scheme gemini generator.
;; r7rs and very rigid, so read the doc.
;; run this code with "gauche schini.scm"
;; gauche scheme has all these modules
;; although i can't r7rs-style (import) srfi-13 ??
;; so i'm doing this the gauche way.
(use srfi-95) ; sorting
(use srfi-13) ; strings
(use srfi-170) ; posix file/dir management
;; consists of: ("dir-to-scan" "# title" "a description")
(define dirs-to-scan '(("log" "log" "stuff i write about~")
("poems" "poems" "this is where i keep my poetry :3")))
;; general variables for the uh atom file
(define author "lin")
(define atom-title "linen :3")
(define atom-url "gemini://cipay.ca/atom.xml")
(define site-url "gemini://cipay.ca")
;; extract the title of the file:
;; "# my title" -> "my title"
(define (extract-title stream)
(with-input-from-file stream
(lambda ()
(string-trim (string-drop (read-line) 1)))))
;; extract the date of the file
(define (extract-date file)
(with-input-from-file file
(lambda ()
(do ((stream (read-line) (read-line))) ; local val / what to iterate with
((eof-object? (peek-char)) stream))))) ; clause, return value
;; format the date to an integer
;; 2023-10-15 -> 20231015
(define (format-date f)
(string-delete #\- (extract-date f)))
;; simply put a / between the two strings.
;; i'm lazy shut up
(define (pathify dir file)
(string-append dir "/" file))
;; generate an alist from DIR with the format:
;; '(("date" "file/path.gmi" "my title"))
;; PROGRESS-BAR is a boolean denoting whether we want to print a dot
(define (gen-list dir progress-bar)
(let ((stream (open-directory dir))) ; the stream of files in the dir
(do ((f (read-directory stream) (read-directory stream))
(list-of-dates '()))
((eof-object? f) list-of-dates)
(if progress-bar (display "."))
(unless (string=? f "index.gmi")
(set! list-of-dates
(cons (list (format-date (pathify dir f))
(pathify dir f)
(extract-title (pathify dir f))
f) ;; the file without the date path attached onto it ig
list-of-dates)))) ))
;; make list of links from files in a dir, a link looks like
;; => file/path.gmi my title
(define (cadddar lst)
(cadr (cddar lst)))
(define (make-links dir)
(do ((dates-titles (sort (gen-list dir #t)) (cdr dates-titles))
(answer '()))
((null? dates-titles) answer)
(let ((date (caar dates-titles))
(title (caddar dates-titles))
(file (cadddar dates-titles)))
(set! answer (cons (string-append "=> " file " " title)
answer)))))
;; generate an index file from dir to dir/index.gmi
(define (make-index dir)
(let* ((mylist (assoc dir dirs-to-scan))
(links (make-links dir))
(desc (caddr mylist))
(title (car mylist)))
(with-output-to-file (string-append dir "/index.gmi")
(lambda ()
(display (string-append
"# " title "\n\n" desc "\n\n"))
(do ((my-links links (cdr my-links)))
((null? my-links) (display ""))
(display (string-append (car my-links) "\n")))))))
(define (make-all-indexes)
(do ((x dirs-to-scan (cdr x)))
((null? x) '())
(make-index (caar x))))
(define (collect-all-links)
(do ((mylst dirs-to-scan (cdr mylst))
(answer '()))
((null? mylst) (reverse (sort answer))) ; new posts at top
(set! answer (append (gen-list (caar mylst) #f) answer))))
;; turn our extracted date string "20231015"
;; into an atom-compliant yyyy-mm-ddThh:mm:ss string
(define (atomify-date date-string)
(let* ((year (substring date-string 0 4)) ; yyyy
(month (substring date-string 4 6)) ; mm
(day (substring date-string 6 8))) ; dd
(string-append year "-" month "-" day "T12:00:00")))
(define (make-atom-entries)
(do ((mylst (collect-all-links) (cdr mylst))
(answer '()))
((null? mylst) answer)
(set! answer
(cons (make-atom-entry mylst) answer))))
(define (make-atom-entry list-of-links)
(let* ((lst list-of-links)
(date (caar lst))
(file (cadar lst))
(title (caddar lst)))
(string-append
"" site-url "/" file "" title "" (atomify-date date) "\n\n")))
(define (stringify-atom-entries)
(do ((mylst (make-atom-entries) (cdr mylst))
(answer ""))
((null? mylst) answer)
(set! answer
(string-append (car mylst) answer))))
;; uh just find the newest post and atomify it uwu
(define (last-update)
(let* ((date (caar (collect-all-links))))
(atomify-date date)))
;; i was gonna do this in sxml but i'm sticking with uhhhhh
;; r7rs as much as i can so this is fine
(define atom-layout
(string-append
"
" atom-title "" site-url "" author "" (last-update) "
\n\n"
(stringify-atom-entries)
""))
(define (start)
(display "------------")
(newline)
(display "schini, scheme gemini index generator")
(newline);; print this
(with-output-to-file "atom.xml"
(lambda ()
(display atom-layout)))
(display "printed atom.xml\n")
(display "progress: ")
(make-all-indexes)
(display "\ndone!\n"))
(start)
;; notes
;; so yeah yyyy-mm-dd is the best date format
;; cause i can just sort it as an int and it comes out right >:3