Some documentation.
[pelican-mode.git] / pelican-mode.el
index 4c3428a..6dceba5 100644 (file)
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+
 ;;; Commentary:
 ;;
 ;;; Commentary:
 ;;
-;; Probably, this doesn't handle a lot of error cases.  I also never
-;; tested it on networked drives and the lookup for pelicanconf.py
-;; might slow it down considerably.
+;; pelican-mode is an Emacs minor mode for editing pages and posts in
+;; Pelican (URL http://getpelican.com/) sites.
+;;
+;; 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:
+;;
+;;  * The existence of ``pelicanconf.py'' and ``Makefile'' in some
+;;    ancestor directory.
+;;  * The first component of the path (e.g. ``content'') after that
+;;    ancestor is irrelevant.
+;;  * If the next component is ``pages'', that indicates a page
+;;    rather than an article.
 
 
 ;;; Code:
 
 
 ;;; Code:
@@ -54,6 +65,16 @@ about metadata fields and special values."
   :group 'pelican
   :type '(plist))
 
   :group 'pelican
   :type '(plist))
 
+(defcustom pelican-mode-set-field-alist
+  '((markdown-mode . pelican-mode-set-field-markdown-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
+  :type '(alist :key-type function :value-type function))
+
 (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-timestamp (&optional time)
   "Generate a pelican-mode-compatible timestamp for TIME."
   (format-time-string "%Y-%m-%d %H:%M" time))
@@ -86,7 +107,7 @@ about metadata fields and special values."
        #'pelican-mode-insert-page-header
      #'pelican-mode-insert-draft-article-header)))
 
        #'pelican-mode-insert-page-header
      #'pelican-mode-insert-draft-article-header)))
 
-(defun pelican-mode-set-field/rst-mode (field value)
+(defun pelican-mode-set-field-rst-mode (field value)
   "Set reStructuredText metadata FIELD to VALUE."
   (setq field (downcase field))
   (if (equal field "title")
   "Set reStructuredText metadata FIELD to VALUE."
   (setq field (downcase field))
   (if (equal field "title")
@@ -101,18 +122,20 @@ about metadata fields and special values."
       (if (re-search-forward (format "^:%s:.*\n" (regexp-quote field)) nil t)
           (replace-match (or text ""))
         (when text
       (if (re-search-forward (format "^:%s:.*\n" (regexp-quote field)) nil t)
           (replace-match (or text ""))
         (when text
-          (re-search-forward "^$")
-          (replace-match text))))))
+          (if (re-search-forward "^$" nil t)
+              (replace-match text)
+            (insert text)))))))
 
 
-(defun pelican-mode-set-field/markdown-mode (field value)
+(defun pelican-mode-set-field-markdown-mode (field value)
   "Set Markdown metadata FIELD to VALUE."
   (setq field (capitalize field))
   (let ((text (when value (format "%s: %s\n" field value))))
     (if (re-search-forward (format "^%s:.*\n" (regexp-quote field)) nil t)
         (replace-match text)
       (when value
   "Set Markdown metadata FIELD to VALUE."
   (setq field (capitalize field))
   (let ((text (when value (format "%s: %s\n" field value))))
     (if (re-search-forward (format "^%s:.*\n" (regexp-quote field)) nil t)
         (replace-match text)
       (when value
-        (re-search-forward "^$")
-        (replace-match  text)))))
+        (if (re-search-forward "^$" nil t)
+            (replace-match text)
+          (insert text))))))
 
 (defun pelican-mode-set-field (field value)
   "Set FIELD to VALUE.
 
 (defun pelican-mode-set-field (field value)
   "Set FIELD to VALUE.
@@ -137,13 +160,13 @@ the unquoted printed representation of it is used:
                 (_ value)))
   (when (symbolp field)
     (setq field (string-remove-prefix ":" (symbol-name field))))
                 (_ value)))
   (when (symbolp field)
     (setq field (string-remove-prefix ":" (symbol-name field))))
-  (save-excursion
-    (goto-char 0)
-    (cond ((derived-mode-p 'markdown-mode)
-           (pelican-mode-set-field/markdown-mode field value))
-          ((derived-mode-p 'rst-mode)
-           (pelican-mode-set-field/rst-mode field value))
-          (t (error "Unsupported major mode %S" major-mode)))))
+  (let ((set-field
+         (assoc-default nil pelican-mode-set-field-alist #'derived-mode-p)))
+    (unless set-field
+      (error "Unsupported major mode %S" major-mode))
+    (save-excursion
+      (goto-char 0)
+      (funcall set-field field value))))
 
 (defun pelican-mode-remove-field (field)
   "Remove FIELD."
 
 (defun pelican-mode-remove-field (field)
   "Remove FIELD."
@@ -181,11 +204,8 @@ the unquoted printed representation of it is used:
              (components (if (string= "pages" (car components))
                              (cdr components) components)))
         (mapconcat 'identity components "/"))
              (components (if (string= "pages" (car components))
                              (cdr components) components)))
         (mapconcat 'identity components "/"))
-    (format "%s/%s"
-            (file-name-nondirectory
-             (directory-file-name
-              (file-name-directory file-name)))
-            (file-name-base file-name))))
+    (when-let (file-name (file-name-sans-extension buffer-file-name))
+      (file-name-base file-name))))
 
 (defun pelican-mode-find-in-parents (file-name)
   "Find FILE-NAME in the default directory or one of its parents, or nil."
 
 (defun pelican-mode-find-in-parents (file-name)
   "Find FILE-NAME in the default directory or one of its parents, or nil."
@@ -207,7 +227,7 @@ the unquoted printed representation of it is used:
   (if-let (default-directory (pelican-mode-find-root))
       (compilation-start (format "make %s" target)
                          nil (lambda (_) "*pelican*"))
   (if-let (default-directory (pelican-mode-find-root))
       (compilation-start (format "make %s" target)
                          nil (lambda (_) "*pelican*"))
-    (user-error "This doesn't look like a Pelican site")))
+    (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."