-
Notifications
You must be signed in to change notification settings - Fork 83
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make it possible to use djula as template engine #107
base: master
Are you sure you want to change the base?
Changes from 5 commits
6ab3acc
e59ec41
ce9947d
8dd41e9
6df131d
f2cd595
f648061
ff4e320
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,16 +3,27 @@ | |
(defvar *last-revision* nil | ||
"The git revision prior to the last push. For use with GET-UPDATED-FILES.") | ||
|
||
(defvar *templating-engine* nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer the templating engine (and any related vars like |
||
"The templating engine to use. This will be set during the main routine. | ||
Possible options at this time are djula and cl-closure.") | ||
|
||
(defvar *djula-post-template* nil | ||
"The template to use for rendering a post using a djula template.") | ||
|
||
(defvar *djula-index-template* nil | ||
"The template to use for rendering the index using a djula template.") | ||
|
||
(defun main (repo-dir &optional oldrev) | ||
"Load the user's config file, then compile and deploy the blog stored | ||
in REPO-DIR. Optionally, OLDREV is the revision prior to the last push." | ||
(load-config repo-dir) | ||
(setf *last-revision* oldrev) | ||
(load-content) | ||
(compile-theme (theme *config*)) | ||
(let ((dir (staging-dir *config*))) | ||
(compile-blog dir) | ||
(deploy dir))) | ||
(let ((*templating-engine* (template-engine *config*))) | ||
(setf *last-revision* oldrev) | ||
(load-content) | ||
(compile-theme (theme *config*)) | ||
(let ((dir (staging-dir *config*))) | ||
(compile-blog dir) | ||
(deploy dir)))) | ||
|
||
(defun load-content () | ||
"Load all content stored in the blog's repo." | ||
|
@@ -63,9 +74,16 @@ in REPO-DIR. Optionally, OLDREV is the revision prior to the last push." | |
(defun render-page (content &optional theme-fn &rest render-args) | ||
"Render the given CONTENT to HTML using THEME-FN if supplied. | ||
Additional args to render CONTENT can be passed via RENDER-ARGS." | ||
(funcall (or theme-fn (theme-fn 'base)) | ||
(list :config *config* | ||
:content content | ||
:raw (apply 'render content render-args) | ||
:pubdate (format-rfc1123-timestring nil (local-time:now)) | ||
:injections (find-injections content)))) | ||
(let ((index-args (list :config *config* | ||
:content content | ||
:pubdate (format-rfc1123-timestring nil | ||
(local-time:now)) | ||
:injections (find-injections content)))) | ||
(case *templating-engine* | ||
(cl-closure | ||
(apply (or theme-fn | ||
(theme-fn 'base)) | ||
(append (list :raw (apply 'render content render-args)) | ||
index-args))) | ||
(djula (apply 'render content (append index-args render-args))) | ||
(otherwise (error "Unkown templating engine found"))))) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,9 +26,27 @@ function that takes a DOCUMENT and returns NIL or a STRING for template insertio | |
(or (find-package (format nil "~:@(coleslaw.theme.~A~)" name)) | ||
(error 'theme-does-not-exist :theme name))) | ||
|
||
(defun theme-fn (name &optional (package (theme *config*))) | ||
"Find the symbol NAME inside PACKAGE which defaults to the theme package." | ||
(find-symbol (princ-to-string name) (theme-package package))) | ||
(defun get-djula-theme (name) | ||
(symbol-value (intern (string-upcase (format nil "*djula-~A-template*" (string name)))))) | ||
|
||
(defun theme-fn (name &optional | ||
(package (theme *config*)) | ||
(templating-engine *templating-engine*)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't |
||
"This function returns a function that will accept an arbitrary number of | ||
arguments and will return a html string. If the given templating-engine is not | ||
support this will signal a SIMPLE-ERROR" | ||
(case templating-engine | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To make this extensible, we should dispatch on hash-table instead, something like (if-let (theme-fn (gethash templating-engine *available-engines*))
theme-fn
(error "Theme-fn not found. Unknown template-engine ~A" templating-engine)) |
||
(cl-closure (let ((func (find-symbol (princ-to-string name) | ||
(theme-package package)))) | ||
(lambda (&rest rest) | ||
(funcall func rest)))) | ||
(djula (lambda (&rest rest) | ||
(with-output-to-string (stream) | ||
(apply #'render-template* | ||
(get-djula-theme name) | ||
stream | ||
rest)))) | ||
(otherwise (error "Unkown templating engine found")))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For ease of debuggability, we should include the value that we failed to match, templating-engine in this case. |
||
|
||
(defun find-theme (theme) | ||
"Find the theme prefering themes in the local repo." | ||
|
@@ -38,8 +56,30 @@ function that takes a DOCUMENT and returns NIL or a STRING for template insertio | |
(app-path "themes/~a/" theme)))) | ||
|
||
(defun compile-theme (theme) | ||
"Locate and compile the templates for the given THEME." | ||
(do-files (file (find-theme theme) "tmpl") | ||
"Locate and compile the templates for the given THEME and compile them. In the | ||
case of cl-closure this will define extra functions and in the case of Djula this | ||
will set *DJULA-POST-TEMPLATE* and *DJULA-INDEX-TEMPATE*. This will always define | ||
the cl-closure functions for atom, sitemap and rss." | ||
;; Define functions for atom, sitemap and rss. | ||
(do-files (file (app-path "themes/") | ||
"tmpl") | ||
(compile-template :common-lisp-backend file)) | ||
(do-files (file (app-path "themes/") "tmpl") | ||
(compile-template :common-lisp-backend file))) | ||
;; Now find the correct templates | ||
(let ((theme-base (find-theme theme))) | ||
(format t | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
"~A, ~A, ~A ~A~%" | ||
*templating-engine* | ||
(equal *templating-engine* (intern "DJULA")) | ||
(eql *templating-engine* | ||
(intern "DJULA")) | ||
(equal *templating-engine* 'DJULA)) | ||
(case *templating-engine* | ||
(cl-closure (do-files (file theme-base "tmpl") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the above comment, using hash-table would allow extension |
||
(compile-template :common-lisp-backend file))) | ||
(djula (dolist (page '("post" "index")) | ||
(set (intern (string-upcase (format nil "*djula-~A-template*" page))) | ||
(compile-template* (merge-pathnames theme-base | ||
(make-pathname :directory "/" | ||
:name page | ||
:type "html")))))) | ||
(otherwise (error "Unkown templating engine found at compiling"))))) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<!doctype html> | ||
<html lang="{{ config.lang }}"> | ||
<head> | ||
<title>{{ config.title }}</title> | ||
<meta http-equiv="content-type" content="text/html; charset={{ config.charset }}" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link href="//fonts.googleapis.com/css?family=Vollkorn:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css" /> | ||
<link href="//fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet" type="text/css" /> | ||
<link href= "{{ config.domain }}/css/style.css" rel="stylesheet" type="text/css" /> | ||
<link rel="alternate" href="{{ config.domain }}/rss.xml" type="application/rss+xml" /> | ||
{% if injections.head %} | ||
{% for injection in injections.head %} | ||
{{ injection | safe }} | ||
{% endfor %} | ||
{% endif %} | ||
</head> | ||
<body> | ||
<div class="navigation"> | ||
<a href="{{ config.domain }}">{{ config.title }}</a> | | ||
{% for link in config.sitenav %} | ||
{% if link.relative %} | ||
<a href="{{ config.domain }}/{{ link.url }}">{{ link.name }}</a> | ||
{% else %} | ||
<a href="{{ link.url }}">{{ link.name }}</a> | ||
{% endif %} | ||
{% if not forloop.last %} | {% endif %} | ||
{% endfor %} | ||
</div> | ||
<div id="content"> | ||
{% block content %}{% endblock %} | ||
</div> | ||
{% if injections.body %} | ||
{% for injection in injections.body %} | ||
{{ injection | safe }} | ||
{% endfor %} | ||
{% endif %} | ||
<div class="fineprint"> | ||
<hr> | ||
Unless otherwise credited all material | ||
{% if config.license %} | ||
{{ config.license }} | ||
{% else %} | ||
<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/deed.en_US"> | ||
<img alt="Creative Commons License" style="border-width:0" src="{{ config.domain }}/css/cc-by-sa.png" /> | ||
</a> | ||
{% endif %} | ||
by {{ config.author }} | ||
<a id="coleslaw-logo" href="https://github.com/redline6561/coleslaw"> | ||
<img src="{{ config.domain }}/css/logo_small.jpg" alt="Coleslaw logo" /> | ||
</a> | ||
</div> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If at all possible, I would prefer we load djula in an
eval-when
in the plugin as we do with other plugins that have additional library dependencies. If it is necessary to also initialize/compile templates at that time, the data necessary to do so can be passed into theenable
method in the plugin and they can be compiled then.