-(defun pelican-timestamp-now ()
- "Generate a Pelican-compatible timestamp."
- (format-time-string "%Y-%m-%d %H:%M"))
-
-(defun pelican-is-markdown ()
- "Check if the buffer is likely using Markdown."
- (eq major-mode 'markdown-mode))
-
-(defun pelican-field (name value)
- "Helper to format a field NAME and VALUE."
- (if value (format "%s: %s\n" name value) ""))
-
-(defun pelican-markdown-header (title date status category tags slug)
- "Generate a Pelican Markdown header.
-
-All parameters but TITLE may be nil to omit them. DATE may be a
-string or 't to use the current date and time."
- (let ((title (format "Title: %s\n" title))
- (status (pelican-field "Status" status))
- (category (pelican-field "Category" category))
- (tags (pelican-field "Tags" tags))
- (slug (pelican-field "Slug" slug))
- (date (if date (format "Date: %s\n"
- (if (stringp date) date
- (pelican-timestamp-now)))
- "")))
- (concat title date status tags category slug "\n")))
-
-(defun pelican-rst-header (title date status category tags slug)
- "Generate a Pelican reStructuredText header.
-
-All parameters but TITLE may be nil to omit them. DATE may be a
-string or 't to use the current date and time."
- (let ((title (format "%s\n%s\n\n" title
- (make-string (string-width title) ?#)))
- (status (pelican-field ":status" status))
- (category (pelican-field ":category" category))
- (tags (pelican-field ":tags" tags))
- (slug (pelican-field ":slug" slug))
- (date (if date (format ":date: %s\n"
- (if (stringp date) date
- (pelican-timestamp-now)))
- "")))
- (concat title date status tags category slug "\n")))
-
-(defun pelican-insert-draft-post-header (title tags)
- "Insert a Pelican header for a draft post."
- (interactive "sPost title: \nsTags: ")
- (let ((slug (pelican-default-slug))
- (header (if (pelican-is-markdown)
- 'pelican-markdown-header 'pelican-rst-header)))
- (save-excursion
- (goto-char 0)
- (insert (funcall header title 't "draft" nil tags slug)))))
-
-(defun pelican-insert-page-header (title hidden)
- "Insert a Pelican header for a page."
+(require 'seq)
+(require 'subr-x)
+
+(defgroup pelican-mode nil
+ "Support for Pelican articles 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-mode-set-field' for more information
+about metadata fields and special values."
+ :group 'pelican
+ :type '(plist))
+
+(defcustom pelican-mode-default-article-fields
+ '(:date now :status "draft" :slug slug)
+ "Fields to include when creating a new article.
+
+See the documentation for `pelican-mode-set-field' for more information
+about metadata fields and special values."
+ :group 'pelican
+ :type '(plist))
+
+(defun pelican-mode-timestamp (&optional time)
+ "Generate a pelican-mode-compatible timestamp for TIME."
+ (format-time-string "%Y-%m-%d %H:%M" time))
+
+(defun pelican-mode-insert-header (&rest fields)
+ "Insert a Pelican header for an article with metadata FIELDS."
+ (mapc (apply-partially #'apply #'pelican-mode-set-field)
+ (seq-partition fields 2)))
+
+(defun pelican-mode-insert-draft-article-header (title tags)
+ "Insert a Pelican header for a draft with a TITLE and TAGS."
+ (interactive "sArticle title: \nsTags: ")
+ (apply #'pelican-mode-insert-header
+ `(:title ,title ,@pelican-mode-default-article-fields :tags ,tags)))
+
+(defun pelican-mode-insert-page-header (title &optional hidden)
+ "Insert a Pelican header for a page with a TITLE, potentially HIDDEN."