From 81859f5c1d5b9b3b462edd1e5ed0e0e7e358ea2f Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sat, 11 May 2019 20:28:21 +0200 Subject: [PATCH 01/12] Update template and table to hold regexp-keys --- yasnippet.el | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 2ec192a7..f6de2d6e 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1075,7 +1075,7 @@ Meaning it's visiting a file under one of the mode directories in (table key content &optional xname condition group - expand-env load-file xkeybinding xuuid save-file + expand-env load-file xkeybinding xuuid regexp-key save-file &aux (name (or xname ;; A little redundant: we always get a name @@ -1093,6 +1093,7 @@ Meaning it's visiting a file under one of the mode directories in (and old (yas--template-perm-group old)))))) "A template for a snippet." key + regexp-key content name condition @@ -1136,12 +1137,21 @@ Has the following fields: `yas--table-uuidhash' A hash table mapping snippets uuid's to the same `yas--template' - objects. A snippet uuid defaults to the snippet's name." + objects. A snippet uuid defaults to the snippet's name. + +`yas--table-regexp-templates' + + A list with elements on the form ((REGEXP-KEY . TEMPLATE) . + ORDER). REGEXP-KEY is a string, TEMPLATE is `yas--template' + object and ORDER is a number. The list is sorted by ORDER where + smaller values of ORDER are first." + name (hash (make-hash-table :test 'equal)) (uuidhash (make-hash-table :test 'equal)) (parents nil) - (direct-keymap (make-sparse-keymap))) + (direct-keymap (make-sparse-keymap)) + (regexp-templates '())) (defun yas--get-template-by-uuid (mode uuid) "Find the snippet template in MODE by its UUID." From 49f993121dee9cefa52406aea9e3665eee44edb2 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sat, 11 May 2019 20:31:20 +0200 Subject: [PATCH 02/12] Update yas--parse-templates to parse regexp-key directive --- yasnippet.el | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index f6de2d6e..c7af5f86 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1593,7 +1593,7 @@ 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) + (KEY TEMPLATE NAME CONDITION GROUP VARS LOAD-FILE KEYBINDING UUID REGEXP-KEY REGEXP-ORDER) If the buffer contains a line of \"# --\" then the contents above this line are ignored. Directives can set most of these with the syntax: @@ -1610,12 +1610,15 @@ Here's a list of currently recognized directives: * key * expand-env * binding - * uuid" + * uuid + * regexp-key + * regexp-order" (goto-char (point-min)) (let* ((type 'snippet) (name (and file (file-name-nondirectory file))) (key nil) + (regexp-key nil) template bound condition @@ -1639,6 +1642,8 @@ Here's a list of currently recognized directives: 'snippet))) (when (string= "key" (match-string-no-properties 1)) (setq key (match-string-no-properties 2))) + (when (string= "regexp-key" (match-string-no-properties 1)) + (setq regexp-key (concat (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)) @@ -1647,7 +1652,7 @@ Here's a list of currently recognized directives: (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))) + 'nil-on-error))) (when (string= "binding" (match-string-no-properties 1)) (setq binding (match-string-no-properties 2))))) (setq template @@ -1658,7 +1663,7 @@ Here's a list of currently recognized directives: (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))) + (list key template name condition group expand-env file binding uuid regexp-key))) (defun yas--calculate-group (file) "Calculate the group for snippet file path FILE." @@ -1823,7 +1828,7 @@ Optional PROMPT sets the prompt to use." 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) + (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID REGEXP-KEY SAVE-FILE) Within these, only KEY and TEMPLATE are actually mandatory. From 65a6d33a8014f073298e63b04b0d53924afa1469 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sat, 11 May 2019 20:33:02 +0200 Subject: [PATCH 03/12] Update functions that depend on positions in snippet definition --- yasnippet.el | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index c7af5f86..03e49d21 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1251,8 +1251,12 @@ KEY can be a string (trigger key) of a vector (direct keybinding)." (let ((name (yas--template-name template)) (key (yas--template-key template)) + (regexp-key (yas--template-regexp-key template)) (keybinding (yas--template-keybinding template)) (_menu-binding-pair (yas--template-menu-binding-pair-get-create template))) + (when regexp-key + (setf (yas--table-regexp-templates table) + (cons `(,regexp-key . ,template) (yas--table-regexp-templates table)))) (dolist (k (remove nil (list key keybinding))) (puthash name template @@ -1828,7 +1832,7 @@ Optional PROMPT sets the prompt to use." SNIPPETS is a list of snippet definitions, each taking the following form - (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID REGEXP-KEY SAVE-FILE) + (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID REGEXP-KEY REGEXP-ORDER SAVE-FILE) Within these, only KEY and TEMPLATE are actually mandatory. @@ -1854,12 +1858,12 @@ the current buffers contents." (insert ";;; Snippet definitions:\n;;;\n") (dolist (snippet snippets) ;; Fill in missing elements with nil. - (setq snippet (append snippet (make-list (- 10 (length snippet)) nil))) + (setq snippet (append snippet (make-list (- 11 (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))) + (setcar (nthcdr 10 snippet) load-file))) (insert (pp-to-string `(yas-define-snippets ',mode ',snippets))) (insert "\n\n")) From b2072550bb0b748cbdd52687083438c8941b6c5f Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sat, 11 May 2019 20:33:17 +0200 Subject: [PATCH 04/12] Add yas-expand-regexp --- yasnippet.el | 64 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 03e49d21..b0d91dac 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1419,8 +1419,41 @@ conditions to filter out potential expansions." (defun yas--templates-for-key-at-point () "Find `yas--template' objects for any trigger keys preceding point. Returns (TEMPLATES START END). This function respects -`yas-key-syntaxes', which see." +`yas-key-syntaxes', which see. + +If any regexp-key matches then only that keys template gets returned. + +Regexp-keys do not respect `yas-key-syntaxes'." + (let* ((regexp-keys (yas--filter-templates-by-condition + (apply #'append (mapcar + #'yas--table-regexp-templates + (yas--get-snippet-tables))) #'cdar)) + (found-regexp-match nil) + (found-template) + (found-key) + (found-start) + (found-end)) + (setq found-regexp-match + (cl-block found-match + (cl-loop for k in regexp-keys do + (let* ((regexp (caar k)) + (template (cdar k)) + (text (buffer-substring-no-properties (line-beginning-position) (point))) + (matched-index (string-match regexp text)) + (matched-buffer-index (when matched-index + (+ (line-beginning-position) matched-index)))) + (when matched-index + (setq found-template template) + (setq found-start (+ (line-beginning-position) matched-index)) + (setq found-end (point)) + (setq found-key (buffer-substring-no-properties found-start found-end)) + (cl-return-from found-match t)))))) + (if found-regexp-match + (progn + (setq yas-matched-regexp-key found-key) + (list (list `(,found-key . ,found-template)) found-start found-end)) (save-excursion + (setq yas-matched-regexp-key nil) (let ((original (point)) (methods yas-key-syntaxes) (templates) @@ -1452,7 +1485,7 @@ Returns (TEMPLATES START END). This function respects (yas--fetch table possible-key)) (yas--get-snippet-tables)))))) (when templates - (list templates (point) original))))) + (list templates (point) original))))))) (defun yas--table-all-keys (table) "Get trigger keys of all active snippets in TABLE." @@ -2359,7 +2392,32 @@ value for the first time then always returns a cached value.") ))) (put ',func 'yas--condition-cache (cons yas--condition-cache-timestamp new-value)) new-value))))) - +(defvar yas-matched-regexp-key nil + "The text that was used as a key for this snippet, if it was expanded using a regexp-key.") +(defun yas-expand-regexp () + (interactive) + (let* ((tables (yas--get-snippet-tables)) + (regexp-keys (apply #'append (mapcar #'yas--table-regexp-templates tables))) + (found-regexp-match nil)) + (setq found-regexp-match + (cl-block found-match + (cl-loop for k in regexp-keys do + (let* ((regexp (car k)) + (template (cdr k)) + (text (buffer-substring-no-properties (line-beginning-position) (point))) + (matched-index (string-match regexp text)) + (matched-buffer-index (when matched-index + (+ (line-beginning-position) matched-index)))) + (when matched-index + (setq yas-matched-regexp-key + (buffer-substring-no-properties matched-buffer-index (point))) + (delete-region matched-buffer-index (point)) + (yas-expand-snippet template) + ;; Reset the value + (setq yas-matched-regexp-key nil) + (cl-return-from found-match t)))))) + (when (not found-regexp-match) + (yas-expand)))) (defalias 'yas-expand 'yas-expand-from-trigger-key) (defun yas-expand-from-trigger-key (&optional field) "Expand a snippet before point. From 6bed96eb1edc56f4aae1669a1af2abb2cdc77418 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sun, 19 May 2019 17:02:16 +0200 Subject: [PATCH 05/12] Also honour yas-buffer-local-condition --- yasnippet.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index b0d91dac..eac1acfb 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -2397,7 +2397,8 @@ value for the first time then always returns a cached value.") (defun yas-expand-regexp () (interactive) (let* ((tables (yas--get-snippet-tables)) - (regexp-keys (apply #'append (mapcar #'yas--table-regexp-templates tables))) + (regexp-keys (yas--filter-templates-by-condition + (apply #'append (mapcar #'yas--table-regexp-templates tables)))) (found-regexp-match nil)) (setq found-regexp-match (cl-block found-match From 21c47072298679a64513a85e55903669fd2606a0 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sun, 19 May 2019 18:12:42 +0200 Subject: [PATCH 06/12] Make regexp-key a valid substitute for key or binding Previously either of the directives "binding" or "key" had to be present in a snippet for it to load properly. If both are absent the resulting template gets the file name as a key. With this change "regexp-key" also has that status. --- yasnippet.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index eac1acfb..a6111f7f 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1257,7 +1257,7 @@ keybinding)." (when regexp-key (setf (yas--table-regexp-templates table) (cons `(,regexp-key . ,template) (yas--table-regexp-templates table)))) - (dolist (k (remove nil (list key keybinding))) + (dolist (k (remove nil (list key keybinding regexp-key))) (puthash name template (or (gethash k @@ -1694,7 +1694,7 @@ Here's a list of currently recognized directives: (setq binding (match-string-no-properties 2))))) (setq template (buffer-substring-no-properties (point-min) (point-max)))) - (unless (or key binding) + (unless (or key binding regexp-key) (setq key (and file (file-name-nondirectory file)))) (when (eq type 'command) (setq template (yas--read-lisp (concat "(progn" template ")")))) From ea8854a18fea96342811b2dd306551ec37d65c8a Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Mon, 20 May 2019 21:59:26 +0200 Subject: [PATCH 07/12] Add ordering to regexp-snippets Different regexp keys could match the same text(say "[a-z]" and "[a-c]") while normal keys cannot(I think). This means that an ordering or priority between snippets become meaningful. For the above example it would not be clear which key would match the text "abc". If however, "[a-c]" has higher priority than "[a-z]" there would be only one choice: "[a-c]" would match. --- yasnippet.el | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index a6111f7f..61435b2c 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1075,7 +1075,7 @@ Meaning it's visiting a file under one of the mode directories in (table key content &optional xname condition group - expand-env load-file xkeybinding xuuid regexp-key save-file + expand-env load-file xkeybinding xuuid regexp-key regexp-order save-file &aux (name (or xname ;; A little redundant: we always get a name @@ -1094,6 +1094,7 @@ Meaning it's visiting a file under one of the mode directories in "A template for a snippet." key regexp-key + regexp-order content name condition @@ -1252,11 +1253,18 @@ keybinding)." (let ((name (yas--template-name template)) (key (yas--template-key template)) (regexp-key (yas--template-regexp-key template)) + (regexp-order (yas--template-regexp-order template)) (keybinding (yas--template-keybinding template)) (_menu-binding-pair (yas--template-menu-binding-pair-get-create template))) (when regexp-key (setf (yas--table-regexp-templates table) - (cons `(,regexp-key . ,template) (yas--table-regexp-templates table)))) + (cons `((,regexp-key . ,template) . ,(if regexp-order + regexp-order + 10)) + (yas--table-regexp-templates table))) + (setf (yas--table-regexp-templates table) + (sort (yas--table-regexp-templates table) + (lambda (a b) (< (cdr a) (cdr b)))))) (dolist (k (remove nil (list key keybinding regexp-key))) (puthash name template @@ -1365,20 +1373,29 @@ string and TEMPLATE is a `yas--template' structure." nil)))) -(defun yas--filter-templates-by-condition (templates) +(defun yas--filter-templates-by-condition (templates &optional get-template-func) "Filter the templates using the applicable condition. 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 -`yas-buffer-local-condition'. See that variables documentation." +`yas-buffer-local-condition'. See that variables documentation. + +GET-TEMPLATE-FUNC takes an element from TEMPLATES and returns the +template object. + +If GET-TEMPLATE-FUNC is non-nil TEMPLATES do not have to be a +list of cons-cells. It can be a list of anything as long as +GET-TEMPLATE-FUNC can retreive it." (let ((requirement (yas--require-template-specific-condition-p))) (if (eq requirement 'always) templates (cl-remove-if-not (lambda (pair) (yas--template-can-expand-p - (yas--template-condition (cdr pair)) requirement)) + (yas--template-condition (if get-template-func + (funcall get-template-func pair) + (cdr pair))) requirement)) templates)))) (defun yas--require-template-specific-condition-p () @@ -1656,6 +1673,7 @@ Here's a list of currently recognized directives: (file-name-nondirectory file))) (key nil) (regexp-key nil) + (regexp-order nil) template bound condition @@ -1681,6 +1699,8 @@ Here's a list of currently recognized directives: (setq key (match-string-no-properties 2))) (when (string= "regexp-key" (match-string-no-properties 1)) (setq regexp-key (concat (match-string-no-properties 2) "$"))) + (when (string= "regexp-order" (match-string-no-properties 1)) + (setq regexp-order (string-to-number (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)) @@ -1700,7 +1720,7 @@ Here's a list of currently recognized directives: (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 regexp-key))) + (list key template name condition group expand-env file binding uuid regexp-key regexp-order))) (defun yas--calculate-group (file) "Calculate the group for snippet file path FILE." @@ -1891,12 +1911,12 @@ the current buffers contents." (insert ";;; Snippet definitions:\n;;;\n") (dolist (snippet snippets) ;; Fill in missing elements with nil. - (setq snippet (append snippet (make-list (- 11 (length snippet)) nil))) + (setq snippet (append snippet (make-list (- 12 (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 10 snippet) load-file))) + (setcar (nthcdr 11 snippet) load-file))) (insert (pp-to-string `(yas-define-snippets ',mode ',snippets))) (insert "\n\n")) From 56740bcf8a45dfda485138afa2e86d2e69431e9e Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sat, 25 May 2019 18:02:38 +0200 Subject: [PATCH 08/12] Move appending "$" to where regexp-matching is done --- yasnippet.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 61435b2c..1c92db81 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1456,7 +1456,7 @@ Regexp-keys do not respect `yas-key-syntaxes'." (let* ((regexp (caar k)) (template (cdar k)) (text (buffer-substring-no-properties (line-beginning-position) (point))) - (matched-index (string-match regexp text)) + (matched-index (string-match (concat regexp "$") text)) (matched-buffer-index (when matched-index (+ (line-beginning-position) matched-index)))) (when matched-index @@ -1698,7 +1698,7 @@ Here's a list of currently recognized directives: (when (string= "key" (match-string-no-properties 1)) (setq key (match-string-no-properties 2))) (when (string= "regexp-key" (match-string-no-properties 1)) - (setq regexp-key (concat (match-string-no-properties 2) "$"))) + (setq regexp-key (match-string-no-properties 2))) (when (string= "regexp-order" (match-string-no-properties 1)) (setq regexp-order (string-to-number (match-string-no-properties 2)))) (when (string= "name" (match-string-no-properties 1)) From 5949cbc70138796e131067c1372988c79f518626 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Wed, 5 Jun 2019 19:55:28 +0200 Subject: [PATCH 09/12] Add support for key-syntaxes for regexp-keys --- yasnippet.el | 115 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 45 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 1c92db81..9b33054f 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -434,6 +434,7 @@ The condition will respect the value of `yas-keymap-disable-hook'." map) "The active keymap while a snippet expansion is in progress.") +(defvar yas-regexp-key-syntaxes (list (lambda (original) (goto-char (line-beginning-position))))) (defvar yas-key-syntaxes (list #'yas-try-key-from-whitespace "w_.()" "w_." "w_" "w") "Syntaxes and functions to help look for trigger keys before point. @@ -1433,50 +1434,23 @@ conditions to filter out potential expansions." (yas--table-hash table)) (yas--filter-templates-by-condition acc)))) -(defun yas--templates-for-key-at-point () - "Find `yas--template' objects for any trigger keys preceding point. -Returns (TEMPLATES START END). This function respects -`yas-key-syntaxes', which see. +(defun yas--templates-for-key-at-point-helper (methods template-fun) + "Helper function for yas--templates-for-key-at-point. -If any regexp-key matches then only that keys template gets returned. +Goes backwards according to METHODS(which is either +yas-key-syntaxes or yas-regexp-key-syntaxes), then calls +TEMPLATE-FUN with a possible-key start-pos and end-pos where -Regexp-keys do not respect `yas-key-syntaxes'." - (let* ((regexp-keys (yas--filter-templates-by-condition - (apply #'append (mapcar - #'yas--table-regexp-templates - (yas--get-snippet-tables))) #'cdar)) - (found-regexp-match nil) - (found-template) - (found-key) - (found-start) - (found-end)) - (setq found-regexp-match - (cl-block found-match - (cl-loop for k in regexp-keys do - (let* ((regexp (caar k)) - (template (cdar k)) - (text (buffer-substring-no-properties (line-beginning-position) (point))) - (matched-index (string-match (concat regexp "$") text)) - (matched-buffer-index (when matched-index - (+ (line-beginning-position) matched-index)))) - (when matched-index - (setq found-template template) - (setq found-start (+ (line-beginning-position) matched-index)) - (setq found-end (point)) - (setq found-key (buffer-substring-no-properties found-start found-end)) - (cl-return-from found-match t)))))) - (if found-regexp-match - (progn - (setq yas-matched-regexp-key found-key) - (list (list `(,found-key . ,found-template)) found-start found-end)) +- start-pos is the point where methods took us +- end-pos is (point) +- possible-key is the string between start-pos and end-pos" (save-excursion - (setq yas-matched-regexp-key nil) + (setq yas-matched-regexp-key nil) (let ((original (point)) - (methods yas-key-syntaxes) - (templates) + (templates-and-pos) (method)) (while (and methods - (not templates)) + (not templates-and-pos)) (unless (eq method (car methods)) ;; TRICKY: `eq'-ness test means we can only be here if ;; `method' is a function that returned `again', and hence @@ -1494,15 +1468,66 @@ Regexp-keys do not respect `yas-key-syntaxes'." (t (setq methods (cdr methods)) (yas--warning "Invalid element `%s' in `yas-key-syntaxes'" method))) - (let ((possible-key (buffer-substring-no-properties (point) original))) + (let ((possible-key (buffer-substring-no-properties (point) original)) + (syntax-start-pos (point))) (save-excursion (goto-char original) - (setq templates - (cl-mapcan (lambda (table) - (yas--fetch table possible-key)) - (yas--get-snippet-tables)))))) - (when templates - (list templates (point) original))))))) + (setq templates-and-pos + ;; (cl-mapcan (lambda (table) + ;; (yas--fetch table possible-key)) + ;; (yas--get-snippet-tables)) + (funcall template-fun possible-key syntax-start-pos original))))) + (when templates-and-pos + templates-and-pos)))) + +(defun yas--templates-for-key-at-point () + "Find `yas--template' objects for any trigger keys preceding point. +Returns (TEMPLATES START END). This function respects +`yas-key-syntaxes', which see. + +If any regexp-key matches then only that keys template gets returned." + (let* ((regexp-keys (yas--filter-templates-by-condition + (apply #'append (mapcar + #'yas--table-regexp-templates + (yas--get-snippet-tables))) #'cdar)) + (found-regexp-match nil) + (found-template) + (found-key) + (found-start) + (found-end)) + (let ((templates + (yas--templates-for-key-at-point-helper + yas-regexp-key-syntaxes + (lambda (possible-key start-pos end-pos) + (setq found-regexp-match + (cl-block found-match + (cl-loop for k in regexp-keys do + (let* ((regexp (caar k)) + (template (cdar k)) + (text possible-key) + (matched-index (string-match (concat regexp "\\'") text)) + (matched-buffer-index (when matched-index + (+ start-pos matched-index)))) + (when matched-index + (setq found-template template) + (setq found-start (+ start-pos matched-index)) + (setq found-end end-pos) + (setq found-key (buffer-substring-no-properties found-start found-end)) + (cl-return-from found-match t)))))) + (when found-regexp-match + (progn + (setq yas-matched-regexp-key found-key) + (list (list `(,found-key . ,found-template)) found-start found-end))))))) + (if templates + templates + (yas--templates-for-key-at-point-helper + yas-key-syntaxes + (lambda (possible-key start-pos end-pos) + (let ((templates(cl-mapcan (lambda (table) + (yas--fetch table possible-key)) + (yas--get-snippet-tables)))) + (when (car templates) + (list templates start-pos end-pos))))))))) (defun yas--table-all-keys (table) "Get trigger keys of all active snippets in TABLE." From b5c81da642014d5fcb31fa4183d0fd881d7bbd32 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Sun, 2 Jun 2019 21:17:13 +0200 Subject: [PATCH 10/12] Add a couple of tests to regexp-keys --- yasnippet-tests.el | 104 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index db9c177e..71ec2933 100644 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -1671,6 +1671,110 @@ add the snippets associated with the given mode." (yas-should-expand '(("car" . "(car )"))))))) +(ert-deftest regexp-key-simple-integration-test () + (clrhash yas--tables) + (with-temp-buffer + (insert "# name: test\n# regexp-key: [a-z]*\n# --\nfoo") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (yas-minor-mode 1) + (insert "foobarquux") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "foo")) + (clrhash yas--tables)) + +(ert-deftest regexp-key-simple-integration-test-key-syntaxes () + (clrhash yas--tables) + (with-temp-buffer + (insert "# name: test\n# regexp-key: ([^b-a]*)\n# --\nfoo") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (with-temp-buffer + (yas-minor-mode 1) + (insert "(asdf)") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "foo"))) + (with-temp-buffer + (yas-minor-mode 1) + (insert " (test whitespace before)") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) " foo"))) + (with-temp-buffer + (yas-minor-mode 1) + (insert "(kdkd\n)") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "(kdkd\n)"))) + (with-temp-buffer + (yas-minor-mode 1) + (insert "(foobarquux\n)") + (let ((yas-regexp-key-syntaxes (list (lambda (original) (goto-char (line-beginning-position 0)))))) + (ert-simulate-command '(yas-expand))) + (should (equal (buffer-string) "foo"))) + (with-temp-buffer + (yas-minor-mode 1) + (insert "(foobarquux)") + (let ((yas-regexp-key-syntaxes (list "(w)"))) + (ert-simulate-command '(yas-expand))) + (should (equal (buffer-string) "foo"))) + (with-temp-buffer + (yas-minor-mode 1) + (insert "(foo barquux)") + (let ((yas-regexp-key-syntaxes (list "(w)"))) + (ert-simulate-command '(yas-expand))) + (should (equal (buffer-string) "(foo barquux)"))) + (clrhash yas--tables)) +(ert-deftest regexp-matched-regexp-key () + (clrhash yas--tables) + (with-temp-buffer + (insert "# name: test\n# regexp-key: [a-z]*\n# --\n(`yas-matched-regexp-key`)") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (yas-minor-mode 1) + (insert "foobarquux") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "(foobarquux)")) + (clrhash yas--tables)) + +(ert-deftest regexp-key-order-default () + (clrhash yas--tables) + (with-temp-buffer + (insert "# name: test\n# regexp-order: 1\n# regexp-key: [a-z]*\n# --\norder1") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (with-temp-buffer + (insert "# name: test\n# regexp-key: [a-z]*\n# --\norderdefault") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (yas-minor-mode 1) + (insert "foobarquux") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "order1")) + (clrhash yas--tables)) + +(ert-deftest regexp-key-order () + (clrhash yas--tables) + (with-temp-buffer + (insert "# name: test\n# regexp-order: 0\n# regexp-key: [a-z]*\n# --\norder0") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (with-temp-buffer + (insert "# name: test\n# regexp-order: 1\n# regexp-key: [a-z]*\n# --\norder1") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (yas-minor-mode 1) + (insert "foobarquux") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "order0")) + (clrhash yas--tables)) + +(ert-deftest regexp-key-simple-nested () + (clrhash yas--tables) + (with-temp-buffer + (insert "# name: test\n\n# regexp-key: foo+\n# --\n(${1:foo})$0") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (with-temp-buffer + (insert "# name: test1\n\n# regexp-key: bar+\n# --\nbaz") + (yas-define-snippets 'fundamental-mode (list (yas--parse-template)))) + (yas-minor-mode 1) + (insert "foo") + (ert-simulate-command '(yas-expand)) + (insert "bar") + (ert-simulate-command '(yas-expand)) + (should (equal (buffer-string) "(baz)")) + (clrhash yas--tables)) (provide 'yasnippet-tests) ;; Local Variables: From 17393beac5fcac1a85e433d2a00aa06e04a0a850 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Tue, 11 Jun 2019 15:31:21 +0200 Subject: [PATCH 11/12] Remove old function --- yasnippet.el | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 9b33054f..b97e791a 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -2439,31 +2439,6 @@ value for the first time then always returns a cached value.") new-value))))) (defvar yas-matched-regexp-key nil "The text that was used as a key for this snippet, if it was expanded using a regexp-key.") -(defun yas-expand-regexp () - (interactive) - (let* ((tables (yas--get-snippet-tables)) - (regexp-keys (yas--filter-templates-by-condition - (apply #'append (mapcar #'yas--table-regexp-templates tables)))) - (found-regexp-match nil)) - (setq found-regexp-match - (cl-block found-match - (cl-loop for k in regexp-keys do - (let* ((regexp (car k)) - (template (cdr k)) - (text (buffer-substring-no-properties (line-beginning-position) (point))) - (matched-index (string-match regexp text)) - (matched-buffer-index (when matched-index - (+ (line-beginning-position) matched-index)))) - (when matched-index - (setq yas-matched-regexp-key - (buffer-substring-no-properties matched-buffer-index (point))) - (delete-region matched-buffer-index (point)) - (yas-expand-snippet template) - ;; Reset the value - (setq yas-matched-regexp-key nil) - (cl-return-from found-match t)))))) - (when (not found-regexp-match) - (yas-expand)))) (defalias 'yas-expand 'yas-expand-from-trigger-key) (defun yas-expand-from-trigger-key (&optional field) "Expand a snippet before point. From 155ebfa13e1d87582aca79d3c34ce1f1137cb5b0 Mon Sep 17 00:00:00 2001 From: Leo Okawa Ericson Date: Mon, 19 Aug 2019 22:53:00 +0200 Subject: [PATCH 12/12] Add yas-matched-regexp-key-groups --- yasnippet.el | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index b97e791a..23b8f2ca 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1509,13 +1509,26 @@ If any regexp-key matches then only that keys template gets returned." (matched-buffer-index (when matched-index (+ start-pos matched-index)))) (when matched-index + (setq yas-matched-regexp-key-groups + (reverse (let ((i 0) + (new-list nil)) + (while (< i (length (match-data))) + (setq new-list (cons + (let ((beg (nth i (match-data))) + (end (nth (+ i 1) (match-data)))) + (substring text beg end)) + new-list)) + (setq i (+ i 2))) + new-list))) (setq found-template template) (setq found-start (+ start-pos matched-index)) (setq found-end end-pos) (setq found-key (buffer-substring-no-properties found-start found-end)) + (cl-return-from found-match t)))))) (when found-regexp-match (progn + (setq yas-matched-regexp-key found-key) (list (list `(,found-key . ,found-template)) found-start found-end))))))) (if templates @@ -2437,6 +2450,20 @@ value for the first time then always returns a cached value.") ))) (put ',func 'yas--condition-cache (cons yas--condition-cache-timestamp new-value)) new-value))))) +(defvar yas-matched-regexp-key-groups nil + "A list containg match-data from the regexp-search made with the regexp-key. +The first item is the whole text matched by the regexp. +Subsequent items are text matched by the nth parenthesized expression by the + regexp-key. +Example: +# regexp-key: \([A-Za-z]\)\([0-9]\) +# name: subscript +# -- +`(nth 1 yas-matched-regexp-key-groups)`_`(nth 2 yas-matched-regexp-key-groups)` + +The snippet above will match any text on the form {Letter}{Number}. This is then +expanded to {Letter}_{Number} (i.e. the snippet places a underscore between any +letter and number).") (defvar yas-matched-regexp-key nil "The text that was used as a key for this snippet, if it was expanded using a regexp-key.") (defalias 'yas-expand 'yas-expand-from-trigger-key)