* Butchered template choosing code

TODO:

* Still some old syntax to take care of (simple ${field} without number)
* Add messages to snippet events, not just errors
* fix many bugs
* make the customization group
* merge from trunk
...
This commit is contained in:
capitaomorte 2009-07-12 19:59:32 +00:00
parent 01c626efbd
commit 3dd0ba6106

View File

@ -114,15 +114,13 @@ return the error string instead.")
(t (:background "tomato"))) (t (:background "tomato")))
"The face used for debugging") "The face used for debugging")
(defvar yas/window-system-popup-function #'yas/x-popup-menu-for-template (defvar yas/popup-functions
"When there's multiple candidate for a snippet key. This function '( yas/x-popup
is called to let user select one of them. `yas/text-popup-function' yas/ido-popup
is used instead when not in a window system.") yas/dropdown-popup
(defvar yas/text-popup-function #'yas/x-popup-menu-for-template yas/completing-popup
"When there's multiple candidate for a snippet key. If not in a yas/no-popup ))
window system, this function is called to let user select one of
them. `yas/window-system-popup-function' is used instead when in
a window system.")
(defvar yas/extra-mode-hooks (defvar yas/extra-mode-hooks
'() '()
@ -327,23 +325,25 @@ set to t."
(remove-if-not '(lambda (pair) (remove-if-not '(lambda (pair)
(let ((condition (yas/template-condition (cdr pair)))) (let ((condition (yas/template-condition (cdr pair))))
(if (null condition) (if (null condition)
(if yas/require-template-condition (if (yas/require-template-condition)
nil nil
t) t)
(let ((result (let ((result
(yas/template-condition-predicate condition))) (yas/template-condition-predicate condition)))
(if yas/require-template-condition (if (yas/require-template-condition)
(if (eq yas/require-template-condition t) (if (eq (yas/require-template-condition) t)
result result
(eq result yas/require-template-condition)) (eq result (yas/require-template-condition)))
result))))) result)))))
templates)) templates))
(defun yas/snippet-table-fetch (table key) (defun yas/snippet-table-fetch (table key &optional no-condition)
"Fetch a snippet binding to KEY from TABLE. If not found, "Fetch a snippet binding to KEY from TABLE. If not found,
fetch from parent if any." fetch from parent if any."
(let ((templates (yas/filter-templates-by-condition (let* ((unfiltered (gethash key (yas/snippet-table-hash table)))
(gethash key (yas/snippet-table-hash table))))) (templates (or (and no-condition
unfiltered)
(yas/filter-templates-by-condition unfiltered))))
(when (and (null templates) (when (and (null templates)
(not (null (yas/snippet-table-parent table)))) (not (null (yas/snippet-table-parent table))))
(setq templates (yas/snippet-table-fetch (setq templates (yas/snippet-table-fetch
@ -357,17 +357,18 @@ fetch from parent if any."
(maphash #'(lambda (key templates) (maphash #'(lambda (key templates)
(setq acc (append acc templates))) (setq acc (append acc templates)))
(yas/snippet-table-hash table)) (yas/snippet-table-hash table))
(append acc (append (yas/filter-templates-by-condition acc)
(yas/snippet-table-all-templates (yas/snippet-table-parent table)))))) (yas/snippet-table-all-templates (yas/snippet-table-parent table))))))
(defun yas/snippet-table-all-keys (table) (defun yas/snippet-table-all-keys (table)
(when table (when table
(let ((acc)) (let ((acc))
(maphash #'(lambda (key templates) (maphash #'(lambda (key templates)
(push key acc)) (when (yas/filter-templates-by-condition templates)
(push key acc)))
(yas/snippet-table-hash table)) (yas/snippet-table-hash table))
(append acc (append acc
(yas/snippet-table-all-templates (yas/snippet-table-parent table)))))) (yas/snippet-table-all-keys (yas/snippet-table-parent table))))))
(defun yas/snippet-table-store (table full-key key template) (defun yas/snippet-table-store (table full-key key template)
"Store a snippet template in the table." "Store a snippet template in the table."
@ -400,9 +401,9 @@ a list of modes like this to help the judgement."
(or (fboundp mode) (or (fboundp mode)
(find mode yas/known-modes))) (find mode yas/known-modes)))
;; TODO: This is a possible optimization point, the expression could
;; be stored in cons format instead of string,
(defun yas/eval-string (string) (defun yas/eval-string (string)
;; TODO: This is a possible optimization point, the expression could
;; be stored in cons format instead of string,
"Evaluate STRING and convert the result to string." "Evaluate STRING and convert the result to string."
(condition-case err (condition-case err
(save-excursion (save-excursion
@ -413,9 +414,9 @@ a list of modes like this to help the judgement."
(when result (when result
(format "%s" result)))))) (format "%s" result))))))
(error (if yas/good-grace (error (if yas/good-grace
(format "(yasnippet: error in elisp evaluation: %s)" (format "([yas] elisp error: %s"
(error-message-string err)) (error-message-string err))
(error (format "(yasnippet: error in elisp evaluation: %s)" (error (format "([yas] elisp error: %s"
(error-message-string err))))))) (error-message-string err)))))))
(defun yas/snippet-table (mode) (defun yas/snippet-table (mode)
@ -529,59 +530,74 @@ Here's a list of currently recognized variables:
(setcdr pair value) (setcdr pair value)
alist))) alist)))
(defun yas/fake-keymap-for-popup (templates) ;; Popping up for keys and templates
"Create a fake keymap for popup menu usage." ;;
(cons 'keymap (defun yas/popup-for-template-content (templates)
(mapcar (lambda (pair) "Interactively choose a template's content from the list
(let* ((template (cdr pair)) TEMPLATES."
(name (yas/template-name template)) (let ((template (some #'(lambda (fn)
(content (yas/template-content template))) (funcall fn "Choose a snippet: " templates #'(lambda (template)
(list content 'menu-item name t))) (yas/template-name template))))
templates))) yas/popup-functions)))
(when template
(yas/template-content template))))
(defun yas/point-to-coord (&optional point) (defun yas/popup-for-keys (keys)
"Get the xoffset/yoffset information of POINT. "Interactively choose a template key from the list KEYS."
If POINT is not given, default is to current point. (some #'(lambda (fn)
If `posn-at-point' is not available (like in Emacs 21.3), (funcall fn "Choose a snippet key: " keys))
t is returned simply." yas/popup-functions))
(if (fboundp 'posn-at-point)
(let ((x-y (posn-x-y (posn-at-point (or point (point))))))
(list (list (+ (car x-y) 10)
(+ (cdr x-y) 20))
(selected-window)))
t))
(defun yas/x-popup-menu-for-template (templates) (defun yas/x-popup (prompt choices &optional display-fn)
"Show a popup menu listing templates to let the user select one." (when window-system
(car (x-popup-menu (yas/point-to-coord) (let ((keymap (cons 'keymap
(yas/fake-keymap-for-popup templates)))) (cons
prompt
(mapcar (lambda (choice)
(list choice
'menu-item
(if display-fn
(funcall display-fn choice)
choice)
t))
choices)))))
(when (cdr keymap)
(car (x-popup-menu (if (fboundp 'posn-at-point)
(let ((x-y (posn-x-y (posn-at-point (point)))))
(list (list (+ (car x-y) 10)
(+ (cdr x-y) 20))
(selected-window)))
t)
keymap))))))
(defun yas/text-popup-for-template (templates)
"Can't display popup menu in text mode. Just select the first one."
(yas/template-content (cdar templates)))
(defun yas/dropdown-list-popup-for-template (templates) (defun yas/ido-popup (prompt choices &optional display-fn)
"Use dropdown-list.el to popup for templates. Better than the (when (featurep 'ido)
default \"select first\" behavior of `yas/text-popup-for-template'. (let* ((formatted-choices (or (and display-fn
You can also use this in window-system. (mapcar display-fn choices))
choices))
(chosen (and choices
(ido-completing-read prompt
formatted-choices
nil
'require-match
nil
nil))))
(when chosen
(nth (position chosen formatted-choices) choices)))))
NOTE: You need to download and install dropdown-list.el to use this." (defun yas/dropdown-popup (prompt choices &optional display-fn)
(if (fboundp 'dropdown-list) (when (featurep 'dropdown-list)
(let ((n (dropdown-list (mapcar (lambda (i) ))
(yas/template-name
(cdr i)))
templates))))
(if n
(yas/template-content
(cdr (nth n templates)))
nil))
(error "Please download and install dropdown-list.el to use this")))
(defun yas/popup-for-template (templates) (defun yas/completing-popup (prompt choices &optional display-fn)
(if window-system )
(funcall yas/window-system-popup-function templates)
(funcall yas/text-popup-function templates)))
(defun yas/no-popup (prompt choices &optional display-fn)
)
;; Loading snippets
;;
(defun yas/load-directory-1 (directory &optional parent) (defun yas/load-directory-1 (directory &optional parent)
"Really do the job of loading snippets from a directory "Really do the job of loading snippets from a directory
hierarchy." hierarchy."
@ -811,46 +827,55 @@ when the condition evaluated to non-nil."
(undo 1)) (undo 1))
nil)) nil))
;; (defun yas/completing-expand () (defun yas/require-template-condition ()
;; "Choose a snippet to expand, pop-up a list of choices according (let ((local-condition (yas/template-condition-predicate
;; to `yas/popup-function'" yas/buffer-local-condition)))
;; (let ((keys) (and local-condition
;; (choice)) (consp local-condition)
;; (maphash #'(lambda (key val) (eq 'require-snippet-condition (car local-condition))
;; (push key keys)) (yas/current-snippet-table)) (symbolp (cdr local-condition))
;; (let ((choice (and keys (cdr local-condition))))
;; (ido-completing-read "Choose: " keys nil nil nil nil (car possibilities))))
;; (template (and choice
;; (gethash choice (yas/current-snippet-table)))))
(defun yas/expand () (defun yas/expand ()
"Expand a snippet." "Expand a snippet."
(interactive) (interactive)
(let ((local-condition (yas/template-condition-predicate (multiple-value-bind (templates start end) (yas/current-key)
yas/buffer-local-condition))) (if templates
(if local-condition (let ((template-content (yas/popup-for-template-content templates)))
(let ((yas/require-template-condition (when template-content
(if (and (consp local-condition) (yas/expand-snippet start end template-content)))
(eq 'require-snippet-condition (car local-condition)) (if (eq yas/fallback-behavior 'return-nil)
(symbolp (cdr local-condition))) nil ; return nil
(cdr local-condition) (let* ((yas/minor-mode nil)
nil))) (command (key-binding yas/trigger-key)))
(multiple-value-bind (templates start end) (yas/current-key) (when (commandp command)
(if templates (call-interactively command)))))))
(let ((template (if (null (cdr templates)) ; only 1 template
(yas/template-content (cdar templates)) (defvar yas/complete-for-keys t
(yas/popup-for-template templates)))) "If non-nil, `yas/completing-expand' prompts for key, then for template.
(if template
(progn (yas/expand-snippet start end template) Otherwise 'yas/completing-expand' prompts for all possible
'expanded) ; expanded successfully templates and inserts the selected one.")
'interrupted)) ; interrupted by user
(if (eq yas/fallback-behavior 'return-nil) (defun yas/completing-expand ()
nil ; return nil "Choose a snippet to expand, pop-up a list of choices according
(let* ((yas/minor-mode nil) to `yas/popup-function'."
(command (key-binding yas/trigger-key))) (interactive)
(when (commandp command) (let* ((templates (mapcar #'cdr
(call-interactively command)))))))))) (if yas/complete-for-keys
(let ((key (yas/popup-for-keys (yas/snippet-table-all-keys (yas/current-snippet-table)))))
(when key
(yas/snippet-table-fetch (yas/current-snippet-table) key 'no-condition)))
(yas/snippet-table-all-templates (yas/current-snippet-table)))))
(template-content (and templates
(or (and (cdr templates)
(yas/popup-for-template-content templates))
(yas/template-content (car templates)))))
(where (if mark-active
(cons (region-beginning) (region-end))
(cons (point) (point)))))
(when template-content
(yas/expand-snippet (car where) (cdr where) template-content))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Snippet expansion and field managment ;;; Snippet expansion and field managment
@ -859,7 +884,7 @@ when the condition evaluated to non-nil."
"Overlays the currently active field") "Overlays the currently active field")
(defvar yas/field-protection-overlays nil (defvar yas/field-protection-overlays nil
"Two overlays protect the current active field ") "Two overlays protect the current actipve field ")
(defvar yas/deleted-text nil (defvar yas/deleted-text nil
"The text deleted in the last snippet expansion") "The text deleted in the last snippet expansion")
@ -1378,7 +1403,7 @@ will be deleted before inserting template."
(setq snippet (yas/snippet-create (point-min) (point-max)))) (setq snippet (yas/snippet-create (point-min) (point-max))))
(error (error
(push (cons (point-min) (point-max)) buffer-undo-list) (push (cons (point-min) (point-max)) buffer-undo-list)
(signal (car err) (cadr err))))) (error (cadr err)))))
;; Delete the trigger key, this *does* get undo-recorded. ;; Delete the trigger key, this *does* get undo-recorded.
;; ;;