Commit 5cbd0ab6 authored by Dave Cooper's avatar Dave Cooper
Browse files

Support for content/*.lisp files in addition to content/*.html.

parent 821b70e4
...@@ -24,6 +24,10 @@ Load with this command: ...@@ -24,6 +24,10 @@ Load with this command:
(ql:quickload :cl-site) (ql:quickload :cl-site)
To clean any old output/ directory:
(cl-site:make-clean)
To generate the site: To generate the site:
(cl-site::make-site) (cl-site::make-site)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
:author "C. Yang & Common-Lisp.Net maintainers" :author "C. Yang & Common-Lisp.Net maintainers"
:licence "TBD" :licence "TBD"
:description "Static site generator for common-lisp.net, written in CL" :description "Static site generator for common-lisp.net, written in CL"
:depends-on (:cl-mustache :plump :cl-markdown :closer-mop :cl-who :cl-yaml) :depends-on (:cl-mustache :plump :markdown.cl :closer-mop :cl-who :cl-yaml)
:components ((:module source :components ((:module source
:pathname "" :pathname ""
:serial t :serial t
......
(in-package :cl-site) (in-package :cl-site-content)
(add-content (add-content
"about.html" :title "Common-Lisp.net | About"
:html-string
(with-cl-who-string (:indent t) (with-cl-who-string (:indent t)
(:h1 ((:i :class "far fa-question-circle")) " About Common-Lisp.net") (:h1 ((:i :class "far fa-question-circle")) " About Common-Lisp.net")
......
...@@ -24,15 +24,27 @@ ...@@ -24,15 +24,27 @@
(defparameter *PRIVATE-KEYS* '(:slug :content)) (defparameter *PRIVATE-KEYS* '(:slug :content))
(defparameter *PAGES* (defun populate-pages ()
(mapcar (lambda (p) (mapcar (lambda (p)
(list (cons :content (file-namestring p)) (list (cons :content (file-namestring p))
(cons :title (file-namestring p)))) (cons :title (file-namestring p))))
(directory (make-pathname :defaults *PAGES-DIR* ;;
:name :wild ;; At this point there could be duplicate, i.e. a .html and a .lisp file.
:type "html"))) ;;
(append
(directory (make-pathname :defaults *PAGES-DIR* :name :wild :type "html"))
(directory (make-pathname :defaults *PAGES-DIR* :name :wild :type "lisp")))))
(defparameter *PAGES* (populate-pages)
"Each page is an alist containing info to be sent to the template via the context.") "Each page is an alist containing info to be sent to the template via the context.")
;; Initialize global context (will be appended to all individual page contexts) ;; Initialize global context (will be appended to all individual page contexts)
;; Used to store things like stylesheets, etc... ;; Used to store things like stylesheets, etc...
(defparameter *GLOBAL-CONTEXT* ()) (defparameter *GLOBAL-CONTEXT* ())
(defparameter *computed-page-content* nil
"Used as dynamically bound variable in preprocess-lisp-pages, to
capture output when compile/loading any lispy html content files
wrapped with calls to add-content. Global value should always be
nil.")
...@@ -6,3 +6,13 @@ ...@@ -6,3 +6,13 @@
(format t "Generating site in ~A.~%" *output-dir*) (format t "Generating site in ~A.~%" *output-dir*)
(process-static) (process-static)
(process-pages *pages*))) (process-pages *pages*)))
(defun make-clean (&optional (output-dir *output-dir*))
(when (probe-file output-dir)
(uiop:delete-directory-tree
output-dir
:validate #'(lambda(dir)
(string-equal (first (last (pathname-directory dir)))
"output"))))
(ensure-directories-exist output-dir))
(defpackage #:cl-site (defpackage #:cl-site
(:use :cl) (:use :cl)
(:export (:export #:make-site #:make-clean #:add-content #:wmd :with-cl-who-string))
#:make-site))
(defpackage #:cl-site-content (defpackage #:cl-site-content
(:use :cl)) (:use :cl :cl-site :cl-who))
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
(header content) (header content)
(split-content-from-header page-path) (split-content-from-header page-path)
(let* ((header-text (format nil "~{~A~%~}" header)) (let* ((header-text (format nil "~{~A~%~}" header))
(content-text (format nil "~{~A~%~}" content)) (content-text (format nil "~{~A~%~}" (remove nil content)))
(parsed-header (yaml:parse header-text)) (parsed-header (yaml:parse header-text))
(page-context (page-context
(when parsed-header (when parsed-header
...@@ -54,52 +54,62 @@ ...@@ -54,52 +54,62 @@
(mustache:render template-path (append (acons :page-content content-text page-context) *GLOBAL-CONTEXT*) (mustache:render template-path (append (acons :page-content content-text page-context) *GLOBAL-CONTEXT*)
output-stream)))))) output-stream))))))
(defun process-pages (pages)
(format t "Processing pages...~%")
;;
;; Go through all the pages in *page-context* and look for
;; corresponding .lisp file. If it exists, it's assumed this is
;; using `add-content' (defined below) to generate an HTML string and
;; add it to the :content field of its entry in *page-context*. So
;; we compile/load this lisp file then write the content out to the
;; html file. Yes, this is turning into a goddamn Rube Goldberg
;; setup and at some point we will need to clean up and simplify
;; this whole process... But trying to get to where we can at least
;; experiment with using LHTML and markdown to author and maintain
;; page content.
;;
(dolist (page *page-context*)
(let* ((html-file (first page))
(lisp-file (probe-file (make-pathname :defaults *pages-dir*
:name (pathname-name html-file)
:type "lisp"))))
(when lisp-file
(format t "Compile/loading ~a and creating fresh ~a...~%" (file-namestring lisp-file) html-file)
(let ((fasl (compile-file lisp-file)))
(load fasl) (delete-file fasl))
(let ((content (page-content html-file)))
(with-open-file (out (merge-pathnames html-file *pages-dir*) :if-exists :supersede
:if-does-not-exist :create :direction :output)
(write-string content out))))))
(defun process-pages (pages)
(format t "Processing pages...~%")
(preprocess-lisp-pages pages)
(generate-news) (generate-news)
(let ((template-path (pathname (merge-pathnames *LAYOUT-DIR* *DEFAULT-PAGE-TEMPLATE*)))) (let ((template-path (pathname (merge-pathnames *LAYOUT-DIR* *DEFAULT-PAGE-TEMPLATE*))))
(ensure-directories-exist *OUTPUT-DIR*) (ensure-directories-exist *OUTPUT-DIR*)
(loop for page in pages (setq pages (populate-pages))
do (dolist (page pages)
(format t "Rendering ~A~%" (cdr (assoc :content page))) (let ((page-pathname (merge-pathnames (page-content page) *pages-dir*)))
(render-page page template-path)) (when (string-equal (pathname-type page-pathname) "html")
(format t "Rendering ~A~%" (cdr (assoc :content page)))
(render-page page template-path)
(when (probe-file (make-pathname :defaults page-pathname :type "lisp"))
(format t "Deleting temporary generated ~a~%" (file-namestring page-pathname))
(delete-file page-pathname)
))))
(format t "Done.~%"))) (format t "Done.~%")))
(defun preprocess-lisp-pages (pages)
(dolist (page pages)
(let* ((lisp-file (page-content page)))
(when (string-equal (pathname-type lisp-file) "lisp")
(let ((html-file (make-pathname :defaults lisp-file :type "html")))
(format t "Compile/loading ~a and creating fresh ~a...~%"
(file-namestring lisp-file) html-file)
(let ((fasl (compile-file (merge-pathnames lisp-file *pages-dir*)))
*computed-page-content*)
(load fasl) (delete-file fasl)
(with-open-file (out (merge-pathnames html-file *pages-dir*) :if-exists :supersede
:if-does-not-exist :create :direction :output)
(format out "title: ~a~%---~%" (getf *computed-page-content* :title))
(write-string (getf *computed-page-content* :html-string) out))))))))
;; Process news ;; Process news
(defparameter +edit-news-link+ "https://gitlab.common-lisp.net/clo/cl-site/edit/master/content/news.md") (defparameter +edit-news-link+ "https://gitlab.common-lisp.net/clo/cl-site/edit/master/content/news.md")
;;
;; FLAG -- If news.html is converted to news.lisp (a la about.lisp)
;; then the following only will have to deal with generating the
;; newsbox. The news.lisp would have to include the hardcoded HTML
;; which is injected below as well.
;;
(defun generate-news () (defun generate-news ()
(let ((html (let ((html
(with-output-to-string (ss) (markdown:parse-file (merge-pathnames "news.md" *PAGES-DIR*))))
(cl-markdown:markdown (merge-pathnames "news.md" *PAGES-DIR*) :stream ss))))
(with-open-file (f (merge-pathnames "news.html" *PAGES-DIR*) (with-open-file (f (merge-pathnames "news.html" *PAGES-DIR*)
:direction :output :direction :output
:if-does-not-exist :create :if-does-not-exist :create
...@@ -191,13 +201,20 @@ of writing to a stream." ...@@ -191,13 +201,20 @@ of writing to a stream."
"Form suitable for inclusion in cl-who LHTML context. Returns an "Form suitable for inclusion in cl-who LHTML context. Returns an
`str` form after passing it through cl-markdown's markdown processor. `str` form after passing it through cl-markdown's markdown processor.
" "
`(cl-who:str ;;
(with-output-to-string (ss) ;; FLAG -- should we be checking for loaded markdown package at compile-time instead?
(cl-markdown:markdown ,string :stream ss)))) ;;
`(cl-who:str (cond ((find-package :markdown.cl)
(funcall (read-from-string "markdown.cl:parse") ,string))
((find-package :cl-markdown)
(with-output-to-string (ss)
(funcall (read-from-string "cl-markdown:markdown") ,string :stream ss))))))
(defun page-content (page) (rest (assoc :content page)))
(defun add-content (&key title html-string)
(setq *computed-page-content* (list :title title :html-string html-string)))
(defun add-content (page-name content-string)
(pushnew (cons :content content-string)
(first (rest (assoc page-name *page-context* :test #'string-equal)))))
(defun page-content (page-name)
(rest (assoc :content (page-context page-name))))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment