;;; editor/snippets/config.el -*- lexical-binding: t; -*- (defvar +snippets-dir (expand-file-name "snippets/" doom-private-dir) "Directory where `yasnippet' will search for your private snippets.") ;; ;;; Packages (use-package! yasnippet :defer-incrementally eldoc easymenu help-mode :commands (yas-minor-mode-on yas-expand yas-expand-snippet yas-lookup-snippet yas-insert-snippet yas-new-snippet yas-visit-snippet-file yas-activate-extra-mode yas-deactivate-extra-mode) :init ;; Remove default ~/.emacs.d/snippets (defvar yas-snippet-dirs nil) (unless (daemonp) ;; Ensure `yas-reload-all' is called as late as possible. Other modules ;; could have additional configuration for yasnippet. For example, ;; file-templates. (add-transient-hook! 'yas-minor-mode-hook (yas-reload-all))) (add-hook! '(text-mode-hook prog-mode-hook conf-mode-hook snippet-mode-hook) #'yas-minor-mode-on) :config (add-to-list 'doom-debug-variables '(yas-verbosity . 3)) ;; Allow private snippets in DOOMDIR/snippets (add-to-list 'yas-snippet-dirs '+snippets-dir) ;; Reduce verbosity. 3 is too chatty about initializing yasnippet. 2 is just ;; right (only shows errors). (setq yas-verbosity (if doom-debug-p 3 0)) ;; default snippets library, if available (add-to-list 'load-path +snippets-dir) (require 'doom-snippets nil t) ;; HACK In case `+snippets-dir' and `doom-snippets-dir' are the same, or ;; duplicates exist in `yas-snippet-dirs'. (advice-add #'yas-snippet-dirs :filter-return #'delete-dups) ;; Remove GUI dropdown prompt (prefer ivy/helm) (delq! 'yas-dropdown-prompt yas-prompt-functions) ;; Prioritize private snippets in `+snippets-dir' over built-in ones if there ;; are multiple choices. (add-to-list 'yas-prompt-functions #'+snippets-prompt-private) ;; Register `def-project-mode!' modes with yasnippet. This enables project ;; specific snippet libraries (e.g. for Laravel, React or Jekyll projects). (add-hook 'doom-project-hook #'+snippets-enable-project-modes-h) ;; Exit snippets on ESC from normal mode (add-hook 'doom-escape-hook #'yas-abort-snippet) (after! smartparens ;; tell smartparens overlays not to interfere with yasnippet keybinds (advice-add #'yas-expand :before #'sp-remove-active-pair-overlay)) ;; (Evil only) fix off-by-one issue with line-wise visual selections in ;; `yas-insert-snippet', and switches to insert mode afterwards. (advice-add #'yas-insert-snippet :around #'+snippets-expand-on-region-a) ;; Show keybind hints in snippet header-line (add-hook 'snippet-mode-hook #'+snippets-show-hints-in-header-line-h) ;; Enable `read-only-mode' for built-in snippets (in `doom-local-dir') (add-hook 'snippet-mode-hook #'+snippets-read-only-maybe-h) (map! :map yas-keymap "C-e" #'+snippets/goto-end-of-field "C-a" #'+snippets/goto-start-of-field [M-right] #'+snippets/goto-end-of-field [M-left] #'+snippets/goto-start-of-field [M-backspace] #'+snippets/delete-to-start-of-field [backspace] #'+snippets/delete-backward-char [delete] #'+snippets/delete-forward-char-or-field ;; Replace commands with superior alternatives :map yas-minor-mode-map [remap yas-new-snippet] #'+snippets/new [remap yas-visit-snippet-file] #'+snippets/edit) ;; REVIEW Fix #2639: For some reason `yas--all-templates' returns duplicates ;; of some templates. Until I figure out the real cause this fixes it. (defadvice! +snippets--remove-duplicates-a (templates) :filter-return #'yas--all-templates (cl-delete-duplicates templates :test #'equal)) ;; HACK Smartparens will interfere with snippets expanded by `hippie-expand`, ;; so temporarily disable smartparens during snippet expansion. (after! hippie-exp (defvar +snippets--smartparens-enabled-p t) (defvar +snippets--expanding-p nil) ;; Is called for all snippet expansions, (add-hook! 'yas-before-expand-snippet-hook (defun +snippets--disable-smartparens-before-expand-h () ;; Remember the initial smartparens state only once, when expanding a ;; top-level snippet. (unless +snippets--expanding-p (setq +snippets--expanding-p t +snippets--smartparens-enabled-p smartparens-mode)) (when smartparens-mode (smartparens-mode -1)))) ;; Is called only for the top level snippet, but not for the nested ones. ;; Hence `+snippets--expanding-p'. (add-hook! 'yas-after-exit-snippet-hook (defun +snippets--restore-smartparens-after-expand-h () (setq +snippets--expanding-p nil) (when +snippets--smartparens-enabled-p (smartparens-mode 1))))) ;; If in a daemon session, front-load this expensive work: (if (daemonp) (yas-reload-all))) (use-package! auto-yasnippet :defer t :config (setq aya-persist-snippets-dir +snippets-dir) (defadvice! +snippets--inhibit-yas-global-mode-a (orig-fn &rest args) "auto-yasnippet enables `yas-global-mode'. This is obnoxious for folks like us who use yas-minor-mode and enable yasnippet more selectively. This advice swaps `yas-global-mode' with `yas-minor-mode'." :around '(aya-expand aya-open-line) (letf! ((#'yas-global-mode #'yas-minor-mode) (yas-global-mode yas-minor-mode)) (apply orig-fn args))))