diff --git a/README.org b/README.org index 921642ab..7c455f72 100644 --- a/README.org +++ b/README.org @@ -144,6 +144,9 @@ variables and functions with their descriptions. lines again. If the input begins with "! SPC", the filter matches the complement. In contrast to =consult-keep-lines= this function does not edit the buffer. + - =consult-yasnippet=: Expand [[https://github.com/joaotavora/yasnippet][yasnippet]] snippets in the current buffer. + This command is available from the additional =consult-yasnippet.el= + package. ** Navigation :properties: @@ -237,9 +240,6 @@ variables and functions with their descriptions. components. - =consult-flymake=: Jump to Flymake diagnostic, like =consult-flycheck=. -- =consult-yasnippet=: Expand [[https://github.com/joaotavora/yasnippet][yasnippet]] snippets in the current buffer. - This command is available from the additional =consult-yasnippet.el= - package. ** Histories :properties: diff --git a/consult-yasnippet.el b/consult-yasnippet.el index a9ed2f94..fe6b388a 100644 --- a/consult-yasnippet.el +++ b/consult-yasnippet.el @@ -37,36 +37,19 @@ (require 'consult) (require 'yasnippet) -(defgroup consult-yasnippet nil - "Consulting `completing-read' for yasnippet snippets." - :group 'consult - :prefix "consult-yasnippet-") - -(defvar consult-yasnippet--snippets nil - "Snippet collection for current `consult-snippet' session.") - -(defvar consult-yasnippet--buffer nil - "The buffer in which `consult-yasnippet' was begun") - -(defvar consult-yasnippet--region nil - "The position (a cons of the start and end `point's) of where `consult-yasnippet' was begun") - -(defvar consult-yasnippet--region-contents "" - "The original contents of `consult-yasnippet--region'.") - -(defun consult-yasnippet--expand-template (template) +(defun consult-yasnippet--expand-template (template region region-contents) "Expand the yasnippet template TEMPLATE at point." (deactivate-mark) - (goto-char (car consult-yasnippet--region)) - (when (not (string-equal "" consult-yasnippet--region-contents)) + (goto-char (car region)) + (when (not (string-equal "" region-contents)) (push-mark (point)) - (push-mark (cdr consult-yasnippet--region) nil t)) + (push-mark (cdr region) nil t)) (yas-expand-snippet (yas--template-content template) nil nil (yas--template-expand-env template))) -(defun consult-yasnippet--preview (template _) +(defun consult-yasnippet--preview () "Previewer for `consult--read'. This function expands TEMPLATE at point in the buffer `consult-yasnippet--read-snippet' was started in. This includes @@ -75,51 +58,49 @@ previews that're already active. When TEMPLATE is not given, this function essentially just resets the state of the current buffer to before any snippets were previewed." - (with-current-buffer consult-yasnippet--buffer - (let ((yas-verbosity 0) - (inhibit-redisplay t) - (inhibit-read-only t) - (orig-offset (- (point-max) (cdr consult-yasnippet--region))) - (yas-prompt-functions '(yas-no-prompt))) - - ;; We always undo any snippet previews before maybe setting up - ;; some new previews. - (delete-region (car consult-yasnippet--region) - (cdr consult-yasnippet--region)) - (goto-char (car consult-yasnippet--region)) - (setcar consult-yasnippet--region (point)) - (insert consult-yasnippet--region-contents) - (setcdr consult-yasnippet--region (point)) - - (when template - (unwind-protect - (consult-yasnippet--expand-template template) - (unwind-protect - (mapc #'yas--commit-snippet - (yas-active-snippets (point-min) (point-max))) - (setcdr consult-yasnippet--region (- (point-max) orig-offset)))) - (redisplay))))) - -(defmacro consult-yasnippet--setup (&rest body) - "Setup the local variables and environment for `consult-yasnippet'. -This environment is used both in `consult-yasnippet--preview'and -`consult-yasnippet--expand-template'." - `(progn - (barf-if-buffer-read-only) - (unless (bound-and-true-p yas-minor-mode) - (error "`yas-minor-mode' not enabled in current buffer")) - - (let* ((consult-yasnippet--snippets - (mapcar (lambda (template) - (cons (yas--template-name template) template)) - (yas--all-templates (yas--get-snippet-tables)))) - (consult-yasnippet--buffer (current-buffer)) - (consult-yasnippet--region (if (region-active-p) - (cons (region-beginning) (region-end)) - (cons (point) (point)))) - (consult-yasnippet--region-contents (buffer-substring (car consult-yasnippet--region) - (cdr consult-yasnippet--region)))) - ,@body))) + (let* ((buf (current-buffer)) + (region (if (region-active-p) + (cons (region-beginning) (region-end)) + (cons (point) (point)))) + (region-contents (buffer-substring (car region) (cdr region)))) + (lambda (template restore) + (with-current-buffer buf + (let ((yas-verbosity 0) + (inhibit-redisplay t) + (inhibit-read-only t) + (orig-offset (- (point-max) (cdr region))) + (yas-prompt-functions '(yas-no-prompt))) + + ;; We always undo any snippet previews before maybe setting up + ;; some new previews. + (delete-region (car region) (cdr region)) + (goto-char (car region)) + (setcar region (point)) + (insert region-contents) + (setcdr region (point)) + + (when (and template (not restore)) + (unwind-protect + (consult-yasnippet--expand-template template region region-contents) + (unwind-protect + (mapc #'yas--commit-snippet + (yas-active-snippets (point-min) (point-max))) + (setcdr region (- (point-max) orig-offset)))) + (redisplay))))))) + +(defun consult-yasnippet--candidates (&rest body) + "Retrieve the list of available snippets in the current buffer." + (unless (bound-and-true-p yas-minor-mode) + (error "`yas-minor-mode' not enabled in current buffer")) + + (cl-loop for template in (yas--all-templates (yas--get-snippet-tables)) + with annotation = nil + ;; TODO: custom face + do (setq annotation + (propertize (yas--template-key template) 'face 'font-lock-type-face)) + collect (cons (concat (yas--template-name template) + (propertize " " 'display (concat " [" annotation "]"))) + template))) (defun consult-yasnippet--read-snippet () "Backend implementation of `consult-yasnippet'. @@ -130,17 +111,16 @@ replacing the active region with the snippet expansion. This function doesn't actually expand the snippet, it only reads and then returns a snippet template from the user." - (consult-yasnippet--setup - (let ((buffer-undo-list t)) ; Prevent querying user (and showing previews) from updating the undo-history - (unwind-protect - (consult--read - "Choose a snippet: " - consult-yasnippet--snippets - :lookup 'consult--lookup-cdr - :require-match t - :preview #'consult-yasnippet--preview - :category 'yasnippet) - (consult-yasnippet--preview nil t))))) ; Restore contents of region from before preview (while still ignoring undo history). + (barf-if-buffer-read-only) + + (let* ((buffer-undo-list t)) ; Prevent querying user (and showing previews) from updating the undo-history + (consult--read + "Choose a snippet: " + (consult-yasnippet--candidates) + :lookup 'consult--lookup-cdr + :require-match t + :preview (consult-yasnippet--preview) + :category 'yasnippet))) (defun consult-yasnippet-visit-snippet-file (snippet) (interactive (list (consult-yasnippet--read-snippet))) @@ -148,10 +128,12 @@ returns a snippet template from the user." (defun consult-yasnippet (template) (interactive (list (consult-yasnippet--read-snippet))) - ;; We need to first restore the local environment for - ;; `consult-yasnippet--expand-template' to work. - (consult-yasnippet--setup - (consult-yasnippet--expand-template template))) + (barf-if-buffer-read-only) + (let* ((region (if (region-active-p) + (cons (region-beginning) (region-end)) + (cons (point) (point)))) + (region-contents (buffer-substring (car region) (cdr region)))) + (consult-yasnippet--expand-template template region region-contents))) (provide 'consult-yasnippet)