;; M-x yas-expand
;;
;; Try to expand snippets before point. In `yas-minor-mode',
-;; this is bound to `yas-trigger-key' which you can customize.
+;; this is normally bound to TAB, but you can customize it in
+;; `yas-minor-mode-map'.
;;
;; M-x yas-load-directory
;;
:type 'boolean
:group 'yasnippet)
-(defcustom yas-trigger-key "<tab>"
- "The key bound to `yas-expand' when `yas-minor-mode' is active.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'."
- :type 'string
- :group 'yasnippet
- :set #'(lambda (symbol key)
- (let ((old (and (boundp symbol)
- (symbol-value symbol))))
- (set-default symbol key)
- ;; On very first loading of this defcustom,
- ;; `yas-trigger-key' is *not* loaded.
- (if (fboundp 'yas--trigger-key-reload)
- (yas--trigger-key-reload old)))))
-
-(defcustom yas-next-field-key '("TAB" "<tab>")
- "The key to navigate to next field when a snippet is active.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'.
-
-Can also be a list of strings."
- :type '(choice (string :tag "String")
- (repeat :args (string) :tag "List of strings"))
- :group 'yasnippet
- :set #'(lambda (symbol val)
- (set-default symbol val)
- (if (fboundp 'yas--init-yas-in-snippet-keymap)
- (yas--init-yas-in-snippet-keymap))))
-
-
-(defcustom yas-prev-field-key '("<backtab>" "<S-tab>")
- "The key to navigate to previous field when a snippet is active.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'.
-
-Can also be a list of strings."
- :type '(choice (string :tag "String")
- (repeat :args (string) :tag "List of strings"))
- :group 'yasnippet
- :set #'(lambda (symbol val)
- (set-default symbol val)
- (if (fboundp 'yas--init-yas-in-snippet-keymap)
- (yas--init-yas-in-snippet-keymap))))
-
-(defcustom yas-skip-and-clear-key '("C-d" "<delete>" "<deletechar>")
- "The key to clear the currently active field.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'.
-
-Can also be a list of strings."
- :type '(choice (string :tag "String")
- (repeat :args (string) :tag "List of strings"))
- :group 'yasnippet
- :set #'(lambda (symbol val)
- (set-default symbol val)
- (if (fboundp 'yas--init-yas-in-snippet-keymap)
- (yas--init-yas-in-snippet-keymap))))
-
(defcustom yas-triggers-in-field nil
- "If non-nil, `yas-next-field-key' can trigger stacked expansions.
+ "If non-nil, allow stacked expansions (snippets inside snippets).
-Otherwise, `yas-next-field-key' just tries to move on to the next
-field"
+Otherwise `yas-next-field-or-maybe-expand' just moves on to the
+next field"
:type 'boolean
:group 'yasnippet)
(defcustom yas-fallback-behavior 'call-other-command
- "How to act when `yas-trigger-key' does *not* expand a snippet.
+ "How to act when `yas-expand' does *not* expand a snippet.
- `call-other-command' means try to temporarily disable YASnippet
- and call the next command bound to `yas-trigger-key'.
+ and call the next command bound to whatever key was used to
+ invoke `yas-expand'.
- nil or the symbol `return-nil' mean do nothing. (and
`yas-expand' returns nil)
:group 'yasnippet)
\f
-;;; User can also customize the next defvars
-
-(defun yas--define-some-keys (keys keymap definition)
- "Bind KEYS to DEFINITION in KEYMAP, read with `read-kbd-macro'."
- (let ((keys (or (and (listp keys) keys)
- (list keys))))
- (dolist (key keys)
- (define-key keymap (read-kbd-macro key) definition))))
-
-(defun yas--init-yas-in-snippet-keymap ()
- "Set the value of `yas-keymap'."
- (setq yas-keymap
- (let ((map (make-sparse-keymap)))
- (mapc #'(lambda (binding)
- (yas--define-some-keys (car binding) map (cdr binding)))
- `((,yas-next-field-key . yas-next-field-or-maybe-expand)
- (,yas-prev-field-key . yas-prev-field)
- ("C-g" . yas-abort-snippet)
- (,yas-skip-and-clear-key . yas-skip-and-clear-or-delete-char)))
- map)))
-
-(defvar yas-keymap (yas--init-yas-in-snippet-keymap)
- "The keymap active while a snippet expansion is in progress.")
+(defvar yas-keymap (let ((map (make-sparse-keymap)))
+ (define-key map [(tab)] 'yas-next-field-or-maybe-expand)
+ (define-key map (kbd "TAB") 'yas-next-field-or-maybe-expand)
+ (define-key map [(shift tab)] 'yas-prev-field)
+ (define-key map [backtab] 'yas-prev-field)
+ (define-key map (kbd "C-g") 'yas-abort-snippet)
+ (define-key map (kbd "C-d") 'yas-skip-and-clear-or-delete-char)
+ map)
+ "The active keymap while a snippet expansion is in progress.")
(defvar yas-key-syntaxes (list "w" "w_" "w_." "w_.()" "^ ")
"List of character syntaxes used to find a trigger key before point.
;; Now for the stuff that has direct keybindings
;;
+ (define-key map [(tab)] 'yas-expand)
+ (define-key map (kbd "TAB") 'yas-expand)
(define-key map "\C-c&\C-s" 'yas-insert-snippet)
(define-key map "\C-c&\C-n" 'yas-new-snippet)
(define-key map "\C-c&\C-v" 'yas-visit-snippet-file)
(defvar yas-minor-mode-map (yas--init-minor-keymap)
"The keymap used when `yas-minor-mode' is active.")
-(defun yas--trigger-key-reload (&optional unbind-key)
- "Rebind `yas-expand' to the new value of `yas-trigger-key'.
-
-With optional UNBIND-KEY, try to unbind that key from
-`yas-minor-mode-map'."
- (when (and unbind-key
- (stringp unbind-key)
- (not (string= unbind-key "")))
- (define-key yas-minor-mode-map (read-kbd-macro unbind-key) nil))
- (when (and yas-trigger-key
- (stringp yas-trigger-key)
- (not (string= yas-trigger-key "")))
- (define-key yas-minor-mode-map (read-kbd-macro yas-trigger-key) 'yas-expand)))
-
(defvar yas--tables (make-hash-table)
"A hash table of mode symbols to `yas--table' objects.")
(define-minor-mode yas-minor-mode
"Toggle YASnippet mode.
-When YASnippet mode is enabled, the `yas-trigger-key' key expands
-snippets of code depending on the major mode.
+When YASnippet mode is enabled, `yas-expand', normally bound to
+the TAB key, expands snippets of code depending on the major
+mode.
With no argument, this command toggles the mode.
positive prefix argument turns on the mode.
Negative prefix argument turns off the mode.
-You can customize the key through `yas-trigger-key'.
-
Key bindings:
\\{yas-minor-mode-map}"
nil
" yas"
:group 'yasnippet
(cond (yas-minor-mode
- ;; Reload the trigger key
- ;;
- (yas--trigger-key-reload)
;; Install the direct keymaps in `emulation-mode-map-alists'
;; (we use `add-hook' even though it's not technically a hook,
;; but it works). Then define variables named after modes to
;; Reload the direct keybindings
;;
(yas-direct-keymaps-reload)
- ;; Reload the trigger-key (shouldn't be needed, but see issue #237)
- ;;
- (yas--trigger-key-reload)
(yas--message 3 "Reloaded everything%s...%s."
(if interactive "" " (snippets will load just-in-time)")
end
(yas--template-expand-env yas--current-template)))))
-(defun yas--trigger-key-for-fallback ()
- ;; When `yas-trigger-key' is <tab> it correctly overrides
- ;; org-mode's <tab>, for example and searching for fallbacks
- ;; correctly returns `org-cycle'. However, most other modes bind
- ;; "TAB" (which is translated from <tab>), and calling
- ;; (key-binding "TAB") does not place return that command into
- ;; our command-2 local. So we cheat.
- ;;
- (if (string= yas-trigger-key "<tab>")
- "TAB"
- yas-trigger-key))
-
+;; Apropos the trigger key and the fallback binding:
+;;
+;; When `yas-minor-mode-map' binds <tab>, that correctly overrides
+;; org-mode's <tab>, for example and searching for fallbacks correctly
+;; returns `org-cycle'. However, most other modes bind "TAB". TODO,
+;; improve this explanation.
+;;
(defun yas--fallback (&optional from-trigger-key-p)
"Fallback after expansion has failed.
;; return nil
nil)
((eq yas-fallback-behavior 'call-other-command)
- (let* ((yas-minor-mode nil)
- (yas--direct-keymaps nil)
- (yas-trigger-key (yas--trigger-key-for-fallback))
- (keys-1 (this-command-keys-vector))
- (keys-2 (and yas-trigger-key
- from-trigger-key-p
- (stringp yas-trigger-key)
- (read-kbd-macro yas-trigger-key)))
- (command-1 (and keys-1 (key-binding keys-1)))
- (command-2 (and keys-2 (key-binding keys-2)))
- ;; An (ugly) safety: prevents infinite recursion of
- ;; yas-expand* calls.
- (command (or (and (symbolp command-1)
- (not (string-match "yas-expand" (symbol-name command-1)))
- command-1)
- (and (symbolp command-2)
- command-2))))
- (when (and (commandp command)
- (not (string-match "yas-expand" (symbol-name command))))
- (setq this-command command)
- (call-interactively command))))
+ (let* ((beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
+ (yas--message 4 "Falling back to %s" beyond-yasnippet)
+ (assert (or (null beyond-yasnippet) (commandp beyond-yasnippet)))
+ (setq this-original-command beyond-yasnippet)
+ (call-interactively beyond-yasnippet)))
((and (listp yas-fallback-behavior)
(cdr yas-fallback-behavior)
(eq 'apply (car yas-fallback-behavior)))
;; also return nil if all the other fallbacks have failed
nil)))
+(defun yas--keybinding-beyond-yasnippet ()
+ "Returns the "
+ (let* ((yas-minor-mode nil)
+ (yas--direct-keymaps nil)
+ (keys (this-single-command-keys)))
+ (or (key-binding keys t)
+ (key-binding (yas--fallback-translate-input keys) t))))
+
+(defun yas--fallback-translate-input (keys)
+ "Emulate `read-key-sequence', at least what I think it does.
+
+Keys should be an untranslated key vector. Returns a translated
+vector of keys. FIXME not thoroughly tested"
+ (let ((retval [])
+ (i 0))
+ (while (< i (length keys))
+ (let ((j i)
+ (translated local-function-key-map))
+ (while (and (< j (length keys))
+ translated
+ (keymapp translated))
+ (setq translated (aget (remove 'keymap translated) (aref keys j))
+ j (1+ j)))
+ (setq retval (vconcat retval (cond ((symbolp translated)
+ `[,translated])
+ ((vectorp translated)
+ translated)
+ (t
+ (substring keys i j)))))
+ (setq i j)))
+ retval))
\f
;;; Utils for snippet development:
"A doc synthesizer for `yas--expand-from-trigger-key-doc'."
(let ((fallback-description
(cond ((eq yas-fallback-behavior 'call-other-command)
- (let* ((yas-minor-mode nil)
- (fallback (key-binding (read-kbd-macro (yas--trigger-key-for-fallback)))))
+ (let* ((fallback (yas--keybinding-beyond-yasnippet)))
(or (and fallback
(format " call command `%s'." (pp-to-string fallback)))
- " do nothing.")))
+ " do nothing (`yas-expand' doesn't shadow\nanything)")))
((eq yas-fallback-behavior 'return-nil)
", do nothing.")
(t
- ", defer to `yas--fallback-behaviour' :-)"))))
+ ", defer to `yas-fallback-behaviour' (which see)"))))
(concat "Expand a snippet before point. If no snippet
expansion is possible,"
fallback-description
yas-indent-line
yas-also-auto-indent-first-line
yas-snippet-revival
- yas-trigger-key
- yas-next-field-key
- yas-prev-field-key
- yas-skip-and-clear-key
yas-triggers-in-field
yas-fallback-behavior
yas-choose-keys-first