config

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

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