From 06f94c27e7e28b21dc784faa2648a0d8916cdc09 Mon Sep 17 00:00:00 2001 From: Ursus Wigger Date: Tue, 22 Oct 2024 09:47:41 +0200 Subject: [PATCH 1/2] Added feature: :enable-function --- README.org | 19 +++++++++++++------ tempel.el | 48 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/README.org b/README.org index 948abd5..4549980 100644 --- a/README.org +++ b/README.org @@ -110,12 +110,15 @@ contributions. The templates are defined in a Lisp data file configured by ~tempel-path~. Lisp data files are files containing Lisp s-expressions (see ~lisp-data-mode~). By default the file =~/.config/emacs/templates= is used. The templates are grouped by -major mode with an optional ~:when~ condition. Each template is a list in the -concise form of the Emacs Tempo syntax. The first element of each list is the -name of the template. I recommend to use avoid special letters for the template -names, since special letters may carry meaning during completion filtering and -as such make it harder to select the desired template. Thus the name =lett= is -better than =let*=. Behind the name, the Tempo syntax elements follow. +major mode. Each template is a list in the concise form of the Emacs Tempo +syntax. The first element of each list is the name of the template. I recommend +to use avoid special letters for the template names, since special letters may +carry meaning during completion filtering and as such make it harder to select +the desired template. Thus the name =lett= is better than =let*=. Behind the name, +the Tempo syntax elements follow. + +You may use ~:when~ as a condition whether the group should be loaded or set +~:enable-function~ which evaluates whether the templates can be expanded or not. In addition, each template may specify a =:pre= and/or =:post= key with a FORM that is evaluated before the template is expanded or after it is finalized, @@ -279,6 +282,10 @@ org-mode (inlsrc "src_" p "{" q "}") (title "#+title: " p n "#+author: Daniel Mendler" n "#+language: en") +org-mode :enable-function org-inside-LaTeX-fragment-p + +(int "\\int_{" p "}^{" p "} " p "\\,dx") + ;; Local Variables: ;; mode: lisp-data ;; outline-regexp: "[a-z]" diff --git a/tempel.el b/tempel.el index 8ccca65..57e66e4 100644 --- a/tempel.el +++ b/tempel.el @@ -486,7 +486,7 @@ This is meant to be a source in `tempel-template-sources'." (cl-loop for (modes plist . templates) in (cdr tempel--path-templates) if (tempel--condition-p modes plist) - append templates)) + collect (list modes plist templates))) (defun tempel--condition-p (modes plist) "Return non-nil if one of MODES matches and the PLIST condition is satisfied." @@ -516,6 +516,17 @@ This is meant to be a source in `tempel-template-sources'." nil)) result)) + +(defun tempel--enabled-templates () + "Return enabled templates for the current mode." + (cl-loop + for (modes plist templates) in (tempel--templates) + if (if-let ((enablefun (plist-get plist :enable-function))) + (funcall enablefun) + t) + append templates) + ) + (defun tempel--region () "Return region bounds." (when (use-region-p) @@ -680,7 +691,7 @@ command." (interactive (list t)) (if interactive (tempel--interactive #'tempel-expand) - (when-let ((templates (tempel--templates)) + (when-let ((templates (tempel--enabled-templates)) (bounds (tempel--prefix-bounds)) (name (buffer-substring-no-properties (car bounds) (cdr bounds))) @@ -707,7 +718,7 @@ Capf, otherwise like an interactive completion command." (insert tempel-trigger-prefix)) (tempel--interactive #'tempel-complete)) (let ((region (tempel--region))) - (when-let ((templates (tempel--templates)) + (when-let ((templates (tempel--enabled-templates)) (bounds (or (and (not region) (tempel--prefix-bounds)) (and (not tempel-trigger-prefix) (cons (point) (point)))))) (list (car bounds) (cdr bounds) @@ -738,7 +749,7 @@ If called interactively, select a template with `completing-read'." (interactive (list nil)) (tempel--insert (if (consp template-or-name) template-or-name - (let* ((templates (or (tempel--templates) + (let* ((templates (or (tempel--enabled-templates) (error "Tempel: No templates for %s" major-mode))) (completion-extra-properties (and tempel-insert-annotation @@ -789,16 +800,25 @@ If called interactively, select a template with `completing-read'." (default-value 'abbrev-minor-mode-table-alist)) (kill-local-variable 'abbrev-minor-mode-table-alist)) (when tempel-abbrev-mode - (let ((table (make-abbrev-table))) - (dolist (template (tempel--templates)) - (let* ((name (symbol-name (car template))) - (hook (make-symbol name))) - (fset hook (apply-partially #'tempel--abbrev-hook name (cdr template))) - (put hook 'no-self-insert t) - (define-abbrev table name 'Template hook :system t))) - (setq-local abbrev-minor-mode-table-alist - (cons `(tempel-abbrev-mode . ,table) - abbrev-minor-mode-table-alist))))) + (cl-loop + for (modes plist templates) in (tempel--templates) + do (let ((table (make-abbrev-table))) + (dolist (template templates) + (let* ((name (symbol-name (car template))) + (hook (make-symbol name))) + (fset hook (apply-partially #'tempel--abbrev-hook name (cdr template))) + (put hook 'no-self-insert t) + (define-abbrev table name 'Template hook :system t))) + + (when-let (enablefun (plist-get plist :enable-function)) + (if (functionp enablefun) + (abbrev-table-put table :enable-function enablefun)) + (error "%s is not a function!" enablefun)) + + (setq-local abbrev-minor-mode-table-alist + (cons `(tempel-abbrev-mode . ,table) + abbrev-minor-mode-table-alist)) + )))) ;;;###autoload (define-globalized-minor-mode global-tempel-abbrev-mode From d69f37c80f909e8a9e684723f6b9f4c2f5461abf Mon Sep 17 00:00:00 2001 From: Ursus Wigger Date: Tue, 22 Oct 2024 13:24:46 +0200 Subject: [PATCH 2/2] Use :when instead of :enable-function for tempel-abbrev-mode --- README.org | 19 ++++--------- tempel.el | 81 ++++++++++++++++++++++++++++-------------------------- 2 files changed, 48 insertions(+), 52 deletions(-) diff --git a/README.org b/README.org index 4549980..948abd5 100644 --- a/README.org +++ b/README.org @@ -110,15 +110,12 @@ contributions. The templates are defined in a Lisp data file configured by ~tempel-path~. Lisp data files are files containing Lisp s-expressions (see ~lisp-data-mode~). By default the file =~/.config/emacs/templates= is used. The templates are grouped by -major mode. Each template is a list in the concise form of the Emacs Tempo -syntax. The first element of each list is the name of the template. I recommend -to use avoid special letters for the template names, since special letters may -carry meaning during completion filtering and as such make it harder to select -the desired template. Thus the name =lett= is better than =let*=. Behind the name, -the Tempo syntax elements follow. - -You may use ~:when~ as a condition whether the group should be loaded or set -~:enable-function~ which evaluates whether the templates can be expanded or not. +major mode with an optional ~:when~ condition. Each template is a list in the +concise form of the Emacs Tempo syntax. The first element of each list is the +name of the template. I recommend to use avoid special letters for the template +names, since special letters may carry meaning during completion filtering and +as such make it harder to select the desired template. Thus the name =lett= is +better than =let*=. Behind the name, the Tempo syntax elements follow. In addition, each template may specify a =:pre= and/or =:post= key with a FORM that is evaluated before the template is expanded or after it is finalized, @@ -282,10 +279,6 @@ org-mode (inlsrc "src_" p "{" q "}") (title "#+title: " p n "#+author: Daniel Mendler" n "#+language: en") -org-mode :enable-function org-inside-LaTeX-fragment-p - -(int "\\int_{" p "}^{" p "} " p "\\,dx") - ;; Local Variables: ;; mode: lisp-data ;; outline-regexp: "[a-z]" diff --git a/tempel.el b/tempel.el index 57e66e4..4ad63c8 100644 --- a/tempel.el +++ b/tempel.el @@ -483,25 +483,27 @@ This is meant to be a source in `tempel-template-sources'." (unless (equal (car tempel--path-templates) timestamps) (setq tempel--path-templates (cons timestamps (mapcan #'tempel--file-read files)))))) + (cl-loop for (modes plist . templates) in (cdr tempel--path-templates) - if (tempel--condition-p modes plist) + if (tempel--mode-matches-p modes) collect (list modes plist templates))) -(defun tempel--condition-p (modes plist) - "Return non-nil if one of MODES matches and the PLIST condition is satisfied." - (and - (cl-loop - for m in modes thereis - (or (eq m #'fundamental-mode) - (derived-mode-p m) - (when-let ((remap (alist-get m (bound-and-true-p major-mode-remap-alist)))) - (derived-mode-p remap)))) - (or (not (plist-member plist :when)) - (save-excursion - (save-restriction - (save-match-data - (eval (plist-get plist :when) 'lexical))))))) +(defun tempel--mode-matches-p (modes) + "Return non-nil if one of MODES matches." + (cl-loop + for m in modes thereis + (or (eq m #'fundamental-mode) + (derived-mode-p m) + (when-let ((remap (alist-get m (bound-and-true-p major-mode-remap-alist)))) + (derived-mode-p remap))))) + +(defun tempel--eval-condition (condition) + "Return non-nil if CONDITION is satisfied." + (save-excursion + (save-restriction + (save-match-data + (eval condition 'lexical))))) (defun tempel--templates () "Return templates for current mode." @@ -520,12 +522,11 @@ This is meant to be a source in `tempel-template-sources'." (defun tempel--enabled-templates () "Return enabled templates for the current mode." (cl-loop - for (modes plist templates) in (tempel--templates) - if (if-let ((enablefun (plist-get plist :enable-function))) - (funcall enablefun) - t) - append templates) - ) + for (modes plist templates) in (tempel--templates) + if (tempel--eval-condition (if-let (condition (plist-get plist :when)) + (tempel--eval-condition condition) + t)) + append templates)) (defun tempel--region () "Return region bounds." @@ -801,24 +802,26 @@ If called interactively, select a template with `completing-read'." (kill-local-variable 'abbrev-minor-mode-table-alist)) (when tempel-abbrev-mode (cl-loop - for (modes plist templates) in (tempel--templates) - do (let ((table (make-abbrev-table))) - (dolist (template templates) - (let* ((name (symbol-name (car template))) - (hook (make-symbol name))) - (fset hook (apply-partially #'tempel--abbrev-hook name (cdr template))) - (put hook 'no-self-insert t) - (define-abbrev table name 'Template hook :system t))) - - (when-let (enablefun (plist-get plist :enable-function)) - (if (functionp enablefun) - (abbrev-table-put table :enable-function enablefun)) - (error "%s is not a function!" enablefun)) - - (setq-local abbrev-minor-mode-table-alist - (cons `(tempel-abbrev-mode . ,table) - abbrev-minor-mode-table-alist)) - )))) + for (modes plist templates) in (tempel--templates) + do (let ((table (make-abbrev-table))) + (dolist (template templates) + (let* ((name (symbol-name (car template))) + (hook (make-symbol name))) + (fset hook (apply-partially #'tempel--abbrev-hook name (cdr template))) + (put hook 'no-self-insert t) + (define-abbrev table name 'Template hook :system t))) + + (when-let (condition (plist-get plist :when)) + (abbrev-table-put table + :enable-function + (lambda () + (tempel--eval-condition condition)))) + + + (setq-local abbrev-minor-mode-table-alist + (cons `(tempel-abbrev-mode . ,table) + abbrev-minor-mode-table-alist)) + )))) ;;;###autoload (define-globalized-minor-mode global-tempel-abbrev-mode