X-Git-Url: https://code.delx.au/gnu-emacs-elpa/blobdiff_plain/29972ef7578ee79cffc77471497be60aef813a8e..9d24d5d30085ba6d9a62d3f8ea2d52a358ea98c8:/packages/yasnippet/yasnippet.el diff --git a/packages/yasnippet/yasnippet.el b/packages/yasnippet/yasnippet.el index dcec0e258..cff623fb6 100644 --- a/packages/yasnippet/yasnippet.el +++ b/packages/yasnippet/yasnippet.el @@ -1,13 +1,15 @@ ;;; yasnippet.el --- Yet another snippet extension for Emacs. -;; Copyright (C) 2008-2013, 2015 Free Software Foundation, Inc. -;; Authors: pluskid , João Távora , Noam Postavsky +;; Copyright (C) 2008-2016 Free Software Foundation, Inc. +;; Authors: pluskid , +;; João Távora , +;; Noam Postavsky ;; Maintainer: Noam Postavsky -;; Version: 0.8.1 -;; Package-version: 0.8.0 +;; Version: 0.9.1 ;; X-URL: http://github.com/capitaomorte/yasnippet ;; Keywords: convenience, emulation ;; URL: http://github.com/capitaomorte/yasnippet +;; Package-Requires: ((cl-lib "0.5")) ;; EmacsWiki: YaSnippetMode ;; This program is free software: you can redistribute it and/or modify @@ -154,10 +156,10 @@ (defvar yas-installed-snippets-dir nil) (setq yas-installed-snippets-dir (when load-file-name - (concat (file-name-directory load-file-name) "snippets"))) + (expand-file-name "snippets" (file-name-directory load-file-name)))) (defconst yas--default-user-snippets-dir - (concat user-emacs-directory "snippets")) + (expand-file-name "snippets" user-emacs-directory)) (defcustom yas-snippet-dirs (remove nil (list yas--default-user-snippets-dir @@ -173,8 +175,9 @@ snippets. The first directory is taken as the default for storing snippet's created with `yas-new-snippet'. " - :type '(choice (string :tag "Single directory (string)") - (repeat :args (string) :tag "List of directories (strings)")) + :type '(choice (directory :tag "Single directory") + (repeat :tag "List of directories" + (choice (directory) (variable)))) :group 'yasnippet :require 'yasnippet :set #'(lambda (symbol new) @@ -202,10 +205,9 @@ created with `yas-new-snippet'. " (defvaralias 'yas/root-directory 'yas-snippet-dirs) (defcustom yas-new-snippet-default "\ -# -*- mode: snippet; require-final-newline: nil -*- +# -*- mode: snippet -*- # name: $1 -# key: ${2:${1:$(yas--key-from-desc yas-text)}}${3: -# binding: ${4:direct-keybinding}} +# key: ${2:${1:$(yas--key-from-desc yas-text)}} # -- $0" "Default snippet to use when creating a new snippet. @@ -213,8 +215,7 @@ If nil, don't use any snippet." :type 'string :group 'yasnippet) -(defcustom yas-prompt-functions '(yas-x-prompt - yas-dropdown-prompt +(defcustom yas-prompt-functions '(yas-dropdown-prompt yas-completing-prompt yas-maybe-ido-prompt yas-no-prompt) @@ -510,7 +511,7 @@ snippets returning the symbol 'force-in-comment in their conditions. (add-hook 'python-mode-hook - '(lambda () + (lambda () (setq yas-buffer-local-condition '(if (python-in-string/comment) '(require-snippet-condition . force-in-comment) @@ -524,7 +525,7 @@ snippet itself contains a condition that returns the symbol ;;; Internal variables -(defvar yas--version "0.8.0beta") +(defvar yas--version "0.9.1") (defvar yas--menu-table (make-hash-table) "A hash table of MAJOR-MODE symbols to menu keymaps.") @@ -690,7 +691,7 @@ snippet itself contains a condition that returns the symbol This variable probably makes more sense as buffer-local, so ensure your use `make-local-variable' when you set it.") -(define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.8.1") +(define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.9.1") (defvar yas--tables (make-hash-table) "A hash table of mode symbols to `yas--table' objects.") @@ -729,22 +730,24 @@ defined direct keybindings to the command yas--tables)) (defun yas--modes-to-activate (&optional mode) - "Compute list of mode symbols that are active for `yas-expand' -and friends." + "Compute list of mode symbols that are active for `yas-expand' and friends." + (defvar yas--dfs) ;We rely on dynbind. We could use `letrec' instead! (let* ((explored (if mode (list mode) ; Building up list in reverse. (cons major-mode (reverse yas--extra-modes)))) - (dfs + (yas--dfs (lambda (mode) (cl-loop for neighbour in (cl-list* (get mode 'derived-mode-parent) - (ignore-errors (symbol-function mode)) + ;; NOTE: `fboundp' check is redundant + ;; since Emacs 24.4. + (and (fboundp mode) (symbol-function mode)) (gethash mode yas--parents)) when (and neighbour (not (memq neighbour explored)) (symbolp neighbour)) do (push neighbour explored) - (funcall dfs neighbour))))) - (mapcar dfs explored) + (funcall yas--dfs neighbour))))) + (mapc yas--dfs explored) (nreverse explored))) (defvar yas-minor-mode-hook nil @@ -776,8 +779,8 @@ Key bindings: ;; ;; Also install the post-command-hook. ;; - (add-hook 'emulation-mode-map-alists 'yas--direct-keymaps) - (add-hook 'post-command-hook 'yas--post-command-handler nil t) + (cl-pushnew 'yas--direct-keymaps emulation-mode-map-alists) + (add-hook 'post-command-hook #'yas--post-command-handler nil t) ;; Set the `yas--direct-%s' vars for direct keymap expansion ;; (dolist (mode (yas--modes-to-activate)) @@ -790,8 +793,9 @@ Key bindings: (t ;; Uninstall the direct keymaps and the post-command hook ;; - (remove-hook 'post-command-hook 'yas--post-command-handler t) - (remove-hook 'emulation-mode-map-alists 'yas--direct-keymaps)))) + (remove-hook 'post-command-hook #'yas--post-command-handler t) + (setq emulation-mode-map-alists + (remove 'yas--direct-keymaps emulation-mode-map-alists))))) (defun yas-activate-extra-mode (mode) "Activates the snippets for the given `mode' in the buffer. @@ -868,22 +872,26 @@ Honour `yas-dont-activate', which see." "Run `yas-reload-all' when `yas-global-mode' is on." (when yas-global-mode (yas-reload-all))) -(add-hook 'yas-global-mode-hook 'yas--global-mode-reload-with-jit-maybe) +(add-hook 'yas-global-mode-hook #'yas--global-mode-reload-with-jit-maybe) ;;; Major mode stuff (defvar yas--font-lock-keywords (append '(("^#.*$" . font-lock-comment-face)) - lisp-font-lock-keywords-2 + (with-temp-buffer + (emacs-lisp-mode) + (font-lock-set-defaults) + (if (eq t (car-safe font-lock-keywords)) + ;; They're "compiled", so extract the source. + (cadr font-lock-keywords) + font-lock-keywords)) '(("$\\([0-9]+\\)" (0 font-lock-keyword-face) (1 font-lock-string-face t)) ("${\\([0-9]+\\):?" (0 font-lock-keyword-face) (1 font-lock-warning-face t)) - ("${" . font-lock-keyword-face) - ("$[0-9]+?" . font-lock-preprocessor-face) ("\\(\\$(\\)" 1 font-lock-preprocessor-face) ("}" (0 font-lock-keyword-face))))) @@ -1476,10 +1484,7 @@ Here's a list of currently recognized directives: (let* ((dominating-dir (locate-dominating-file file ".yas-make-groups")) (extra-path (and dominating-dir - (replace-regexp-in-string (concat "^" - (expand-file-name dominating-dir)) - "" - (expand-file-name file)))) + (file-relative-name file dominating-dir))) (extra-dir (and extra-path (file-name-directory extra-path))) (group (and extra-dir @@ -1490,17 +1495,17 @@ Here's a list of currently recognized directives: (defun yas--subdirs (directory &optional filep) "Return subdirs or files of DIRECTORY according to FILEP." - (remove-if (lambda (file) - (or (string-match "^\\." - (file-name-nondirectory file)) - (string-match "^#.*#$" - (file-name-nondirectory file)) - (string-match "~$" - (file-name-nondirectory file)) - (if filep - (file-directory-p file) - (not (file-directory-p file))))) - (directory-files directory t))) + (cl-remove-if (lambda (file) + (or (string-match "\\`\\." + (file-name-nondirectory file)) + (string-match "\\`#.*#\\'" + (file-name-nondirectory file)) + (string-match "~\\'" + (file-name-nondirectory file)) + (if filep + (file-directory-p file) + (not (file-directory-p file))))) + (directory-files directory t))) (defun yas--make-menu-binding (template) (let ((mode (yas--table-mode (yas--template-table template)))) @@ -1772,7 +1777,7 @@ With prefix argument USE-JIT do jit-loading of snippets." (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string))))) ;; Normal case. - (unless (file-exists-p (concat directory "/" ".yas-skip")) + (unless (file-exists-p (expand-file-name ".yas-skip" directory)) (unless (and (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas-verbosity 3)) (progn (yas--message 2 "Loaded compiled snippets from %s" directory) t)) (yas--message 2 "Loading snippet files from %s" directory) @@ -1947,7 +1952,7 @@ This works by stubbing a few functions, then calling ;;; Apropos snippet menu: ;; -;; The snippet menu keymaps are store by mode in hash table called +;; The snippet menu keymaps are stored by mode in hash table called ;; `yas--menu-table'. They are linked to the main menu in ;; `yas--menu-keymap-get-create' and are initially created empty, ;; reflecting the table hierarchy. @@ -1969,9 +1974,9 @@ This works by stubbing a few functions, then calling ;; duplicate entries. The `yas--template' objects are created in ;; `yas-define-menu', holding nothing but the menu entry, ;; represented by a pair of ((menu-item NAME :keys KEYS) TYPE) and -;; stored in `yas--template-menu-binding-pair'. The (menu-item ...) +;; stored in `yas--template-menu-binding-pair'. The (menu-item ...) ;; part is then stored in the menu keymap itself which make the item -;; appear to the user. These limitations could probably be revised. +;; appear to the user. These limitations could probably be revised. ;; ;; * The `yas--template-perm-group' slot is only used in ;; `yas-describe-tables'. @@ -2160,9 +2165,9 @@ object satisfying `yas--field-p' to restrict the expansion to." (yas--templates-for-key-at-point)) (yas--templates-for-key-at-point)))) (if templates-and-pos - (yas--expand-or-prompt-for-template (first templates-and-pos) - (second templates-and-pos) - (third templates-and-pos)) + (yas--expand-or-prompt-for-template (nth 0 templates-and-pos) + (nth 1 templates-and-pos) + (nth 2 templates-and-pos)) (yas--fallback)))) (defun yas-expand-from-keymap () @@ -2409,13 +2414,11 @@ tables (or optional TABLE). Returns a list of elements (TABLE . DIRS) where TABLE is a `yas--table' object and DIRS is a list of all possible directories where snippets of table might exist." - (let ((main-dir (replace-regexp-in-string - "/+$" "" - (or (first (or (yas-snippet-dirs) - (setq yas-snippet-dirs (list yas--default-user-snippets-dir))))))) - (tables (or (and table - (list table)) - (yas--get-snippet-tables)))) + (let ((main-dir (car (or (yas-snippet-dirs) + (setq yas-snippet-dirs + (list yas--default-user-snippets-dir))))) + (tables (if table (list table) + (yas--get-snippet-tables)))) ;; HACK! the snippet table created here is actually registered! ;; (unless (or table (gethash major-mode yas--tables)) @@ -2425,7 +2428,7 @@ where snippets of table might exist." (mapcar #'(lambda (table) (cons table (mapcar #'(lambda (subdir) - (concat main-dir "/" subdir)) + (expand-file-name subdir main-dir)) (yas--guess-snippet-directories-1 table)))) tables))) @@ -2587,9 +2590,10 @@ and `kill-buffer' instead." (when chosen (let ((default-file-name (or (and file (file-name-nondirectory file)) (yas--template-name yas--editing-template)))) - (write-file (concat chosen "/" - (read-from-minibuffer (format "File name to create in %s? " chosen) - default-file-name))) + (write-file (expand-file-name + (read-file-name (format "File name to create in %s? " chosen) + chosen default-file-name) + chosen)) (setf (yas--template-load-file yas--editing-template) buffer-file-name)))))) (when buffer-file-name (save-buffer) @@ -2609,10 +2613,10 @@ and `kill-buffer' instead." (and parsed (fboundp test-mode) (yas--make-template :table nil ;; no tables for ephemeral snippets - :key (first parsed) - :content (second parsed) - :name (third parsed) - :expand-env (sixth parsed))))) + :key (nth 0 parsed) + :content (nth 1 parsed) + :name (nth 2 parsed) + :expand-env (nth 5 parsed))))) (cond (yas--current-template (let ((buffer-name (format "*testing snippet: %s*" (yas--template-name yas--current-template)))) (kill-buffer (get-buffer-create buffer-name)) @@ -2662,7 +2666,7 @@ and `kill-buffer' instead." (setq buffer-read-only nil) (erase-buffer) (cond ((not by-name-hash) - (insert "YASnippet tables: \n") + (insert "YASnippet tables:\n") (while (and table-lists continue) (dolist (table (car table-lists)) @@ -2718,31 +2722,32 @@ and `kill-buffer' instead." (setq group (truncate-string-to-width group 25 0 ? "...")) (insert (make-string 100 ?-) "\n") (dolist (p templates) - (let ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas--template-name p)) - 'yasnippet p) - 50 0 ? "...")) - (group (prog1 group - (setq group (make-string (length group) ? )))) - (condition-string (let ((condition (yas--template-condition p))) - (if (and condition - original-buffer) - (with-current-buffer original-buffer - (if (yas--eval-condition condition) - "(y)" - "(s)")) - "(a)")))) - (insert group " ") - (insert condition-string " ") - (insert name - (if (string-match "\\.\\.\\.$" name) - "'" - " ") - " ") - (insert (truncate-string-to-width (or (yas--template-key p) "") - 15 0 ? "...") " ") - (insert (truncate-string-to-width (key-description (yas--template-keybinding p)) - 15 0 ? "...") " ") - (insert "\n")))) + (let* ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas--template-name p)) + 'yasnippet p) + 50 0 ? "...")) + (group (prog1 group + (setq group (make-string (length group) ? )))) + (condition-string (let ((condition (yas--template-condition p))) + (if (and condition + original-buffer) + (with-current-buffer original-buffer + (if (yas--eval-condition condition) + "(y)" + "(s)")) + "(a)"))) + (key-description-string (key-description (yas--template-keybinding p))) + (template-key-padding (if (string= key-description-string "") nil ? ))) + (insert group " " + condition-string " " + name (if (string-match "\\.\\.\\.$" name) + "'" " ") + " " + (truncate-string-to-width (or (yas--template-key p) "") + 15 0 template-key-padding "...") + (or template-key-padding "") + (truncate-string-to-width key-description-string + 15 0 nil "...") + "\n")))) groups-hash))) @@ -3385,7 +3390,22 @@ Move the overlay, or create it if it does not exit." (overlay-put yas--active-field-overlay 'insert-behind-hooks '(yas--on-field-overlay-modification)))) -(defun yas--on-field-overlay-modification (overlay after? _beg _end &optional _length) +(defun yas--skip-and-clear-field-p (field _beg _end &optional _length) + "Tell if newly modified FIELD should be cleared and skipped. +BEG, END and LENGTH like overlay modification hooks." + (and (not (yas--field-modified-p field)) + (= (point) (yas--field-start field)) + (require 'delsel) + ;; `yank' sets `this-command' to t during execution. + (let* ((command (if (commandp this-command) this-command + this-original-command)) + (clearp (if (symbolp command) (get command 'delete-selection)))) + (when (and (not (memq clearp '(yank supersede kill))) + (functionp clearp)) + (setq clearp (funcall clearp))) + clearp))) + +(defun yas--on-field-overlay-modification (overlay after? beg end &optional _length) "Clears the field and updates mirrors, conditionally. Only clears the field if it hasn't been modified and point is at @@ -3401,9 +3421,7 @@ field start. This hook does nothing if an undo is in progress." (yas--field-update-display field)) (yas--update-mirrors snippet)) (field - (when (and (eq this-command 'self-insert-command) - (not (yas--field-modified-p field)) - (= (point) (yas--field-start field))) + (when (yas--skip-and-clear-field-p field beg end) (yas--skip-and-clear field)) (setf (yas--field-modified-p field) t)))))) @@ -4181,23 +4199,24 @@ When multiple expressions are found, only the last one counts." (defun yas--update-mirrors (snippet) "Update all the mirrors of SNIPPET." (save-excursion - (dolist (field-and-mirror (sort - ;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...) - ;; where F is the field that M is mirroring - ;; - (mapcan #'(lambda (field) - (mapcar #'(lambda (mirror) - (cons field mirror)) - (yas--field-mirrors field))) - (yas--snippet-fields snippet)) - ;; then sort this list so that entries with mirrors with parent - ;; fields appear before. This was important for fixing #290, and - ;; luckily also handles the case where a mirror in a field causes - ;; another mirror to need reupdating - ;; - #'(lambda (field-and-mirror1 field-and-mirror2) - (> (yas--calculate-mirror-depth (cdr field-and-mirror1)) - (yas--calculate-mirror-depth (cdr field-and-mirror2)))))) + (dolist (field-and-mirror + (sort + ;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...) + ;; where F is the field that M is mirroring + ;; + (cl-mapcan #'(lambda (field) + (mapcar #'(lambda (mirror) + (cons field mirror)) + (yas--field-mirrors field))) + (yas--snippet-fields snippet)) + ;; then sort this list so that entries with mirrors with parent + ;; fields appear before. This was important for fixing #290, and + ;; luckily also handles the case where a mirror in a field causes + ;; another mirror to need reupdating + ;; + #'(lambda (field-and-mirror1 field-and-mirror2) + (> (yas--calculate-mirror-depth (cdr field-and-mirror1)) + (yas--calculate-mirror-depth (cdr field-and-mirror2)))))) (let* ((field (car field-and-mirror)) (mirror (cdr field-and-mirror)) (parent-field (yas--mirror-parent-field mirror))) @@ -4309,7 +4328,7 @@ object satisfying `yas--field-p' to restrict the expansion to."))) '(yas--expand-from-keymap-doc t)) (defun yas--expand-from-keymap-doc (context) "A doc synthesizer for `yas--expand-from-keymap-doc'." - (add-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce) + (add-hook 'temp-buffer-show-hook #'yas--snippet-description-finish-runonce) (concat "Expand/run snippets from keymaps, possibly falling back to original binding.\n" (when (and context (eq this-command 'describe-key)) (let* ((vec (this-single-command-keys)) @@ -4344,7 +4363,8 @@ object satisfying `yas--field-p' to restrict the expansion to."))) (defun yas--snippet-description-finish-runonce () "Final adjustments for the help buffer when snippets are concerned." (yas--create-snippet-xrefs) - (remove-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce)) + (remove-hook 'temp-buffer-show-hook + #'yas--snippet-description-finish-runonce)) (defun yas--create-snippet-xrefs () (save-excursion @@ -4551,7 +4571,7 @@ and return the directory. Return nil if not found." They are mapped to \"yas/*\" variants.") (dolist (sym yas--backported-syms) - (let ((backported (intern (replace-regexp-in-string "^yas-" "yas/" (symbol-name sym))))) + (let ((backported (intern (replace-regexp-in-string "\\`yas-" "yas/" (symbol-name sym))))) (when (boundp sym) (make-obsolete-variable backported sym "yasnippet 0.8") (defvaralias backported sym)) @@ -4566,7 +4586,7 @@ They are mapped to \"yas/*\" variants.") (not (get atom 'byte-obsolete-variable))) (and (fboundp atom) (not (get atom 'byte-obsolete-info)))) - (string-match-p "^yas-[^-]" (symbol-name atom))) + (string-match-p "\\`yas-[^-]" (symbol-name atom))) (push atom exported)))) exported) "Exported yasnippet symbols.