From: Federico Tedin Date: Tue, 14 May 2019 12:16:00 +0000 (-0300) Subject: Use lexical-binding in tempo.el and add tests X-Git-Tag: emacs-27.0.90~2805^2~18 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=eb2e9a2ca29f7d5e3b97709e9eca14fa5556ac63;p=emacs.git 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. --- diff --git a/lisp/tempo.el b/lisp/tempo.el index 28afbec0f49..e3b9c76a5b8 100644 --- a/lisp/tempo.el +++ b/lisp/tempo.el @@ -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 ;; 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)) diff --git a/test/lisp/tempo-tests.el b/test/lisp/tempo-tests.el new file mode 100644 index 00000000000..6e610ffa6ea --- /dev/null +++ b/test/lisp/tempo-tests.el @@ -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 +;; 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 . + +;;; 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