Hey gang,
So initially I had something pretty simple to have “snippets” in my Emacs config, using Skeletons and Abbrevs. I’ve expanded on it a little bit since then, but I’m running into an issue where the abbrev no longer expands to call the skeleton function.
Here’s what I have:
;;;###autoload
(defun abbrev::abbrev-table-add-props (abbrev-table props)
"Add one or more PROPS to an existing ABBREV-TABLE.
PROPS should be a plist of (PROP VALUE).
Example:
(:enable-function (lambda (&rest _) (do-something)))"
(if (cddr props)
(cl-loop for (k v) on props by #'cddr
unless (not (abbrev-table-p abbrev-table))
unless (abbrev-table-get abbrev-table k)
do (abbrev-table-put abbrev-table k v))
(unless (and (not (abbrev-table-p abbrev-table))
(abbrev-table-get abbrev-table (car props)))
(abbrev-table-put abbrev-table (car props) (cadr props)))))
;;;###autoload
(defmacro def-mode-snippet (name
mode
docstring
&rest prompt-and-or-skeleton)
"Create a MODES specific \"snippet\" with NAME and SKELETON.
NAME must be valid in the Emacs Lisp naming convention.
MODE must be a valid major or minor mode that is known to Emacs.
Example: ‘org-mode’, ‘emacs-lisp-mode’, etc.
DOCSTRING is used in the abbrev rather than the skeleton.
PROMPT-AND-OR-SKELETON can be any of the following:
1. A valid Skeleton that uses the internal `Skeleton' langauge
2. A key/value \"pair\" that’s :prompt STRING, followed by
a valid Skeleton that uses the internal `Skeleton' language.
The prompt given is used by the Skeleton to prompt the user for an input.
This macro makes use of `define-skeleton' and `define-abbrev' in order to
create something similar to a code/writing snippet system, like that of
`YASnippet'. Keep in mind that all abbreviations created are put in the abbrev
table of MODE you passed to this macro.
Example: passing ‘org-mode’ will add the abbrev to the ‘org-mode-abbrev-table’.
That may or may not be something you want depending on your uses.
If you're looking to only define an abbrev globally, see `def-global-snippet'."
(declare (debug t)
(doc-string 3)
(indent defun))
;; TODO need to figure out how to work with lists better
(let* ((snip-name (symbol-name `,name))
(func-name (intern (concat (symbol-name mode) "-" snip-name "-skel")))
(var-str (concat (symbol-name mode) "-abbrev-table"))
(abbrev-table (intern-soft var-str))
(has-prompt (keywordp (car prompt-and-or-skeleton)))
(prompt (if has-prompt (cadr prompt-and-or-skeleton) nil))
(skeleton (if (not has-prompt) prompt-and-or-skeleton (cddr prompt-and-or-skeleton)))
;; Not using this for now until the issue with abbrevs not expanding is solved.
;;(enable-fn (lambda (&rest _) (or (eq major-mode 'mode) (numberp (cl-position 'mode minor-mode-list)))))
)
(macroexp-progn
`((define-skeleton ,func-name
,(format "%s %s %s %s." snip-name "skeleton. Defined in" var-str "abbreviaton table")
,prompt
,@skeleton)
,(if (not (abbrev-table-p abbrev-table))
`(define-abbrev ,abbrev-table
,snip-name
',func-name)
`(define-abbrev-table ',abbrev-table
'((,snip-name ',func-name))
,(format "An abbrev table for %s" mode)
:system t
:case-fixed t)
(abbrev::abbrev-table-add-props ,abbrev-table
'(:system t
:case-fixed t)))))))
The example I can give is the following:
(def-mode-snippet defun emacs-lisp-mode
"defun snippet for Emacs Lisp"
> "(defun " @ - " (" @ _ ")" \n
> -2 "\"" @ _ "\"" \n
> -1 @ _ ")")
And that will macro-expand to:
(progn
(define-skeleton emacs-lisp-mode-defun-skel "defun skeleton. Defined in emacs-lisp-mode-abbrev-table abbreviaton table." nil > "(defun " @ - " (" @ _ ")" n > -2 "\"" @ _ "\"" n > -1 @ _ ")")
(define-abbrev emacs-lisp-mode-abbrev-table "defun" 'emacs-lisp-mode-defun-skel))
Which evals fine, even though I think the n
would not be valid to Skeleton, but I’m not sure.
EDIT: I’ve put up a question on The Emacs StackExchange with more details if anyone is interested. Also, if it helps looking at my full config you can view it here.
You must log in or register to comment.