;; Copyright 2013-2017 Joe Wreschnig
;;
;; Author: Joe Wreschnig <joe.wreschnig@gmail.com>
-;; Package-Version: 20170730
+;; Package-Version: 20170807
;; Package-Requires: ((emacs "25"))
+;; URL: https://git.korewanetadesu.com/pelican-mode.git
;; Keywords: convenience, editing
;;
;; This program is free software; you can redistribute it and/or modify
;;; Commentary:
;;
-;; pelican-mode is an Emacs minor mode for editing pages and posts in
-;; Pelican sites. Pelican is a static site generator which can
+;; pelican-mode is an Emacs minor mode for editing articles and pages
+;; in Pelican sites. Pelican is a static site generator which can
;; process a variety of text file formats. For more information, see
;; URL https://blog.getpelican.com/.
;;
-;; It's intended to be used alongside `markdown-mode' or `rst-mode'.
-;; It also assumes you've set up Pelican with ``pelican-quickstart''
-;; or something like it. In particular it assumes:
+;; It's intended to be used alongside a major mode for the Pelican
+;; document. Currently supported formats are Markdown,
+;; reStructuredText, AsciiDoc, and Org. It also assumes you've set up
+;; Pelican with ``pelican-quickstart'' or something like it. In
+;; particular it expects:
;;
;; * The existence of ``pelicanconf.py'' and ``Makefile'' in some
;; ancestor directory.
(require 'seq)
(require 'subr-x)
+;; Customizations
+
+(defgroup pelican-mode nil
+ "Support for Pelican articles and pages.
+
+For more information about Pelican see URL https://blog.getpelican.com/."
+ :group 'convenience)
+
+(defcustom pelican-mode-keymap-prefix (kbd "C-c P")
+ "Pelican mode keymap prefix."
+ :group 'pelican-mode
+ :type 'string)
+
+(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-mode
+ :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-mode
+ :type '(plist))
+
+(defcustom pelican-mode-formats
+ '((adoc-mode . pelican-mode-set-field-adoc-mode)
+ (markdown-mode . pelican-mode-set-field-markdown-mode)
+ (org-mode . pelican-mode-set-field-org-mode)
+ (rst-mode . pelican-mode-set-field-rst-mode))
+ "Functions to handle setting metadata, based on major mode.
+
+This association list maps modes to functions that take two
+arguments, field and value strings."
+ :group 'pelican-mode
+ :type '(alist :key-type function :value-type function))
+
+\f
+
;; Mode Definition
+(defvar pelican-mode-command-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "d") #'pelican-mode-update-date)
+ (define-key map (kbd "f") #'pelican-mode-set-field)
+ (define-key map (kbd "h") #'pelican-make-html)
+ (define-key map (kbd "n") #'pelican-mode-insert-header)
+ (define-key map (kbd "p") #'pelican-mode-publish)
+ (define-key map (kbd "u") #'pelican-make-rsync-upload)
+ map)
+ "Keymap for Pelican commands after `pelican-mode-keymap-prefix'.")
+(fset 'pelican-mode-command-map pelican-mode-command-map)
+
+(defvar pelican-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map pelican-mode-keymap-prefix
+ 'pelican-mode-command-map)
+ map)
+ "Keymap for Pelican mode.")
+
;;;###autoload
(define-minor-mode pelican-mode
"Toggle Pelican mode.
for editing articles or pages:
\\{pelican-mode-map}"
- :lighter " Pelican"
- :keymap `((,(kbd "C-c P d") . pelican-mode-update-date)
- (,(kbd "C-c P f") . pelican-set-field)
- (,(kbd "C-c P h") . pelican-make-html)
- (,(kbd "C-c P n") . pelican-mode-insert-header)
- (,(kbd "C-c P p") . pelican-mode-publish-draft)
- (,(kbd "C-c P u") . pelican-make-rsync-upload)))
+ :keymap pelican-mode-map
+ :lighter " Pelican")
;;;###autoload
(define-minor-mode pelican-global-mode
\f
-;; Customizations
-
-(defgroup pelican-mode nil
- "Support for Pelican articles and pages.
-
-For more information about Pelican see URL https://blog.getpelican.com/."
- :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-mode
- :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-mode
- :type '(plist))
-
-(defcustom pelican-mode-formats
- '((adoc-mode . pelican-mode-set-field-adoc-mode)
- (markdown-mode . pelican-mode-set-field-markdown-mode)
- (org-mode . pelican-mode-set-field-org-mode)
- (rst-mode . pelican-mode-set-field-rst-mode))
- "Functions to handle setting metadata, based on major mode.
-
-This association list maps modes to functions that take two
-arguments, field and value strings."
- :group 'pelican-mode
- :type '(alist :key-type function :value-type function))
-
-\f
-
;; User Commands
(defun pelican-mode-set-field (field value)
following special values, the unquoted printed representation of
it is used:
-- `now' means the current time; see `pelican-mode-timestamp'.
+- `now' means the current time.
- `slug' means the file's path relative to the document root sans
extension; see `pelican-mode-default-slug'.
for this function to work correctly."
(interactive "sField: \nsValue: ")
(setq value (pcase value
- ('now (pelican-mode-timestamp))
+ ('now (format-time-string "%Y-%m-%d %H:%M"))
('slug (pelican-mode-default-slug))
('"" nil)
(_ value)))
(interactive "P")
(pelican-mode-set-field (if original :date :modified) 'now))
-(defun pelican-mode-publish-draft ()
- "Remove draft status from a Pelican article."
+(defun pelican-mode-publish ()
+ "Remove draft or hidden status from a Pelican article."
(interactive)
(pelican-mode-remove-field :status)
(pelican-mode-update-date :date))
-(defun pelican-mode-insert-draft-article-header (title tags)
- "Insert a Pelican header for a draft with a TITLE and TAGS."
+(defun pelican-mode-insert-article-header (title tags)
+ "Insert a Pelican header for an article with a TITLE and TAGS."
(interactive "sArticle title: \nsTags: ")
- (apply #'pelican-mode-set-fields
- `(:title ,title
- ,@pelican-mode-default-article-fields
- :tags ,tags)))
+ (save-excursion
+ (goto-char 0)
+ (insert "\n")
+ (apply #'pelican-mode-set-fields
+ `(: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.
If HIDDEN is non-nil, the page is marked hidden; otherwise it
has no status."
(interactive "sPage title: \nP")
- (apply #'pelican-mode-set-fields
- (append
- (list :title title :status (when hidden "hidden"))
- pelican-mode-default-page-fields)))
+ (save-excursion
+ (goto-char 0)
+ (insert "\n")
+ (apply #'pelican-mode-set-fields
+ (append
+ (list :title title :status (when hidden "hidden"))
+ pelican-mode-default-page-fields))))
(defun pelican-mode-insert-header ()
"Insert a Pelican header for a page or article."
(call-interactively
(if (pelican-mode-page-p)
#'pelican-mode-insert-page-header
- #'pelican-mode-insert-draft-article-header)))
+ #'pelican-mode-insert-article-header)))
(defun pelican-make (target)
"Execute TARGET in a Makefile at the root of the site."
\f
-(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-set-fields (&rest fields)
"Insert a Pelican header for an article with metadata FIELDS."
(mapc (apply-partially #'apply #'pelican-mode-set-field)
(defun pelican-mode-page-p ()
"Return non-nil the current buffer is a Pelican page."
- (when-let (pelican-mode-base (pelican-mode-find-root))
- (let* ((relative (file-relative-name buffer-file-name pelican-mode-base))
- (components (split-string relative "/")))
- (equal "pages" (cadr components)))))
+ (string-match-p
+ "^[^/]+/pages/"
+ (file-relative-name
+ (abbreviate-file-name (or (buffer-file-name) (buffer-name)))
+ (pelican-mode-find-root))))
(defun pelican-mode-default-slug ()
- "Generate a Pelican article/page slug for the current buffer."
- (if-let ((pelican-mode-base (pelican-mode-find-root))
- (file-name (file-name-sans-extension buffer-file-name)))
- (let* ((relative (file-relative-name file-name pelican-mode-base))
- (components (cdr (split-string relative "/")))
- (components (if (string= "pages" (car components))
- (cdr components) components)))
- (mapconcat 'identity components "/"))
- (when-let (file-name (file-name-sans-extension buffer-file-name))
- (file-name-base file-name))))
+ "Generate a Pelican slug for the current buffer."
+ (file-name-sans-extension
+ (replace-regexp-in-string
+ "^[^/]+/\\(?:pages/\\)?" ""
+ (file-relative-name
+ (abbreviate-file-name (or (buffer-file-name) (buffer-name)))
+ (pelican-mode-find-root)))))
(defun pelican-mode-find-root ()
"Return the root of the buffer's Pelican site, or nil."