From 318784d4141fee096c8e4a86eb807c1355313d38 Mon Sep 17 00:00:00 2001 From: Mohsin Kaleem Date: Wed, 20 Jan 2021 17:45:51 +0000 Subject: [PATCH] (consult-yasnippet): Cleanup and refactor implementation See #173. --- README.org | 6 +- consult-yasnippet.el | 173 +++++++++++++++++++++---------------------- 2 files changed, 87 insertions(+), 92 deletions(-) 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..2b00ef60 100644 --- a/consult-yasnippet.el +++ b/consult-yasnippet.el @@ -37,91 +37,76 @@ (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 +`consult-yasnippet--read-template' was started in. This includes overwriting any region that was active and removing any previous 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))) - -(defun consult-yasnippet--read-snippet () + (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")) + + (let ((annotation) + (cands)) + (dolist (template (yas--all-templates (yas--get-snippet-tables))) + (setq annotation (concat " [" + (propertize (yas--template-key template) + 'face 'font-lock-type-face) + "]")) + (push (cons (concat (yas--template-name template) + (propertize " " 'display annotation)) + template) + cands)) + (nreverse cands))) + +(defun consult-yasnippet--read-template () "Backend implementation of `consult-yasnippet'. This starts a `completing-read' session with all the snippets in the current @@ -130,28 +115,38 @@ 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). - -(defun consult-yasnippet-visit-snippet-file (snippet) - (interactive (list (consult-yasnippet--read-snippet))) + (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 (template) + "Visit the snippet file associated with TEMPLATE. +When called interactively this command previews snippet completions in +the current buffer, and then opens the selected snippets template file +using `yas--visit-snippet-file-1'." + (interactive (list (consult-yasnippet--read-template))) (yas--visit-snippet-file-1 snippet)) (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))) + "Interactively select and expand the yasnippet template TEMPLATE. +When called interactively this command presents a completing read interface +containing all currently available snippet expansions, with live previews for +each snippet. Once selected a chosen snippet will be expanded at point using +`yas-expand-snippet'." + (interactive (list (consult-yasnippet--read-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)