diff --git a/src/coleslaw.lisp b/src/coleslaw.lisp index 552c06e..9269d12 100644 --- a/src/coleslaw.lisp +++ b/src/coleslaw.lisp @@ -9,11 +9,17 @@ If ARGS is provided, use (apply 'format nil PATH ARGS) as the value of PATH." "Convert an iolib file-path back to a pathname." (merge-pathnames (file-path-namestring file) parent)) -(defmacro do-files ((var path) &body body) - "For each file under PATH, run BODY." - `(iolib.os:mapdir (lambda (x) - (let ((,var (to-pathname x ,path))) - ,@body)) ,path)) +(defmacro do-files ((var path &optional extension) &body body) + "For each file under PATH, run BODY. If EXTENSION is provided, only run BODY +on files that match the given extension." + (alexandria:with-gensyms (ext) + `(iolib.os:mapdir (lambda (x) + (let* ((,var (to-pathname x ,path)) + ,@(when extension `((,ext (pathname-type ,var))))) + ,@(if extension + `((when (and ,ext (string= ,ext ,extension)) + ,@body)) + `,body))) ,path))) (defun compile-blog () (let ((staging #p"/tmp/coleslaw/")) diff --git a/src/posts.lisp b/src/posts.lisp index b0e311e..52cbf69 100644 --- a/src/posts.lisp +++ b/src/posts.lisp @@ -1,34 +1,38 @@ (in-package :coleslaw) +(defparameter *metadata* (make-hash-table :test #'equal)) + (defclass post () - ((id :initform nil :initarg :id - :accessor post-id) - (title :initform nil :initarg :title - :accessor post-title) - (tags :initform nil :initarg :tags - :accessor post-tags) - (date :initform nil :initarg :date - :accessor post-date) - (content :initform nil :initarg :content - :accessor post-content) - (aliases :initform nil :initarg :aliases - :accessor post-aliases))) + ((slug :initform nil :initarg :slug :accessor post-slug) + (title :initform nil :initarg :title :accessor post-title) + (tags :initform nil :initarg :tags :accessor post-tags) + (date :initform nil :initarg :date :accessor post-date) + (format :initform nil :initarg :format :accessor post-format) + (content :initform nil :initarg :content :accessor post-content) + (aliases :initform nil :initarg :aliases :accessor post-aliases))) -(defgeneric make-post (title tags date content - &key id aliases &allow-other-keys) - (:documentation "Create a POST with the given data.")) +(defun render-posts () + (do-files (file (repo *config*) "post") + (with-open-file (in file) + (let ((post (read-post in))) + (setf (gethash (post-slug post) *metadata*) post))) + (maphash #'write-post *metadata*))) -(defgeneric add-post (post id) - (:documentation "Insert a post into *storage* with the given ID.")) +(defun read-post (stream) + "Make a POST instance based on the data from STREAM." -(defgeneric remove-post (id) - (:documentation "Remove a post from *storage* matching ID.")) + ) -(defgeneric render-post (id) - (:documentation "Generate the final HTML for the post with given ID.")) - -(defgeneric find-post (id) - (:documentation "Retrieve a post from *storage* matching ID.")) - -(defgeneric post-url (id) - (:documentation "Return the URL for the post with the given ID.")) +(defun write-post (slug post) + "Write out the HTML for POST in SLUG.html." + (with-open-file (out (format nil "~a.html" slug) + :direction :output + :if-does-not-exist :create) + (let ((content (funcall (theme-fn "POST") + (list :title (post-title post) + :tags (post-tags post) + :date (post-date post) + :content (post-content post) + :prev nil + :next nil)))) + (write content out)))) diff --git a/src/themes.lisp b/src/themes.lisp index 4af27bf..7857bb2 100644 --- a/src/themes.lisp +++ b/src/themes.lisp @@ -1,19 +1,24 @@ (in-package :coleslaw) +(defparameter *injections* (make-hash-table :test #'equal)) + (defgeneric add-injection (str location) - (:documentation "Add STR to the list of elements injected in LOCATION.")) + (:documentation "Add STR to the list of elements injected in LOCATION.") + (:method ((str string) location) + (pushnew str (gethash location *injections*) :test #'string=))) (defgeneric remove-injection (str location) - (:documentation "Remove STR from the list of elements injected in LOCATION.")) + (:documentation "Remove STR from the list of elements injected in LOCATION.") + (:method ((str string) location) + (setf (gethash location *injections*) + (remove str (gethash location *injections*) :test #'string=)))) (defun theme-package (&key (name (theme *config*))) (find-package (string-upcase (concatenate 'string "coleslaw.theme." name)))) (defun compile-theme (&key (theme-dir (app-path "themes/~a/" (theme *config*)))) - (do-files (file theme-dir) - (let ((extension (pathname-type file))) - (when (and extension (string= extension "tmpl")) - (compile-template :common-lisp-backend file))))) + (do-files (file theme-dir "tmpl") + (compile-template :common-lisp-backend file))) ;; DOCUMENTATION ;; A theme directory should be named after the theme and contain *.tmpl files