yasnippet-capf.el (5446B)
1 ;;; yasnippet-capf.el --- Yasnippet Completion At Point Function -*- lexical-binding: t; -*- 2 ;; 3 ;; Copyright (C) 2022 Ellis Kenyő 4 ;; SPDX-License-Identifier: GPL-3.0-or-later 5 ;; 6 ;; Author: Ellis Kenyő <me@elken.dev> 7 ;; Maintainer: Ellis Kenyő <me@elken.dev> 8 ;; Created: August 11, 2022 9 ;; Modified: August 11, 2022 10 ;; Version: 0.0.3 11 ;; Homepage: https://github.com/elken/yasnippet-capf 12 ;; Package-Requires: ((emacs "25.1") (yasnippet "0.14.0")) 13 ;; 14 ;; This file is not part of GNU Emacs. 15 ;; 16 ;;; Commentary: 17 ;; 18 ;; Yasnippet Completion at Point Function to lookup snippets by name 19 ;; 20 ;; Simply add to the list of existing `completion-at-point-functions' thus: 21 ;; (add-to-list 'completion-at-point-functions #'yasnippet-capf) 22 ;; 23 ;; If you prefer to have the lookup done by name rather than key, set 24 ;; `yasnippet-capf-lookup-by'. 25 ;; 26 ;;; Code: 27 28 (require 'thingatpt) 29 (require 'yasnippet) 30 (require 'cl-lib) 31 (require 'subr-x) 32 33 (defgroup yasnippet-capf nil 34 "Yasnippet CAPF." 35 :group 'completion) 36 37 (defcustom yasnippet-capf-lookup-by 'key 38 "The method in which to lookup candidates by." 39 :type '(choice 40 (const :tag "Key" key) 41 (const :tag "Name" name)) 42 :group 'yasnippet-capf) 43 44 (defvar yasnippet-capf--properties 45 (list :annotation-function (lambda (snippet) 46 (format " %s " (or (get-text-property 0 'yas-annotation snippet) 47 (substring-no-properties snippet)))) 48 :company-kind (lambda (_) 'snippet) 49 :company-doc-buffer #'yasnippet-capf--doc-buffer 50 :exit-function (lambda (snippet status) 51 (when (string= "finished" status) 52 (if (eq yasnippet-capf-lookup-by 'name) 53 (yas-expand-snippet 54 (yas-lookup-snippet snippet) 55 (- (point) (length snippet)) 56 (point)) 57 (yas-expand)))) 58 :exclusive 'no) 59 "Completion extra properties for `yasnippet-capf'.") 60 61 (defun yasnippet-capf--doc-buffer (cand) 62 "Calculate the expansion of the snippet for CAND. 63 Returns a buffer to be displayed by popupinfo." 64 (when-let ((mode major-mode) 65 (template (get-text-property 0 'yas-template cand))) 66 (with-current-buffer (get-buffer-create "*yasnippet-capf-doc*") 67 (erase-buffer) 68 (remove-overlays) 69 (yas-minor-mode) 70 (insert "Expands to:" ?\n ?\n) 71 (condition-case error 72 (yas-expand-snippet (yas--template-content template)) 73 (error 74 (message "Error expanding: %s" (error-message-string error)))) 75 (delay-mode-hooks 76 (let ((inhibit-message t)) 77 (when (eq mode 'web-mode) 78 (setq mode 'html-mode)) 79 (funcall mode))) 80 (ignore-errors (font-lock-ensure)) 81 (current-buffer)))) 82 83 (defun yasnippet-capf--lookup-snippet (name) 84 "Get the snippet called NAME in MODE's tables." 85 (let ((yas-choose-tables-first nil) 86 (yas-choose-keys-first nil)) 87 (cl-find name (yas--all-templates 88 (yas--get-snippet-tables major-mode)) 89 :key (intern-soft (format "yas--template-%s" yasnippet-capf-lookup-by)) 90 :test #'string=))) 91 92 (defun yasnippet-capf--completions-for-prefix (prefix tables) 93 "Get a completion candidate for PREFIX with KEY-PREFIX in TABLES." 94 (let ((templates (yas--all-templates tables)) 95 (requirement (yas--require-template-specific-condition-p))) 96 (mapcar (lambda (template) 97 (let ((can-expand (yas--template-can-expand-p 98 (yas--template-condition template) requirement)) 99 (name (yas--template-name template)) 100 (name-or-key 101 (funcall (intern-soft (format "yas--template-%s" yasnippet-capf-lookup-by)) template))) 102 (when can-expand 103 (propertize name-or-key 104 'yas-annotation name 105 'yas-template template 106 'yas-prefix-offset (- (length name-or-key) 107 (length prefix)))))) 108 templates))) 109 110 (defun yasnippet-capf-candidates (&optional prefix) 111 "Return a list of candidate snippets filtered by PREFIX." 112 (pcase yasnippet-capf-lookup-by 113 ('key 114 (thread-last (yas--get-snippet-tables) 115 (yasnippet-capf--completions-for-prefix prefix) 116 (cl-remove-if #'null))) 117 ('name 118 (thread-last (yas--get-snippet-tables) 119 (yas--all-templates) 120 (mapcar #'yas--template-name))) 121 (_ (error "Invalid value for yasnippet-capf-lookup-by: %s" yasnippet-capf-lookup-by)))) 122 123 ;;;###autoload 124 (defun yasnippet-capf (&optional interactive) 125 "Complete with yasnippet at point. 126 If INTERACTIVE is nil the function acts like a Capf." 127 (interactive (list t)) 128 (if interactive 129 (let ((completion-at-point-functions #'yasnippet-capf)) 130 (or (completion-at-point) (user-error "yasnippet-capf: No completions"))) 131 (when (thing-at-point-looking-at "\\(?:\\sw\\|\\s_\\)+") 132 `(,(match-beginning 0) ,(match-end 0) 133 ,(completion-table-with-cache 134 (lambda (input) 135 (yasnippet-capf-candidates input))) 136 ,@yasnippet-capf--properties)))) 137 138 (provide 'yasnippet-capf) 139 ;;; yasnippet-capf.el ends here