* Redesigned directory-guessing mechanism, but kept backward

compatibility

* A mode can now have multiple parent modes using a hidden
  ".yas-parents" file.

* Fixed issue 70.

* Removed a useless condition-case.

* More fixes
This commit is contained in:
capitaomorte 2009-07-29 12:54:54 +00:00
parent ad3c307bbc
commit d42e5a3189

View File

@ -44,6 +44,23 @@
;; Steps 4. and 5. are optional, you don't have to use the minor ;; Steps 4. and 5. are optional, you don't have to use the minor
;; mode to use YASnippet. ;; mode to use YASnippet.
;; ;;
;; Interesting variables are:
;;
;; `yas/root-directory'
;;
;; The directory where user-created snippets are to be
;; stored. Can also be a list of directories that
;; `yas/reload-all' will use for bulk-reloading snippets. In
;; that case the first directory the default for storing new
;; snippets.
;;
;; `yas/mode-symbol'
;;
;; A local variable that you can set in a hook to override
;; snippet-lookup based on major mode. It is a a symbol (or
;; list of symbols) that correspond to subdirectories of
;; `yas/root-directory' and is used for deciding which
;; snippets to consider for the active buffer.
;; ;;
;; Major commands are: ;; Major commands are:
;; ;;
@ -65,8 +82,9 @@
;; ;;
;; M-x yas/find-snippets ;; M-x yas/find-snippets
;; ;;
;; Lets you find the snippet file in the directory the ;; Lets you find the snippet files in the correct
;; snippet was loaded from (if it exists) like ;; subdirectory of `yas/root-directory', according to the
;; active major mode (if it exists) like
;; `find-file-other-window'. ;; `find-file-other-window'.
;; ;;
;; M-x yas/visit-snippet-file ;; M-x yas/visit-snippet-file
@ -76,6 +94,12 @@
;; you directly to the snippet definition's file, if it ;; you directly to the snippet definition's file, if it
;; exists. ;; exists.
;; ;;
;; M-x yas/new-snippet
;;
;; Lets you create a new snippet file in the correct
;; subdirectory of `yas/root-directory', according to the
;; active major mode
;;
;; M-x yas/load-snippet-buffer ;; M-x yas/load-snippet-buffer
;; ;;
;; When editing a snippet, this loads the snippet. This is ;; When editing a snippet, this loads the snippet. This is
@ -121,7 +145,11 @@
(defcustom yas/root-directory nil (defcustom yas/root-directory nil
"Root directory that stores the snippets for each major mode. "Root directory that stores the snippets for each major mode.
Can also be a list of strings, for multiple root directories." Can also be a list of strings, for multiple root directories. If
you make this a list, the first element is always the
user-created snippets directory. Other directories are used for
bulk reloading of all snippets using `yas/reload-all'"
:type '(string) :type '(string)
:group 'yasnippet) :group 'yasnippet)
@ -220,10 +248,21 @@ to expand.
:group 'yasnippet) :group 'yasnippet)
(defcustom yas/choose-keys-first t (defcustom yas/choose-keys-first t
"If non-nil, `yas/insert-snippet' prompts for key, then for template. "If non-nil, prompts for key first, then for template if more than one.
Otherwise `yas/insert-snippet' prompts for all possible Otherwise prompts for all possible templates
templates and inserts the selected one."
This affects `yas/insert-snippet' and `yas/visit-snippet-file'."
:type 'boolean
:group 'yasnippet)
(defcustom yas/choose-tables-first nil
"If non-nil, and multiple eligible snippet tables, prompts user for tables first.
Otherwise, user chooses between the merging together of all
eligible tables.
This affects `yas/insert-snippet', `yas/visit-snippet-file'"
:type 'boolean :type 'boolean
:group 'yasnippet) :group 'yasnippet)
@ -240,21 +279,6 @@ mode will be listed under the menu \"yasnippet\"."
:type 'string :type 'string
:group 'yasnippet) :group 'yasnippet)
(defcustom yas/show-all-modes-in-menu nil
"Display \"artificial\" major modes in menu bar as well.
Currently, YASnippet only all \"real modes\" to menubar. For
example, you define snippets for \"cc-mode\" and make it the
parent of `c-mode', `c++-mode' and `java-mode'. There's really
no such mode like \"cc-mode\". So we don't show it in the yasnippet
menu to avoid the menu becoming too big with strange modes. The
snippets defined for \"cc-mode\" can still be accessed from
menu-bar->c-mode->parent (or c++-mode, java-mode, all are ok).
However, if you really like to show all modes in the menu, set
this variable to t."
:type 'boolean
:group 'yasnippet)
(defcustom yas/wrap-around-region nil (defcustom yas/wrap-around-region nil
"If non-nil, snippet expansion wraps around selected region. "If non-nil, snippet expansion wraps around selected region.
@ -378,12 +402,6 @@ Here's an example:
t))))") t))))")
(make-variable-buffer-local 'yas/buffer-local-condition) (make-variable-buffer-local 'yas/buffer-local-condition)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utility functions for transformations
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal variables ;; Internal variables
;; ;;
@ -543,11 +561,11 @@ Key bindings:
env env
file) file)
(defstruct (yas/snippet-table (:constructor yas/make-snippet-table ())) (defstruct (yas/snippet-table (:constructor yas/make-snippet-table (name)))
"A table to store snippets for a perticular mode." "A table to store snippets for a perticular mode."
name
(hash (make-hash-table :test 'equal)) (hash (make-hash-table :test 'equal))
(default-directory nil) (parents nil))
(parent nil))
(defun yas/template-condition-predicate (condition) (defun yas/template-condition-predicate (condition)
(condition-case err (condition-case err
@ -583,26 +601,23 @@ This function implements the rules described in
templates)))) templates))))
(defun yas/snippet-table-fetch (table key) (defun yas/snippet-table-fetch (table key)
"Fetch a snippet binding to KEY from TABLE. If not found, "Fetch a snippet binding to KEY from TABLE."
fetch from parent if any."
(when table (when table
(let* ((unfiltered (gethash key (yas/snippet-table-hash table))) (yas/filter-templates-by-condition (gethash key (yas/snippet-table-hash table)))))
(templates (yas/filter-templates-by-condition unfiltered)))
(when (and (null templates)
(not (null (yas/snippet-table-parent table))))
(setq templates (yas/snippet-table-fetch
(yas/snippet-table-parent table)
key)))
templates)))
(defun yas/snippet-table-all-templates (table) (defun yas/snippet-table-get-all-parents (table)
(let ((parents (yas/snippet-table-parents table)))
(when parents
(append parents
(mapcan #'yas/snippet-table-get-all-parents parents)))))
(defun yas/snippet-table-templates (table)
(when table (when table
(let ((acc)) (let ((acc))
(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 (yas/filter-templates-by-condition acc) (yas/filter-templates-by-condition acc))))
(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
@ -611,8 +626,7 @@ fetch from parent if any."
(when (yas/filter-templates-by-condition templates) (when (yas/filter-templates-by-condition templates)
(push key acc))) (push key acc)))
(yas/snippet-table-hash table)) (yas/snippet-table-hash table))
(append acc acc)))
(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."
@ -627,16 +641,6 @@ fetch from parent if any."
;; Internal functions ;; Internal functions
;; ;;
(defun yas/ensure-minor-mode-priority ()
"Ensure that the key binding of yas/minor-mode takes priority."
(unless (eq 'yas/minor-mode
(caar minor-mode-map-alist))
(setq minor-mode-map-alist
(cons
(cons 'yas/minor-mode yas/minor-mode-map)
(assq-delete-all 'yas/minor-mode
minor-mode-map-alist)))))
(defun yas/real-mode? (mode) (defun yas/real-mode? (mode)
"Try to find out if MODE is a real mode. The MODE bound to "Try to find out if MODE is a real mode. The MODE bound to
a function (like `c-mode') is considered real mode. Other well a function (like `c-mode') is considered real mode. Other well
@ -668,7 +672,11 @@ a list of modes like this to help the judgement."
(error (cdr retval))) (error (cdr retval)))
retval)) retval))
(defun yas/snippet-table-get-create (mode &optional directory) (defvar yas/mode-symbol nil
"If non-nil, lookup snippets using this instead of `major-mode'.")
(make-variable-buffer-local 'yas/mode-symbol)
(defun yas/snippet-table-get-create (mode)
"Get the snippet table corresponding to MODE. "Get the snippet table corresponding to MODE.
Optional DIRECTORY gets recorded as the default directory to Optional DIRECTORY gets recorded as the default directory to
@ -677,24 +685,35 @@ already have such a property."
(let ((table (gethash mode (let ((table (gethash mode
yas/snippet-tables))) yas/snippet-tables)))
(unless table (unless table
(setq table (yas/make-snippet-table)) (setq table (yas/make-snippet-table (symbol-name mode)))
(puthash mode table yas/snippet-tables)) (puthash mode table yas/snippet-tables))
(unless (or (not directory) (yas/snippet-table-default-directory table))
(setf (yas/snippet-table-default-directory table)
directory))
table)) table))
(defun yas/current-snippet-table (&optional mode-symbol dont-search-parents) (defun yas/get-snippet-tables (&optional mode-symbol dont-search-parents)
"Get the snippet table for current major-mode." "Get snippet tables for current buffer.
(let ((mode (or mode-symbol
major-mode)))
(or (gethash mode
yas/snippet-tables)
(and (not dont-search-parents)
(get mode 'derived-mode-parent)
(yas/current-snippet-table (get mode 'derived-mode-parent))))))
(defun yas/menu-keymap-for-mode (mode) Return tables in this order: optional MODE-SYMBOL, then
`yas/mode-symbol', then `major-mode' then, unless
DONT-SEARCH-PARENTS is non-nil, the guessed parent mode of either
MODE-SYMBOL or `major-mode'."
(let ((mode-tables
(mapcar #'(lambda (mode)
(gethash mode yas/snippet-tables))
(append (list mode-symbol)
(if (listp yas/mode-symbol)
yas/mode-symbol
(list yas/mode-symbol))
(list major-mode
(and (not dont-search-parents)
(get (or mode-symbol major-mode)
'derived-mode-parent))))))
(all-tables))
(dolist (table (remove nil mode-tables))
(push table all-tables)
(nconc all-tables (yas/snippet-table-get-all-parents table)))
(remove-duplicates all-tables)))
(defun yas/menu-keymap-get-create (mode)
"Get the menu keymap correspondong to MODE." "Get the menu keymap correspondong to MODE."
(let ((keymap (gethash mode yas/menu-table))) (let ((keymap (gethash mode yas/menu-table)))
(unless keymap (unless keymap
@ -717,9 +736,9 @@ the template of a snippet in the current snippet-table."
(skip-syntax-backward syntax) (skip-syntax-backward syntax)
(setq start (point))) (setq start (point)))
(setq templates (setq templates
(yas/snippet-table-fetch (mapcan #'(lambda (table)
(yas/current-snippet-table) (yas/snippet-table-fetch table (buffer-substring-no-properties start end)))
(buffer-substring-no-properties start end))) (yas/get-snippet-tables)))
(if templates (if templates
(setq done t) (setq done t)
(setq start end))) (setq start end)))
@ -826,19 +845,27 @@ Here's a list of currently recognized variables:
"Interactively choose a template from the list TEMPLATES. "Interactively choose a template from the list TEMPLATES.
TEMPLATES is a list of `yas/template'." TEMPLATES is a list of `yas/template'."
(let ((template (some #'(lambda (fn) (when templates
(funcall fn (or prompt "Choose a snippet: ") (some #'(lambda (fn)
templates #'(lambda (template) (funcall fn (or prompt "Choose a snippet: ")
(yas/template-name template)))) templates
yas/prompt-functions))) #'yas/template-name))
template)) yas/prompt-functions)))
(defun yas/prompt-for-keys (keys &optional prompt) (defun yas/prompt-for-keys (keys &optional prompt)
"Interactively choose a template key from the list KEYS." "Interactively choose a template key from the list KEYS."
(if keys (when keys
(some #'(lambda (fn) (some #'(lambda (fn)
(funcall fn (or prompt "Choose a snippet key: ") keys)) (funcall fn (or prompt "Choose a snippet key: ") keys))
yas/prompt-functions))) yas/prompt-functions)))
(defun yas/prompt-for-table (tables &optional prompt)
(when tables
(some #'(lambda (fn)
(funcall fn (or prompt "Choose a snippet table: ")
tables
#'yas/snippet-table-name))
yas/prompt-functions)))
(defun yas/x-prompt (prompt choices &optional display-fn) (defun yas/x-prompt (prompt choices &optional display-fn)
(when (and window-system choices) (when (and window-system choices)
@ -909,24 +936,32 @@ TEMPLATES is a list of `yas/template'."
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Loading snippets from files ;; Loading snippets from files
;; ;;
(defun yas/load-directory-1 (directory &optional parent) (defun yas/load-directory-1 (directory &optional parents)
"Recursively load snippet templates from DIRECTORY." "Recursively load snippet templates from DIRECTORY."
(let ((mode-sym (intern (file-name-nondirectory directory))) (let ((mode-sym (intern (file-name-nondirectory directory)))
(snippet-defs nil)) (snippet-defs nil)
(parent-file-name (concat directory "/.yas-parents"))
more-parents)
(with-temp-buffer (with-temp-buffer
(dolist (file (yas/subdirs directory 'no-subdirs-just-files)) (dolist (file (yas/subdirs directory 'no-subdirs-just-files))
(when (file-readable-p file) (when (file-readable-p file)
(insert-file-contents file nil nil nil t) (insert-file-contents file nil nil nil t)
(push (yas/parse-template file) (push (yas/parse-template file)
snippet-defs)))) snippet-defs))))
(when (file-readable-p parent-file-name)
(setq more-parents
(mapcar #'intern
(split-string
(with-temp-buffer
(insert-file parent-file-name)
(buffer-substring-no-properties (point-min)
(point-max)))))))
(yas/define-snippets mode-sym (yas/define-snippets mode-sym
snippet-defs snippet-defs
parent (append parents more-parents))
directory)
(dolist (subdir (yas/subdirs directory)) (dolist (subdir (yas/subdirs directory))
(yas/load-directory-1 subdir mode-sym)))) (yas/load-directory-1 subdir (list mode-sym)))))
(defun yas/load-directory (directory) (defun yas/load-directory (directory)
"Load snippet definition from a directory hierarchy. "Load snippet definition from a directory hierarchy.
@ -990,7 +1025,7 @@ foo\"bar\\! -> \"foo\\\"bar\\\\!\""
t) t)
"\"")) "\""))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Yasnipept Bundle ;;; Yasnippet Bundle
(defun yas/initialize () (defun yas/initialize ()
"For backward compatibility, enable `yas/minor-mode' globally" "For backward compatibility, enable `yas/minor-mode' globally"
@ -1097,7 +1132,7 @@ Here's the default value for all the parameters:
(save-buffer)))) (save-buffer))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; User level functions ;;; Some user level functions
;;; ;;;
(defun yas/about () (defun yas/about ()
@ -1106,37 +1141,35 @@ Here's the default value for all the parameters:
yas/version yas/version
") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>"))) ") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>")))
(defun yas/define-snippets (mode snippets &optional parent-mode directory) (defun yas/define-snippets (mode snippets &optional parent-mode)
"Define snippets for MODE. SNIPPETS is a list of "Define snippets for MODE. SNIPPETS is a list of
snippet definitions, each taking the following form: snippet definitions, each taking the following form:
(KEY TEMPLATE NAME CONDITION GROUP) (KEY TEMPLATE NAME CONDITION GROUP)
NAME, CONDITION or GROUP may be omitted. Optional PARENT-MODE NAME, CONDITION or GROUP may be omitted.
can be used to specify the parent mode of MODE. That is, when
looking a snippet in MODE failed, it can refer to its parent
mode. The PARENT-MODE does not need to be a real mode.
Optional DIRECTORY is recorded in the `yas/snippet-table' if it Optional PARENT-MODE can be used to specify the parent modes of
is created for the first time. Then, it becomes the default MODE. It can be a mode symbol of a list of mode symbols. It does
directory to find snippet files. not need to be a real mode.
That is, when looking a snippet in MODE failed, it can refer to
" its parent modes."
(let ((snippet-table (yas/snippet-table-get-create mode directory)) (let ((snippet-table (yas/snippet-table-get-create mode))
(parent-table (if parent-mode (parent-tables (mapcar #'yas/snippet-table-get-create
(yas/snippet-table-get-create parent-mode) (if (listp parent-mode)
nil)) parent-mode
(list parent-mode))))
(keymap (if yas/use-menu (keymap (if yas/use-menu
(yas/menu-keymap-for-mode mode) (yas/menu-keymap-get-create mode)
nil))) nil)))
(when parent-table (when parent-tables
(setf (yas/snippet-table-parent snippet-table) (setf (yas/snippet-table-parents snippet-table)
parent-table) parent-tables)
(when yas/use-menu (when yas/use-menu
(define-key keymap (vector 'parent-mode) (define-key keymap (vector 'parent-mode)
`(menu-item "parent mode" `(menu-item "parent mode"
,(yas/menu-keymap-for-mode parent-mode))))) ,(yas/menu-keymap-get-create parent-mode)))))
(when (and yas/use-menu (when (and yas/use-menu
(yas/real-mode? mode)) (yas/real-mode? mode))
(define-key yas/minor-mode-menu (vector mode) (define-key yas/minor-mode-menu (vector mode)
@ -1213,23 +1246,13 @@ Skip any submenus named \"parent mode\""
(setf (nthcdr pos-in-keymap keymap) (setf (nthcdr pos-in-keymap keymap)
(nthcdr (+ 1 pos-in-keymap) keymap)))))) (nthcdr (+ 1 pos-in-keymap) keymap))))))
(defun yas/set-mode-parent (mode parent)
"Set parent mode of MODE to PARENT."
(setf (yas/snippet-table-parent
(yas/snippet-table-get-create mode))
(yas/snippet-table-get-create parent))
(when yas/use-menu
(define-key (yas/menu-keymap-for-mode mode) (vector 'parent-mode)
`(menu-item "parent mode"
,(yas/menu-keymap-for-mode parent)))))
(defun yas/define (mode key template &optional name condition group) (defun yas/define (mode key template &optional name condition group)
"Define a snippet. Expanding KEY into TEMPLATE. "Define a snippet. Expanding KEY into TEMPLATE.
NAME is a description to this template. Also update
the menu if `yas/use-menu' is `t'. CONDITION is the NAME is a description to this template. Also update the menu if
condition attached to this snippet. If you attach a `yas/use-menu' is `t'. CONDITION is the condition attached to
condition to a snippet, then it will only be expanded this snippet. If you attach a condition to a snippet, then it
when the condition evaluated to non-nil." will only be expanded when the condition evaluated to non-nil."
(yas/define-snippets mode (yas/define-snippets mode
(list (list key template name condition group)))) (list (list key template name condition group))))
@ -1280,6 +1303,23 @@ conditions to filter out potential expansions."
(setq this-command command) (setq this-command command)
(call-interactively command))))))) (call-interactively command)))))))
(defun yas/all-templates (tables)
"Return all snippet tables applicable for the current buffer.
Honours `yas/choose-tables-first', `yas/choose-keys-first' and
`yas/buffer-local-condition'"
(when yas/choose-tables-first
(setq tables (list (yas/prompt-for-table tables))))
(mapcar #'cdr
(if yas/choose-keys-first
(let ((key (yas/prompt-for-keys
(mapcan #'yas/snippet-table-all-keys tables))))
(when key
(mapcan #'(lambda (table)
(yas/snippet-table-fetch table key))
tables)))
(mapcan #'yas/snippet-table-templates tables))))
(defun yas/insert-snippet (&optional no-condition) (defun yas/insert-snippet (&optional no-condition)
"Choose a snippet to expand, pop-up a list of choices according "Choose a snippet to expand, pop-up a list of choices according
to `yas/prompt-function'. to `yas/prompt-function'.
@ -1290,12 +1330,7 @@ by condition."
(let* ((yas/buffer-local-condition (or (and no-condition (let* ((yas/buffer-local-condition (or (and no-condition
'always) 'always)
yas/buffer-local-condition)) yas/buffer-local-condition))
(templates (mapcar #'cdr (templates (yas/all-templates (yas/get-snippet-tables)))
(if yas/choose-keys-first
(let ((key (yas/prompt-for-keys (yas/snippet-table-all-keys (yas/current-snippet-table)))))
(when key
(yas/snippet-table-fetch (yas/current-snippet-table) key)))
(yas/snippet-table-all-templates (yas/current-snippet-table)))))
(template (and templates (template (and templates
(or (and (rest templates) ;; more than one template for same key (or (and (rest templates) ;; more than one template for same key
(yas/prompt-for-template templates)) (yas/prompt-for-template templates))
@ -1317,13 +1352,7 @@ Only success if selected snippet was loaded from a file. Put the
visited file in `snippet-mode'." visited file in `snippet-mode'."
(interactive) (interactive)
(let* ((yas/buffer-local-condition 'always) (let* ((yas/buffer-local-condition 'always)
(templates (mapcar #'cdr (templates (yas/all-templates (yas/get-snippet-tables)))
(if yas/choose-keys-first
(let ((key (yas/prompt-for-keys (yas/snippet-table-all-keys (yas/current-snippet-table))
"Choose a snippet key to edit: ")))
(when key
(yas/snippet-table-fetch (yas/current-snippet-table) key)))
(yas/snippet-table-all-templates (yas/current-snippet-table)))))
(template (and templates (template (and templates
(or (and (rest templates) ;; more than one template for same key (or (and (rest templates) ;; more than one template for same key
(yas/prompt-for-template templates (yas/prompt-for-template templates
@ -1341,55 +1370,70 @@ visited file in `snippet-mode'."
(message "This snippet was not loaded from a file!"))))))) (message "This snippet was not loaded from a file!")))))))
(defun yas/guess-snippet-directory () (defun yas/guess-snippet-directory ()
"Try to guess the suitable yassnippet based on `major-mode'" "Try to guess suitable directories based on `major-mode' and
(let ((loaded-root (or (and (listp yas/root-directory) also the current active tables."
(first yas/root-directory)) (let ((main-dir (or (and (listp yas/root-directory)
yas/root-directory)) (first yas/root-directory))
yas/root-directory
"~/.emacs.d/snippets"))
(mode major-mode) (mode major-mode)
(path)) (options))
(when loaded-root ;; Lookup main mode and add that to the options
(while mode ;;
(setq path (format "%s/%s" (push (format "%s/%s" main-dir mode) options)
mode ;; Next lookup the main active table
(or path ;;
""))) (let ((active-tables (first (yas/get-snippet-tables)))
(setq mode (get mode 'derived-mode-parent))) (other-path-alternative main-dir))
(concat loaded-root (when active-tables
(unless (string-match "/$" loaded-root) "/") (setq active-tables (cons active-tables
path)))) (yas/snippet-table-get-all-parents active-tables))))
(dolist (table (reverse active-tables))
(setq other-path-alternative
(concat other-path-alternative "/" (yas/snippet-table-name table))))
(push other-path-alternative options))
;; Finally add to the options the guessed parent of major-mode
;; (this is almost never works out)
(when (get mode 'derived-mode-parent)
(push (format "%s/%s" main-dir (get mode 'derived-mode-parent)) options))
(reverse options)))
(defun yas/find-snippets (&optional same-window file)
"Look for user snippets in guessed current mode's directory.
(defun yas/find-snippets (&optional same-window) Calls `find-file' interactively in the guessed directory.
"Looks for snippets file in the current mode's directory.
This can be used to create new snippets for the currently active With prefix arg SAME-WINDOW opens the buffer in the same window.
major mode."
With optional FILE, finds the file directly, i.e. `find-file' is
called non-interactively.
Because snippets can be loaded from many different locations,
this has to guess the correct directory using
`yas/guess-directory', which returns a list of options. If any
one of these exists, it is taken and `find-file' is called there,
otherwise, proposes to create the first option returned by
`yas/guess-directory'."
(interactive "P") (interactive "P")
(let* ((current-table (yas/current-snippet-table major-mode 'dont-search-parents)) (let* ((guessed-directories (yas/guess-snippet-directory))
(parents-table (yas/current-snippet-table major-mode)) (target-directory (first (remove-if-not #'file-exists-p guessed-directories)))
(parents-directory (and parents-table
(yas/snippet-table-default-directory parents-table)))
(guessed-directory (or (and current-table
(yas/snippet-table-default-directory current-table))
(yas/guess-snippet-directory)
default-directory))
(buffer)) (buffer))
(unless (file-exists-p guessed-directory)
(if (y-or-n-p (format "Guessed directory (%s) does not exist! Create? " guessed-directory))
(make-directory guessed-directory 'also-make-parents)
(if parents-directory
(setq guessed-directory parents-directory)
(setq guessed-directory default-directory))))
(let ((default-directory guessed-directory))
(setq buffer (call-interactively (if same-window
'find-file
'find-file-other-window)))
(when buffer
(save-excursion
(set-buffer buffer)
(when (eq major-mode 'fundamental-mode)
(snippet-mode)))))))
(unless target-directory
(when (y-or-n-p (format "Guessed directory (%s) does not exist! Create? " (first guessed-directories)))
(setq target-directory (first guessed-directories))
(make-directory target-directory 'also-make-parents)))
(when target-directory
(let ((default-directory target-directory))
(setq buffer (call-interactively (if same-window
'find-file
'find-file-other-window)))
(when buffer
(save-excursion
(set-buffer buffer)
(when (eq major-mode 'fundamental-mode)
(snippet-mode))))))))
(defun yas/compute-major-mode-and-parent (file &optional prompt-if-failed) (defun yas/compute-major-mode-and-parent (file &optional prompt-if-failed)
(let* ((file-dir (and file (let* ((file-dir (and file
@ -1515,6 +1559,11 @@ Otherwise throw exception."
(when field (when field
(yas/field-text-for-display field)))) (yas/field-text-for-display field))))
(defun yas/oni (text oni-regexp)
"Runs ruby to parse TEXT with Oniguruma regexp ONI-REGEXP."
(shell-command-to-string (format "ruby -e 'print \"%s\".gsub(\"a\",\"b\")'" "aha")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Snippet expansion and field management ;;; Snippet expansion and field management
@ -2248,7 +2297,8 @@ has to be called before the $-constructs are deleted."
(setq soup (setq soup
(sort soup (sort soup
#'yas/compare-fom-begs)) #'yas/compare-fom-begs))
(reduce #'yas/link-foms soup)))) (when soup
(reduce #'yas/link-foms soup)))))
(defun yas/advance-end-maybe (fom newend) (defun yas/advance-end-maybe (fom newend)
"Maybe advance FOM's end to NEWEND if it needs it. "Maybe advance FOM's end to NEWEND if it needs it.
@ -2263,8 +2313,8 @@ If it does, also:
(set-marker (yas/fom-end fom) newend) (set-marker (yas/fom-end fom) newend)
(yas/advance-start-maybe (yas/fom-next fom) newend) (yas/advance-start-maybe (yas/fom-next fom) newend)
(if (and (yas/field-p fom) (if (and (yas/field-p fom)
(yas/field-parent-field field)) (yas/field-parent-field fom))
(yas/advance-end-maybe (yas/field-parent-field field) newend)))) (yas/advance-end-maybe (yas/field-parent-field fom) newend))))
(defun yas/advance-start-maybe (fom newstart) (defun yas/advance-start-maybe (fom newstart)
"Maybe advance FOM's start to NEWSTART if it needs it. "Maybe advance FOM's start to NEWSTART if it needs it.