Remove use of ‘if-let’ for Emacs 26+ compatibility
[pelican-mode.git] / pelican-mode.el
index 60089cd..9886e8c 100644 (file)
@@ -3,8 +3,9 @@
 ;; Copyright 2013-2017 Joe Wreschnig
 ;;
 ;; Author: Joe Wreschnig <joe.wreschnig@gmail.com>
 ;; Copyright 2013-2017 Joe Wreschnig
 ;;
 ;; Author: Joe Wreschnig <joe.wreschnig@gmail.com>
-;; Package-Version: 20170730
+;; Package-Version: 20170808
 ;; Package-Requires: ((emacs "25"))
 ;; 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
 ;; Keywords: convenience, editing
 ;;
 ;; This program is free software; you can redistribute it and/or modify
 
 ;;; Commentary:
 ;;
 
 ;;; 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/.
 ;;
 ;; process a variety of text file formats.  For more information, see
 ;; URL https://blog.getpelican.com/.
 ;;
-;; It's intended to be used alongside a major mode for the Pelican
+;; Its intended to be used alongside a major mode for the Pelican
 ;; document.  Currently supported formats are Markdown,
 ;; 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
+;; reStructuredText, AsciiDoc, and Org.  It also assumes youve set up
+;; Pelican with “pelican-quickstart” or something like it.  In
 ;; particular it expects:
 ;;
 ;; particular it expects:
 ;;
-;;  * The existence of ``pelicanconf.py'' and ``Makefile'' in some
+;;  * The existence of “pelicanconf.py” and “Makefile” in some
 ;;    ancestor directory.
 ;;    ancestor directory.
-;;  * The first component of the path (e.g. ``content'') after that
+;;  * The first component of the path (e.g. “content”) after that
 ;;    ancestor is irrelevant.
 ;;    ancestor is irrelevant.
-;;  * If the next component is ``pages'', that indicates a page
+;;  * If the next component is “pages”, that indicates a page
 ;;    rather than an article.
 ;;
 ;; To enable by default on all text files in a Pelican site:
 ;;    rather than an article.
 ;;
 ;; To enable by default on all text files in a Pelican site:
 ;;     (require 'pelican-mode)
 ;;     (pelican-global-mode)
 ;;
 ;;     (require 'pelican-mode)
 ;;     (pelican-global-mode)
 ;;
-;; Or, register `pelican-mode' or `pelican-mode-enable-if-site'
+;; Or with ‘use-package’ and deferred loading:
+;;
+;;     (use-package pelican-mode
+;;       :demand :after (:any org rst markdown-mode adoc-mode)
+;;       :config
+;;       (pelican-global-mode))
+;;
+;; Or, register ‘pelican-mode’ or ‘pelican-mode-enable-if-site’
 ;; as hook functions for more direct control.
 
 \f
 ;; as hook functions for more direct control.
 
 \f
 (require 'seq)
 (require 'subr-x)
 
 (require 'seq)
 (require 'subr-x)
 
-;; Mode Definition
-
-;;;###autoload
-(define-minor-mode pelican-mode
-  "Toggle Pelican mode.
-With a prefix argument ARG, enable Pelican mode if ARG is
-positive, and disable it otherwise.  If called from Lisp, enable
-the mode if ARG is omitted or nil.
-
-Pelican is a static site generator which can process a variety of
-text file formats.  For more information, see URL
-https://blog.getpelican.com/.
-
-Rather than manually enabling this mode, you may wish to use
-`pelican-global-mode' or `pelican-mode-enable-if-site'.
-
-When Pelican mode is enabled, additional commands are available
-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)))
-
-;;;###autoload
-(define-minor-mode pelican-global-mode
-  "Toggle Pelican global mode.
-With a prefix argument ARG, enable Pelican global mode if ARG is
-positive, and disable it otherwise.  If called from Lisp, enable
-the mode if ARG is omitted or nil.
-
-Pelican is a static site generator which can process a variety of
-text file formats.  For more information, see URL
-https://blog.getpelican.com/.
-
-When Pelican global mode is enabled, text files which seem to
-be part of a Pelican site will have `pelican-mode' automatically
-enabled.
-
-If you disable this, you may still enable `pelican-mode' manually
-or add `pelican-mode-enable-if-site' to more specific mode
-hooks."
-  :global t
-  :group 'pelican-mode
-  (if pelican-global-mode
-      (add-hook 'text-mode-hook #'pelican-mode-enable-if-site)
-    (remove-hook 'text-mode-hook #'pelican-mode-enable-if-site)))
-
-;;;###autoload
-(defun pelican-mode-enable-if-site ()
-  "Enable `pelican-mode' if this buffer is part of a Pelican site.
-
-Pelican sites are detected by looking for a file named `pelicanconf.py'
-in an ancestor directory."
-  (when (pelican-mode-find-root)
-    (pelican-mode)))
-
-\f
-
 ;; Customizations
 
 ;; Customizations
 
-(defgroup pelican-mode nil
+(defgroup pelican nil
   "Support for Pelican articles and pages.
 
 For more information about Pelican see URL https://blog.getpelican.com/."
   :group 'convenience)
 
   "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 =")
+  "Pelican mode keymap prefix."
+  :group 'pelican
+  :type 'string)
+
 (defcustom pelican-mode-default-page-fields
   '(:slug slug)
   "Fields to include when creating a new page.
 
 (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
+See the documentation for ‘pelican-mode-set-field’ for more information
 about metadata fields and special values."
 about metadata fields and special values."
-  :group 'pelican-mode
+  :group 'pelican
   :type '(plist))
 
 (defcustom pelican-mode-default-article-fields
   '(:date now :status "draft" :slug slug)
   "Fields to include when creating a new article.
 
   :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
+See the documentation for ‘pelican-mode-set-field’ for more information
 about metadata fields and special values."
 about metadata fields and special values."
-  :group 'pelican-mode
+  :group 'pelican
   :type '(plist))
 
 (defcustom pelican-mode-formats
   :type '(plist))
 
 (defcustom pelican-mode-formats
@@ -155,31 +105,93 @@ about metadata fields and special values."
 
 This association list maps modes to functions that take two
 arguments, field and value strings."
 
 This association list maps modes to functions that take two
 arguments, field and value strings."
-  :group 'pelican-mode
+  :group 'pelican
   :type '(alist :key-type function :value-type function))
 
 \f
 
   :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.
+With a prefix argument ARG, enable Pelican mode if ARG is
+positive, and disable it otherwise.  If called from Lisp, enable
+the mode if ARG is omitted or nil.
+
+Pelican is a static site generator which can process a variety of
+text file formats.  For more information, see URL
+https://blog.getpelican.com/.
+
+Rather than manually enabling this mode, you may wish to use
+‘pelican-global-mode’ or ‘pelican-mode-enable-if-site’.
+
+When Pelican mode is enabled, additional commands are available
+for editing articles or pages:
+
+\\{pelican-mode-map}"
+  :group 'pelican
+  :keymap pelican-mode-map
+  :lighter " Pelican")
+
+;;;###autoload
+(define-globalized-minor-mode pelican-global-mode pelican-mode
+  (lambda ()
+    (when (derived-mode-p #'text-mode)
+      (pelican-mode-enable-if-site)))
+  :group 'pelican
+  :require 'pelican-mode)
+
+;;;###autoload
+(defun pelican-mode-enable-if-site ()
+  "Enable ‘pelican-mode’ if this buffer is part of a Pelican site.
+
+Pelican sites are detected by looking for a file named
+“pelicanconf.py” in an ancestor directory."
+  (when (pelican-mode-find-root)
+    (pelican-mode)))
+
+\f
+
 ;; User Commands
 
 (defun pelican-mode-set-field (field value)
   "Set FIELD to VALUE.
 
 FIELD may be a string or a symbol; if it is a symbol, the
 ;; User Commands
 
 (defun pelican-mode-set-field (field value)
   "Set FIELD to VALUE.
 
 FIELD may be a string or a symbol; if it is a symbol, the
-symbol name is used (removing a leading ':' if present).
+symbol name is used (removing a leading “:” if present).
 
 When called from Lisp, VALUE may be any value; except for the
 following special values, the unquoted printed representation of
 it is used:
 
 
 When called from Lisp, VALUE may be any value; except for the
 following special values, the unquoted printed representation of
 it is used:
 
-- `now' means the current time.
+- ‘now’ means the current time.
 
 
-- `slug' means the file's path relative to the document root sans
-  extension; see `pelican-mode-default-slug'.
+- ‘slug’ means the file’s path relative to the document root sans
+  extension; see ‘pelican-mode-default-slug’.
 
 - nil or an empty string removes the field.
 
 
 - nil or an empty string removes the field.
 
-The buffer must be in a format listed in `pelican-mode-formats'
+The buffer must be in a format listed in ‘pelican-mode-formats’
 for this function to work correctly."
   (interactive "sField: \nsValue: ")
   (setq value (pcase value
 for this function to work correctly."
   (interactive "sField: \nsValue: ")
   (setq value (pcase value
@@ -208,26 +220,29 @@ for this function to work correctly."
   (pelican-mode-set-field :title title))
 
 (defun pelican-mode-update-date (&optional original)
   (pelican-mode-set-field :title title))
 
 (defun pelican-mode-update-date (&optional original)
-  "Update the document's modification date.
+  "Update the documents modification date.
 
 If ORIGINAL is non-nil, the publication date is updated rather
 than the modification date."
   (interactive "P")
   (pelican-mode-set-field (if original :date :modified) 'now))
 
 
 If ORIGINAL is non-nil, the publication date is updated rather
 than the modification date."
   (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))
 
   (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: ")
   (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.
 
 (defun pelican-mode-insert-page-header (title &optional hidden)
   "Insert a Pelican header for a page with a TITLE.
@@ -235,10 +250,13 @@ than the modification date."
 If HIDDEN is non-nil, the page is marked hidden; otherwise it
 has no status."
   (interactive "sPage title: \nP")
 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."
 
 (defun pelican-mode-insert-header ()
   "Insert a Pelican header for a page or article."
@@ -246,15 +264,16 @@ has no status."
   (call-interactively
    (if (pelican-mode-page-p)
        #'pelican-mode-insert-page-header
   (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."
   (interactive "sMake Pelican target: ")
 
 (defun pelican-make (target)
   "Execute TARGET in a Makefile at the root of the site."
   (interactive "sMake Pelican target: ")
-  (if-let (default-directory (pelican-mode-find-root))
-      (compilation-start (format "make %s" target)
-                         nil (lambda (_) "*pelican*"))
-    (user-error "No Pelican site root could be found")))
+  (let ((default-directory (pelican-mode-find-root)))
+    (if default-directory
+        (compilation-start (format "make %s" target)
+                           nil (lambda (_) "*pelican*"))
+      (user-error "No Pelican site root could be found"))))
 
 (defun pelican-make-html ()
   "Generate HTML via a Makefile at the root of the site."
 
 (defun pelican-make-html ()
   "Generate HTML via a Makefile at the root of the site."
@@ -323,7 +342,7 @@ has no status."
 
 (defun pelican-mode-set-field-org-mode (field value)
   "Set Org global metadata FIELD to VALUE."
 
 (defun pelican-mode-set-field-org-mode (field value)
   "Set Org global metadata FIELD to VALUE."
-  ;; None of org-mode's functions I can find for setting properties
+  ;; None of org-modes functions I can find for setting properties
   ;; operate on the global list, only a single property drawer.
   (setq field (upcase field))
   (setq field
   ;; operate on the global list, only a single property drawer.
   (setq field (upcase field))
   (setq field
@@ -357,14 +376,8 @@ has no status."
      (pelican-mode-find-root)))))
 
 (defun pelican-mode-find-root ()
      (pelican-mode-find-root)))))
 
 (defun pelican-mode-find-root ()
-  "Return the root of the buffer's Pelican site, or nil."
+  "Return the root of the buffers Pelican site, or nil."
   (locate-dominating-file default-directory "pelicanconf.py"))
 
 (provide 'pelican-mode)
 ;;; pelican-mode.el ends here
   (locate-dominating-file default-directory "pelicanconf.py"))
 
 (provide 'pelican-mode)
 ;;; pelican-mode.el ends here
-
-\f
-
-;; Local Variables:
-;; sentence-end-double-space: t
-;; End: