* Snippet table store is now based on two hash tables (keyhash and

namehash) instead of a hash table and an alist (this is still not ideal).

* `yas/wrap-around-region' can now also be 'cua' (undocumented feature)

* More cleanup
This commit is contained in:
capitaomorte 2009-08-16 13:32:19 +00:00
parent 6b1dce61d9
commit f28cc874af

View File

@ -339,7 +339,7 @@ This cafn only work when snippets are loaded from files."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User can also customize these
(defvar yas/keymap (make-sparse-keymap)
(defvar yas/keymap nil
"The keymap active while a snippet expansion is in progress.")
(defun yas/define-some-keys (keys keymap definition)
@ -349,9 +349,14 @@ This cafn only work when snippets are loaded from files."
(dolist (key keys)
(define-key keymap (read-kbd-macro key) definition))))
(yas/define-some-keys yas/next-field-key yas/keymap 'yas/next-field-or-maybe-expand)
(yas/define-some-keys yas/prev-field-key yas/keymap 'yas/prev-field)
(yas/define-some-keys yas/skip-and-clear-key yas/keymap 'yas/skip-and-clear-or-delete-char)
(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)))
(setq yas/keymap map))
(defvar yas/key-syntaxes (list "w" "w_" "w_." "^ ")
"A list of syntax of a key. This list is tried in the order
@ -438,9 +443,6 @@ Here's an example:
(defvar yas/version "0.6.1b")
(defvar yas/snippet-tables (make-hash-table)
"A hash table of MAJOR-MODE symbols to `yas/snippet-table' objects.")
(defvar yas/menu-table (make-hash-table)
"A hash table of MAJOR-MODE symbols to menu keymaps.")
@ -731,12 +733,94 @@ Key bindings:
file
keybinding)
(defvar yas/snippet-tables (make-hash-table)
"A hash table of MAJOR-MODE symbols to `yas/snippet-table' objects.")
(defstruct (yas/snippet-table (:constructor yas/make-snippet-table (name)))
"A table to store snippets for a particular mode."
"A table to store snippets for a particular mode.
Has the following fields:
`yas/snippet-table-name'
A symbol normally corresponding to a major mode, but can also be
a pseudo major-mode to be referenced in `yas/mode-symbol', for
example.
`yas/snippet-table-hash'
A hash table the key is a string (the snippet key) and the
value is yet another hash of (NAME TEMPLATE), where NAME is the
snippet name and TEMPLATE is a `yas/template' object name.
`yas/snippet-table-parents'
A list of tables considered parents of this table: i.e. when
searching for expansions they are searched as well."
name
(hash (make-hash-table :test 'equal))
(parents nil))
(defvar yas/better-guess-for-replacements nil
"If non-nil `yas/store' better guess snippet replacements.")
(defun yas/store (table name key template)
"Store a snippet template in the TABLE."
;; This is dones by searching twice:
;;
;; * Try to get the existing namehash from TABLE using key.
;;
;; * Try to get the existing namehash from by searching the *whole*
;; snippet table for NAME. This is becuase they user might have
;; changed the key and that can no longer be used to locate the
;; previous `yas/template-structure'.
;;
;; * If that returns nothing, oh well...
;;
(dolist (existing-namehash (remove nil (list (gethash key (yas/snippet-table-hash table))
(when yas/better-guess-for-replacements
(let (a)
(maphash #'(lambda (key namehash)
(when (gethash name namehash)
(setq a namehash)))
(yas/snippet-table-hash table))
a)))))
(let ((existing-template (gethash name existing-namehash)))
(when existing-template
;; Remove the existing keybinding
(when (yas/template-keybinding existing-template)
(define-key
(symbol-value (first (yas/template-keybinding existing-template)))
(second (yas/template-keybinding existing-template))
nil)
(setq yas/active-keybindings
(delete (yas/template-keybinding existing-template)
yas/active-keybindings)))
;; Remove the (name . template) mapping from existing-namehash.
(remhash name existing-namehash))))
;; Now store the new template independent of the previous steps.
;;
(puthash name
template
(or (gethash key
(yas/snippet-table-hash table))
(puthash key
(make-hash-table :test 'equal)
(yas/snippet-table-hash table)))))
(defun yas/fetch (table key)
"Fetch a snippet binding to KEY from TABLE."
(let* ((keyhash (yas/snippet-table-hash table))
(namehash (and keyhash (gethash key keyhash))))
(when namehash
(yas/filter-templates-by-condition
(let (alist)
(maphash #'(lambda (k v)
(push (cons k v) alist))
namehash)
alist)))))
;; Filtering/condition logic
@ -755,7 +839,7 @@ Key bindings:
(defun yas/filter-templates-by-condition (templates)
"Filter the templates using the applicable condition.
TEMPLATES is a list of cons (KEY . TEMPLATE) where KEY is a
TEMPLATES is a list of cons (NAME . TEMPLATE) where NAME is a
string and TEMPLATE is a `yas/template' structure.
This function implements the rules described in
@ -800,12 +884,6 @@ conditions to filter out potential expansions."
(t
(eq requirement result)))))
(defun yas/snippet-table-fetch (table key)
"Fetch a snippet binding to KEY from TABLE."
(when table
(yas/filter-templates-by-condition
(copy-list (gethash key (yas/snippet-table-hash table))))))
(defun yas/snippet-table-get-all-parents (table)
(let ((parents (yas/snippet-table-parents table)))
(when parents
@ -815,8 +893,10 @@ conditions to filter out potential expansions."
(defun yas/snippet-table-templates (table)
(when table
(let ((acc (list)))
(maphash #'(lambda (key templates)
(setq acc (nconc acc (copy-list templates))))
(maphash #'(lambda (key namehash)
(maphash #'(lambda (name template)
(push (cons name template) acc))
namehash))
(yas/snippet-table-hash table))
(yas/filter-templates-by-condition acc))))
@ -837,7 +917,7 @@ the template of a snippet in the current snippet-table."
(setq start (point)))
(setq templates
(mapcan #'(lambda (table)
(yas/snippet-table-fetch table (buffer-substring-no-properties start end)))
(yas/fetch table (buffer-substring-no-properties start end)))
(yas/get-snippet-tables)))
(if templates
(setq done t)
@ -856,31 +936,6 @@ the template of a snippet in the current snippet-table."
(yas/snippet-table-hash table))
acc)))
(defun yas/snippet-table-store (table name key template)
"Store a snippet template in the TABLE."
;; If replacing a snippet template, remember to remove its
;; keybinding first.
;;
(let ((existing (aget (gethash key (yas/snippet-table-hash table))
name)))
(when (and existing
(yas/template-keybinding existing))
(define-key
(symbol-value (first (yas/template-keybinding existing)))
(second (yas/template-keybinding existing))
nil)
(setq yas/active-keybindings
(delete (yas/template-keybinding existing)
yas/active-keybindings))))
;; Now store the new template
;;
(puthash key
(yas/modify-alist (gethash key
(yas/snippet-table-hash table))
name
template)
(yas/snippet-table-hash table)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal functions
@ -1006,7 +1061,7 @@ Here's a list of currently recognized variables:
condition
(group (and file
(yas/calculate-group file)))
env
expand-env
binding)
(if (re-search-forward "^# --\n" nil t)
(progn (setq template
@ -1022,14 +1077,14 @@ Here's a list of currently recognized variables:
(when (string= "group" (match-string-no-properties 1))
(setq group (match-string-no-properties 2)))
(when (string= "expand-env" (match-string-no-properties 1))
(setq env (match-string-no-properties 2)))
(setq expand-env (match-string-no-properties 2)))
(when (string= "key" (match-string-no-properties 1))
(setq key (match-string-no-properties 2)))
(when (string= "binding" (match-string-no-properties 1))
(setq binding (match-string-no-properties 2)))))
(setq template
(buffer-substring-no-properties (point-min) (point-max))))
(list key template name condition group env file binding)))
(list key template name condition group expand-env file binding)))
(defun yas/calculate-group (file)
"Calculate the group for snippet file path FILE."
@ -1101,15 +1156,6 @@ Here's a list of currently recognized variables:
(car where)
(cdr where)))))
(defun yas/modify-alist (alist key value)
"Modify ALIST to map KEY to VALUE. return the new alist."
(let ((pair (assoc key alist)))
(if (null pair)
(cons (cons key value)
alist)
(setcdr pair value)
alist)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Popping up for keys and templates
;;
@ -1334,11 +1380,17 @@ foo\"bar\\! -> \"foo\\\"bar\\\\!\""
(defun yas/compile-bundle
(&optional yasnippet yasnippet-bundle snippet-roots code dropdown)
"Compile snippets in SNIPPET-ROOTS to a single bundle file.
YASNIPPET is the yasnippet.el file path.
YASNIPPET-BUNDLE is the output file of the compile result.
SNIPPET-ROOTS is a list of root directories that contains the
snippets definition. YASNIPPET is the yasnippet.el file
path. YASNIPPET-BUNDLE is the output file of the compile
result. CODE is the code you would like to used to initialize
yasnippet. Last optional argument DROPDOWN is the filename of the
snippets definition.
CODE is the code you would like to used to initialize yasnippet.
Last optional argument DROPDOWN is the filename of the
dropdown-list.el library.
Here's the default value for all the parameters:
@ -1346,27 +1398,28 @@ Here's the default value for all the parameters:
(yas/compile-bundle \"yasnippet.el\"
\"./yasnippet-bundle.el\"
'(\"snippets\")
\"(yas/initialize)\")
..
\"(yas/initialize-bundle)\"
\"dropdown-list.el\")
"
(when (null yasnippet)
(setq yasnippet "yasnippet.el"))
(when (null yasnippet-bundle)
(setq yasnippet-bundle "./yasnippet-bundle.el"))
(when (null snippet-roots)
(setq snippet-roots '("snippets")))
(when (null dropdown)
(setq dropdown "dropdown-list.el"))
(when (null code)
(setq code (concat "(yas/initialize-bundle)"
"\n;;;###autoload" ; break through so that won't
"(require 'yasnippet-bundle)"))) ; be treated as magic comment
(interactive "ffind the yasnippet.el file: \nFTarget bundle file: \nDSnippet directory to bundle: \nMExtra code? \nfdropdown-library: ")
(let ((dirs (or (and (listp snippet-roots) snippet-roots)
(list snippet-roots)))
(bundle-buffer nil))
(let* ((yasnippet (or yasnippet
("yasnippet.el")))
(yasnippet-bundle (or yasnippet-bundle
"./yasnippet-bundle.el"))
(snippet-roots (or snippet-roots
"snippets"))
(dropdown (or dropdown
"dropdown-list.el"))
(code (or (and code
(condition-case err (read code) (error nil))
code)
(concat "(yas/initialize-bundle)"
"\n;;;###autoload" ; break through so that won't
"(require 'yasnippet-bundle)")))
(dirs (or (and (listp snippet-roots) snippet-roots)
(list snippet-roots)))
(bundle-buffer nil))
(with-temp-buffer
(setq bundle-buffer (current-buffer))
(insert ";;; yasnippet-bundle.el --- "
@ -1387,34 +1440,28 @@ Here's the default value for all the parameters:
(mode snippets &optional parent-or-parents)
(with-current-buffer bundle-buffer
(insert ";;; snippets for " (symbol-name mode) "\n")
(insert "(yas/define-snippets '" (symbol-name mode) "\n")
(insert "'(\n")
(dolist (snippet snippets)
(insert " ("
(yas/quote-string (car snippet))
" "
(yas/quote-string (nth 1 snippet))
" "
(if (nth 2 snippet)
(yas/quote-string (nth 2 snippet))
"nil")
" "
(if (nth 3 snippet)
(format "'%s" (nth 3 snippet))
"nil")
" "
(if (nth 4 snippet)
(yas/quote-string (nth 4 snippet))
"nil")
")\n"))
(insert " )\n")
(insert (if parent-or-parents
(format "'%s" parent-or-parents)
"nil")
;; (if directory
;; (concat "\"" directory "\"")
;; "nil")
")\n\n"))))
(let ((literal-snippets (list)))
(dolist (snippet snippets)
(let ((key (first snippet))
(template-content (second snippet))
(name (third snippet))
(condition (fourth snippet))
(group (fifth snippet))
(expand-env (sixth snippet))
;; Omit the file on purpose
(file nil);; (seventh snippet))
(binding (eighth snippet)))
(push `(,key
,template-content
,name
,condition
,group
,expand-env
,file
,binding)
literal-snippets)))
(insert (pp-to-string `(yas/define-snippets ',mode ',literal-snippets ',parent-or-parents)))
(insert "\n\n")))))
(dolist (dir dirs)
(dolist (subdir (yas/subdirs dir))
(yas/load-directory-1 subdir nil 'no-hierarchy-parents))))
@ -1519,10 +1566,10 @@ its parent modes."
(setq keybinding (list keymap-symbol
keys
name))
(error "that keymap does not exit"))))
(error (format "keymap \"%s\" does not (yet?) exist" keymap-symbol)))))
(error
(message "[yas] warning: keybinding \"%s\" invalid for snippet \"%s\""
(key-description keybinding) name)
(message "[yas] warning: keybinding \"%s\" invalid for snippet \"%s\" since %s."
keybinding name (error-message-string err))
(setf keybinding nil)))
;; Create the `yas/template' object and store in the
@ -1538,10 +1585,10 @@ its parent modes."
keybinding))
(when (and key
name)
(yas/snippet-table-store snippet-table
name
key
template))
(yas/store snippet-table
name
key
template))
;; If we have a keybinding, register it if it does not
;; conflict!
;;
@ -1593,12 +1640,11 @@ its parent modes."
(concat key yas/trigger-symbol))))))))))
(defun yas/show-menu-p (mode)
(message "what")
(cond ((eq yas/use-menu 'abbreviate)
(find mode (cons major-mode
(if (listp yas/mode-symbol)
yas/mode-symbol
(list yas/mode-symbol)))))
(find mode
(mapcar #'(lambda (table)
(intern (yas/snippet-table-name table)))
(yas/get-snippet-tables))))
((eq yas/use-menu 'real-modes)
(yas/real-mode? mode))
(t
@ -1721,7 +1767,7 @@ Honours `yas/choose-tables-first', `yas/choose-keys-first' and
(mapcan #'yas/snippet-table-all-keys tables))))
(when key
(mapcan #'(lambda (table)
(yas/snippet-table-fetch table key))
(yas/fetch table key))
tables)))
(mapcan #'yas/snippet-table-templates tables))))
@ -1906,9 +1952,10 @@ With optional prefix argument KILL quit the window and buffer."
(name (and parsed
(third parsed))))
(when name
(yas/define-snippets (car major-mode-and-parent)
(list parsed)
(cdr major-mode-and-parent))
(let ((yas/better-guess-for-replacements t))
(yas/define-snippets (car major-mode-and-parent)
(list parsed)
(cdr major-mode-and-parent)))
(when (and (buffer-modified-p)
(y-or-n-p "Save snippet? "))
(save-buffer))
@ -2011,6 +2058,10 @@ Otherwise throw exception."
(when field
(yas/field-text-for-display field))))
(defun yas/default-from-field (number)
(unless yas/modified-p
(yas/field-value number)))
(defun yas/inside-string ()
(equal 'font-lock-string-face (get-char-property (1- (point)) 'face)))
@ -2218,6 +2269,13 @@ Also create some protection overlays"
(interactive)
(yas/next-field -1))
(defun yas/abort-snippet (&optional snippet)
(interactive)
(let ((snippet (or snippet
(car (yas/snippets-at-point)))))
(when snippet
(setf (yas/snippet-force-exit snippet) t))))
(defun yas/exit-snippet (snippet)
"Goto exit-marker of SNIPPET."
(interactive)
@ -3097,8 +3155,14 @@ When multiple expressions are found, only the last one counts."
(yas/make-exit (yas/make-marker (match-end 0))))
(save-excursion
(goto-char (match-beginning 0))
(when (and yas/wrap-around-region yas/selected-text)
(insert yas/selected-text))
(when yas/wrap-around-region
(cond (yas/selected-text
(insert yas/selected-text))
((and (eq yas/wrap-around-region 'cua)
cua-mode
(get-register ?0))
(insert (prog1 (get-register ?0)
(set-register ?0 nil))))))
(push (cons (point) (yas/exit-marker (yas/snippet-exit snippet)))
yas/dollar-regions)))
(t