diff --git a/modules/completion/siren-cape.el b/modules/completion/siren-cape.el index 5f303e5..90592ca 100644 --- a/modules/completion/siren-cape.el +++ b/modules/completion/siren-cape.el @@ -7,6 +7,7 @@ ;;; Code: (require 'siren-company) +(require 'siren-yasnippet) (use-package cape :after company @@ -14,9 +15,6 @@ (lsp-completion-mode . siren-cape-capf-lsp-mode-setup) :preface - (defalias 'siren-yasnippet-capf - (cape-company-to-capf 'company-yasnippet)) - (defun siren-cape-capf-lsp-mode-setup () (siren-cape-capf-add-hooks t)) @@ -25,11 +23,13 @@ ;; Use `siren-prepend' function instead of `add-hook' to ensure our custom ;; completion functions are listed before `lsp-completion-at-point'. (siren-prepend completion-at-point-functions 'cape-file) - (siren-prepend completion-at-point-functions 'siren-yasnippet-capf)) + (siren-prepend completion-at-point-functions 'yasnippet-capf)) + ;; (siren-prepend completion-at-point-functions + ;; (cape-capf-super #'lsp-completion-at-point #'yasnippet-capf)) (defun siren-cape-capf-remove-hooks (&optional local) - (remove-hook 'completion-at-point-functions 'siren-yasnippet-capf local) - (remove-hook 'completion-at-point-functions 'cape-file local)) + (remove-hook 'completion-at-point-functions 'cape-file local) + (remove-hook 'completion-at-point-functions 'yasnippet-capf local)) :init (siren-cape-capf-add-hooks)) diff --git a/modules/completion/siren-company.el b/modules/completion/siren-company.el index 3bbf922..655a37c 100644 --- a/modules/completion/siren-company.el +++ b/modules/completion/siren-company.el @@ -41,56 +41,5 @@ :if window-system :hook (company-mode . company-box-mode)) -(use-package company-yasnippet - :straight company - - :preface - (defgroup siren-company-yasnippet nil - "Siren specific tweaks to company-yasnippet." - :group 'company) - - (defcustom siren-company-yasnippet-exact-match-only nil - "Only match completion when it is a exact match for a snippet key. - -This allows company-yasnippet to be used before company-capf / lsp, allowing -snippets to be easily used when exactly typing out a snippet key." - :type 'boolean - :group 'siren-company-yasnippet) - - :custom - (siren-company-yasnippet-exact-match-only t) - - :config - ;; Dirty hack to optionally enable company-yasnippet to only match exact - ;; snippet keys. - (defun company-yasnippet--completions-for-prefix (prefix key-prefix tables) - (cl-mapcan - (lambda (table) - (let ((keyhash (yas--table-hash table)) - (requirement (yas--require-template-specific-condition-p)) - res) - (when keyhash - (maphash - (lambda (key value) - (when (and (stringp key) - (if siren-company-yasnippet-exact-match-only - (string-equal key-prefix key) - (string-prefix-p key-prefix key))) - (maphash - (lambda (name template) - (when (yas--template-can-expand-p - (yas--template-condition template) requirement) - (push - (propertize key - 'yas-annotation name - 'yas-template template - 'yas-prefix-offset (- (length key-prefix) - (length prefix))) - res))) - value))) - keyhash)) - res)) - tables))) - (provide 'siren-company) ;;; siren-company.el ends here diff --git a/modules/text-editing/siren-yasnippet.el b/modules/text-editing/siren-yasnippet.el index b9d2daa..c21352f 100644 --- a/modules/text-editing/siren-yasnippet.el +++ b/modules/text-editing/siren-yasnippet.el @@ -6,6 +6,8 @@ ;;; Code: +(require 'cl-lib) + (use-package yasnippet :diminish yas-minor-mode :hook (emacs-startup . yas-reload-all) @@ -22,5 +24,45 @@ (when (not (file-exists-p skip-file)) (make-empty-file skip-file t)))) +(use-package yasnippet-capf + :preface + (defgroup siren-yasnippet-capf nil + "Siren specific tweaks to yasnippet-capf." + :group 'yasnippet-capf) + + (defcustom siren-yasnippet-capf-exact-match t + "Only return exact matches. + +When non-nil, only exact matches will be returned by `yasnippet-capf'. +When nil, all matches will be returned. + +Annoyingly, when enabled this seems to hide all completion results for +yasnippet, cause the capf function is run twice, once with the given +prefix, and once without any at all. + +It seems like the first call is used to determine if the next capf function +should be used or not, and the second call is what company-mode uses to render +completions. + +For my use-case, this is fine, as I only want `yasnippet-capf' triggered +for exact matches, and for everything else move on to the lsp-mode's +`lsp-completion-at-point' function." + :type 'boolean + :group 'siren-yasnippet-capf) + + (defun siren-yasnippet-capf--advice-exact-match-only (orig-fun &rest args) + "Advice to filter out non-exact matches." + (let ((candidates (apply orig-fun args)) + (prefix (nth 0 args))) + (if siren-yasnippet-capf-exact-match + (cl-remove-if-not (lambda (candidate) + (string= prefix (substring-no-properties candidate))) + candidates) + candidates))) + + :config + (advice-add 'yasnippet-capf-candidates + :around #'siren-yasnippet-capf--advice-exact-match-only)) + (provide 'siren-yasnippet) ;;; siren-yasnippet.el ends here