emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/tempel 91e1a3487f 1/2: Support specifying multiple path


From: ELPA Syncer
Subject: [elpa] externals/tempel 91e1a3487f 1/2: Support specifying multiple paths for tempel template files. (#4)
Date: Thu, 10 Mar 2022 16:57:47 -0500 (EST)

branch: externals/tempel
commit 91e1a3487f23f59fa96912c5531765985f580dc6
Author: Luis <luis@luishp.xyz>
Commit: GitHub <noreply@github.com>

    Support specifying multiple paths for tempel template files. (#4)
---
 tempel.el | 139 +++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 96 insertions(+), 43 deletions(-)

diff --git a/tempel.el b/tempel.el
index 8624ae8c03..ed0202c038 100644
--- a/tempel.el
+++ b/tempel.el
@@ -26,16 +26,16 @@
 
 ;;; Commentary:
 
-;; Tempel implements a simple template/snippet system. The template
-;; format is compatible with the template format of the Emacs Tempo
-;; library. Your templates are stored in the `tempel-file' (by default
-;; the file "templates" in the `user-emacs-directory'). Bind the
-;; commands `tempel-complete', `tempel-expand' or `tempel-insert' to
-;; some keys in your user configuration. You can jump with the keys M-{
-;; and M-} from field to field. `tempel-complete' and `tempel-expand'
-;; work best with the Corfu completion UI, while `tempel-insert' uses
-;; `completing-read' under the hood. You can also use `tempel-complete'
-;; and `tempel-expand' as `completion-at-point-functions'.
+;; Tempel implements a simple template/snippet system. The template format is
+;; compatible with the template format of the Emacs Tempo library. Your
+;; templates are stored in the `tempel-template-paths' (by default the file
+;; "templates" in the `user-emacs-directory'). Bind the commands
+;; `tempel-complete', `tempel-expand' or `tempel-insert' to some keys in your
+;; user configuration. You can jump with the keys M-{ and M-} from field to
+;; field. `tempel-complete' and `tempel-expand' work best with the Corfu
+;; completion UI, while `tempel-insert' uses `completing-read' under the
+;; hood. You can also use `tempel-complete' and `tempel-expand' as
+;; `completion-at-point-functions'.
 
 ;;; Code:
 
@@ -48,9 +48,9 @@
   :group 'editing
   :prefix "tempel-")
 
-(defcustom tempel-file (expand-file-name "templates" user-emacs-directory)
-  "Path to the template file."
-  :type 'string)
+(defcustom tempel-template-paths (expand-file-name "templates" 
user-emacs-directory)
+  "A file or a list of files and/or directories to look for snippets in."
+  :type '(choice (string list)))
 
 (defcustom tempel-mark
   #(" " 0 1 (display (space :width (1)) face cursor))
@@ -72,12 +72,18 @@ nil or a new template element, which is subsequently 
evaluated."
   :type 'hook)
 
 (defcustom tempel-template-sources
-  (list #'tempel-file-templates)
+  (list #'tempel-path-templates)
   "List of template sources.
 A source can either be a function or a variable symbol. The functions
 must return a list of templates which apply to the buffer or context."
   :type 'hook)
 
+(defcustom tempel-auto-reload-templates-p t
+  "Non-nil means to reload snippets when files specified by 
`tempel-template-paths' change.
+If any file in `tempel-template-paths' is modified or new files are added or
+removed from `tempel-template-paths', reload the templates."
+  :type 'boolean)
+
 (defface tempel-field
   '((((class color) (min-colors 88) (background light))
      :background "#fdf0ff" :foreground "#541f4f")
@@ -102,11 +108,8 @@ must return a list of templates which apply to the buffer 
or context."
     (t :inherit highlight :slant italic))
   "Face used for default values.")
 
-(defvar tempel--file-templates nil
-  "Templates loaded from the `tempel-file'.")
-
-(defvar tempel--file-modified nil
-  "Modification time of `tempel-file' at the last load.")
+(defvar tempel--path-templates nil
+  "Templates loaded from the `tempel-template-paths'.")
 
 (defvar tempel--history nil
   "Completion history used by `tempel-insert'.")
@@ -138,6 +141,13 @@ may be named with `tempel--name' or carry an evaluatable 
Lisp expression
     map)
   "Keymap to navigate across template fields.")
 
+(defvar tempel--modified 0
+  "Most recent modification time of files in `tempel-template-paths' since
+loading the templates.
+If templates have not been loaded yet, this is 0.")
+
+(defvar tempel--old-template-paths tempel-template-paths)
+
 (defun tempel--print-element (elt)
   "Return string representation of template ELT."
   (pcase elt
@@ -149,6 +159,22 @@ may be named with `tempel--name' or carry an evaluatable 
Lisp expression
     ((or 'n 'n> '> '& '% 'o) " ")
     (_ "_")))
 
+(defun tempel--expand-paths (paths)
+  "Return the list of files specified by PATHS.
+PATHS is a list of files and directories."
+  (let ((paths (if (listp paths) paths (list paths)))
+       (file-paths nil))
+    (dolist (path paths)
+      (when (file-exists-p path)
+       (if (file-directory-p path)
+           (setq file-paths (append file-paths (directory-files-recursively 
path "[^z-a]+")))
+         (push path file-paths))))
+    file-paths))
+
+(defun tempel--load-templates ()
+  "Return templates specified `tempel-template-paths'."
+  (mapcan #'tempel--file-read (tempel--expand-paths tempel-template-paths)))
+
 (defun tempel--annotate (templates width ellipsis sep name)
   "Annotate template NAME given the list of TEMPLATES.
 WIDTH, SEP and ELLIPSIS configure the formatting."
@@ -373,11 +399,35 @@ PROMPT is the optional prompt/default value."
     (eval (plist-get plist :post) 'lexical)))
 
 (defun tempel--save ()
-  "Save template file buffer."
-  (when-let (buf (get-file-buffer tempel-file))
-    (with-current-buffer buf
-      (when (and (buffer-modified-p) (y-or-n-p (format "Save file %s? " 
tempel-file)))
-        (save-buffer buf)))))
+  "Prompt to save any modified files in `tempel-template-paths'."
+  (let (modified)
+    (dolist (file (tempel--expand-paths tempel-template-paths))
+      (when-let (buff (get-file-buffer file))
+       (push file modified)))
+    (when (or (and (= (length modified) 1)
+                  (y-or-n-p "Save template file %s? " (car modified)))
+             (y-or-n-p "Save modified template files? "))
+      (mapc #'save-buffer modified))))
+
+(defun tempel--min-modification-time ()
+  "Return the earliest modification time (in seconds)."
+  (if-let (paths (tempel--expand-paths tempel-template-paths))
+      (apply #'min (mapcar (lambda (f) (time-convert 
(file-attribute-modification-time (file-attributes f)) 'integer))
+                          paths))
+    0))
+
+(defun tempel--paths-updated-p ()
+  "Return non-nil if files have been added or removed from 
`tempel-template-paths'."
+  (let* ((old (tempel--expand-paths tempel--old-template-paths))
+        (new (tempel--expand-paths tempel-template-paths))
+        (length-old (length old))
+        (length-new (length new)))
+    (not (and (= length-old length-new)
+             (= length-old (length (cl-intersection old new)))))))
+
+(defun tempel--files-modified-p ()
+  "Return non-nil if any files in `tempel-template-paths' have been modified 
since loading."
+  (< tempel--modified (tempel--min-modification-time)))
 
 (defun tempel--file-read (file)
   "Load templates from FILE."
@@ -400,25 +450,28 @@ PROMPT is the optional prompt/default value."
           (push `(,(nreverse modes) ,(nreverse plist) . ,(nreverse templates)) 
result)))
       result)))
 
-(defun tempel-file-templates ()
-  "Load the templates defined in `tempel-file'."
-  (let ((mod (time-convert (file-attribute-modification-time
-                            (file-attributes tempel-file))
-                           'integer)))
-    (unless (equal tempel--file-modified mod)
-      (setq tempel--file-templates (tempel--file-read tempel-file)
-            tempel--file-modified mod)))
-  (cl-loop
-   for (modes plist . templates) in tempel--file-templates
-   if (and
-       (cl-loop for m in modes
-                thereis (or (derived-mode-p m) (eq m #'fundamental-mode)))
-       (or (not (plist-member plist :condition))
-           (save-excursion
-             (save-restriction
-               (save-match-data
-                 (eval (plist-get plist :condition) 'lexical))))))
-   append templates))
+(defun tempel-path-templates ()
+  "Return templates defined in `tempel-template-paths'.
+Additionally, save any files in `tempel-template-sources' that have been
+modified since the last time this function was called.
+This is meant to be a source in `tempel-template-sources'."
+  (when (and tempel-auto-reload-templates-p
+            (or (zerop tempel--modified)
+                (tempel--files-modified-p)
+                (tempel--paths-updated-p)))
+    (setq tempel--modified (tempel--min-modification-time))
+    (setq tempel--old-template-paths tempel-template-paths)
+    (setq tempel--path-templates (tempel--load-templates)))
+  (let (templates)
+    (pcase-dolist (`(,modes ,plist . ,template) tempel--path-templates)
+      (when (and (seq-some (lambda (m) (or (derived-mode-p m) (eq m 
#'fundamental-mode))) modes)
+                (or (not (plist-member plist :condition))
+                    (save-excursion
+                      (save-restriction
+                        (save-match-data
+                          (eval (plist-get plist :condition) 'lexical))))))
+       (push template templates)))
+    (apply #'append (nreverse templates))))
 
 (defun tempel--templates ()
   "Return templates for current mode."



reply via email to

[Prev in Thread] Current Thread [Next in Thread]