(require 'seq)
(require 'subr-x)
+(defgroup pelican-mode nil
+ "Support for Pelican posts and pages."
+ :group 'convenience)
+
+(defcustom pelican-mode-default-page-fields
+ '(:slug slug)
+ "Fields to include when creating a new page.
+
+See the documentation for `pelican-field' for more information
+about metadata fields and special values."
+ :group 'pelican-mode
+ :type '(plist))
+
+(defcustom pelican-mode-default-post-fields
+ '(:date now :status "draft" :slug slug)
+ "Fields to include when creating a new post.
+
+See the documentation for `pelican-field' for more information
+about metadata fields and special values."
+ :group 'pelican-mode
+ :type '(plist))
(defun pelican-timestamp (&optional time)
"Generate a Pelican-compatible timestamp for TIME."
- `slug' means the file's path relative to the document root sans
extension; see `pelican-default-slug'.
-- nil means return an empty string, without any name or value."
+- nil or an empty strings means return an empty string, without
+ any name or value."
(setq value (pcase value
('now (pelican-timestamp))
('slug (pelican-default-slug))
+ ('"" nil)
(_ value)))
(when (symbolp name)
(setq name (string-remove-prefix ":" (symbol-name name))))
""))
(defun pelican-rst-title (title)
- "Create a ReSt version of TITLE."
+ "Format a reStructureText version of TITLE."
(concat title "\n" (make-string (string-width title) ?#) "\n\n"))
(defun pelican-title (title)
(defun pelican-insert-draft-post-header (title tags)
"Insert a Pelican header for a draft with a TITLE and TAGS."
(interactive "sPost title: \nsTags: ")
- (save-excursion
- (goto-char 0)
- (insert (pelican-header title
- :date 'now
- :status "draft"
- :tags tags
- :slug 'slug))))
+ (apply #'pelican-insert-header
+ `(,title ,@pelican-mode-default-post-fields :tags ,tags)))
(defun pelican-insert-page-header (title &optional hidden)
"Insert a Pelican header for a page with a TITLE, potentially HIDDEN."
(interactive
(list (read-string "Page title: ")
(y-or-n-p "Hidden? ")))
- (save-excursion
- (goto-char 0)
- (insert (pelican-header title
- :status (when hidden "hidden")
- :slug 'slug))))
+ (apply #'pelican-insert-header
+ `(,title ,@pelican-mode-default-page-fields
+ :hidden ,(when hidden "hidden"))))
(defun pelican-insert-auto-header ()
"Insert a Pelican header for a page or post."
(interactive)
- (call-interactively (if (pelican-is-page)
- 'pelican-insert-page-header
- 'pelican-insert-draft-post-header)))
+ (call-interactively
+ (if (pelican-page-p)
+ #'pelican-insert-page-header
+ #'pelican-insert-draft-post-header)))
(defun pelican-set-field (field value)
"Set FIELD to VALUE."
(interactive "sField: \nsValue: ")
(save-excursion
(goto-char 0)
+ (when (and (derived-mode-p 'rst-mode)
+ (re-search-forward "^#" nil t))
+ (forward-line 2))
(if (re-search-forward (concat "^" (pelican-field field ".+*")) nil t)
(replace-match (pelican-field field value))
- (re-search-forward "#")
- (forward-line 2)
- (re-search-forward "^$")
- (replace-match (pelican-field field value)))))
+ (when value
+ (re-search-forward "^$")
+ (replace-match (pelican-field field value))))))
+
+(defun pelican-remove-field (field)
+ "Remove FIELD."
+ (pelican-set-field field nil))
(defun pelican-set-title (title)
"Set the title to TITLE."
(defun pelican-update-date ()
"Update a Pelican date header."
(interactive)
- (pelican-set-field "date" (pelican-timestamp)))
+ (pelican-set-field :date 'now))
(defun pelican-publish-draft ()
"Remove draft status from a Pelican post."
(interactive)
- (pelican-set-field "status" nil)
+ (pelican-remove-field :status)
(pelican-update-date))
-(defun pelican-is-page ()
+(defun pelican-page-p ()
"Guess the current buffer is a Pelican page (vs. a post or neither)."
(when-let (pelican-base (pelican-find-root))
(let* ((relative (file-relative-name buffer-file-name pelican-base))
(when-let (conf (pelican-find-in-parents "pelicanconf.py"))
(file-name-directory conf)))
-(defun pelican-is-in-site ()
+(defun pelican-site-p ()
"Check if this buffer is under a Pelican site."
(not (null (pelican-find-root))))
(interactive)
(pelican-make "rsync_upload"))
-(defconst pelican-keymap (make-sparse-keymap)
- "The default keymap used in Pelican mode.")
-(define-key pelican-keymap (kbd "C-c P n")
- 'pelican-insert-auto-header)
-(define-key pelican-keymap (kbd "C-c P p")
- 'pelican-publish-draft)
-(define-key pelican-keymap (kbd "C-c P t")
- 'pelican-update-date)
-(define-key pelican-keymap (kbd "C-c P h")
- 'pelican-make-html)
-(define-key pelican-keymap (kbd "C-c P u")
- 'pelican-make-rsync-upload)
-
-
;;;###autoload
(define-minor-mode pelican-mode
"Toggle Pelican mode.
Interactively with no argument, this command toggles the mode.
for editing Pelican site files."
- :init-value nil
:lighter " Pelican"
- :keymap pelican-keymap
- :group 'pelican)
+ :group 'pelican
+ :keymap `((,(kbd "C-c P n") . pelican-insert-auto-header)
+ (,(kbd "C-c P p") . pelican-publish-draft)
+ (,(kbd "C-c P t") . pelican-update-date)
+ (,(kbd "C-c P h") . pelican-make-html)
+ (,(kbd "C-c P u") . pelican-make-rsync-upload)))
;;;###autoload
(defun pelican-enable-if-site ()
"Enable `pelican-mode' if this buffer is under a Pelican site."
- (when (pelican-is-in-site)
+ (when (pelican-site-p)
(pelican-mode 1)))
;;;###autoload