From 170d13d0691c5e5bb22ae6c1026eabdd9267508b Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Wed, 25 Mar 2020 22:21:37 -0400 Subject: [PATCH] Scan nested fields properly * yasnippet.el (yas--scan-for-field-end): New function. (yas--field-parse-create): Use it instead of yas--scan-sexps, which isn't able to distinguish between ${...} (a nested field) and {...} (plain old braces in the snippet text). * yasnippet-tests.el (yas-escaping-close-brace): New test. --- yasnippet-tests.el | 12 ++++++++++++ yasnippet.el | 11 ++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index 578125b..a780972 100644 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -947,6 +947,18 @@ mapconcat #'(lambda (arg) (yas-mock-insert "baz") (should (string= (yas--buffer-contents) "foobaaarbazok"))))) +(ert-deftest yas-escaping-close-brace () + "Close braces may be escaped with braces, reduction from eglot issue. +See https://github.com/joaotavora/eglot/issues/336." + (with-temp-buffer + (yas-minor-mode +1) + ;; NOTE: put a period at the end to avoid the bug tested by + ;; `protection-overlay-no-cheating'. + (yas-expand-snippet "${1:one{\\}}, ${2:two{\\}}.") + (yas-next-field) + (yas-next-field) + (should (string= (buffer-string) "one{}, two{}.")))) + ;;; Misc tests ;;; diff --git a/yasnippet.el b/yasnippet.el index bf15b31..8cb27ac 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -4719,6 +4719,13 @@ SAVED-QUOTES is the in format returned by `yas--save-backquotes'." yas--indent-markers)) (setq yas--indent-markers (nreverse yas--indent-markers))) +(defun yas--scan-for-field-end () + (while (progn (re-search-forward "\\${\\|}") + (when (eq (char-before) ?\{) + ;; Nested field. + (yas--scan-for-field-end)))) + (point)) + (defun yas--field-parse-create (snippet &optional parent-field) "Parse most field expressions in SNIPPET, except for the simple one \"$n\". @@ -4735,7 +4742,9 @@ When multiple expressions are found, only the last one counts." ;; (save-excursion (while (re-search-forward yas--field-regexp nil t) - (let* ((brace-scan (yas--scan-sexps (1+ (match-beginning 0)) 1)) + (let* ((brace-scan (save-match-data + (goto-char (match-beginning 2)) + (yas--scan-for-field-end))) ;; if the `brace-scan' didn't reach a brace, we have a ;; snippet with invalid escaping, probably a closing ;; brace escaped with two backslashes (github#979). But