jgkamat-website.el 9.77 KB
Newer Older
1 2 3 4 5 6
;;; jgkamat-website.el --- generation scripts for jgkamat's website

;; Copyright (C) 2016-present Jay Kamat
;; Author: Jay Kamat <jaygkamat@gmail.com>
;; Version: 1.0
;; Keywords: jgkamat
Jay Kamat's avatar
Jay Kamat committed
7
;; URL: https://gitlab.com/jgkamat/jgkamat.gitlab.io
8
;; Package-Requires: ((emacs "25.0") (htmlize))
9 10 11 12 13 14 15 16

;;; Commentary:
;;Creates and builds org project files for my website

;; To run: cask eval "(progn (require 'jgkamat-website) (jgkamat-publish))" in the root of the project.


;;; Code:
Jay Kamat's avatar
Jay Kamat committed
17

18

Jay Kamat's avatar
Jay Kamat committed
19
(require 'ox-publish)
Jay Kamat's avatar
Jay Kamat committed
20 21
(require 'ox-rss)
(require 'cl-lib)
22 23 24 25 26 27 28 29 30 31

(defvar website-publish-dir (concat (file-name-directory load-file-name) "./html"))

;; Force htmlize to activate even in nogui mode:
;; https://stackoverflow.com/questions/3591337/emacs-htmlize-in-batch-mode
;; http://sebastien.kirche.free.fr/emacs_stuff/elisp/my-htmlize.el
;; Get fancy colors! (but this will screw up your native emacs install)
(when noninteractive
  ;; Don't run in interactive mode to avoid breaking your colors
  (custom-set-faces
Jay Kamat's avatar
Jay Kamat committed
32
   ;; Draculized minimal: https://gitlab.com/jgkamat/darculized
33 34 35 36 37 38 39 40 41 42 43 44 45
   ;; TODO find out why default face is not applying.
   '(default                      ((t (:foreground "#909396" :background "#262626"))))
   '(font-lock-builtin-face       ((t (:foreground "#598249"))))
   '(font-lock-comment-face       ((t (:foreground "#5e6263"))))
   '(font-lock-constant-face      ((t (:foreground "#15968D"))))
   '(font-lock-function-name-face ((t (:foreground "#2F7BDE"))))
   '(font-lock-keyword-face       ((t (:foreground "#598249"))))
   '(font-lock-string-face        ((t (:foreground "#15968D"))))
   '(font-lock-type-face		       ((t (:foreground "#598249"))))
   '(font-lock-variable-name-face ((t (:foreground "#2F7BDE"))))
   '(font-lock-warning-face       ((t (:foreground "#bd3832" :weight bold)))))
  (setq htmlize-use-rgb-map 'force)
  (require 'htmlize))
Jay Kamat's avatar
Jay Kamat committed
46

Jay Kamat's avatar
Jay Kamat committed
47 48

;; I reccomend you publish with FORCE on to avoid loosing changes in history files
49
(let ((proj-base (file-name-directory load-file-name)))
50
  (setq project-base (concat proj-base "src/"))
Jay Kamat's avatar
Jay Kamat committed
51 52
  (setq
   org-publish-project-alist
Jay Kamat's avatar
Jay Kamat committed
53
   `(("jgkamat.gitlab.io"
Jay Kamat's avatar
Jay Kamat committed
54 55 56 57
      :base-directory ,project-base
      :recursive t
      :publishing-directory ,website-publish-dir
      ;; Add my CSS and fonts
Jay Kamat's avatar
Jay Kamat committed
58
      :html-head "<link rel=\"stylesheet\" href=\"https://jgkamat.gitlab.io/src/jgkamat.css\"/>"
59
      :html-head-include-default-style nil
Jay Kamat's avatar
Jay Kamat committed
60 61 62 63 64
      :title nil
      :with-headline-numbers nil
      :with-date nil
      :time-stamp-file nil
      :auto-sitemap t
65
      :sitemap-sort-folders first
66
      :exclude "blog/rss.org"
Jay Kamat's avatar
Jay Kamat committed
67
      :sitemap-sort-files anti-chronologically
68
      :exclude-tags ("onlyrss" "noexport")
69
      :publishing-function org-html-publish-to-html)
Jay Kamat's avatar
Jay Kamat committed
70
     ("jgkamat.gitlab.io-blogmap"
Jay Kamat's avatar
Jay Kamat committed
71 72 73 74 75 76
      :base-directory ,(concat project-base "./blog")
      :recursive t
      :publishing-directory ,(concat website-publish-dir "./blog")
      :title nil
      :table-of-contents nil
      :auto-sitemap t
77
      :exclude "home.org"
Jay Kamat's avatar
Jay Kamat committed
78 79 80
      :sitemap-filename "rss.org"
      :sitemap-title "Blog Rss"
      :sitemap-function jay-publish-sitemap-expand
81
      :sitemap-sort-folders first
Jay Kamat's avatar
Jay Kamat committed
82
      :sitemap-sort-files anti-chronologically
83
      :publishing-function ignore)
Jay Kamat's avatar
Jay Kamat committed
84
     ("jgkamat.gitlab.io-rss"
Jay Kamat's avatar
Jay Kamat committed
85 86 87 88 89 90 91 92 93
      :base-directory ,(concat project-base "./blog")
      :recursive t
      :publishing-directory ,(concat website-publish-dir "/blog/")
      :title nil
      :with-headline-numbers nil
      :with-date nil
      :time-stamp-file nil
      :section-numbers nil
      :table-of-contents nil
Jay Kamat's avatar
Jay Kamat committed
94
      :email "jaygkamat@gmail.com"
95
      :author "Jay Kamat"
Jay Kamat's avatar
Jay Kamat committed
96 97
      :html-link-home "https://jgkamat.gitlab.io/blog/"
      :rss-image-url "https://jgkamat.gitlab.io/favicon.ico"
Jay Kamat's avatar
Jay Kamat committed
98 99 100
      :exclude ".*"
      :include ("./rss.org")
      :rss-extension "xml"
101
      :exclude-tags ("norss" "noexport")
Jay Kamat's avatar
Jay Kamat committed
102 103
      :publishing-function (org-rss-publish-to-rss)))))

104 105 106
(setq org-export-date-timestamp-format "%Y-%m-%d"
      org-html-metadata-timestamp-format org-export-date-timestamp-format
      org-html-postamble t
Jay Kamat's avatar
Jay Kamat committed
107
      org-html-postamble-format
108
      '(("en" "
Jay Kamat's avatar
Jay Kamat committed
109
<div>
Jay Kamat's avatar
Jay Kamat committed
110
<p class=\"author\">Author: <a href=\"https://gitlab.com/jgkamat/jgkamat.gitlab.io\">%a</a></p>
111
<p class=\"date\">Published: %d</p>
Jay Kamat's avatar
Jay Kamat committed
112 113
<p class=\"creator\">%c</p>
</div>")))
114

115
(setq blog-homepage (concat project-base "/blog/home.org"))
116
(setq overview-exclude-files '("rss.org"))
117 118


Jay Kamat's avatar
Jay Kamat committed
119
;; Blog generators
120 121 122
(defun org-timestamp-to-str (stamp)
  "Returns string value if org timestamp. Else, return stamp."
  (if (and (not (stringp stamp)) (eql (first stamp) 'timestamp))
123
      (plist-get (second stamp) ':raw-value)
124 125
    stamp))

Jay Kamat's avatar
Jay Kamat committed
126 127 128 129 130 131 132
(defun gen-raw-org-date (filename)
  "Generates raw date headers from filenames"
  (let ((filename (file-relative-name (file-truename filename))))
    (with-temp-buffer
      (insert-file-contents filename)
      (plist-get (org-export-get-environment) ':date))))

Jay Kamat's avatar
Jay Kamat committed
133 134
(defun gen-org-property (filename)
  "Generates an org property from a filename"
135
  (let ((filename (file-relative-name (file-truename filename))))
Jay Kamat's avatar
Jay Kamat committed
136 137 138
    (with-temp-buffer
      (insert-file-contents filename)
      ;; TODO use a plist here instead of hacky ordering
139
      `(,filename ,(plist-get (org-export-get-environment) ':date) ,(plist-get (org-export-get-environment) ':title)))))
Jay Kamat's avatar
Jay Kamat committed
140 141 142 143

(defun gen-links-properties (&optional directory)
  "Gens a sorted (by date) (filename . properties) from an org directory"
  (let* ((directory (or directory (concat project-base "/blog")))
144
         (files (directory-files-recursively directory "^.*\.org$")))
Jay Kamat's avatar
Jay Kamat committed
145
    (sort
146
     ;; Map environments to (filename . property titles)
147 148 149 150 151 152 153
     (mapcar #'gen-org-property
             (seq-remove
              (lambda (test-file)
                (cl-find-if (lambda (exclude-file)
                              (file-equal-p test-file exclude-file))
                            overview-exclude-files))
              files))
154 155 156 157 158 159 160 161 162
     (lambda (one two)
       (let ((x (org-timestamp-to-str (first (second one))))
             (y (org-timestamp-to-str (first (second two)))))
         ;; (print (concat x " " y))
         (when (and (not (or (eql x nil) (eql y nil)))
                    (or (eql 0 (org-2ft x)) (eql 0 (org-2ft y))))
           (error (concat "Org parsing error found: "
                          x ":" y)))
         (org-time< x y))))))
Jay Kamat's avatar
Jay Kamat committed
163

164
(defun org-property-to-link (x &optional pre post)
Jay Kamat's avatar
Jay Kamat committed
165
  "Turns a property genrated by gen-org-properties into an org link"
166 167
  (let ((pre (or pre "")) (post (or post "")))
    (format "[[file:%s][%s%s%s]]\n" (first x) pre (first (first (last x))) post)))
Jay Kamat's avatar
Jay Kamat committed
168
;; The directory you pass in must be the relative directory to work from (and must be relative to this file)
169
(defun gen-links (&optional directory)
Jay Kamat's avatar
Jay Kamat committed
170
  "Generates a list of links from a directory"
171
  (interactive)
Jay Kamat's avatar
Jay Kamat committed
172 173
  ;; Reduce everything into a string
  (reduce #'concat
174 175 176 177 178 179
          ;; Get desired sorting order
          (reverse
           ;; Map properties to strings
           (mapcar (lambda (x)
                     (format "1. %s" (org-property-to-link x)))
                   (gen-links-properties directory)))))
Jay Kamat's avatar
Jay Kamat committed
180 181 182 183


(defun gen-prev-next (&optional directory)
  (interactive)
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
  (unless (cl-find-if (lambda (exclude-file)
                        (file-equal-p buffer-file-name exclude-file))
                      overview-exclude-files)
    (let* ((current-property (gen-org-property buffer-file-name))
           (properties (gen-links-properties directory))
           (index (position current-property properties :test #'equal)))
      (when (eql index nil)
        (error "This org file was not part of this project"))
      (let* ((next (elt properties (min (1- (length properties)) (+ index 1))))
             (prev (elt properties (max 0 (- index 1)))))
        (concat
         "#+begin_div-wrap\n"
         "#+begin_div-left\n"
         (org-property-to-link prev "\\leftarrow ")
         "#+end_div-left\n"
         "#+begin_div-center\n"
         (format "[[file:%s][⟨Blog Home⟩]]\n" (file-relative-name blog-homepage))
         "#+end_div-center\n"
         "#+begin_div-right\n"
         (org-property-to-link next nil " \\rightarrow")
         "\n#+end_div-right"
         "\n#+end_div-wrap")))))
Jay Kamat's avatar
Jay Kamat committed
206

207 208 209 210 211 212 213

;; Don't prompt for build stuff
(defun my-org-confirm-babel-evaluate (lang body)
  (not (member lang '("emacs-lisp" "python" "sh" "dot"))))
(setq org-confirm-babel-evaluate 'my-org-confirm-babel-evaluate)

(setq org-cycle-include-plain-lists 'integrate ;; Cycle through plain lists
214 215
      org-pretty-entities t
      org-src-fontify-natively t)
216 217

(defun jgkamat-publish ()
218 219 220
  "Export this website.  Assumes this file has set up the projects already."
  (let ((make-backup-files nil))
    (org-publish-all t)))
221

Jay Kamat's avatar
Jay Kamat committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
(defun jay-publish-sitemap-expand (title list)
  "Site map, as a string.
TITLE is the the title of the site map.  LIST is an internal
representation for the files to include, as returned by
`org-list-to-lisp'.  PROJECT is the current project."
  (with-temp-buffer
    (org-mode)
    (insert (org-list-to-subtree list))
    (org-map-entries
     (lambda ()
       (let* (
              ;; TODO stop hard-coding blog dir here.
              (default-directory (concat project-base "./blog/"))
              (line (thing-at-point 'line t))
              (components (org-heading-components))
              (title (cl-fifth components))
              (link-target-raw (and (string-match org-bracket-link-regexp title)
                                    (match-string 1 title)))
              (link-target (car-safe (last (split-string link-target-raw ":"))))
              (rss-permalink (concat (file-name-sans-extension link-target) ".html")))

         (end-of-line)
         (insert (concat "\n"
                         "#+INCLUDE: \"" link-target) "\" :only-contents t :lines \"4-\"")
         (org-set-property "PUBDATE" (org-timestamp-to-str (first (gen-raw-org-date link-target))))
         (org-set-property "RSS_PERMALINK" rss-permalink))))
    (buffer-string)))

250 251 252
(provide 'jgkamat-website)

;;; jgkamat-website.el ends here