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
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"
task :convert_bundles do

View File

@ -198,6 +198,12 @@
(should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend")))))
(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
(yas-minor-mode 1)
(let ((snippet "\\${${1:1}:`yas/selected-text`}"))
@ -438,23 +444,30 @@ TODO: be meaner"
(yas-minor-mode 1)
(should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
(yas-expand-snippet "$1 $2 $3")
(dolist (k (if (listp yas-next-field-key)
yas-next-field-key
(list yas-next-field-key)))
(should (eq (key-binding (yas--read-keybinding k)) 'yas-next-field-or-maybe-expand)))
(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)))))
(should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
(should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
(should (eq (key-binding [(shift tab)]) 'yas-prev-field))
(should (eq (key-binding [backtab]) 'yas-prev-field))))
(ert-deftest test-yas-in-org ()
(with-temp-buffer
(org-mode)
(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
;;;
(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)
(dolist (key-and-expansion keys-and-expansions)

View File

@ -63,7 +63,8 @@
;; 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
;;
@ -245,81 +246,20 @@ Naturally this is only valid when `yas-indent-line' is `auto'"
: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)
@ -426,29 +366,15 @@ the trigger key itself."
:group 'yasnippet)
;;; 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.
@ -705,6 +631,8 @@ snippet itself contains a condition that returns the symbol
;; 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)
@ -713,20 +641,6 @@ snippet itself contains a condition that returns the symbol
(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.")
@ -785,15 +699,14 @@ and friends."
(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
@ -801,9 +714,6 @@ Key bindings:
" 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
@ -1822,9 +1732,6 @@ loading."
;; 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)")
@ -2280,18 +2187,13 @@ expand immediately. Common gateway for
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.
@ -2301,27 +2203,11 @@ Common gateway for `yas-expand-from-trigger-key' and
;; 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)))
@ -2335,6 +2221,37 @@ Common gateway for `yas-expand-from-trigger-key' and
;; 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))
;;; 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'."
(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
@ -4466,10 +4382,6 @@ handle the end-of-buffer error fired in it by calling
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