Merge branch 'trigger-key-fallback-cleanup'

Conflicts:
	yasnippet.el
This commit is contained in:
João Távora 2012-11-06 14:16:46 +00:00
commit 73a1b485d6
3 changed files with 95 additions and 165 deletions

View File

@ -9,6 +9,11 @@ end
find_version find_version
FileUtils.mkdir_p('pkg') FileUtils.mkdir_p('pkg')
desc "run tests in batch mode"
task :tests do
$EMACS=ENV["EMACS"] || "emacs"
sh "#{$EMACS} -Q -L . -l yasnippet-tests.el -nw --batch -e yas/ert"
end
desc "convert some textmate bundles to yasnippets" desc "convert some textmate bundles to yasnippets"
task :convert_bundles do task :convert_bundles do

View File

@ -198,6 +198,12 @@
(should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend"))))) (should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend")))))
(ert-deftest another-example-for-issue-271 () (ert-deftest another-example-for-issue-271 ()
;; expect this to fail in batch mode since `region-active-p' doesn't
;; used by `yas-expand-snippet' doesn't make sense in that context.
;;
:expected-result (if noninteractive
:failed
:passed)
(with-temp-buffer (with-temp-buffer
(yas-minor-mode 1) (yas-minor-mode 1)
(let ((snippet "\\${${1:1}:`yas/selected-text`}")) (let ((snippet "\\${${1:1}:`yas/selected-text`}"))
@ -438,23 +444,30 @@ TODO: be meaner"
(yas-minor-mode 1) (yas-minor-mode 1)
(should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand)) (should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
(yas-expand-snippet "$1 $2 $3") (yas-expand-snippet "$1 $2 $3")
(dolist (k (if (listp yas-next-field-key) (should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
yas-next-field-key (should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
(list yas-next-field-key))) (should (eq (key-binding [(shift tab)]) 'yas-prev-field))
(should (eq (key-binding (yas--read-keybinding k)) 'yas-next-field-or-maybe-expand))) (should (eq (key-binding [backtab]) 'yas-prev-field))))
(dolist (k (if (listp yas-prev-field-key)
yas-prev-field-key
(list yas-prev-field-key)))
(should (eq (key-binding (yas--read-keybinding k)) 'yas-prev-field)))))
(ert-deftest test-yas-in-org () (ert-deftest test-yas-in-org ()
(with-temp-buffer (with-temp-buffer
(org-mode) (org-mode)
(yas-minor-mode 1) (yas-minor-mode 1)
(should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand)))) (should (eq (key-binding [(tab)]) 'yas-expand))
(should (eq (key-binding (kbd "TAB")) 'yas-expand))))
;;; Helpers ;;; Helpers
;;; ;;;
(defun yas/ert ()
(interactive)
(with-temp-buffer
(flet ((message (&rest args)
(declare (ignore args))
nil))
(ert t (buffer-name (current-buffer)))
(princ (buffer-string)))))
(defun yas-should-expand (keys-and-expansions) (defun yas-should-expand (keys-and-expansions)
(dolist (key-and-expansion keys-and-expansions) (dolist (key-and-expansion keys-and-expansions)

View File

@ -63,7 +63,8 @@
;; M-x yas-expand ;; M-x yas-expand
;; ;;
;; Try to expand snippets before point. In `yas-minor-mode', ;; 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 ;; M-x yas-load-directory
;; ;;
@ -245,81 +246,20 @@ Naturally this is only valid when `yas-indent-line' is `auto'"
:type 'boolean :type 'boolean
:group 'yasnippet) :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 (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 Otherwise `yas-next-field-or-maybe-expand' just moves on to the
field" next field"
:type 'boolean :type 'boolean
:group 'yasnippet) :group 'yasnippet)
(defcustom yas-fallback-behavior 'call-other-command (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 - `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 - nil or the symbol `return-nil' mean do nothing. (and
`yas-expand' returns nil) `yas-expand' returns nil)
@ -426,29 +366,15 @@ the trigger key itself."
:group 'yasnippet) :group 'yasnippet)
;;; User can also customize the next defvars (defvar yas-keymap (let ((map (make-sparse-keymap)))
(define-key map [(tab)] 'yas-next-field-or-maybe-expand)
(defun yas--define-some-keys (keys keymap definition) (define-key map (kbd "TAB") 'yas-next-field-or-maybe-expand)
"Bind KEYS to DEFINITION in KEYMAP, read with `read-kbd-macro'." (define-key map [(shift tab)] 'yas-prev-field)
(let ((keys (or (and (listp keys) keys) (define-key map [backtab] 'yas-prev-field)
(list keys)))) (define-key map (kbd "C-g") 'yas-abort-snippet)
(dolist (key keys) (define-key map (kbd "C-d") 'yas-skip-and-clear-or-delete-char)
(define-key keymap (read-kbd-macro key) definition)))) map)
"The active keymap while a snippet expansion is in progress.")
(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-key-syntaxes (list "w" "w_" "w_." "w_.()" "^ ") (defvar yas-key-syntaxes (list "w" "w_" "w_." "w_.()" "^ ")
"List of character syntaxes used to find a trigger key before point. "List of character syntaxes used to find a trigger key before point.
@ -705,6 +631,8 @@ snippet itself contains a condition that returns the symbol
;; Now for the stuff that has direct keybindings ;; 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-s" 'yas-insert-snippet)
(define-key map "\C-c&\C-n" 'yas-new-snippet) (define-key map "\C-c&\C-n" 'yas-new-snippet)
(define-key map "\C-c&\C-v" 'yas-visit-snippet-file) (define-key map "\C-c&\C-v" 'yas-visit-snippet-file)
@ -713,20 +641,6 @@ snippet itself contains a condition that returns the symbol
(defvar yas-minor-mode-map (yas--init-minor-keymap) (defvar yas-minor-mode-map (yas--init-minor-keymap)
"The keymap used when `yas-minor-mode' is active.") "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) (defvar yas--tables (make-hash-table)
"A hash table of mode symbols to `yas--table' objects.") "A hash table of mode symbols to `yas--table' objects.")
@ -785,15 +699,14 @@ and friends."
(define-minor-mode yas-minor-mode (define-minor-mode yas-minor-mode
"Toggle YASnippet mode. "Toggle YASnippet mode.
When YASnippet mode is enabled, the `yas-trigger-key' key expands When YASnippet mode is enabled, `yas-expand', normally bound to
snippets of code depending on the major mode. the TAB key, expands snippets of code depending on the major
mode.
With no argument, this command toggles the mode. With no argument, this command toggles the mode.
positive prefix argument turns on the mode. positive prefix argument turns on the mode.
Negative prefix argument turns off the mode. Negative prefix argument turns off the mode.
You can customize the key through `yas-trigger-key'.
Key bindings: Key bindings:
\\{yas-minor-mode-map}" \\{yas-minor-mode-map}"
nil nil
@ -801,9 +714,6 @@ Key bindings:
" yas" " yas"
:group 'yasnippet :group 'yasnippet
(cond (yas-minor-mode (cond (yas-minor-mode
;; Reload the trigger key
;;
(yas--trigger-key-reload)
;; Install the direct keymaps in `emulation-mode-map-alists' ;; Install the direct keymaps in `emulation-mode-map-alists'
;; (we use `add-hook' even though it's not technically a hook, ;; (we use `add-hook' even though it's not technically a hook,
;; but it works). Then define variables named after modes to ;; but it works). Then define variables named after modes to
@ -1822,9 +1732,6 @@ loading."
;; Reload the direct keybindings ;; Reload the direct keybindings
;; ;;
(yas-direct-keymaps-reload) (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." (yas--message 3 "Reloaded everything%s...%s."
(if interactive "" " (snippets will load just-in-time)") (if interactive "" " (snippets will load just-in-time)")
@ -2280,18 +2187,13 @@ expand immediately. Common gateway for
end end
(yas--template-expand-env yas--current-template))))) (yas--template-expand-env yas--current-template)))))
(defun yas--trigger-key-for-fallback () ;; Apropos the trigger key and the fallback binding:
;; When `yas-trigger-key' is <tab> it correctly overrides ;;
;; org-mode's <tab>, for example and searching for fallbacks ;; When `yas-minor-mode-map' binds <tab>, that correctly overrides
;; correctly returns `org-cycle'. However, most other modes bind ;; org-mode's <tab>, for example and searching for fallbacks correctly
;; "TAB" (which is translated from <tab>), and calling ;; returns `org-cycle'. However, most other modes bind "TAB". TODO,
;; (key-binding "TAB") does not place return that command into ;; improve this explanation.
;; our command-2 local. So we cheat. ;;
;;
(if (string= yas-trigger-key "<tab>")
"TAB"
yas-trigger-key))
(defun yas--fallback (&optional from-trigger-key-p) (defun yas--fallback (&optional from-trigger-key-p)
"Fallback after expansion has failed. "Fallback after expansion has failed.
@ -2301,27 +2203,11 @@ Common gateway for `yas-expand-from-trigger-key' and
;; return nil ;; return nil
nil) nil)
((eq yas-fallback-behavior 'call-other-command) ((eq yas-fallback-behavior 'call-other-command)
(let* ((yas-minor-mode nil) (let* ((beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
(yas--direct-keymaps nil) (yas--message 4 "Falling back to %s" beyond-yasnippet)
(yas-trigger-key (yas--trigger-key-for-fallback)) (assert (or (null beyond-yasnippet) (commandp beyond-yasnippet)))
(keys-1 (this-command-keys-vector)) (setq this-original-command beyond-yasnippet)
(keys-2 (and yas-trigger-key (call-interactively beyond-yasnippet)))
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))))
((and (listp yas-fallback-behavior) ((and (listp yas-fallback-behavior)
(cdr yas-fallback-behavior) (cdr yas-fallback-behavior)
(eq 'apply (car yas-fallback-behavior))) (eq 'apply (car yas-fallback-behavior)))
@ -2335,6 +2221,37 @@ Common gateway for `yas-expand-from-trigger-key' and
;; also return nil if all the other fallbacks have failed ;; also return nil if all the other fallbacks have failed
nil))) 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))
;;; Utils for snippet development: ;;; Utils for snippet development:
@ -4278,15 +4195,14 @@ When multiple expressions are found, only the last one counts."
"A doc synthesizer for `yas--expand-from-trigger-key-doc'." "A doc synthesizer for `yas--expand-from-trigger-key-doc'."
(let ((fallback-description (let ((fallback-description
(cond ((eq yas-fallback-behavior 'call-other-command) (cond ((eq yas-fallback-behavior 'call-other-command)
(let* ((yas-minor-mode nil) (let* ((fallback (yas--keybinding-beyond-yasnippet)))
(fallback (key-binding (read-kbd-macro (yas--trigger-key-for-fallback)))))
(or (and fallback (or (and fallback
(format " call command `%s'." (pp-to-string 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) ((eq yas-fallback-behavior 'return-nil)
", do nothing.") ", do nothing.")
(t (t
", defer to `yas--fallback-behaviour' :-)")))) ", defer to `yas-fallback-behaviour' (which see)"))))
(concat "Expand a snippet before point. If no snippet (concat "Expand a snippet before point. If no snippet
expansion is possible," expansion is possible,"
fallback-description fallback-description
@ -4466,10 +4382,6 @@ handle the end-of-buffer error fired in it by calling
yas-indent-line yas-indent-line
yas-also-auto-indent-first-line yas-also-auto-indent-first-line
yas-snippet-revival yas-snippet-revival
yas-trigger-key
yas-next-field-key
yas-prev-field-key
yas-skip-and-clear-key
yas-triggers-in-field yas-triggers-in-field
yas-fallback-behavior yas-fallback-behavior
yas-choose-keys-first yas-choose-keys-first