yasnippet-capf.el (5161B)
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 (_ status) 51 (when (string= "finished" status) 52 (yas-expand))) 53 :exclusive 'no) 54 "Completion extra properties for `yasnippet-capf'.") 55 56 (defun yasnippet-capf--doc-buffer (cand) 57 "Calculate the expansion of the snippet for CAND. 58 Returns a buffer to be displayed by popupinfo." 59 (when-let ((mode major-mode) 60 (template (get-text-property 0 'yas-template cand))) 61 (with-current-buffer (get-buffer-create "*yasnippet-capf-doc*") 62 (erase-buffer) 63 (remove-overlays) 64 (yas-minor-mode) 65 (insert "Expands to:" ?\n ?\n) 66 (condition-case error 67 (yas-expand-snippet (yas--template-content template)) 68 (error 69 (message "Error expanding: %s" (error-message-string error)))) 70 (delay-mode-hooks 71 (let ((inhibit-message t)) 72 (when (eq mode 'web-mode) 73 (setq mode 'html-mode)) 74 (funcall mode))) 75 (ignore-errors (font-lock-ensure)) 76 (current-buffer)))) 77 78 (defun yasnippet-capf--lookup-snippet (name) 79 "Get the snippet called NAME in MODE's tables." 80 (let ((yas-choose-tables-first nil) 81 (yas-choose-keys-first nil)) 82 (cl-find name (yas--all-templates 83 (yas--get-snippet-tables major-mode)) 84 :key (intern-soft (format "yas--template-%s" yasnippet-capf-lookup-by)) 85 :test #'string=))) 86 87 (defun yasnippet-capf--completions-for-prefix (prefix tables) 88 "Get a completion candidate for PREFIX with KEY-PREFIX in TABLES." 89 (let ((templates (yas--all-templates tables)) 90 (requirement (yas--require-template-specific-condition-p))) 91 (mapcar (lambda (template) 92 (let ((can-expand (yas--template-can-expand-p 93 (yas--template-condition template) requirement)) 94 (name (yas--template-name template)) 95 (name-or-key 96 (funcall (intern-soft (format "yas--template-%s" yasnippet-capf-lookup-by)) template))) 97 (when can-expand 98 (propertize name-or-key 99 'yas-annotation name 100 'yas-template template 101 'yas-prefix-offset (- (length name-or-key) 102 (length prefix)))))) 103 templates))) 104 105 (defun yasnippet-capf-candidates (&optional prefix) 106 "Return a list of candidate snippets filtered by PREFIX." 107 (pcase yasnippet-capf-lookup-by 108 ('key 109 (thread-last (yas--get-snippet-tables) 110 (yasnippet-capf--completions-for-prefix prefix) 111 (cl-remove-if #'null))) 112 ('name 113 (thread-last (yas--get-snippet-tables) 114 (yas--all-templates) 115 (mapcar #'yas--template-name))) 116 (_ (error "Invalid value for yasnippet-capf-lookup-by: %s" yasnippet-capf-lookup-by)))) 117 118 ;;;###autoload 119 (defun yasnippet-capf (&optional interactive) 120 "Complete with yasnippet at point. 121 If INTERACTIVE is nil the function acts like a Capf." 122 (interactive (list t)) 123 (if interactive 124 (let ((completion-at-point-functions #'yasnippet-capf)) 125 (or (completion-at-point) (user-error "yasnippet-capf: No completions"))) 126 (when (thing-at-point-looking-at "\\(?:\\sw\\|\\s_\\)+") 127 `(,(match-beginning 0) ,(match-end 0) 128 ,(completion-table-with-cache 129 (lambda (input) 130 (yasnippet-capf-candidates input))) 131 ,@yasnippet-capf--properties)))) 132 133 (provide 'yasnippet-capf) 134 ;;; yasnippet-capf.el ends here