Use lexical-binding in tempo.el and add tests
For discussion, see the following thread: https://lists.gnu.org/archive/html/emacs-devel/2019-05/msg00395.html * lisp/tempo.el: Use lexical-binding. (tempo-define-template): Expand documentation to mention `tempo-user-elements'. (tempo-local-tags, tempo-collection, tempo-dirty-collection) (tempo-marks, tempo-match-finder): Define with defvar-local. (tempo-named-insertions, tempo-region-start, tempo-region-stop): Make them automatically buffer-local. * test/lisp/tempo-tests.el: Add tests for tempo.el.
This commit is contained in:
parent
5856512911
commit
eb2e9a2ca2
2 changed files with 246 additions and 23 deletions
|
@ -1,11 +1,11 @@
|
|||
;;; tempo.el --- Flexible template insertion
|
||||
;;; tempo.el --- Flexible template insertion -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 1994-1995, 2001-2019 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: David Kågedal <davidk@lysator.liu.se>
|
||||
;; Created: 16 Feb 1994
|
||||
;; Kågedal's last version number: 1.2.4
|
||||
;; Keywords: extensions, languages, tools
|
||||
;; Keywords: abbrev, extensions, languages, tools
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
|
@ -152,7 +152,7 @@ setting it to (upcase), for example.")
|
|||
(defvar tempo-tags nil
|
||||
"An association list with tags and corresponding templates.")
|
||||
|
||||
(defvar tempo-local-tags '((tempo-tags . nil))
|
||||
(defvar-local tempo-local-tags '((tempo-tags . nil))
|
||||
"A list of locally installed tag completion lists.
|
||||
It is an association list where the car of every element is a symbol
|
||||
whose variable value is a template list. The cdr part, if non-nil,
|
||||
|
@ -161,16 +161,16 @@ documentation for the function `tempo-complete-tag' for more info.
|
|||
|
||||
`tempo-tags' is always in the last position in this list.")
|
||||
|
||||
(defvar tempo-collection nil
|
||||
(defvar-local tempo-collection nil
|
||||
"A collection of all the tags defined for the current buffer.")
|
||||
|
||||
(defvar tempo-dirty-collection t
|
||||
(defvar-local tempo-dirty-collection t
|
||||
"Indicates if the tag collection needs to be rebuilt.")
|
||||
|
||||
(defvar tempo-marks nil
|
||||
(defvar-local tempo-marks nil
|
||||
"A list of marks to jump to with `\\[tempo-forward-mark]' and `\\[tempo-backward-mark]'.")
|
||||
|
||||
(defvar tempo-match-finder "\\b\\([[:word:]]+\\)\\="
|
||||
(defvar-local tempo-match-finder "\\b\\([[:word:]]+\\)\\="
|
||||
"The regexp or function used to find the string to match against tags.
|
||||
|
||||
If `tempo-match-finder' is a string, it should contain a regular
|
||||
|
@ -195,23 +195,15 @@ A list of symbols which are bound to functions that take one argument.
|
|||
This function should return something to be sent to `tempo-insert' if
|
||||
it recognizes the argument, and nil otherwise.")
|
||||
|
||||
(defvar tempo-named-insertions nil
|
||||
(defvar-local tempo-named-insertions nil
|
||||
"Temporary storage for named insertions.")
|
||||
|
||||
(defvar tempo-region-start (make-marker)
|
||||
(defvar-local tempo-region-start (make-marker)
|
||||
"Region start when inserting around the region.")
|
||||
|
||||
(defvar tempo-region-stop (make-marker)
|
||||
(defvar-local tempo-region-stop (make-marker)
|
||||
"Region stop when inserting around the region.")
|
||||
|
||||
;; Make some variables local to every buffer
|
||||
|
||||
(make-variable-buffer-local 'tempo-marks)
|
||||
(make-variable-buffer-local 'tempo-local-tags)
|
||||
(make-variable-buffer-local 'tempo-match-finder)
|
||||
(make-variable-buffer-local 'tempo-collection)
|
||||
(make-variable-buffer-local 'tempo-dirty-collection)
|
||||
|
||||
;;; Functions
|
||||
|
||||
;;
|
||||
|
@ -268,11 +260,14 @@ The elements in ELEMENTS can be of several types:
|
|||
- `n>': Inserts a newline and indents line.
|
||||
- `o': Like `%' but leaves the point before the newline.
|
||||
- nil: It is ignored.
|
||||
- Anything else: It is evaluated and the result is treated as an
|
||||
element to be inserted. One additional tag is useful for these
|
||||
cases. If an expression returns a list (l foo bar), the elements
|
||||
after `l' will be inserted according to the usual rules. This makes
|
||||
it possible to return several elements from one expression."
|
||||
- Anything else: Each function in `tempo-user-elements' is called
|
||||
with it as argument until one of them returns non-nil, and the
|
||||
result is inserted. If all of them return nil, it is evaluated and
|
||||
the result is treated as an element to be inserted. One additional
|
||||
tag is useful for these cases. If an expression returns a list (l
|
||||
foo bar), the elements after `l' will be inserted according to the
|
||||
usual rules. This makes it possible to return several elements
|
||||
from one expression."
|
||||
(let* ((template-name (intern (concat "tempo-template-"
|
||||
name)))
|
||||
(command-name template-name))
|
||||
|
|
228
test/lisp/tempo-tests.el
Normal file
228
test/lisp/tempo-tests.el
Normal file
|
@ -0,0 +1,228 @@
|
|||
;;; tempo-tests.el --- Test suite for tempo.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Federico Tedin <federicotedin@gmail.com>
|
||||
;; Keywords: abbrev
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'tempo)
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
|
||||
(ert-deftest tempo-string-element-test ()
|
||||
"Test a template containing a string element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("GNU Emacs Tempo test"))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "GNU Emacs Tempo test"))))
|
||||
|
||||
(ert-deftest tempo-p-bare-element-test ()
|
||||
"Test a template containing a bare `p' element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("abcde" p))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(tempo-forward-mark)
|
||||
(should (equal (point) 6))))
|
||||
|
||||
(ert-deftest tempo-r-bare-element-test ()
|
||||
"Test a template containing a bare `r' element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("abcde" r "ghijk"))
|
||||
(insert "F")
|
||||
(set-mark (point))
|
||||
(goto-char (point-min))
|
||||
(tempo-insert-template 'tempo-template-test t)
|
||||
(should (equal (buffer-string) "abcdeFghijk"))))
|
||||
|
||||
(ert-deftest tempo-p-element-test ()
|
||||
"Testing template containing a `p' (prompt) element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("hello " (p ">")))
|
||||
(let ((tempo-interactive t))
|
||||
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "world")))
|
||||
(tempo-insert-template 'tempo-template-test nil))
|
||||
(should (equal (buffer-string) "hello world")))))
|
||||
|
||||
(ert-deftest tempo-P-element-test ()
|
||||
"Testing template containing a `P' (prompt) element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("hello " (P ">")))
|
||||
;; By default, `tempo-interactive' is nil, `P' should ignore this.
|
||||
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "world")))
|
||||
(tempo-insert-template 'tempo-template-test nil))
|
||||
(should (equal (buffer-string) "hello world"))))
|
||||
|
||||
(ert-deftest tempo-r-element-test ()
|
||||
"Testing template containing an `r' (with prompt) element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("abcde" (r ">") "ghijk"))
|
||||
(let ((tempo-interactive t))
|
||||
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "F")))
|
||||
(tempo-insert-template 'tempo-template-test nil))
|
||||
(should (equal (buffer-string) "abcdeFghijk")))))
|
||||
|
||||
(ert-deftest tempo-s-element-test ()
|
||||
"Testing template containing an `s' element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("hello " (p ">" P1) " " (s P1)))
|
||||
(let ((tempo-interactive t))
|
||||
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "world!")))
|
||||
(tempo-insert-template 'tempo-template-test nil))
|
||||
(should (equal (buffer-string) "hello world! world!")))))
|
||||
|
||||
(ert-deftest tempo-&-element-test ()
|
||||
"Testing template containing an `&' element."
|
||||
(tempo-define-template "test" '(& "test"))
|
||||
(with-temp-buffer
|
||||
(insert " ")
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) " test")))
|
||||
(with-temp-buffer
|
||||
(insert "hello")
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "hello\ntest"))))
|
||||
|
||||
(ert-deftest tempo-%-element-test ()
|
||||
"Testing template containing an `%' element."
|
||||
(tempo-define-template "test" '("test" %))
|
||||
(with-temp-buffer
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "test")))
|
||||
(with-temp-buffer
|
||||
(insert "hello")
|
||||
(goto-char (point-min))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "test\nhello"))))
|
||||
|
||||
(ert-deftest tempo-n-element-test ()
|
||||
"Testing template containing an `n' element."
|
||||
(tempo-define-template "test" '("test" n "test"))
|
||||
(with-temp-buffer
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "test\ntest"))))
|
||||
|
||||
(ert-deftest tempo-n>-element-test ()
|
||||
"Testing template containing an `n>' element."
|
||||
(tempo-define-template "test" '("(progn" n> "(list 1 2 3))"))
|
||||
(with-temp-buffer
|
||||
(emacs-lisp-mode)
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
;; Tempo should have inserted two spaces before (list 1 2 3)
|
||||
(should (equal (buffer-string) "(progn\n (list 1 2 3))"))))
|
||||
|
||||
(ert-deftest tempo->-element-test ()
|
||||
"Testing template containing a `>' element."
|
||||
(with-temp-buffer
|
||||
(emacs-lisp-mode)
|
||||
(insert "(progn\n)")
|
||||
(backward-char)
|
||||
(tempo-define-template "test" '("(list 1 2 3)" >))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
;; Tempo should have inserted two spaces before (list 1 2 3)
|
||||
(should (equal (buffer-string) "(progn\n (list 1 2 3))"))))
|
||||
|
||||
(ert-deftest tempo-r>-bare-element-test ()
|
||||
"Testing template containing a bare `r>' element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("(progn" n r> ")"))
|
||||
(emacs-lisp-mode)
|
||||
(insert "(list 1 2 3)")
|
||||
(set-mark (point))
|
||||
(goto-char (point-min))
|
||||
(tempo-insert-template 'tempo-template-test t)
|
||||
;; Tempo should have inserted two spaces before (list 1 2 3)
|
||||
(should (equal (buffer-string) "(progn\n (list 1 2 3))"))))
|
||||
|
||||
(ert-deftest tempo-r>-element-test ()
|
||||
"Testing template containing an `r>' (with prompt) element."
|
||||
(tempo-define-template "test" '("(progn" n (r> ":") ")"))
|
||||
(with-temp-buffer
|
||||
;; Test on-region use
|
||||
(emacs-lisp-mode)
|
||||
(insert "(list 1 2 3)")
|
||||
(set-mark (point))
|
||||
(goto-char (point-min))
|
||||
(tempo-insert-template 'tempo-template-test t)
|
||||
(should (equal (buffer-string) "(progn\n (list 1 2 3))")))
|
||||
(with-temp-buffer
|
||||
;; Test interactive use
|
||||
(emacs-lisp-mode)
|
||||
(let ((tempo-interactive t))
|
||||
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) " (list 1 2 3)")))
|
||||
(tempo-insert-template 'tempo-template-test nil))
|
||||
(should (equal (buffer-string) "(progn\n (list 1 2 3))")))))
|
||||
|
||||
(ert-deftest tempo-o-element-test ()
|
||||
"Testing template containing an `o' element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("test" o))
|
||||
(insert "hello")
|
||||
(goto-char (point-min))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "test\nhello"))
|
||||
(should (equal (point) 5))))
|
||||
|
||||
(ert-deftest tempo-nil-element-test ()
|
||||
"Testing template with nil elements."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("Hello," nil " World!"))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "Hello, World!"))))
|
||||
|
||||
(ert-deftest tempo-eval-element-test ()
|
||||
"Testing template with Emacs Lisp expressions."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '((int-to-string (+ 1 1)) "=" (concat "1" "+1")))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "2=1+1"))))
|
||||
|
||||
(ert-deftest tempo-l-element-test ()
|
||||
"Testing template containing an `l' element."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("list: " (l "1, " "2, " (int-to-string (+ 1 2)))))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "list: 1, 2, 3"))))
|
||||
|
||||
(ert-deftest tempo-tempo-user-elements-test ()
|
||||
"Testing a template with elements for `tempo-user-elements'."
|
||||
(with-temp-buffer
|
||||
(make-local-variable 'tempo-user-elements)
|
||||
(add-to-list 'tempo-user-elements (lambda (x) (int-to-string (* x x))))
|
||||
(tempo-define-template "test" '(1 " " 2 " " 3 " " 4))
|
||||
(tempo-insert-template 'tempo-template-test nil)
|
||||
(should (equal (buffer-string) "1 4 9 16"))))
|
||||
|
||||
(ert-deftest tempo-expand-tag-test ()
|
||||
"Testing expansion of a template with a tag."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("Hello, World!") "hello")
|
||||
(insert "hello")
|
||||
(tempo-complete-tag)
|
||||
(should (equal (buffer-string) "Hello, World!"))))
|
||||
|
||||
(ert-deftest tempo-expand-partial-tag-test ()
|
||||
"Testing expansion of a template with a tag, with a partial match."
|
||||
(with-temp-buffer
|
||||
(tempo-define-template "test" '("Hello, World!") "hello")
|
||||
(insert "hel")
|
||||
(tempo-complete-tag)
|
||||
(should (equal (buffer-string) "Hello, World!"))))
|
||||
|
||||
(provide 'tempo-tests)
|
||||
;;; tempo-tests.el ends here
|
Loading…
Add table
Reference in a new issue