]> code.delx.au - gnu-emacs-elpa/blobdiff - company-yasnippet.el
Bump copyright
[gnu-emacs-elpa] / company-yasnippet.el
index 4730b211b7989e09d2639155a511b1154d79ccf6..e5fded4d19e27811402d754c79a2b76afea984a9 100644 (file)
@@ -1,6 +1,6 @@
-;;; company-yasnippet.el --- company-mode completion back-end for Yasnippet
+;;; company-yasnippet.el --- company-mode completion backend for Yasnippet
 
-;; Copyright (C) 2014  Free Software Foundation, Inc.
+;; Copyright (C) 2014, 2015  Free Software Foundation, Inc.
 
 ;; Author: Dmitry Gutov
 
 
 ;;; Code:
 
+(require 'company)
 (require 'cl-lib)
-(require 'yasnippet)
+
+(declare-function yas--table-hash "yasnippet")
+(declare-function yas--get-snippet-tables "yasnippet")
+(declare-function yas-expand-snippet "yasnippet")
+(declare-function yas--template-content "yasnippet")
+(declare-function yas--template-expand-env "yasnippet")
+(declare-function yas--warning "yasnippet")
+
+(defun company-yasnippet--key-prefixes ()
+  ;; Mostly copied from `yas--templates-for-key-at-point'.
+  (defvar yas-key-syntaxes)
+  (save-excursion
+    (let ((original (point))
+          (methods yas-key-syntaxes)
+          prefixes
+          method)
+      (while methods
+        (unless (eq method (car methods))
+          (goto-char original))
+        (setq method (car methods))
+        (cond ((stringp method)
+               (skip-syntax-backward method)
+               (setq methods (cdr methods)))
+              ((functionp method)
+               (unless (eq (funcall method original)
+                           'again)
+                 (setq methods (cdr methods))))
+              (t
+               (setq methods (cdr methods))
+               (yas--warning "Invalid element `%s' in `yas-key-syntaxes'" method)))
+        (let ((prefix (buffer-substring-no-properties (point) original)))
+          (unless (equal prefix (car prefixes))
+            (push prefix prefixes))))
+      prefixes)))
 
 (defun company-yasnippet--candidates (prefix)
-  (mapcan
+  ;; Process the prefixes in reverse: unlike Yasnippet, we look for prefix
+  ;; matches, so the longest prefix with any matches should be the most useful.
+  (cl-loop with tables = (yas--get-snippet-tables)
+           for key-prefix in (company-yasnippet--key-prefixes)
+           ;; Only consider keys at least as long as the symbol at point.
+           when (>= (length key-prefix) (length prefix))
+           thereis (company-yasnippet--completions-for-prefix prefix
+                                                              key-prefix
+                                                              tables)))
+
+(defun company-yasnippet--completions-for-prefix (prefix key-prefix tables)
+  (cl-mapcan
    (lambda (table)
      (let ((keyhash (yas--table-hash table))
            res)
          (maphash
           (lambda (key value)
             (when (and (stringp key)
-                       (string-prefix-p prefix key))
+                       (string-prefix-p key-prefix key))
               (maphash
                (lambda (name template)
                  (push
                   (propertize key
                               'yas-annotation name
-                              'yas-template template)
+                              'yas-template template
+                              'yas-prefix-offset (- (length key-prefix)
+                                                    (length prefix)))
                   res))
                value)))
           keyhash))
        res))
-   (yas--get-snippet-tables)))
+   tables))
 
 ;;;###autoload
 (defun company-yasnippet (command &optional arg &rest ignore)
-  "`company-mode' back-end for `yasnippet'.
+  "`company-mode' backend for `yasnippet'.
 
-This back-end should be used with care, because as long as there are
-snippets defined for the current major mode, this back-end will always
-shadow back-ends that come after it.  Recommended usages:
+This backend should be used with care, because as long as there are
+snippets defined for the current major mode, this backend will always
+shadow backends that come after it.  Recommended usages:
 
-* In a buffer-local value of `company-backends', grouped with a back-end or
+* In a buffer-local value of `company-backends', grouped with a backend or
   several that provide actual text completions.
 
   (add-hook 'js-mode-hook
@@ -66,7 +113,7 @@ shadow back-ends that come after it.  Recommended usages:
               (set (make-local-variable 'company-backends)
                    '((company-dabbrev-code company-yasnippet)))))
 
-* After keyword `:with', grouped with other back-ends.
+* After keyword `:with', grouped with other backends.
 
   (push '(company-semantic :with company-yasnippet) company-backends)
 
@@ -80,14 +127,19 @@ shadow back-ends that come after it.  Recommended usages:
     (prefix
      ;; Should probably use `yas--current-key', but that's bound to be slower.
      ;; How many trigger keys start with non-symbol characters anyway?
-     (and yas-minor-mode
+     (and (bound-and-true-p yas-minor-mode)
           (company-grab-symbol)))
-    (annotation (concat " -> " (get-text-property 0 'yas-annotation arg)))
+    (annotation
+     (concat
+      (unless company-tooltip-align-annotations " -> ")
+      (get-text-property 0 'yas-annotation arg)))
     (candidates (company-yasnippet--candidates arg))
+    (no-cache t)
     (post-completion
-     (let ((template (get-text-property 0 'yas-template arg)))
+     (let ((template (get-text-property 0 'yas-template arg))
+           (prefix-offset (get-text-property 0 'yas-prefix-offset arg)))
        (yas-expand-snippet (yas--template-content template)
-                           (- (point) (length arg))
+                           (- (point) (length arg) prefix-offset)
                            (point)
                            (yas--template-expand-env template))))))