config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

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