Closes #271: save backquoted elisp and re-insert at end of expansion

This commit is contained in:
João Távora 2012-08-01 23:38:19 +01:00
parent 6be1de4a09
commit f35d2dba11
2 changed files with 95 additions and 12 deletions

View File

@ -112,17 +112,78 @@
(should (string= (yas--buffer-contents) "blabla}ble"))
(should (string= (yas-field-value 1) "bla}"))))
(ert-deftest escape-backslashes ()
(with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet "bla\\ble")
(should (string= (yas--buffer-contents) "bla\\ble"))))
(ert-deftest escape-some-elisp-with-strings ()
"elisp with strings and unbalance parens inside it"
(with-temp-buffer
(yas-minor-mode 1)
;; The rules here is: to output a literal `"' you need to escape
;; it with one backslash. You don't need to escape them in
;; embedded elisp.
(yas-expand-snippet "soon \\\"`(concat (upcase \"(my arms)\")\"\\\" were all around her\")`")
(should (string= (yas--buffer-contents) "soon \"MY ARMS\" were all around her"))))
(yas-expand-snippet "soon \\\"`(concat (upcase \"(my arms\")\"\\\" were all around her\")`")
(should (string= (yas--buffer-contents) "soon \"(MY ARMS\" were all around her"))))
(ert-deftest escape-some-elisp-with-backslashes ()
(with-temp-buffer
(yas-minor-mode 1)
;; And the rule here is: to output a literal `\' inside a string
;; inside embedded elisp you need a total of six `\'
(yas-expand-snippet "bla`(upcase \"hey\\\\\\yo\")`ble")
(should (string= (yas--buffer-contents) "blaHEY\\YOble"))))
(ert-deftest be-careful-when-escaping-in-yas-selected-text ()
(with-temp-buffer
(yas-minor-mode 1)
(let ((yas/selected-text "He\\\\o world!"))
(yas-expand-snippet "Look ma! `(yas/selected-text)`")
(should (string= (yas--buffer-contents) "Look ma! He\\\\o world!")))
(yas-exit-all-snippets)
(erase-buffer)
(let ((yas/selected-text "He\"o world!"))
(yas-expand-snippet "Look ma! `(yas/selected-text)`")
(should (string= (yas--buffer-contents) "Look ma! He\"o world!")))
(yas-exit-all-snippets)
(erase-buffer)
(let ((yas/selected-text "He\"\)\\o world!"))
(yas-expand-snippet "Look ma! `(yas/selected-text)`")
(should (string= (yas--buffer-contents) "Look ma! He\"\)\\o world!")))
(yas-exit-all-snippets)
(erase-buffer))))
(ert-deftest be-careful-when-escaping-in-yas-selected-text-2 ()
(with-temp-buffer
(let ((yas/selected-text "He)}o world!"))
(yas-expand-snippet "Look ma! ${1:`(yas/selected-text)`} OK?")
(should (string= (yas--buffer-contents) "Look ma! He)}o world! OK?")))))
(ert-deftest mirror-transformation ()
(with-temp-buffer
(yas-minor-mode 1)
(let ((snippet "${1:`(concat \"foo\" \"bar\")`} ${1:$(concat (upcase yas/text) \"baz\")}"))
(yas-expand-snippet snippet)
(should (string= (yas--buffer-contents) "foobar FOOBARbaz"))
(yas-exit-all-snippets)
(erase-buffer)
(yas-expand-snippet snippet)
(ert-simulate-command `(yas-mock-insert "bla"))
(should (string= (yas--buffer-contents) "bla BLAbaz")))))
(ert-deftest primary-field-transformation ()
(with-temp-buffer
(yas-minor-mode 1)
;; The rules here is: to output a literal `"' you need to escape
;; it with one backslash. You don't need to escape them in
;; embedded elisp.
(let ((snippet "${1:$$(upcase yas/text)}${1:$(concat \"bar\" yas/text)}"))
(yas-expand-snippet snippet)
(should (string= (yas--buffer-contents) "bar"))
(ert-simulate-command `(yas-mock-insert "foo"))
(should (string= (yas--buffer-contents) "FOObarFOO")))))
;;; Misc tests

View File

@ -3745,6 +3745,11 @@ next FOM. Works its way up recursively for parents of parents."
"When expanding the snippet the \"parse-create\" functions add
cons cells to this var")
(defvar yas--backquote-markers-and-strings nil
"List of (MARKER . STRING) marking where the the values
from backquoted lisp expressions should be inserted at the end of
expansion" )
(defun yas--snippet-parse-create (snippet)
"Parse a recently inserted snippet template, creating all
necessary fields, mirrors and exit points.
@ -3760,12 +3765,7 @@ Meant to be called in a narrowed buffer, does various passes"
;; replace all backquoted expressions
;;
(goto-char parse-start)
(yas--replace-backquotes)
;; protect escapes again since previous steps might have generated
;; more characters needing escaping
;;
(goto-char parse-start)
(yas--protect-escapes)
(yas--save-backquotes)
;; parse fields with {}
;;
(goto-char parse-start)
@ -3784,6 +3784,9 @@ Meant to be called in a narrowed buffer, does various passes"
;; Delete $-constructs
;;
(yas--delete-regions yas--dollar-regions)
;; restore backquoted expression values
;;
(yas--restore-backquotes)
;; restore escapes
;;
(goto-char parse-start)
@ -3915,15 +3918,34 @@ With optional string TEXT do it in string instead of the buffer."
(or escaped yas--escaped-characters))
changed-text))
(defun yas--replace-backquotes ()
"Replace all the \"`(lisp-expression)`\"-style expression
with their evaluated value"
(defun yas--save-backquotes ()
"Save all the \"`(lisp-expression)`\"-style expression
with their evaluated value into `yas--backquote-markers-and-strings'"
(while (re-search-forward yas--backquote-lisp-expression-regexp nil t)
(let ((current-string (match-string 1)) transformed)
(delete-region (match-beginning 0) (match-end 0))
(setq transformed (yas--eval-lisp (yas--read-lisp (yas--restore-escapes current-string))))
(goto-char (match-beginning 0))
(when transformed (insert transformed)))))
(when transformed
(let ((marker (make-marker)))
(insert "Y") ;; quite horrendous, I love it :)
(set-marker marker (point))
(insert "Y")
(push (cons marker transformed) yas--backquote-markers-and-strings))))))
(defun yas--restore-backquotes ()
"Replace all the markers in
`yas--backquote-markers-and-strings' with their values"
(while yas--backquote-markers-and-strings
(let* ((marker-and-string (pop yas--backquote-markers-and-strings))
(marker (car marker-and-string))
(string (cdr marker-and-string)))
(save-excursion
(goto-char marker)
(delete-char -1)
(insert string)
(delete-char 1)
(set-marker marker nil)))))
(defun yas--scan-sexps (from count)
(condition-case err