From 77cddb69a6b0739f17c008179cfb735ed091999e Mon Sep 17 00:00:00 2001 From: Shuguang Sun Date: Wed, 2 Sep 2020 14:19:20 +0800 Subject: [PATCH 1/4] refactor: mutiple key support --- yasnippet.el | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 78ef38ac..51d855ff 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1615,7 +1615,8 @@ Here's a list of currently recognized directives: (yas--calculate-group file))) expand-env binding - uuid) + uuid + results) (if (re-search-forward "^# --\\s-*\n" nil t) (progn (setq template (buffer-substring-no-properties (point) @@ -1630,7 +1631,7 @@ Here's a list of currently recognized directives: 'command 'snippet))) (when (string= "key" (match-string-no-properties 1)) - (setq key (match-string-no-properties 2))) + (cl-pushnew (match-string-no-properties 2) key)) (when (string= "name" (match-string-no-properties 1)) (setq name (match-string-no-properties 2))) (when (string= "condition" (match-string-no-properties 1)) @@ -1645,12 +1646,18 @@ Here's a list of currently recognized directives: (setq template (buffer-substring-no-properties (point-min) (point-max)))) (unless (or key binding) - (setq key (and file (file-name-nondirectory file)))) + (cl-pushnew (and file (file-name-nondirectory file)) key) + ) (when (eq type 'command) (setq template (yas--read-lisp (concat "(progn" template ")")))) (when group (setq group (split-string group "\\."))) - (list key template name condition group expand-env file binding uuid))) + (if key + (dolist (k key results) + (push (list k template (format "%s (%s)" name k) condition group expand-env file binding uuid) results)) + (setq results (list (list key template name condition group expand-env file binding uuid)))) + results + )) (defun yas--calculate-group (file) "Calculate the group for snippet file path FILE." @@ -1959,7 +1966,8 @@ With prefix argument USE-JIT do jit-loading of snippets." ;; (yas--load-yas-setup-file (expand-file-name ".yas-setup" directory)) (let* ((default-directory directory) - (snippet-defs nil)) + (snippet-defs nil) + parsed) ;; load the snippet files ;; (with-temp-buffer @@ -1969,8 +1977,12 @@ With prefix argument USE-JIT do jit-loading of snippets." ;; `insert-file-contents' (avoids Emacs bug #23659). (erase-buffer) (insert-file-contents file) - (push (yas--parse-template file) - snippet-defs)))) + (setq parsed (yas--parse-template file)) + (if (listp (car parsed)) ;; If car is a list + (dolist (sp parsed) + (push sp snippet-defs)) + (push parsed snippet-defs) + )))) (when snippet-defs (yas-define-snippets mode-sym snippet-defs)) From 9a881071dec0580a4e177ea94a2f9fc8318a8c81 Mon Sep 17 00:00:00 2001 From: Shuguang Sun Date: Wed, 2 Sep 2020 16:34:01 +0800 Subject: [PATCH 2/4] fix: make copy of the funtion --- yasnippet.el | 163 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 158 insertions(+), 5 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 51d855ff..73723c68 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1839,6 +1839,55 @@ defining snippets. UUID is the snippet's \"unique-id\". Loading a second snippet file with the same uuid would replace the previous snippet. +You can use `yas--parse-template' to return such lists based on +the current buffers contents." + (if yas--creating-compiled-snippets + (let ((print-length nil)) + (insert ";;; Snippet definitions:\n;;;\n") + (dolist (snippet snippets) + ;; Fill in missing elements with nil. + (setq snippet (append snippet (make-list (- 10 (length snippet)) nil))) + ;; Move LOAD-FILE to SAVE-FILE because we will load from the + ;; compiled file, not LOAD-FILE. + (let ((load-file (nth 6 snippet))) + (setcar (nthcdr 6 snippet) nil) + (setcar (nthcdr 9 snippet) load-file))) + (insert (pp-to-string + `(yas-define-snippets ',mode ',snippets))) + (insert "\n\n")) + ;; Normal case. + (let ((snippet-table (yas--table-get-create mode)) + (template nil)) + (dolist (snippet snippets) + (setq template (yas--define-snippets-1 snippet + snippet-table))) + template))) + +(defun yas-define-snippets-for-compile (mode snippets) + "Define SNIPPETS for MODE. + +SNIPPETS is a list of snippet definitions, each taking the +following form + + (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID SAVE-FILE) + +Within these, only KEY and TEMPLATE are actually mandatory. + +TEMPLATE might be a Lisp form or a string, depending on whether +this is a snippet or a snippet-command. + +CONDITION, EXPAND-ENV and KEYBINDING are Lisp forms, they have +been `yas--read-lisp'-ed and will eventually be +`yas--eval-for-string'-ed. + +The remaining elements are strings. + +FILE is probably of very little use if you're programatically +defining snippets. + +UUID is the snippet's \"unique-id\". Loading a second snippet +file with the same uuid would replace the previous snippet. + You can use `yas--parse-template' to return such lists based on the current buffers contents." (if yas--creating-compiled-snippets @@ -1943,6 +1992,58 @@ With prefix argument USE-JIT do jit-loading of snippets." (when interactive (yas--message 3 "Loaded snippets from %s." top-level-dir))) +(defun yas-load-directory-for-compile (top-level-dir &optional use-jit interactive) + "Load snippets in directory hierarchy TOP-LEVEL-DIR. + +Below TOP-LEVEL-DIR each directory should be a mode name. + +With prefix argument USE-JIT do jit-loading of snippets." + (interactive + (list (read-directory-name "Select the root directory: " nil nil t) + current-prefix-arg t)) + (unless yas-snippet-dirs + (setq yas-snippet-dirs top-level-dir)) + (let ((impatient-buffers)) + (dolist (dir (yas--subdirs top-level-dir)) + (let* ((major-mode-and-parents (yas--compute-major-mode-and-parents + (concat dir "/dummy"))) + (mode-sym (car major-mode-and-parents)) + (parents (cdr major-mode-and-parents))) + ;; Attention: The parents and the menus are already defined + ;; here, even if the snippets are later jit-loaded. + ;; + ;; * We need to know the parents at this point since entering a + ;; given mode should jit load for its parents + ;; immediately. This could be reviewed, the parents could be + ;; discovered just-in-time-as well + ;; + ;; * We need to create the menus here to support the `full' + ;; option to `yas-use-menu' (all known snippet menus are shown to the user) + ;; + (yas--define-parents mode-sym parents) + (yas--menu-keymap-get-create mode-sym) + (let ((fun (apply-partially #'yas--load-directory-1-for-compile dir mode-sym))) + (if use-jit + (yas--schedule-jit mode-sym fun) + (funcall fun))) + ;; Look for buffers that are already in `mode-sym', and so + ;; need the new snippets immediately... + ;; + (when use-jit + (cl-loop for buffer in (buffer-list) + do (with-current-buffer buffer + (when (eq major-mode mode-sym) + (yas--message 4 "Discovered there was already %s in %s" buffer mode-sym) + (push buffer impatient-buffers))))))) + ;; ...after TOP-LEVEL-DIR has been completely loaded, call + ;; `yas--load-pending-jits' in these impatient buffers. + ;; + (cl-loop for buffer in impatient-buffers + do (with-current-buffer buffer (yas--load-pending-jits)))) + (when interactive + (yas--message 3 "Loaded snippets from %s." top-level-dir))) + + (defun yas--load-directory-1 (directory mode-sym) "Recursively load snippet templates from DIRECTORY." (if yas--creating-compiled-snippets @@ -1961,7 +2062,51 @@ With prefix argument USE-JIT do jit-loading of snippets." (yas--message 4 "Loading snippet files from %s" directory) (yas--load-directory-2 directory mode-sym))))) +(defun yas--load-directory-1-for-compile (directory mode-sym) + "Recursively load snippet templates from DIRECTORY." + (if yas--creating-compiled-snippets + (let ((output-file (expand-file-name ".yas-compiled-snippets.el" + directory))) + (with-temp-file output-file + (insert (format ";;; Compiled snippets and support files for `%s'\n" + mode-sym)) + (yas--load-directory-2-for-compile directory mode-sym) + (insert (format ";;; Do not edit! File generated at %s\n" + (current-time-string))))) + ;; Normal case. + (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 4 "Loaded compiled snippets from %s" directory) t)) + (yas--message 4 "Loading snippet files from %s" directory) + (yas--load-directory-2 directory mode-sym))))) + (defun yas--load-directory-2 (directory mode-sym) + ;; Load .yas-setup.el files wherever we find them + ;; + (yas--load-yas-setup-file (expand-file-name ".yas-setup" directory)) + (let* ((default-directory directory) + (snippet-defs nil)) + ;; load the snippet files + ;; + (with-temp-buffer + (dolist (file (yas--subdirs directory 'no-subdirs-just-files)) + (when (file-readable-p file) + ;; Erase the buffer instead of passing non-nil REPLACE to + ;; `insert-file-contents' (avoids Emacs bug #23659). + (erase-buffer) + (insert-file-contents file) + (push (yas--parse-template file) + snippet-defs)))) + (when snippet-defs + (yas-define-snippets mode-sym + snippet-defs)) + ;; now recurse to a lower level + ;; + (dolist (subdir (yas--subdirs directory)) + (yas--load-directory-2 subdir + mode-sym)))) + +(defun yas--load-directory-2-for-compile (directory mode-sym) ;; Load .yas-setup.el files wherever we find them ;; (yas--load-yas-setup-file (expand-file-name ".yas-setup" directory)) @@ -1977,19 +2122,18 @@ With prefix argument USE-JIT do jit-loading of snippets." ;; `insert-file-contents' (avoids Emacs bug #23659). (erase-buffer) (insert-file-contents file) - (setq parsed (yas--parse-template file)) + (setq parsed (yas--parse-template-for-compile file)) (if (listp (car parsed)) ;; If car is a list (dolist (sp parsed) (push sp snippet-defs)) - (push parsed snippet-defs) - )))) + (push parsed snippet-defs))))) (when snippet-defs - (yas-define-snippets mode-sym + (yas-define-snippets-for-compile mode-sym snippet-defs)) ;; now recurse to a lower level ;; (dolist (subdir (yas--subdirs directory)) - (yas--load-directory-2 subdir + (yas--load-directory-2-for-compile subdir mode-sym)))) (defun yas--load-snippet-dirs (&optional nojit) @@ -2105,6 +2249,15 @@ prefix argument." ;;; Snippet compilation function +(defun yas-compile-directory-for-compile (top-level-dir) + "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR. + +This works by stubbing a few functions, then calling +`yas-load-directory'." + (interactive "DTop level snippet directory?") + (let ((yas--creating-compiled-snippets t)) + (yas-load-directory-for-compile top-level-dir nil))) + (defun yas-compile-directory (top-level-dir) "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR. From 65761e1cf7d7c388c5843cdb5774647d0fd928d8 Mon Sep 17 00:00:00 2001 From: Shuguang Sun Date: Wed, 2 Sep 2020 16:40:18 +0800 Subject: [PATCH 3/4] fix: some fixes --- yasnippet.el | 106 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 91 insertions(+), 15 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 73723c68..e08abeb7 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1592,6 +1592,84 @@ this line are ignored. Directives can set most of these with the syntax: # directive-name : directive-value +Here's a list of currently recognized directives: + + * type + * name + * contributor + * condition + * group + * key + * expand-env + * binding + * uuid" + (goto-char (point-min)) + (let* ((type 'snippet) + (name (and file + (file-name-nondirectory file))) + (key nil) + template + bound + condition + (group (and file + (yas--calculate-group file))) + expand-env + binding + uuid) + (if (re-search-forward "^# --\\s-*\n" nil t) + (progn (setq template + (buffer-substring-no-properties (point) + (point-max))) + (setq bound (point)) + (goto-char (point-min)) + (while (re-search-forward "^# *\\([^ ]+?\\) *: *\\(.*?\\)[[:space:]]*$" bound t) + (when (string= "uuid" (match-string-no-properties 1)) + (setq uuid (match-string-no-properties 2))) + (when (string= "type" (match-string-no-properties 1)) + (setq type (if (string= "command" (match-string-no-properties 2)) + 'command + 'snippet))) + (when (string= "key" (match-string-no-properties 1)) + (setq key (match-string-no-properties 2))) + (when (string= "name" (match-string-no-properties 1)) + (setq name (match-string-no-properties 2))) + (when (string= "condition" (match-string-no-properties 1)) + (setq condition (yas--read-lisp (match-string-no-properties 2)))) + (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 expand-env (yas--read-lisp (match-string-no-properties 2) + 'nil-on-error))) + (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)))) + (unless (or key binding) + (setq key (and file (file-name-nondirectory file)))) + (when (eq type 'command) + (setq template (yas--read-lisp (concat "(progn" template ")")))) + (when group + (setq group (split-string group "\\."))) + (list key template name condition group expand-env file binding uuid))) + +(defun yas--parse-template-for-mulkey (&optional file) + "Parse the template in the current buffer. + +Optional FILE is the absolute file name of the file being +parsed. + +Optional GROUP is the group where the template is to go, +otherwise we attempt to calculate it from FILE. + +Return a snippet-definition, i.e. a list + + (KEY TEMPLATE NAME CONDITION GROUP VARS LOAD-FILE KEYBINDING UUID) + +If the buffer contains a line of \"# --\" then the contents above +this line are ignored. Directives can set most of these with the syntax: + +# directive-name : directive-value + Here's a list of currently recognized directives: * type @@ -1646,8 +1724,7 @@ Here's a list of currently recognized directives: (setq template (buffer-substring-no-properties (point-min) (point-max)))) (unless (or key binding) - (cl-pushnew (and file (file-name-nondirectory file)) key) - ) + (cl-pushnew (and file (file-name-nondirectory file)) key)) (when (eq type 'command) (setq template (yas--read-lisp (concat "(progn" template ")")))) (when group @@ -1656,8 +1733,7 @@ Here's a list of currently recognized directives: (dolist (k key results) (push (list k template (format "%s (%s)" name k) condition group expand-env file binding uuid) results)) (setq results (list (list key template name condition group expand-env file binding uuid)))) - results - )) + results)) (defun yas--calculate-group (file) "Calculate the group for snippet file path FILE." @@ -1863,7 +1939,7 @@ the current buffers contents." snippet-table))) template))) -(defun yas-define-snippets-for-compile (mode snippets) +(defun yas-define-snippets-for-mulkey (mode snippets) "Define SNIPPETS for MODE. SNIPPETS is a list of snippet definitions, each taking the @@ -1992,7 +2068,7 @@ With prefix argument USE-JIT do jit-loading of snippets." (when interactive (yas--message 3 "Loaded snippets from %s." top-level-dir))) -(defun yas-load-directory-for-compile (top-level-dir &optional use-jit interactive) +(defun yas-load-directory-for-mulkey (top-level-dir &optional use-jit interactive) "Load snippets in directory hierarchy TOP-LEVEL-DIR. Below TOP-LEVEL-DIR each directory should be a mode name. @@ -2022,7 +2098,7 @@ With prefix argument USE-JIT do jit-loading of snippets." ;; (yas--define-parents mode-sym parents) (yas--menu-keymap-get-create mode-sym) - (let ((fun (apply-partially #'yas--load-directory-1-for-compile dir mode-sym))) + (let ((fun (apply-partially #'yas--load-directory-1-for-mulkey dir mode-sym))) (if use-jit (yas--schedule-jit mode-sym fun) (funcall fun))) @@ -2062,7 +2138,7 @@ With prefix argument USE-JIT do jit-loading of snippets." (yas--message 4 "Loading snippet files from %s" directory) (yas--load-directory-2 directory mode-sym))))) -(defun yas--load-directory-1-for-compile (directory mode-sym) +(defun yas--load-directory-1-for-mulkey (directory mode-sym) "Recursively load snippet templates from DIRECTORY." (if yas--creating-compiled-snippets (let ((output-file (expand-file-name ".yas-compiled-snippets.el" @@ -2070,7 +2146,7 @@ With prefix argument USE-JIT do jit-loading of snippets." (with-temp-file output-file (insert (format ";;; Compiled snippets and support files for `%s'\n" mode-sym)) - (yas--load-directory-2-for-compile directory mode-sym) + (yas--load-directory-2-for-mulkey directory mode-sym) (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string))))) ;; Normal case. @@ -2106,7 +2182,7 @@ With prefix argument USE-JIT do jit-loading of snippets." (yas--load-directory-2 subdir mode-sym)))) -(defun yas--load-directory-2-for-compile (directory mode-sym) +(defun yas--load-directory-2-for-mulkey (directory mode-sym) ;; Load .yas-setup.el files wherever we find them ;; (yas--load-yas-setup-file (expand-file-name ".yas-setup" directory)) @@ -2122,18 +2198,18 @@ With prefix argument USE-JIT do jit-loading of snippets." ;; `insert-file-contents' (avoids Emacs bug #23659). (erase-buffer) (insert-file-contents file) - (setq parsed (yas--parse-template-for-compile file)) + (setq parsed (yas--parse-template-for-mulkey file)) (if (listp (car parsed)) ;; If car is a list (dolist (sp parsed) (push sp snippet-defs)) (push parsed snippet-defs))))) (when snippet-defs - (yas-define-snippets-for-compile mode-sym + (yas-define-snippets-for-mulkey mode-sym snippet-defs)) ;; now recurse to a lower level ;; (dolist (subdir (yas--subdirs directory)) - (yas--load-directory-2-for-compile subdir + (yas--load-directory-2-for-mulkey subdir mode-sym)))) (defun yas--load-snippet-dirs (&optional nojit) @@ -2249,14 +2325,14 @@ prefix argument." ;;; Snippet compilation function -(defun yas-compile-directory-for-compile (top-level-dir) +(defun yas-compile-directory-for-mulkey (top-level-dir) "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR. This works by stubbing a few functions, then calling `yas-load-directory'." (interactive "DTop level snippet directory?") (let ((yas--creating-compiled-snippets t)) - (yas-load-directory-for-compile top-level-dir nil))) + (yas-load-directory-for-mulkey top-level-dir nil))) (defun yas-compile-directory (top-level-dir) "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR. From f93997d3f34a32c7cba55767e116b7469d0f94f8 Mon Sep 17 00:00:00 2001 From: Shuguang Sun Date: Thu, 3 Sep 2020 09:49:14 +0800 Subject: [PATCH 4/4] add: yas-recompile-all-for-mulkye --- yasnippet.el | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index e08abeb7..b0028cc4 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -2348,6 +2348,11 @@ This works by stubbing a few functions, then calling (interactive) (mapc #'yas-compile-directory (yas-snippet-dirs))) +(defun yas-recompile-all-for-mulkey () + "Compile every dir in `yas-snippet-dirs'." + (interactive) + (mapc #'yas-compile-directory-for-mulkey (yas-snippet-dirs))) + ;;; JIT loading ;;;