;;; build-comments.el --- Comment manifest and export filter -*- lexical-binding: t; -*- ;;; Code: (require 'cl-lib) (require 'json) (require 'org) (defun z/comments-file-p (file) "Return non-nil if FILE has #+COMMENTS: t." (when (and file (file-exists-p file)) (with-temp-buffer (insert-file-contents file) (org-mode) (let* ((keywords (org-collect-keywords '("COMMENTS"))) (val (cadr (assoc "COMMENTS" keywords)))) (and val (string-match-p "^\\s-*t\\s-*$" (downcase val))))))) (defun z/comments-file-slug (file) "Return page slug from #+SLUG: or fallback to filename base." (with-temp-buffer (insert-file-contents file) (org-mode) (let* ((keywords (org-collect-keywords '("SLUG"))) (slug (cadr (assoc "SLUG" keywords)))) (if (and slug (string-match-p "\\S-" slug)) slug (file-name-base file))))) (defun z/comment-page-url (file) "Return root-relative published HTML URL for source FILE." (concat "/" (file-name-sans-extension (file-relative-name file z/site-root)) ".html")) (defun z/comment-page-title (file) "Return exported page title for FILE, or the file basename." (with-temp-buffer (insert-file-contents file nil 0 4096) (goto-char (point-min)) (if (re-search-forward "^#\\+TITLE:[ \t]*\\(.+?\\)[ \t]*$" nil t) (match-string 1) (file-name-base file)))) (defun z/comment-page-record (file) "Return a JSON-ready comment page record for FILE." `((slug . ,(z/comments-file-slug file)) (title . ,(z/comment-page-title file)) (url . ,(z/comment-page-url file)))) (defun z/generate-comment-pages-json () "Write a slug-to-page manifest for comment-enabled Org files." (let* ((files (directory-files-recursively z/site-root "\\.org\\'")) (records (cl-loop for file in files unless (or (string-prefix-p (site-path "output/") file) (string-prefix-p (site-path "backups/") file) (string-prefix-p (site-path ".org-timestamps/") file) (string-prefix-p (site-path ".packages/") file)) when (z/comments-file-p file) collect (z/comment-page-record file))) (target (site-path "assets/content/comment-pages.json")) (json-encoding-pretty-print t)) (make-directory (file-name-directory target) t) (with-temp-file target (insert (json-encode (vconcat records))) (insert "\n")) (z/log 'done "Wrote comment page manifest (%d pages)" (length records)))) (defun z/org-html-insert-comments-into-body (body backend info) "Append a comments section to BODY for files that opt in." (if (org-export-derived-backend-p backend 'html) (let ((input-file (plist-get info :input-file))) (if (and input-file (z/comments-file-p input-file)) (let* ((slug (z/comments-file-slug input-file)) (html (format "\n

Comments

\n" slug))) (concat body html)) body)) body)) (provide 'build-comments) ;;; build-comments.el ends here