aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoakim Verona2015-01-21 00:26:56 +0100
committerJoakim Verona2015-01-21 00:26:56 +0100
commit8628a48fec7fcd8bdbbf6ce5808fc574631d1541 (patch)
tree3dfc3b71850123e7514ddb149a0ba768618cfddf
parentffd9ee1d6412a6e61383930562e6167a458f0d5f (diff)
parent0dd19ac82662c5710e73852f438fd55e1d9225b7 (diff)
downloademacs-8628a48fec7fcd8bdbbf6ce5808fc574631d1541.tar.gz
emacs-8628a48fec7fcd8bdbbf6ce5808fc574631d1541.zip
Merge branch 'master' into xwidget
-rw-r--r--etc/NEWS15
-rw-r--r--lisp/ChangeLog83
-rw-r--r--lisp/descr-text.el96
-rw-r--r--lisp/emacs-lisp/bytecomp.el2
-rw-r--r--lisp/emacs-lisp/cl-generic.el23
-rw-r--r--lisp/emacs-lisp/eieio-compat.el246
-rw-r--r--lisp/emacs-lisp/eieio-core.el87
-rw-r--r--lisp/emacs-lisp/eieio-generic.el907
-rw-r--r--lisp/emacs-lisp/eieio.el1
-rw-r--r--lisp/emacs-lisp/eldoc.el7
-rw-r--r--lisp/emacs-lisp/macroexp.el39
-rw-r--r--lisp/hexl.el4
-rw-r--r--lisp/ielm.el6
-rw-r--r--lisp/progmodes/cfengine.el3
-rw-r--r--lisp/progmodes/elisp-mode.el4
-rw-r--r--lisp/progmodes/etags.el24
-rw-r--r--lisp/progmodes/octave.el3
-rw-r--r--lisp/progmodes/python.el4
-rw-r--r--lisp/progmodes/xref.el6
-rw-r--r--lisp/simple.el4
-rw-r--r--lisp/textmodes/paragraphs.el4
-rw-r--r--lisp/textmodes/tildify.el105
-rw-r--r--lisp/vc/vc-dir.el2
-rw-r--r--src/ChangeLog54
-rw-r--r--src/alloc.c4
-rw-r--r--src/coding.c4
-rw-r--r--src/dispnew.c16
-rw-r--r--src/gtkutil.c2
-rw-r--r--src/lisp.h8
-rw-r--r--src/minibuf.c2
-rw-r--r--src/nsfont.m2
-rw-r--r--src/nsterm.m5
-rw-r--r--src/w32fns.c2
-rw-r--r--src/xdisp.c39
-rw-r--r--src/xfns.c6
-rw-r--r--test/ChangeLog26
-rw-r--r--test/automated/descr-text-test.el94
-rw-r--r--test/automated/package-test.el17
-rw-r--r--test/automated/tildify-tests.el71
39 files changed, 983 insertions, 1044 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 4551c9c6b79..548b54df0da 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -208,6 +208,8 @@ If you need your objects to be named, do it by inheriting from `eieio-named'.
208*** The <class>-list-p and <class>-child-p functions are declared obsolete. 208*** The <class>-list-p and <class>-child-p functions are declared obsolete.
209*** The <class> variables are declared obsolete. 209*** The <class> variables are declared obsolete.
210*** The <initarg> variables are declared obsolete. 210*** The <initarg> variables are declared obsolete.
211*** defgeneric and defmethod are declared obsolete.
212
211** ido 213** ido
212*** New command `ido-bury-buffer-at-head' bound to C-S-b 214*** New command `ido-bury-buffer-at-head' bound to C-S-b
213Bury the buffer at the head of `ido-matches', analogous to how C-k 215Bury the buffer at the head of `ido-matches', analogous to how C-k
@@ -238,8 +240,12 @@ typing RET.
238result of the calculation into the current buffer. 240result of the calculation into the current buffer.
239 241
240** ElDoc 242** ElDoc
241*** New minor mode global-eldoc-mode 243*** New minor mode `global-eldoc-mode'
242*** eldoc-documentation-function now defaults to nil 244*** `eldoc-documentation-function' now defaults to `ignore'
245*** `describe-char-eldoc' displays information about character at point,
246and can be used as a default value of `eldoc-documentation-function'. It is
247useful when, for example, one needs to distinguish various spaces (e.g. ] [,
248] [, ] [, etc.) while using mono-spaced font.
243 249
244** eww 250** eww
245 251
@@ -494,6 +500,11 @@ As a result of the above, these commands are now obsolete:
494** let-alist is a new macro (and a package) that allows one to easily 500** let-alist is a new macro (and a package) that allows one to easily
495let-bind the values stored in an alist. 501let-bind the values stored in an alist.
496 502
503** `tildify-mode' allows to automatically insert hard spaces as one
504types the text. Breaking line after a single-character words is
505forbidden by Czech and Polish typography (and may be discouraged in
506other languages), so `auto-tildify-mode' makes it easier to create
507a typographically-correct documents.
497 508
498* Incompatible Lisp Changes in Emacs 25.1 509* Incompatible Lisp Changes in Emacs 25.1
499 510
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index b1a3a73864c..b5824abd01f 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,77 @@
12015-01-20 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * emacs-lisp/eieio-generic.el: Remove.
4 (defgeneric, defmethod): Move to eieio-compat.el. Mark obsolete.
5 * emacs-lisp/eieio-compat.el: New file.
6 * emacs-lisp/eieio.el: Don't require eieio-generic any more.
7 * emacs-lisp/eieio-core.el (eieio--slot-originating-class-p):
8 Remove unused function.
9 (eieio-defclass): Move to eieio-compat.el.
10 * emacs-lisp/macroexp.el (macroexp-macroexpand): New function.
11 (macroexp--expand-all): Use it.
12 * emacs-lisp/bytecomp.el (byte-compile-recurse-toplevel): Here too.
13
142015-01-20 Michal Nazarewicz <mina86@mina86.com>
15
16 * emacs-lisp/eldoc.el (eldoc-documentation-function): Describe how
17 major modes should use `add-function' to alter value of the variable.
18 * hexl.el (hexl-mode):
19 * ielm.el (inferior-emacs-lisp-mode):
20 * progmodes/cfengine.el (cfengine3-mode):
21 * progmodes/elisp-mode (emacs-lisp-mode):
22 * progmodes/octave.el (octave-mode):
23 * progmodes/python.el (python-mode):
24 * simple.el (read--expression): Set `eldoc-documentation-function'
25 using `add-function' so the default value is always used.
26
27 * descr-text.el (describe-char-eldoc): New function returning
28 basic Unicode codepoint information (e.g. name) about character
29 at point. It is meant to be used as a default value of the
30 `eldoc-documentation-function' variable.
31 (describe-char-eldoc--format, describe-char-eldoc--truncate):
32 New helper functions for `describe-char-eldoc' function.
33
342015-01-20 Michal Nazarewicz <mina86@mina86.com>
35
36 * textmodes/paragraphs.el (sentence-end-base): Include an
37 ellipsis (…) and interrobang (‽) characters as end of a sentence,
38 and a closing single quote (’) as an end of a quote.
39
402015-01-20 Michal Nazarewicz <mina86@mina86.com>
41
42 * textmodes/tildify.el (tildify-double-space-undos): A new
43 variable specifying whether pressing space in `tildify-mode' after
44 a space has been replaced with hard space undos the substitution.
45 (tildify-space): Add code branch for handling `tildify-doule-space'.
46
47 * textmodes/tildify.el (tildify-space): A new function
48 which can be used as a `post-self-insert-hook' to automatically
49 convert spaces into hard spaces.
50 (tildify-space-pattern): A new variable specifying pattern where
51 `tildify-space' should take effect.
52 (tildify-space-predicates): A new variable specifying list of
53 predicate functions that all must return non-nil for
54 `tildify-space' to take effect.
55 (tildify-space-region-predicate): A new functions meant to be
56 used as a predicate in `tildify-space-predicates' list.
57 (tildify-mode): A new minor mode enabling `tildify-space' as a
58 `post-self-insert-hook'
59
602015-01-20 Daniel Colascione <dancol@dancol.org>
61
62 * vc/vc-dir.el (vc-dir): Default to repository root, not
63 default-directory.
64
652015-01-20 Dmitry Gutov <dgutov@yandex.ru>
66
67 * progmodes/etags.el (xref-etags-location): New class.
68 (xref-make-etags-location): New function.
69 (etags--xref-find-definitions): Use it.
70 (xref-location-marker): New method implementation.
71
72 * progmodes/xref.el: Mention that xref-location is an EIEIO class.
73 (xref--insert-xrefs): Expand help-echo string.
74
12015-01-19 Dmitry Gutov <dgutov@yandex.ru> 752015-01-19 Dmitry Gutov <dgutov@yandex.ru>
2 76
3 * ido.el: Update Customization instructions. 77 * ido.el: Update Customization instructions.
@@ -32,8 +106,8 @@
32 (xref--save-to-history): New function. 106 (xref--save-to-history): New function.
33 (xref--display-position): Use it. Add new argument. 107 (xref--display-position): Use it. Add new argument.
34 (xref--restore-window-configuration): Remove. 108 (xref--restore-window-configuration): Remove.
35 (xref--show-location, xref-show-location-at-point): Update 109 (xref--show-location, xref-show-location-at-point):
36 accordingly. 110 Update accordingly.
37 (xref--xref-buffer-mode): Don't use `pre-command-hook'. 111 (xref--xref-buffer-mode): Don't use `pre-command-hook'.
38 (xref--quit): New command. 112 (xref--quit): New command.
39 (xref-goto-xref): Use it. 113 (xref-goto-xref): Use it.
@@ -79,6 +153,11 @@
79 153
802015-01-18 Stefan Monnier <monnier@iro.umontreal.ca> 1542015-01-18 Stefan Monnier <monnier@iro.umontreal.ca>
81 155
156 * emacs-lisp/eieio-core.el: Add `subclass' specializer for cl-generic.
157 (eieio--generic-subclass-tagcode, eieio--generic-subclass-tag-types):
158 New functions.
159 (cl-generic-tagcode-function, cl-generic-tag-types-function): Use them.
160
82 * emacs-lisp/cl-macs.el (cl-defstruct): Minor optimization when include 161 * emacs-lisp/cl-macs.el (cl-defstruct): Minor optimization when include
83 or print is nil. 162 or print is nil.
84 (cl-struct-type-p): New function. 163 (cl-struct-type-p): New function.
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index b16c007e5b9..d6f64c77e61 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -825,6 +825,102 @@ relevant to POS."
825 825
826(define-obsolete-function-alias 'describe-char-after 'describe-char "22.1") 826(define-obsolete-function-alias 'describe-char-after 'describe-char "22.1")
827 827
828;;; Describe-Char-ElDoc
829
830(defun describe-char-eldoc--truncate (name width)
831 "Truncate NAME at white spaces such that it is no longer than WIDTH.
832
833Split NAME on white space character and return string with as
834many leading words of NAME as possible without exceeding WIDTH
835characters. If NAME consists of white space characters only,
836return an empty string. Three dots (\"...\") are appended to
837returned string if some of the words from NAME have been omitted.
838
839NB: Function may return string longer than WIDTH if name consists
840of a single word, or it's first word is longer than WIDTH
841characters."
842 (let ((words (split-string name)))
843 (if words
844 (let ((last words))
845 (setq width (- width (length (car words))))
846 (while (and (cdr last)
847 (<= (+ (length (cadr last)) (if (cddr last) 4 1)) width))
848 (setq last (cdr last))
849 (setq width (- width (length (car last)) 1)))
850 (let ((ellipsis (and (cdr last) "...")))
851 (setcdr last nil)
852 (concat (mapconcat 'identity words " ") ellipsis)))
853 "")))
854
855(defun describe-char-eldoc--format (ch &optional width)
856 "Format a description for character CH which is no more than WIDTH characters.
857
858Full description message has a \"U+HEX: NAME (GC: GENERAL-CATEGORY)\"
859format where:
860- HEX is a hexadecimal codepoint of the character (zero-padded to at
861 least four digits),
862- NAME is name of the character.
863- GC is a two-letter abbreviation of the general-category of the
864 character, and
865- GENERAL-CATEGORY is full name of the general-category of the
866 character.
867
868If WIDTH is non-nil some elements of the description may be
869omitted to accommodate the length restriction. Under certain
870condition, the function may return string longer than WIDTH, see
871`describe-char-eldoc--truncate'."
872 (let ((name (get-char-code-property ch 'name)))
873 (when name
874 (let* ((code (propertize (format "U+%04X" ch)
875 'face 'font-lock-constant-face))
876 (gc (get-char-code-property ch 'general-category))
877 (gc-desc (char-code-property-description 'general-category gc)))
878
879 (unless (or (not width) (<= (length name) width))
880 (setq name (describe-char-eldoc--truncate name width)))
881 (setq name (concat (substring name 0 1) (downcase (substring name 1))))
882 (setq name (propertize name 'face 'font-lock-variable-name-face))
883
884 (setq gc (propertize (symbol-name gc) 'face 'font-lock-comment-face))
885 (when gc-desc
886 (setq gc-desc (propertize gc-desc 'face 'font-lock-comment-face)))
887
888 (let ((lcode (length code))
889 (lname (length name))
890 (lgc (length gc))
891 (lgc-desc (and gc-desc (length gc-desc))))
892 (cond
893 ((and gc-desc
894 (or (not width) (<= (+ lcode lname lgc lgc-desc 7) width)))
895 (concat code ": " name " (" gc ": " gc-desc ")"))
896 ((and gc-desc (<= (+ lcode lname lgc-desc 5) width))
897 (concat code ": " name " (" gc-desc ")"))
898 ((or (not width) (<= (+ lcode lname lgc 5) width))
899 (concat code ": " name " (" gc ")"))
900 ((<= (+ lname lgc 3) width)
901 (concat name " (" gc ")"))
902 (t name)))))))
903
904;;;###autoload
905(defun describe-char-eldoc ()
906 "Return a description of character at point for use by ElDoc mode.
907
908Return nil if character at point is a printable ASCII
909character (i.e. codepoint between 32 and 127 inclusively).
910Otherwise return a description formatted by
911`describe-char-eldoc--format' function taking into account value
912of `eldoc-echo-area-use-multiline-p' variable and width of
913minibuffer window for width limit.
914
915This function is meant to be used as a value of
916`eldoc-documentation-function' variable."
917 (let ((ch (following-char)))
918 (when (and (not (zerop ch)) (or (< ch 32) (> ch 127)))
919 (describe-char-eldoc--format
920 ch
921 (unless (eq eldoc-echo-area-use-multiline-p t)
922 (1- (window-width (minibuffer-window))))))))
923
828(provide 'descr-text) 924(provide 'descr-text)
829 925
830;;; descr-text.el ends here 926;;; descr-text.el ends here
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 1acd4fe76b2..8440570d755 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -433,7 +433,7 @@ Return the compile-time value of FORM."
433 ;; 3.2.3.1, "Processing of Top Level Forms". The semantics are very 433 ;; 3.2.3.1, "Processing of Top Level Forms". The semantics are very
434 ;; subtle: see test/automated/bytecomp-tests.el for interesting 434 ;; subtle: see test/automated/bytecomp-tests.el for interesting
435 ;; cases. 435 ;; cases.
436 (setf form (macroexpand form byte-compile-macro-environment)) 436 (setf form (macroexp-macroexpand form byte-compile-macro-environment))
437 (if (eq (car-safe form) 'progn) 437 (if (eq (car-safe form) 'progn)
438 (cons 'progn 438 (cons 'progn
439 (mapcar (lambda (subform) 439 (mapcar (lambda (subform)
diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el
index 544f1fa140f..3bbddfc45a1 100644
--- a/lisp/emacs-lisp/cl-generic.el
+++ b/lisp/emacs-lisp/cl-generic.el
@@ -37,9 +37,26 @@
37;; Added elements: 37;; Added elements:
38;; - We support aliases to generic functions. 38;; - We support aliases to generic functions.
39;; - The kind of thing on which to dispatch can be extended. 39;; - The kind of thing on which to dispatch can be extended.
40;; There is support in this file for (eql <val>) dispatch as well as dispatch 40;; There is support in this file for dispatch on:
41;; on the type of CL structs, and eieio-core.el adds support for EIEIO 41;; - (eql <val>)
42;; defclass objects. 42;; - plain old types
43;; - type of CL structs
44;; eieio-core adds dispatch on:
45;; - class of eieio objects
46;; - actual class argument, using the syntax (subclass <class>).
47
48;; Efficiency considerations: overall, I've made an effort to make this fairly
49;; efficient for the expected case (e.g. no constant redefinition of methods).
50;; - Generic functions which do not dispatch on any argument are implemented
51;; optimally (just as efficient as plain old functions).
52;; - Generic functions which only dispatch on one argument are fairly efficient
53;; (not a lot of room for improvement, I think).
54;; - Multiple dispatch is implemented rather naively. There's an extra `apply'
55;; function call for every dispatch; we don't optimize each dispatch
56;; based on the set of candidate methods remaining; we don't optimize the
57;; order in which we performs the dispatches either; If/when this
58;; becomes a problem, we can try and optimize it.
59;; - call-next-method could be made more efficient, but isn't too terrible.
43 60
44;;; Code: 61;;; Code:
45 62
diff --git a/lisp/emacs-lisp/eieio-compat.el b/lisp/emacs-lisp/eieio-compat.el
new file mode 100644
index 00000000000..34c06c01763
--- /dev/null
+++ b/lisp/emacs-lisp/eieio-compat.el
@@ -0,0 +1,246 @@
1;;; eieio-compat.el --- Compatibility with Older EIEIO versions -*- lexical-binding:t -*-
2
3;; Copyright (C) 1995-1996, 1998-2015 Free Software Foundation, Inc.
4
5;; Author: Eric M. Ludlam <zappo@gnu.org>
6;; Keywords: OO, lisp
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23;;; Commentary:
24
25;; Backward compatibility definition of old EIEIO functions in
26;; terms of newer equivalent.
27
28;; The main elements are the old EIEIO `defmethod' and `defgeneric' which are
29;; now implemented on top of cl-generic. The differences we have to
30;; accommodate are:
31;; - EIEIO's :static methods (turned into a new `eieio--static' specializer).
32;; - EIEIO's support for `call-next-method' and `next-method-p' instead of
33;; `cl-next-method-p' and `cl-call-next-method' (simple matter of renaming).
34;; - Different errors are signaled.
35;; - EIEIO's defgeneric does not reset the function.
36;; - EIEIO's no-next-method and no-applicable-method can't be aliases of
37;; cl-generic's namesakes since they have different calling conventions,
38;; which means that packages that (defmethod no-next-method ..) don't work.
39;; - EIEIO's `call-next-method' and `next-method-p' had dynamic scope whereas
40;; cl-generic's `cl-next-method-p' and `cl-call-next-method' are lexically
41;; scoped.
42
43;;; Code:
44
45(require 'eieio-core)
46(require 'cl-generic)
47
48(put 'eieio--defalias 'byte-hunk-handler
49 #'byte-compile-file-form-defalias) ;;(get 'defalias 'byte-hunk-handler)
50;;;###autoload
51(defun eieio--defalias (name body)
52 "Like `defalias', but with less side-effects.
53More specifically, it has no side-effects at all when the new function
54definition is the same (`eq') as the old one."
55 (cl-assert (not (symbolp body)))
56 (while (and (fboundp name) (symbolp (symbol-function name)))
57 ;; Follow aliases, so methods applied to obsolete aliases still work.
58 (setq name (symbol-function name)))
59 (unless (and (fboundp name)
60 (eq (symbol-function name) body))
61 (defalias name body)))
62
63;;;###autoload
64(defmacro defgeneric (method args &optional doc-string)
65 "Create a generic function METHOD.
66DOC-STRING is the base documentation for this class. A generic
67function has no body, as its purpose is to decide which method body
68is appropriate to use. Uses `defmethod' to create methods, and calls
69`defgeneric' for you. With this implementation the ARGS are
70currently ignored. You can use `defgeneric' to apply specialized
71top level documentation to a method."
72 (declare (doc-string 3) (obsolete cl-defgeneric "25.1"))
73 `(eieio--defalias ',method
74 (eieio--defgeneric-init-form
75 ',method
76 ,(if doc-string (help-add-fundoc-usage doc-string args)))))
77
78;;;###autoload
79(defmacro defmethod (method &rest args)
80 "Create a new METHOD through `defgeneric' with ARGS.
81
82The optional second argument KEY is a specifier that
83modifies how the method is called, including:
84 :before - Method will be called before the :primary
85 :primary - The default if not specified
86 :after - Method will be called after the :primary
87 :static - First arg could be an object or class
88The next argument is the ARGLIST. The ARGLIST specifies the arguments
89to the method as with `defun'. The first argument can have a type
90specifier, such as:
91 ((VARNAME CLASS) ARG2 ...)
92where VARNAME is the name of the local variable for the method being
93created. The CLASS is a class symbol for a class made with `defclass'.
94A DOCSTRING comes after the ARGLIST, and is optional.
95All the rest of the args are the BODY of the method. A method will
96return the value of the last form in the BODY.
97
98Summary:
99
100 (defmethod mymethod [:before | :primary | :after | :static]
101 ((typearg class-name) arg2 &optional opt &rest rest)
102 \"doc-string\"
103 body)"
104 (declare (doc-string 3) (obsolete cl-defmethod "25.1")
105 (debug
106 (&define ; this means we are defining something
107 [&or name ("setf" :name setf name)]
108 ;; ^^ This is the methods symbol
109 [ &optional symbolp ] ; this is key :before etc
110 list ; arguments
111 [ &optional stringp ] ; documentation string
112 def-body ; part to be debugged
113 )))
114 (let* ((key (if (keywordp (car args)) (pop args)))
115 (params (car args))
116 (arg1 (car params))
117 (fargs (if (consp arg1)
118 (cons (car arg1) (cdr params))
119 params))
120 (class (if (consp arg1) (nth 1 arg1)))
121 (code `(lambda ,fargs ,@(cdr args))))
122 `(progn
123 ;; Make sure there is a generic and the byte-compiler sees it.
124 (defgeneric ,method ,args)
125 (eieio--defmethod ',method ',key ',class #',code))))
126
127(add-function :before-until cl-generic-tagcode-function
128 #'eieio--generic-static-tagcode)
129(defun eieio--generic-static-tagcode (type name)
130 (and (eq 'eieio--static (car-safe type))
131 `(40 . (cond
132 ((symbolp ,name) (eieio--class-v ,name))
133 ((vectorp ,name) (aref ,name 0))))))
134
135(add-function :around cl-generic-tag-types-function
136 #'eieio--generic-static-tag-types)
137(defun eieio--generic-static-tag-types (orig-fun tag)
138 (cond
139 ((or (eieio--class-p tag)
140 (and (symbolp tag) (boundp tag) (eieio--class-p (symbol-value tag))))
141 (let ((superclasses (funcall orig-fun tag))
142 (types ()))
143 ;; Interleave: (subclass <foo>) (eieio--static <foo>) <subclass <bar>) ..
144 (dolist (superclass superclasses)
145 (push superclass types)
146 (push `(eieio--static
147 ,(if (consp superclass) (cadr superclass) superclass))
148 types))
149 (nreverse types)))
150 (t (funcall orig-fun tag))))
151
152;;;###autoload
153(defun eieio--defgeneric-init-form (method doc-string)
154 (if doc-string (put method 'function-documentation doc-string))
155 (if (memq method '(no-next-method no-applicable-method))
156 (symbol-function method)
157 (let ((generic (cl-generic-ensure-function method)))
158 (symbol-function (cl--generic-name generic)))))
159
160;;;###autoload
161(defun eieio--defmethod (method kind argclass code)
162 (setq kind (intern (downcase (symbol-name kind))))
163 (let* ((specializer (if (not (eq kind :static))
164 (or argclass t)
165 (setq kind nil)
166 `(eieio--static ,argclass)))
167 (uses-cnm (not (memq kind '(:before :after))))
168 (specializers `((arg ,specializer)))
169 (code
170 ;; Backward compatibility for `no-next-method' and
171 ;; `no-applicable-method', which have slightly different calling
172 ;; convention than their cl-generic counterpart.
173 (pcase method
174 (`no-next-method
175 (setq method 'cl-no-next-method)
176 (setq specializers `(generic method ,@specializers))
177 (lambda (_generic _method &rest args) (apply code args)))
178 (`no-applicable-method
179 (setq method 'cl-no-applicable-method)
180 (setq specializers `(generic ,@specializers))
181 (lambda (generic arg &rest args) (apply code arg generic args)))
182 (_ code))))
183 (cl-generic-define-method
184 method (if kind (list kind)) specializers uses-cnm
185 (if uses-cnm
186 (let* ((docstring (documentation code 'raw))
187 (args (help-function-arglist code 'preserve-names))
188 (doc-only (if docstring
189 (let ((split (help-split-fundoc docstring nil)))
190 (if split (cdr split) docstring))))
191 (new-docstring (help-add-fundoc-usage doc-only
192 (cons 'cl-cnm args))))
193 ;; FIXME: ¡Add the new-docstring to those closures!
194 (lambda (cnm &rest args)
195 (cl-letf (((symbol-function 'call-next-method) cnm)
196 ((symbol-function 'next-method-p)
197 (lambda () (cl--generic-isnot-nnm-p cnm))))
198 (apply code args))))
199 code))))
200
201;; Compatibility with code which tries to catch `no-method-definition' errors.
202(push 'no-method-definition (get 'cl-no-applicable-method 'error-conditions))
203
204(defun generic-p (fname) (not (null (cl--generic fname))))
205
206(defun no-next-method (&rest args)
207 (declare (obsolete cl-no-next-method "25.1"))
208 (apply #'cl-no-next-method 'unknown nil args))
209
210(defun no-applicable-method (object method &rest args)
211 (declare (obsolete cl-no-applicable-method "25.1"))
212 (apply #'cl-no-applicable-method method object args))
213
214(define-obsolete-function-alias 'call-next-method 'cl-call-next-method "25.1")
215(define-obsolete-function-alias 'next-method-p 'cl-next-method-p "25.1")
216
217;;;###autoload
218(defun eieio-defmethod (method args)
219 "Obsolete work part of an old version of the `defmethod' macro."
220 (declare (obsolete cl-defmethod "24.1"))
221 (eval `(defmethod ,method ,@args))
222 method)
223
224;;;###autoload
225(defun eieio-defgeneric (method doc-string)
226 "Obsolete work part of an old version of the `defgeneric' macro."
227 (declare (obsolete cl-defgeneric "24.1"))
228 ;; Don't do this over and over.
229 (unless (fboundp 'method)
230 (eval `(defgeneric ,method (x) ,@(if doc-string `(,doc-string))))
231 ;; Return the method
232 'method))
233
234;;;###autoload
235(defun eieio-defclass (cname superclasses slots options)
236 (declare (obsolete eieio-defclass-internal "25.1"))
237 (eval `(defclass ,cname ,superclasses ,slots ,@options)))
238
239
240;; Local Variables:
241;; generated-autoload-file: "eieio-core.el"
242;; End:
243
244(provide 'eieio-compat)
245
246;;; eieio-compat.el ends here
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el
index e4221e48fe2..b89ccfdfb2b 100644
--- a/lisp/emacs-lisp/eieio-core.el
+++ b/lisp/emacs-lisp/eieio-core.el
@@ -1025,20 +1025,6 @@ Fills in the default value in CLASS' in SLOT with VALUE."
1025 1025
1026;;; EIEIO internal search functions 1026;;; EIEIO internal search functions
1027;; 1027;;
1028(defun eieio--slot-originating-class-p (start-class slot)
1029 "Return non-nil if START-CLASS is the first class to define SLOT.
1030This is for testing if the class currently in scope is the class that defines SLOT
1031so that we can protect private slots."
1032 (let ((par (eieio--class-parent start-class))
1033 (ret t))
1034 (or (not par)
1035 (progn
1036 (while (and par ret)
1037 (if (gethash slot (eieio--class-symbol-hashtable (car par)))
1038 (setq ret nil))
1039 (setq par (cdr par)))
1040 ret))))
1041
1042(defun eieio--slot-name-index (class obj slot) 1028(defun eieio--slot-name-index (class obj slot)
1043 "In CLASS for OBJ find the index of the named SLOT. 1029 "In CLASS for OBJ find the index of the named SLOT.
1044The slot is a symbol which is installed in CLASS by the `defclass' 1030The slot is a symbol which is installed in CLASS by the `defclass'
@@ -1271,13 +1257,76 @@ method invocation orders of the involved classes."
1271 ,(if (symbolp class) class (eieio--class-symbol class)))) 1257 ,(if (symbolp class) class (eieio--class-symbol class))))
1272 (eieio--class-precedence-list tag)))) 1258 (eieio--class-precedence-list tag))))
1273 1259
1274;;; Backward compatibility functions 1260
1275;; To support .elc files compiled for older versions of EIEIO. 1261;;;### (autoloads nil "eieio-compat" "eieio-compat.el" "b177169dfbad7fb2e9d500b9c40002fa")
1262;;; Generated autoloads from eieio-compat.el
1263
1264(autoload 'eieio--defalias "eieio-compat" "\
1265Like `defalias', but with less side-effects.
1266More specifically, it has no side-effects at all when the new function
1267definition is the same (`eq') as the old one.
1268
1269\(fn NAME BODY)" nil nil)
1270
1271(autoload 'defgeneric "eieio-compat" "\
1272Create a generic function METHOD.
1273DOC-STRING is the base documentation for this class. A generic
1274function has no body, as its purpose is to decide which method body
1275is appropriate to use. Uses `defmethod' to create methods, and calls
1276`defgeneric' for you. With this implementation the ARGS are
1277currently ignored. You can use `defgeneric' to apply specialized
1278top level documentation to a method.
1279
1280\(fn METHOD ARGS &optional DOC-STRING)" nil t)
1281
1282(function-put 'defgeneric 'doc-string-elt '3)
1283
1284(make-obsolete 'defgeneric 'cl-defgeneric '"25.1")
1285
1286(autoload 'defmethod "eieio-compat" "\
1287Create a new METHOD through `defgeneric' with ARGS.
1288
1289The optional second argument KEY is a specifier that
1290modifies how the method is called, including:
1291 :before - Method will be called before the :primary
1292 :primary - The default if not specified
1293 :after - Method will be called after the :primary
1294 :static - First arg could be an object or class
1295The next argument is the ARGLIST. The ARGLIST specifies the arguments
1296to the method as with `defun'. The first argument can have a type
1297specifier, such as:
1298 ((VARNAME CLASS) ARG2 ...)
1299where VARNAME is the name of the local variable for the method being
1300created. The CLASS is a class symbol for a class made with `defclass'.
1301A DOCSTRING comes after the ARGLIST, and is optional.
1302All the rest of the args are the BODY of the method. A method will
1303return the value of the last form in the BODY.
1304
1305Summary:
1276 1306
1277(defun eieio-defclass (cname superclasses slots options) 1307 (defmethod mymethod [:before | :primary | :after | :static]
1278 (declare (obsolete eieio-defclass-internal "25.1")) 1308 ((typearg class-name) arg2 &optional opt &rest rest)
1279 (eval `(defclass ,cname ,superclasses ,slots ,@options))) 1309 \"doc-string\"
1310 body)
1280 1311
1312\(fn METHOD &rest ARGS)" nil t)
1313
1314(function-put 'defmethod 'doc-string-elt '3)
1315
1316(make-obsolete 'defmethod 'cl-defmethod '"25.1")
1317
1318(autoload 'eieio--defgeneric-init-form "eieio-compat" "\
1319
1320
1321\(fn METHOD DOC-STRING)" nil nil)
1322
1323(autoload 'eieio--defmethod "eieio-compat" "\
1324
1325
1326\(fn METHOD KIND ARGCLASS CODE)" nil nil)
1327
1328;;;***
1329
1281 1330
1282(provide 'eieio-core) 1331(provide 'eieio-core)
1283 1332
diff --git a/lisp/emacs-lisp/eieio-generic.el b/lisp/emacs-lisp/eieio-generic.el
deleted file mode 100644
index 74ecefe7863..00000000000
--- a/lisp/emacs-lisp/eieio-generic.el
+++ /dev/null
@@ -1,907 +0,0 @@
1;;; eieio-generic.el --- CLOS-style generics for EIEIO -*- lexical-binding:t -*-
2
3;; Copyright (C) 1995-1996, 1998-2015 Free Software Foundation, Inc.
4
5;; Author: Eric M. Ludlam <zappo@gnu.org>
6;; Keywords: OO, lisp
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software: you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
22
23;;; Commentary:
24;;
25;; The "core" part of EIEIO is the implementation for the object
26;; system (such as eieio-defclass, or eieio-defmethod) but not the
27;; base classes for the object system, which are defined in EIEIO.
28;;
29;; See the commentary for eieio.el for more about EIEIO itself.
30
31;;; Code:
32
33(require 'eieio-core)
34(declare-function child-of-class-p "eieio")
35
36(put 'eieio--defalias 'byte-hunk-handler
37 #'byte-compile-file-form-defalias) ;;(get 'defalias 'byte-hunk-handler)
38(defun eieio--defalias (name body)
39 "Like `defalias', but with less side-effects.
40More specifically, it has no side-effects at all when the new function
41definition is the same (`eq') as the old one."
42 (while (and (fboundp name) (symbolp (symbol-function name)))
43 ;; Follow aliases, so methods applied to obsolete aliases still work.
44 (setq name (symbol-function name)))
45 (unless (and (fboundp name)
46 (eq (symbol-function name) body))
47 (defalias name body)))
48
49(defconst eieio--method-static 0 "Index into :static tag on a method.")
50(defconst eieio--method-before 1 "Index into :before tag on a method.")
51(defconst eieio--method-primary 2 "Index into :primary tag on a method.")
52(defconst eieio--method-after 3 "Index into :after tag on a method.")
53(defconst eieio--method-num-lists 4 "Number of indexes into methods vector in which groups of functions are kept.")
54(defconst eieio--method-generic-before 4 "Index into generic :before tag on a method.")
55(defconst eieio--method-generic-primary 5 "Index into generic :primary tag on a method.")
56(defconst eieio--method-generic-after 6 "Index into generic :after tag on a method.")
57(defconst eieio--method-num-slots 7 "Number of indexes into a method's vector.")
58
59(defsubst eieio--specialized-key-to-generic-key (key)
60 "Convert a specialized KEY into a generic method key."
61 (cond ((eq key eieio--method-static) 0) ;; don't convert
62 ((< key eieio--method-num-lists) (+ key 3)) ;; The conversion
63 (t key) ;; already generic.. maybe.
64 ))
65
66
67(defsubst generic-p (method)
68 "Return non-nil if symbol METHOD is a generic function.
69Only methods have the symbol `eieio-method-hashtable' as a property
70\(which contains a list of all bindings to that method type.)"
71 (and (fboundp method) (get method 'eieio-method-hashtable)))
72
73(defun eieio--generic-primary-only-p (method)
74 "Return t if symbol METHOD is a generic function with only primary methods.
75Only methods have the symbol `eieio-method-hashtable' as a property (which
76contains a list of all bindings to that method type.)
77Methods with only primary implementations are executed in an optimized way."
78 (and (generic-p method)
79 (let ((M (get method 'eieio-method-tree)))
80 (not (or (>= 0 (length (aref M eieio--method-primary)))
81 (aref M eieio--method-static)
82 (aref M eieio--method-before)
83 (aref M eieio--method-after)
84 (aref M eieio--method-generic-before)
85 (aref M eieio--method-generic-primary)
86 (aref M eieio--method-generic-after)))
87 )))
88
89(defun eieio--generic-primary-only-one-p (method)
90 "Return t if symbol METHOD is a generic function with only primary methods.
91Only methods have the symbol `eieio-method-hashtable' as a property (which
92contains a list of all bindings to that method type.)
93Methods with only primary implementations are executed in an optimized way."
94 (and (generic-p method)
95 (let ((M (get method 'eieio-method-tree)))
96 (not (or (/= 1 (length (aref M eieio--method-primary)))
97 (aref M eieio--method-static)
98 (aref M eieio--method-before)
99 (aref M eieio--method-after)
100 (aref M eieio--method-generic-before)
101 (aref M eieio--method-generic-primary)
102 (aref M eieio--method-generic-after)))
103 )))
104
105(defun eieio--defgeneric-init-form (method doc-string)
106 "Form to use for the initial definition of a generic."
107 (while (and (fboundp method) (symbolp (symbol-function method)))
108 ;; Follow aliases, so methods applied to obsolete aliases still work.
109 (setq method (symbol-function method)))
110
111 (cond
112 ((or (not (fboundp method))
113 (autoloadp (symbol-function method)))
114 ;; Make sure the method tables are installed.
115 (eieio--mt-install method)
116 ;; Construct the actual body of this function.
117 (if doc-string (put method 'function-documentation doc-string))
118 (eieio--defgeneric-form method))
119 ((generic-p method) (symbol-function method)) ;Leave it as-is.
120 (t (error "You cannot create a generic/method over an existing symbol: %s"
121 method))))
122
123(defun eieio--defgeneric-form (method)
124 "The lambda form that would be used as the function defined on METHOD.
125All methods should call the same EIEIO function for dispatch.
126DOC-STRING is the documentation attached to METHOD."
127 (lambda (&rest local-args)
128 (eieio--generic-call method local-args)))
129
130(defun eieio--defgeneric-form-primary-only (method)
131 "The lambda form that would be used as the function defined on METHOD.
132All methods should call the same EIEIO function for dispatch.
133DOC-STRING is the documentation attached to METHOD."
134 (lambda (&rest local-args)
135 (eieio--generic-call-primary-only method local-args)))
136
137(defvar eieio--generic-call-arglst nil
138 "When using `call-next-method', provides a context for parameters.")
139(defvar eieio--generic-call-key nil
140 "When using `call-next-method', provides a context for the current key.
141Keys are a number representing :before, :primary, and :after methods.")
142(defvar eieio--generic-call-next-method-list nil
143 "When executing a PRIMARY or STATIC method, track the 'next-method'.
144During executions, the list is first generated, then as each next method
145is called, the next method is popped off the stack.")
146
147(defun eieio--defgeneric-form-primary-only-one (method class impl)
148 "The lambda form that would be used as the function defined on METHOD.
149All methods should call the same EIEIO function for dispatch.
150CLASS is the class symbol needed for private method access.
151IMPL is the symbol holding the method implementation."
152 (lambda (&rest local-args)
153 ;; This is a cool cheat. Usually we need to look up in the
154 ;; method table to find out if there is a method or not. We can
155 ;; instead make that determination at load time when there is
156 ;; only one method. If the first arg is not a child of the class
157 ;; of that one implementation, then clearly, there is no method def.
158 (if (not (eieio-object-p (car local-args)))
159 ;; Not an object. Just signal.
160 (signal 'no-method-definition
161 (list method local-args))
162
163 ;; We do have an object. Make sure it is the right type.
164 (if (not (child-of-class-p (eieio--object-class-object (car local-args))
165 class))
166
167 ;; If not the right kind of object, call no applicable
168 (apply #'no-applicable-method (car local-args)
169 method local-args)
170
171 ;; It is ok, do the call.
172 ;; Fill in inter-call variables then evaluate the method.
173 (let ((eieio--generic-call-next-method-list nil)
174 (eieio--generic-call-key eieio--method-primary)
175 (eieio--generic-call-arglst local-args)
176 )
177 (apply impl local-args))))))
178
179(defun eieio-unbind-method-implementations (method)
180 "Make the generic method METHOD have no implementations.
181It will leave the original generic function in place,
182but remove reference to all implementations of METHOD."
183 (put method 'eieio-method-tree nil)
184 (put method 'eieio-method-hashtable nil))
185
186(defun eieio--method-optimize-primary (method)
187 (when eieio-optimize-primary-methods-flag
188 ;; Optimizing step:
189 ;;
190 ;; If this method, after this setup, only has primary methods, then
191 ;; we can setup the generic that way.
192 ;; Use `defalias' so as to interact properly with nadvice.el.
193 (defalias method
194 (if (eieio--generic-primary-only-p method)
195 ;; If there is only one primary method, then we can go one more
196 ;; optimization step.
197 (if (eieio--generic-primary-only-one-p method)
198 (let* ((M (get method 'eieio-method-tree))
199 (entry (car (aref M eieio--method-primary))))
200 (eieio--defgeneric-form-primary-only-one
201 method (car entry) (cdr entry)))
202 (eieio--defgeneric-form-primary-only method))
203 (eieio--defgeneric-form method)))))
204
205(defun eieio--defmethod (method kind argclass code)
206 "Work part of the `defmethod' macro defining METHOD with ARGS."
207 (let ((key
208 ;; Find optional keys.
209 (cond ((memq kind '(:BEFORE :before)) eieio--method-before)
210 ((memq kind '(:AFTER :after)) eieio--method-after)
211 ((memq kind '(:STATIC :static)) eieio--method-static)
212 ((memq kind '(:PRIMARY :primary nil)) eieio--method-primary)
213 ;; Primary key.
214 ;; (t eieio--method-primary)
215 (t (error "Unknown method kind %S" kind)))))
216
217 (while (and (fboundp method) (symbolp (symbol-function method)))
218 ;; Follow aliases, so methods applied to obsolete aliases still work.
219 (setq method (symbol-function method)))
220
221 ;; Make sure there is a generic (when called from defclass).
222 (eieio--defalias
223 method (eieio--defgeneric-init-form
224 method (or (documentation code)
225 (format "Generically created method `%s'." method))))
226 ;; Create symbol for property to bind to. If the first arg is of
227 ;; the form (varname vartype) and `vartype' is a class, then
228 ;; that class will be the type symbol. If not, then it will fall
229 ;; under the type `primary' which is a non-specific calling of the
230 ;; function.
231 (if argclass
232 (if (not (class-p argclass)) ;FIXME: Accept cl-defstructs!
233 (error "Unknown class type %s in method parameters"
234 argclass))
235 ;; Generics are higher.
236 (setq key (eieio--specialized-key-to-generic-key key)))
237 ;; Put this lambda into the symbol so we can find it.
238 (eieio--mt-add method code key argclass)
239 )
240
241 (eieio--method-optimize-primary method)
242
243 method)
244
245(define-obsolete-variable-alias 'eieio-pre-method-execution-hooks
246 'eieio-pre-method-execution-functions "24.3")
247(defvar eieio-pre-method-execution-functions nil
248 "Abnormal hook run just before an EIEIO method is executed.
249The hook function must accept one argument, the list of forms
250about to be executed.")
251
252(defun eieio--generic-call (method args)
253 "Call METHOD with ARGS.
254ARGS provides the context on which implementation to use.
255This should only be called from a generic function."
256 ;; We must expand our arguments first as they are always
257 ;; passed in as quoted symbols
258 (let ((newargs nil) (mclass nil) (lambdas nil) (tlambdas nil) (keys nil)
259 (eieio--generic-call-arglst args)
260 (firstarg nil)
261 (primarymethodlist nil))
262 ;; get a copy
263 (setq newargs args
264 firstarg (car newargs))
265 ;; Is the class passed in autoloaded?
266 ;; Since class names are also constructors, they can be autoloaded
267 ;; via the autoload command. Check for this, and load them in.
268 ;; It is ok if it doesn't turn out to be a class. Probably want that
269 ;; function loaded anyway.
270 (if (and (symbolp firstarg)
271 (fboundp firstarg)
272 (autoloadp (symbol-function firstarg)))
273 (autoload-do-load (symbol-function firstarg)))
274 ;; Determine the class to use.
275 (cond ((eieio-object-p firstarg)
276 (setq mclass (eieio--object-class-name firstarg)))
277 ((class-p firstarg)
278 (setq mclass firstarg))
279 )
280 ;; Make sure the class is a valid class
281 ;; mclass can be nil (meaning a generic for should be used.
282 ;; mclass cannot have a value that is not a class, however.
283 (unless (or (null mclass) (class-p mclass))
284 (error "Cannot dispatch method %S on class %S"
285 method mclass)
286 )
287 ;; Now create a list in reverse order of all the calls we have
288 ;; make in order to successfully do this right. Rules:
289 ;; 1) Only call static if this is a static method.
290 ;; 2) Only call specifics if the definition allows for them.
291 ;; 3) Call in order based on :before, :primary, and :after
292 (when (eieio-object-p firstarg)
293 ;; Non-static calls do all this stuff.
294
295 ;; :after methods
296 (setq tlambdas
297 (if mclass
298 (eieio--mt-method-list method eieio--method-after mclass)
299 (list (eieio--generic-form method eieio--method-after nil)))
300 ;;(or (and mclass (eieio--generic-form method eieio--method-after mclass))
301 ;; (eieio--generic-form method eieio--method-after nil))
302 )
303 (setq lambdas (append tlambdas lambdas)
304 keys (append (make-list (length tlambdas) eieio--method-after) keys))
305
306 ;; :primary methods
307 (setq tlambdas
308 (or (and mclass (eieio--generic-form method eieio--method-primary mclass))
309 (eieio--generic-form method eieio--method-primary nil)))
310 (when tlambdas
311 (setq lambdas (cons tlambdas lambdas)
312 keys (cons eieio--method-primary keys)
313 primarymethodlist
314 (eieio--mt-method-list method eieio--method-primary mclass)))
315
316 ;; :before methods
317 (setq tlambdas
318 (if mclass
319 (eieio--mt-method-list method eieio--method-before mclass)
320 (list (eieio--generic-form method eieio--method-before nil)))
321 ;;(or (and mclass (eieio--generic-form method eieio--method-before mclass))
322 ;; (eieio--generic-form method eieio--method-before nil))
323 )
324 (setq lambdas (append tlambdas lambdas)
325 keys (append (make-list (length tlambdas) eieio--method-before) keys))
326 )
327
328 (if mclass
329 ;; For the case of a class,
330 ;; if there were no methods found, then there could be :static methods.
331 (when (not lambdas)
332 (setq tlambdas
333 (eieio--generic-form method eieio--method-static mclass))
334 (setq lambdas (cons tlambdas lambdas)
335 keys (cons eieio--method-static keys)
336 primarymethodlist ;; Re-use even with bad name here
337 (eieio--mt-method-list method eieio--method-static mclass)))
338 ;; For the case of no class (ie - mclass == nil) then there may
339 ;; be a primary method.
340 (setq tlambdas
341 (eieio--generic-form method eieio--method-primary nil))
342 (when tlambdas
343 (setq lambdas (cons tlambdas lambdas)
344 keys (cons eieio--method-primary keys)
345 primarymethodlist
346 (eieio--mt-method-list method eieio--method-primary nil)))
347 )
348
349 (run-hook-with-args 'eieio-pre-method-execution-functions
350 primarymethodlist)
351
352 ;; Now loop through all occurrences forms which we must execute
353 ;; (which are happily sorted now) and execute them all!
354 (let ((rval nil) (lastval nil) (found nil))
355 (while lambdas
356 (if (car lambdas)
357 (let* ((eieio--generic-call-key (car keys))
358 (has-return-val
359 (or (= eieio--generic-call-key eieio--method-primary)
360 (= eieio--generic-call-key eieio--method-static)))
361 (eieio--generic-call-next-method-list
362 ;; Use the cdr, as the first element is the fcn
363 ;; we are calling right now.
364 (when has-return-val (cdr primarymethodlist)))
365 )
366 (setq found t)
367 ;;(setq rval (apply (car (car lambdas)) newargs))
368 (setq lastval (apply (car (car lambdas)) newargs))
369 (when has-return-val
370 (setq rval lastval))
371 ))
372 (setq lambdas (cdr lambdas)
373 keys (cdr keys)))
374 (if (not found)
375 (if (eieio-object-p (car args))
376 (setq rval (apply #'no-applicable-method (car args) method args))
377 (signal
378 'no-method-definition
379 (list method args))))
380 rval)))
381
382(defun eieio--generic-call-primary-only (method args)
383 "Call METHOD with ARGS for methods with only :PRIMARY implementations.
384ARGS provides the context on which implementation to use.
385This should only be called from a generic function.
386
387This method is like `eieio--generic-call', but only
388implementations in the :PRIMARY slot are queried. After many
389years of use, it appears that over 90% of methods in use
390have :PRIMARY implementations only. We can therefore optimize
391for this common case to improve performance."
392 ;; We must expand our arguments first as they are always
393 ;; passed in as quoted symbols
394 (let ((newargs nil) (mclass nil) (lambdas nil)
395 (eieio--generic-call-arglst args)
396 (firstarg nil)
397 (primarymethodlist nil)
398 )
399 ;; get a copy
400 (setq newargs args
401 firstarg (car newargs))
402
403 ;; Determine the class to use.
404 (cond ((eieio-object-p firstarg)
405 (setq mclass (eieio--object-class-name firstarg)))
406 ((not firstarg)
407 (error "Method %s called on nil" method))
408 (t
409 (error "Primary-only method %s called on something not an object" method)))
410 ;; Make sure the class is a valid class
411 ;; mclass can be nil (meaning a generic for should be used.
412 ;; mclass cannot have a value that is not a class, however.
413 (when (null mclass)
414 (error "Cannot dispatch method %S on class %S" method mclass)
415 )
416
417 ;; :primary methods
418 (setq lambdas (eieio--generic-form method eieio--method-primary mclass))
419 (setq primarymethodlist ;; Re-use even with bad name here
420 (eieio--mt-method-list method eieio--method-primary mclass))
421
422 ;; Now loop through all occurrences forms which we must execute
423 ;; (which are happily sorted now) and execute them all!
424 (let* ((rval nil) (lastval nil)
425 (eieio--generic-call-key eieio--method-primary)
426 ;; Use the cdr, as the first element is the fcn
427 ;; we are calling right now.
428 (eieio--generic-call-next-method-list (cdr primarymethodlist))
429 )
430
431 (if (or (not lambdas) (not (car lambdas)))
432
433 ;; No methods found for this impl...
434 (if (eieio-object-p (car args))
435 (setq rval (apply #'no-applicable-method
436 (car args) method args))
437 (signal
438 'no-method-definition
439 (list method args)))
440
441 ;; Do the regular implementation here.
442
443 (run-hook-with-args 'eieio-pre-method-execution-functions
444 lambdas)
445
446 (setq lastval (apply (car lambdas) newargs))
447 (setq rval lastval))
448
449 rval)))
450
451(defun eieio--mt-method-list (method key class)
452 "Return an alist list of methods lambdas.
453METHOD is the method name.
454KEY represents either :before, or :after methods.
455CLASS is the starting class to search from in the method tree.
456If CLASS is nil, then an empty list of methods should be returned."
457 ;; Note: eieiomt - the MT means MethodTree. See more comments below
458 ;; for the rest of the eieiomt methods.
459
460 ;; Collect lambda expressions stored for the class and its parent
461 ;; classes.
462 (let (lambdas)
463 (dolist (ancestor (eieio--class-precedence-list (eieio--class-v class)))
464 ;; Lookup the form to use for the PRIMARY object for the next level
465 (let ((tmpl (eieio--generic-form method key ancestor)))
466 (when (and tmpl
467 (or (not lambdas)
468 ;; This prevents duplicates coming out of the
469 ;; class method optimizer. Perhaps we should
470 ;; just not optimize before/afters?
471 (not (member tmpl lambdas))))
472 (push tmpl lambdas))))
473
474 ;; Return collected lambda. For :after methods, return in current
475 ;; order (most general class last); Otherwise, reverse order.
476 (if (eq key eieio--method-after)
477 lambdas
478 (nreverse lambdas))))
479
480
481;;;
482;; eieio-method-tree : eieio--mt-
483;;
484;; Stored as eieio-method-tree in property list of a generic method
485;;
486;; (eieio-method-tree . [BEFORE PRIMARY AFTER
487;; genericBEFORE genericPRIMARY genericAFTER])
488;; and
489;; (eieio-method-hashtable . [BEFORE PRIMARY AFTER
490;; genericBEFORE genericPRIMARY genericAFTER])
491;; where the association is a vector.
492;; (aref 0 -- all static methods.
493;; (aref 1 -- all methods classified as :before
494;; (aref 2 -- all methods classified as :primary
495;; (aref 3 -- all methods classified as :after
496;; (aref 4 -- a generic classified as :before
497;; (aref 5 -- a generic classified as :primary
498;; (aref 6 -- a generic classified as :after
499;;
500(defvar eieio--mt--optimizing-hashtable nil
501 "While mapping atoms, this contain the hashtable being optimized.")
502
503(defun eieio--mt-install (method-name)
504 "Install the method tree, and hashtable onto METHOD-NAME.
505Do not do the work if they already exist."
506 (unless (and (get method-name 'eieio-method-tree)
507 (get method-name 'eieio-method-hashtable))
508 (put method-name 'eieio-method-tree
509 (make-vector eieio--method-num-slots nil))
510 (let ((emto (put method-name 'eieio-method-hashtable
511 (make-vector eieio--method-num-slots nil))))
512 (aset emto 0 (make-hash-table :test 'eq))
513 (aset emto 1 (make-hash-table :test 'eq))
514 (aset emto 2 (make-hash-table :test 'eq))
515 (aset emto 3 (make-hash-table :test 'eq)))))
516
517(defun eieio--mt-add (method-name method key class)
518 "Add to METHOD-NAME the forms METHOD in a call position KEY for CLASS.
519METHOD-NAME is the name created by a call to `defgeneric'.
520METHOD are the forms for a given implementation.
521KEY is an integer (see comment in eieio.el near this function) which
522is associated with the :static :before :primary and :after tags.
523It also indicates if CLASS is defined or not.
524CLASS is the class this method is associated with."
525 (if (or (> key eieio--method-num-slots) (< key 0))
526 (error "eieio--mt-add: method key error!"))
527 (let ((emtv (get method-name 'eieio-method-tree))
528 (emto (get method-name 'eieio-method-hashtable)))
529 ;; Make sure the method tables are available.
530 (unless (and emtv emto)
531 (error "Programmer error: eieio--mt-add"))
532 ;; only add new cells on if it doesn't already exist!
533 (if (assq class (aref emtv key))
534 (setcdr (assq class (aref emtv key)) method)
535 (aset emtv key (cons (cons class method) (aref emtv key))))
536 ;; Add function definition into newly created symbol, and store
537 ;; said symbol in the correct hashtable, otherwise use the
538 ;; other array to keep this stuff.
539 (if (< key eieio--method-num-lists)
540 (puthash (eieio--class-v class) (list method) (aref emto key)))
541 ;; Save the defmethod file location in a symbol property.
542 (let ((fname (if load-in-progress
543 load-file-name
544 buffer-file-name)))
545 (when fname
546 (when (string-match "\\.elc\\'" fname)
547 (setq fname (substring fname 0 (1- (length fname)))))
548 (cl-pushnew (list class fname) (get method-name 'method-locations)
549 :test 'equal)))
550 ;; Now optimize the entire hashtable.
551 (if (< key eieio--method-num-lists)
552 (let ((eieio--mt--optimizing-hashtable (aref emto key)))
553 ;; @todo - Is this overkill? Should we just clear the symbol?
554 (maphash #'eieio--mt--sym-optimize eieio--mt--optimizing-hashtable)))
555 ))
556
557(defun eieio--mt-next (class)
558 "Return the next parent class for CLASS.
559If CLASS is a superclass, return variable `eieio-default-superclass'.
560If CLASS is variable `eieio-default-superclass' then return nil.
561This is different from function `class-parent' as class parent returns
562nil for superclasses. This function performs no type checking!"
563 ;; No type-checking because all calls are made from functions which
564 ;; are safe and do checking for us.
565 (or (eieio--class-parent (eieio--class-v class))
566 (if (eq class 'eieio-default-superclass)
567 nil
568 '(eieio-default-superclass))))
569
570(defun eieio--mt--sym-optimize (class s)
571 "Find the next class above S which has a function body for the optimizer."
572 ;; Set the value to nil in case there is no nearest cell.
573 (setcdr s nil)
574 ;; Find the nearest cell that has a function body. If we find one,
575 ;; we replace the nil from above.
576 (catch 'done
577 (dolist (ancestor
578 (cl-rest (eieio--class-precedence-list class)))
579 (let ((ov (gethash ancestor eieio--mt--optimizing-hashtable)))
580 (when (car ov)
581 (setcdr s ancestor) ;; store ov as our next symbol
582 (throw 'done ancestor))))))
583
584(defun eieio--generic-form (method key class)
585 "Return the lambda form belonging to METHOD using KEY based upon CLASS.
586If CLASS is not a class then use `generic' instead. If class has
587no form, but has a parent class, then trace to that parent class.
588The first time a form is requested from a symbol, an optimized path
589is memorized for faster future use."
590 (if (symbolp class) (setq class (eieio--class-v class)))
591 (let ((emto (aref (get method 'eieio-method-hashtable)
592 (if class key (eieio--specialized-key-to-generic-key key)))))
593 (if (eieio--class-p class)
594 ;; 1) find our symbol
595 (let ((cs (gethash class emto)))
596 (unless cs
597 ;; 2) If there isn't one, then make one.
598 ;; This can be slow since it only occurs once
599 (puthash class (setq cs (list nil)) emto)
600 ;; 2.1) Cache its nearest neighbor with a quick optimize
601 ;; which should only occur once for this call ever
602 (let ((eieio--mt--optimizing-hashtable emto))
603 (eieio--mt--sym-optimize class cs)))
604 ;; 3) If it's bound return this one.
605 (if (car cs)
606 (cons (car cs) class)
607 ;; 4) If it's not bound then this variable knows something
608 (if (cdr cs)
609 (progn
610 ;; 4.1) This symbol holds the next class in its value
611 (setq class (cdr cs)
612 cs (gethash class emto))
613 ;; 4.2) The optimizer should always have chosen a
614 ;; function-symbol
615 ;;(if (car cs)
616 (cons (car cs) class)
617 ;;(error "EIEIO optimizer: erratic data loss!"))
618 )
619 ;; There never will be a funcall...
620 nil)))
621 ;; for a generic call, what is a list, is the function body we want.
622 (let ((emtl (aref (get method 'eieio-method-tree)
623 (if class key (eieio--specialized-key-to-generic-key key)))))
624 (if emtl
625 ;; The car of EMTL is supposed to be a class, which in this
626 ;; case is nil, so skip it.
627 (cons (cdr (car emtl)) nil)
628 nil)))))
629
630
631(define-error 'no-method-definition "No method definition")
632(define-error 'no-next-method "No next method")
633
634;;; CLOS methods and generics
635;;
636(defmacro defgeneric (method args &optional doc-string)
637 "Create a generic function METHOD.
638DOC-STRING is the base documentation for this class. A generic
639function has no body, as its purpose is to decide which method body
640is appropriate to use. Uses `defmethod' to create methods, and calls
641`defgeneric' for you. With this implementation the ARGS are
642currently ignored. You can use `defgeneric' to apply specialized
643top level documentation to a method."
644 (declare (doc-string 3))
645 `(eieio--defalias ',method
646 (eieio--defgeneric-init-form
647 ',method
648 ,(if doc-string (help-add-fundoc-usage doc-string args)))))
649
650(defmacro defmethod (method &rest args)
651 "Create a new METHOD through `defgeneric' with ARGS.
652
653The optional second argument KEY is a specifier that
654modifies how the method is called, including:
655 :before - Method will be called before the :primary
656 :primary - The default if not specified
657 :after - Method will be called after the :primary
658 :static - First arg could be an object or class
659The next argument is the ARGLIST. The ARGLIST specifies the arguments
660to the method as with `defun'. The first argument can have a type
661specifier, such as:
662 ((VARNAME CLASS) ARG2 ...)
663where VARNAME is the name of the local variable for the method being
664created. The CLASS is a class symbol for a class made with `defclass'.
665A DOCSTRING comes after the ARGLIST, and is optional.
666All the rest of the args are the BODY of the method. A method will
667return the value of the last form in the BODY.
668
669Summary:
670
671 (defmethod mymethod [:before | :primary | :after | :static]
672 ((typearg class-name) arg2 &optional opt &rest rest)
673 \"doc-string\"
674 body)"
675 (declare (doc-string 3)
676 (debug
677 (&define ; this means we are defining something
678 [&or name ("setf" :name setf name)]
679 ;; ^^ This is the methods symbol
680 [ &optional symbolp ] ; this is key :before etc
681 list ; arguments
682 [ &optional stringp ] ; documentation string
683 def-body ; part to be debugged
684 )))
685 (let* ((key (if (keywordp (car args)) (pop args)))
686 (params (car args))
687 (arg1 (car params))
688 (fargs (if (consp arg1)
689 (cons (car arg1) (cdr params))
690 params))
691 (class (if (consp arg1) (nth 1 arg1)))
692 (code `(lambda ,fargs ,@(cdr args))))
693 `(progn
694 ;; Make sure there is a generic and the byte-compiler sees it.
695 (defgeneric ,method ,args)
696 (eieio--defmethod ',method ',key ',class #',code))))
697
698
699
700;;;
701;; Method Calling Functions
702
703(defun next-method-p ()
704 "Return non-nil if there is a next method.
705Returns a list of lambda expressions which is the `next-method'
706order."
707 eieio--generic-call-next-method-list)
708
709(defun call-next-method (&rest replacement-args)
710 "Call the superclass method from a subclass method.
711The superclass method is specified in the current method list,
712and is called the next method.
713
714If REPLACEMENT-ARGS is non-nil, then use them instead of
715`eieio--generic-call-arglst'. The generic arg list are the
716arguments passed in at the top level.
717
718Use `next-method-p' to find out if there is a next method to call."
719 (if (and (/= eieio--generic-call-key eieio--method-primary)
720 (/= eieio--generic-call-key eieio--method-static))
721 (error "Cannot `call-next-method' except in :primary or :static methods")
722 )
723 (let ((newargs (or replacement-args eieio--generic-call-arglst))
724 (next (car eieio--generic-call-next-method-list))
725 )
726 (if (not (and next (car next)))
727 (apply #'no-next-method newargs)
728 (let* ((eieio--generic-call-next-method-list
729 (cdr eieio--generic-call-next-method-list))
730 (eieio--generic-call-arglst newargs)
731 (fcn (car next))
732 )
733 (apply fcn newargs)) )))
734
735(defgeneric no-applicable-method (object method &rest args)
736 "Called if there are no implementations for OBJECT in METHOD.")
737
738(defmethod no-applicable-method (object method &rest _args)
739 "Called if there are no implementations for OBJECT in METHOD.
740OBJECT is the object which has no method implementation.
741ARGS are the arguments that were passed to METHOD.
742
743Implement this for a class to block this signal. The return
744value becomes the return value of the original method call."
745 (signal 'no-method-definition (list method object)))
746
747(defgeneric no-next-method (object &rest args)
748"Called from `call-next-method' when no additional methods are available.")
749
750(defmethod no-next-method (object &rest args)
751 "Called from `call-next-method' when no additional methods are available.
752OBJECT is othe object being called on `call-next-method'.
753ARGS are the arguments it is called by.
754This method signals `no-next-method' by default. Override this
755method to not throw an error, and its return value becomes the
756return value of `call-next-method'."
757 (signal 'no-next-method (list object args)))
758
759(add-hook 'help-fns-describe-function-functions 'eieio--help-generic)
760(defun eieio--help-generic (generic)
761 "Describe GENERIC if it is a generic function."
762 (when (and (symbolp generic) (generic-p generic))
763 (save-excursion
764 (goto-char (point-min))
765 (when (re-search-forward " in `.+'.$" nil t)
766 (replace-match ".")))
767 (save-excursion
768 (insert "\n\nThis is a generic function"
769 (cond
770 ((and (eieio--generic-primary-only-p generic)
771 (eieio--generic-primary-only-one-p generic))
772 " with only one primary method")
773 ((eieio--generic-primary-only-p generic)
774 " with only primary methods")
775 (t ""))
776 ".\n\n")
777 (insert (propertize "Implementations:\n\n" 'face 'bold))
778 (let ((i 4)
779 (prefix [ ":STATIC" ":BEFORE" ":PRIMARY" ":AFTER" ] ))
780 ;; Loop over fanciful generics
781 (while (< i 7)
782 (let ((gm (aref (get generic 'eieio-method-tree) i)))
783 (when gm
784 (insert "Generic "
785 (aref prefix (- i 3))
786 "\n"
787 (or (nth 2 gm) "Undocumented")
788 "\n\n")))
789 (setq i (1+ i)))
790 (setq i 0)
791 ;; Loop over defined class-specific methods
792 (while (< i 4)
793 (let* ((gm (reverse (aref (get generic 'eieio-method-tree) i)))
794 cname location)
795 (while gm
796 (setq cname (caar gm))
797 (insert "`")
798 (help-insert-xref-button (symbol-name cname)
799 'help-variable cname)
800 (insert "' " (aref prefix i) " ")
801 ;; argument list
802 (let* ((func (cdr (car gm)))
803 (arglst (help-function-arglist func)))
804 (prin1 arglst (current-buffer)))
805 (insert "\n"
806 (or (documentation (cdr (car gm)))
807 "Undocumented"))
808 ;; Print file location if available
809 (when (and (setq location (get generic 'method-locations))
810 (setq location (assoc cname location)))
811 (setq location (cadr location))
812 (insert "\n\nDefined in `")
813 (help-insert-xref-button
814 (file-name-nondirectory location)
815 'eieio-method-def cname generic location)
816 (insert "'\n"))
817 (setq gm (cdr gm))
818 (insert "\n")))
819 (setq i (1+ i)))))))
820
821;;; Obsolete backward compatibility functions.
822;; Needed to run byte-code compiled with the EIEIO of Emacs-23.
823
824(defun eieio-defmethod (method args)
825 "Obsolete work part of an old version of the `defmethod' macro."
826 (let ((key nil) (body nil) (firstarg nil) (argfix nil) (argclass nil) loopa)
827 ;; find optional keys
828 (setq key
829 (cond ((memq (car args) '(:BEFORE :before))
830 (setq args (cdr args))
831 eieio--method-before)
832 ((memq (car args) '(:AFTER :after))
833 (setq args (cdr args))
834 eieio--method-after)
835 ((memq (car args) '(:STATIC :static))
836 (setq args (cdr args))
837 eieio--method-static)
838 ((memq (car args) '(:PRIMARY :primary))
839 (setq args (cdr args))
840 eieio--method-primary)
841 ;; Primary key.
842 (t eieio--method-primary)))
843 ;; Get body, and fix contents of args to be the arguments of the fn.
844 (setq body (cdr args)
845 args (car args))
846 (setq loopa args)
847 ;; Create a fixed version of the arguments.
848 (while loopa
849 (setq argfix (cons (if (listp (car loopa)) (car (car loopa)) (car loopa))
850 argfix))
851 (setq loopa (cdr loopa)))
852 ;; Make sure there is a generic.
853 (eieio-defgeneric
854 method
855 (if (stringp (car body))
856 (car body) (format "Generically created method `%s'." method)))
857 ;; create symbol for property to bind to. If the first arg is of
858 ;; the form (varname vartype) and `vartype' is a class, then
859 ;; that class will be the type symbol. If not, then it will fall
860 ;; under the type `primary' which is a non-specific calling of the
861 ;; function.
862 (setq firstarg (car args))
863 (if (listp firstarg)
864 (progn
865 (setq argclass (nth 1 firstarg))
866 (if (not (class-p argclass))
867 (error "Unknown class type %s in method parameters"
868 (nth 1 firstarg))))
869 ;; Generics are higher.
870 (setq key (eieio--specialized-key-to-generic-key key)))
871 ;; Put this lambda into the symbol so we can find it.
872 (if (byte-code-function-p (car-safe body))
873 (eieio--mt-add method (car-safe body) key argclass)
874 (eieio--mt-add method (append (list 'lambda (reverse argfix)) body)
875 key argclass))
876 )
877
878 (eieio--method-optimize-primary method)
879
880 method)
881(make-obsolete 'eieio-defmethod 'eieio--defmethod "24.1")
882
883(defun eieio-defgeneric (method doc-string)
884 "Obsolete work part of an old version of the `defgeneric' macro."
885 (if (and (fboundp method) (not (generic-p method))
886 (or (byte-code-function-p (symbol-function method))
887 (not (eq 'autoload (car (symbol-function method)))))
888 )
889 (error "You cannot create a generic/method over an existing symbol: %s"
890 method))
891 ;; Don't do this over and over.
892 (unless (fboundp 'method)
893 ;; This defun tells emacs where the first definition of this
894 ;; method is defined.
895 `(defun ,method nil)
896 ;; Make sure the method tables are installed.
897 (eieio--mt-install method)
898 ;; Apply the actual body of this function.
899 (put method 'function-documentation doc-string)
900 (fset method (eieio--defgeneric-form method))
901 ;; Return the method
902 'method))
903(make-obsolete 'eieio-defgeneric nil "24.1")
904
905(provide 'eieio-generic)
906
907;;; eieio-generic.el ends here
diff --git a/lisp/emacs-lisp/eieio.el b/lisp/emacs-lisp/eieio.el
index 0c85d90151a..b64eba1de1f 100644
--- a/lisp/emacs-lisp/eieio.el
+++ b/lisp/emacs-lisp/eieio.el
@@ -53,7 +53,6 @@
53 (message eieio-version)) 53 (message eieio-version))
54 54
55(require 'eieio-core) 55(require 'eieio-core)
56(require 'eieio-generic)
57 56
58 57
59;;; Defining a new class 58;;; Defining a new class
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 0c74f3fedc0..d527d676d51 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -336,7 +336,12 @@ the variables `eldoc-argument-case' and `eldoc-echo-area-use-multiline-p',
336and the face `eldoc-highlight-function-argument', if they are to have any 336and the face `eldoc-highlight-function-argument', if they are to have any
337effect. 337effect.
338 338
339This variable is expected to be set buffer-locally by modes that support ElDoc.") 339Major modes should modify this variable using `add-function', for example:
340 (add-function :before-until (local 'eldoc-documentation-function)
341 #'foo-mode-eldoc-function)
342so that the global documentation function (i.e. the default value of the
343variable) is taken into account if the major mode specific function does not
344return any documentation.")
340 345
341(defun eldoc-print-current-symbol-info () 346(defun eldoc-print-current-symbol-info ()
342 ;; This is run from post-command-hook or some idle timer thing, 347 ;; This is run from post-command-hook or some idle timer thing,
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index ecebdeb5a75..797de9abb5b 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -168,6 +168,26 @@ and also to avoid outputting the warning during normal execution."
168 form)))))))) 168 form))))))))
169 (t form))) 169 (t form)))
170 170
171(defun macroexp-macroexpand (form env)
172 "Like `macroexpand' but checking obsolescence."
173 (let ((new-form
174 (macroexpand form env)))
175 (if (and (not (eq form new-form)) ;It was a macro call.
176 (car-safe form)
177 (symbolp (car form))
178 (get (car form) 'byte-obsolete-info)
179 (or (not (fboundp 'byte-compile-warning-enabled-p))
180 (byte-compile-warning-enabled-p 'obsolete)))
181 (let* ((fun (car form))
182 (obsolete (get fun 'byte-obsolete-info)))
183 (macroexp--warn-and-return
184 (macroexp--obsolete-warning
185 fun obsolete
186 (if (symbolp (symbol-function fun))
187 "alias" "macro"))
188 new-form))
189 new-form)))
190
171(defun macroexp--expand-all (form) 191(defun macroexp--expand-all (form)
172 "Expand all macros in FORM. 192 "Expand all macros in FORM.
173This is an internal version of `macroexpand-all'. 193This is an internal version of `macroexpand-all'.
@@ -180,24 +200,7 @@ Assumes the caller has bound `macroexpand-all-environment'."
180 (macroexpand (macroexp--all-forms form 1) 200 (macroexpand (macroexp--all-forms form 1)
181 macroexpand-all-environment) 201 macroexpand-all-environment)
182 ;; Normal form; get its expansion, and then expand arguments. 202 ;; Normal form; get its expansion, and then expand arguments.
183 (let ((new-form 203 (setq form (macroexp-macroexpand form macroexpand-all-environment))
184 (macroexpand form macroexpand-all-environment)))
185 (setq form
186 (if (and (not (eq form new-form)) ;It was a macro call.
187 (car-safe form)
188 (symbolp (car form))
189 (get (car form) 'byte-obsolete-info)
190 (or (not (fboundp 'byte-compile-warning-enabled-p))
191 (byte-compile-warning-enabled-p 'obsolete)))
192 (let* ((fun (car form))
193 (obsolete (get fun 'byte-obsolete-info)))
194 (macroexp--warn-and-return
195 (macroexp--obsolete-warning
196 fun obsolete
197 (if (symbolp (symbol-function fun))
198 "alias" "macro"))
199 new-form))
200 new-form)))
201 (pcase form 204 (pcase form
202 (`(cond . ,clauses) 205 (`(cond . ,clauses)
203 (macroexp--cons 'cond (macroexp--all-clauses clauses) form)) 206 (macroexp--cons 'cond (macroexp--all-clauses clauses) form))
diff --git a/lisp/hexl.el b/lisp/hexl.el
index 3751bcf4bb3..27d46592698 100644
--- a/lisp/hexl.el
+++ b/lisp/hexl.el
@@ -395,8 +395,8 @@ You can use \\[hexl-find-file] to visit a file in Hexl mode.
395 (add-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer nil t) 395 (add-hook 'change-major-mode-hook 'hexl-maybe-dehexlify-buffer nil t)
396 396
397 ;; Set a callback function for eldoc. 397 ;; Set a callback function for eldoc.
398 (hexl-mode--setq-local 'eldoc-documentation-function 398 (add-function :before-until (local 'eldoc-documentation-function)
399 #'hexl-print-current-point-info) 399 #'hexl-print-current-point-info)
400 (eldoc-add-command-completions "hexl-") 400 (eldoc-add-command-completions "hexl-")
401 (eldoc-remove-command "hexl-save-buffer" 401 (eldoc-remove-command "hexl-save-buffer"
402 "hexl-current-address") 402 "hexl-current-address")
diff --git a/lisp/ielm.el b/lisp/ielm.el
index d7bf60fe074..be877eb250a 100644
--- a/lisp/ielm.el
+++ b/lisp/ielm.el
@@ -380,7 +380,7 @@ nonempty, then flushes the buffer."
380 (*3 ***) 380 (*3 ***)
381 (active-process (ielm-process)) 381 (active-process (ielm-process))
382 (old-standard-output standard-output) 382 (old-standard-output standard-output)
383 new-standard-output 383 new-standard-output
384 ielm-temp-buffer) 384 ielm-temp-buffer)
385 (set-match-data ielm-match-data) 385 (set-match-data ielm-match-data)
386 (save-excursion 386 (save-excursion
@@ -542,8 +542,8 @@ Customized bindings may be defined in `ielm-map', which currently contains:
542 (set (make-local-variable 'completion-at-point-functions) 542 (set (make-local-variable 'completion-at-point-functions)
543 '(comint-replace-by-expanded-history 543 '(comint-replace-by-expanded-history
544 ielm-complete-filename elisp-completion-at-point)) 544 ielm-complete-filename elisp-completion-at-point))
545 (setq-local eldoc-documentation-function 545 (add-function :before-until (local 'eldoc-documentation-function)
546 #'elisp-eldoc-documentation-function) 546 #'elisp-eldoc-documentation-function)
547 (set (make-local-variable 'ielm-prompt-internal) ielm-prompt) 547 (set (make-local-variable 'ielm-prompt-internal) ielm-prompt)
548 (set (make-local-variable 'comint-prompt-read-only) ielm-prompt-read-only) 548 (set (make-local-variable 'comint-prompt-read-only) ielm-prompt-read-only)
549 (setq comint-get-old-input 'ielm-get-old-input) 549 (setq comint-get-old-input 'ielm-get-old-input)
diff --git a/lisp/progmodes/cfengine.el b/lisp/progmodes/cfengine.el
index b485a5d269b..aec7d208022 100644
--- a/lisp/progmodes/cfengine.el
+++ b/lisp/progmodes/cfengine.el
@@ -1350,7 +1350,8 @@ to the action header."
1350 (when buffer-file-name 1350 (when buffer-file-name
1351 (shell-quote-argument buffer-file-name))))) 1351 (shell-quote-argument buffer-file-name)))))
1352 1352
1353 (setq-local eldoc-documentation-function #'cfengine3-documentation-function) 1353 (add-function :before-until (local 'eldoc-documentation-function)
1354 #'cfengine3-documentation-function)
1354 1355
1355 (add-hook 'completion-at-point-functions 1356 (add-hook 'completion-at-point-functions
1356 #'cfengine3-completion-function nil t) 1357 #'cfengine3-completion-function nil t)
diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el
index 4de40eff538..b2c5fbfe60e 100644
--- a/lisp/progmodes/elisp-mode.el
+++ b/lisp/progmodes/elisp-mode.el
@@ -231,8 +231,8 @@ Blank lines separate paragraphs. Semicolons start comments.
231 (defvar xref-identifier-completion-table-function) 231 (defvar xref-identifier-completion-table-function)
232 (lisp-mode-variables nil nil 'elisp) 232 (lisp-mode-variables nil nil 'elisp)
233 (setq imenu-case-fold-search nil) 233 (setq imenu-case-fold-search nil)
234 (setq-local eldoc-documentation-function 234 (add-function :before-until (local 'eldoc-documentation-function)
235 #'elisp-eldoc-documentation-function) 235 #'elisp-eldoc-documentation-function)
236 (setq-local xref-find-function #'elisp-xref-find) 236 (setq-local xref-find-function #'elisp-xref-find)
237 (setq-local xref-identifier-completion-table-function 237 (setq-local xref-identifier-completion-table-function
238 #'elisp--xref-identifier-completion-table) 238 #'elisp--xref-identifier-completion-table)
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index 47b305fb081..dc3380d02f6 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -2100,17 +2100,35 @@ for \\[find-tag] (which see)."
2100 (< (hash-table-count marks) etags--xref-limit)) 2100 (< (hash-table-count marks) etags--xref-limit))
2101 (when (funcall order-fun pattern) 2101 (when (funcall order-fun pattern)
2102 (beginning-of-line) 2102 (beginning-of-line)
2103 (cl-destructuring-bind (hint line &rest pos) (etags-snarf-tag) 2103 (pcase-let* ((tag-info (etags-snarf-tag))
2104 (`(,hint ,line . _) tag-info))
2104 (unless (eq hint t) ; hint==t if we are in a filename line 2105 (unless (eq hint t) ; hint==t if we are in a filename line
2105 (let* ((file (file-of-tag)) 2106 (let* ((file (file-of-tag))
2106 (mark-key (cons file line))) 2107 (mark-key (cons file line)))
2107 (unless (gethash mark-key marks) 2108 (unless (gethash mark-key marks)
2108 (let ((loc (xref-make-file-location 2109 (let ((loc (xref-make-etags-location
2109 (expand-file-name file) line 0))) 2110 tag-info (expand-file-name file))))
2110 (push (xref-make hint loc) xrefs) 2111 (push (xref-make hint loc) xrefs)
2111 (puthash mark-key t marks))))))))))) 2112 (puthash mark-key t marks)))))))))))
2112 (nreverse xrefs))) 2113 (nreverse xrefs)))
2113 2114
2115(defclass xref-etags-location (xref-location)
2116 ((tag-info :type list :initarg :tag-info)
2117 (file :type string :initarg :file
2118 :reader xref-location-group))
2119 :documentation "Location of an etags tag.")
2120
2121(defun xref-make-etags-location (tag-info file)
2122 (make-instance 'xref-etags-location :tag-info tag-info
2123 :file (expand-file-name file)))
2124
2125(defmethod xref-location-marker ((l xref-etags-location))
2126 (with-slots (tag-info file) l
2127 (let ((buffer (find-file-noselect file)))
2128 (with-current-buffer buffer
2129 (etags-goto-tag-location tag-info)
2130 (point-marker)))))
2131
2114 2132
2115(provide 'etags) 2133(provide 'etags)
2116 2134
diff --git a/lisp/progmodes/octave.el b/lisp/progmodes/octave.el
index cbdaae6fa71..8541cced3a5 100644
--- a/lisp/progmodes/octave.el
+++ b/lisp/progmodes/octave.el
@@ -601,7 +601,8 @@ Key bindings:
601 (add-hook 'before-save-hook 'octave-sync-function-file-names nil t) 601 (add-hook 'before-save-hook 'octave-sync-function-file-names nil t)
602 (setq-local beginning-of-defun-function 'octave-beginning-of-defun) 602 (setq-local beginning-of-defun-function 'octave-beginning-of-defun)
603 (and octave-font-lock-texinfo-comment (octave-font-lock-texinfo-comment)) 603 (and octave-font-lock-texinfo-comment (octave-font-lock-texinfo-comment))
604 (setq-local eldoc-documentation-function 'octave-eldoc-function) 604 (add-function :before-until (local 'eldoc-documentation-function)
605 'octave-eldoc-function)
605 606
606 (easy-menu-add octave-mode-menu)) 607 (easy-menu-add octave-mode-menu))
607 608
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index 1e8623dd901..d298f96bc81 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -4662,8 +4662,8 @@ Arguments START and END narrow the buffer region to work on."
4662 (current-column)))) 4662 (current-column))))
4663 (^ '(- (1+ (current-indentation)))))) 4663 (^ '(- (1+ (current-indentation))))))
4664 4664
4665 (set (make-local-variable 'eldoc-documentation-function) 4665 (add-function :before-until (local 'eldoc-documentation-function)
4666 #'python-eldoc-function) 4666 #'python-eldoc-function)
4667 4667
4668 (add-to-list 'hs-special-modes-alist 4668 (add-to-list 'hs-special-modes-alist
4669 `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#" 4669 `(python-mode "^\\s-*\\(?:def\\|class\\)\\>" nil "#"
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 12123c8f2e2..92144cf8049 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -34,7 +34,9 @@
34;; 34;;
35;; One would usually call `make-xref' and `xref-make-file-location', 35;; One would usually call `make-xref' and `xref-make-file-location',
36;; `xref-make-buffer-location' or `xref-make-bogus-location' to create 36;; `xref-make-buffer-location' or `xref-make-bogus-location' to create
37;; them. 37;; them. More generally, a location must be an instance of an EIEIO
38;; class inheriting from `xref-location' and implementing
39;; `xref-location-group' and `xref-location-marker'.
38;; 40;;
39;; Each identifier must be represented as a string. Implementers can 41;; Each identifier must be represented as a string. Implementers can
40;; use string properties to store additional information about the 42;; use string properties to store additional information about the
@@ -456,7 +458,7 @@ GROUP is a string for decoration purposes and XREF is an
456 'face 'font-lock-keyword-face 458 'face 'font-lock-keyword-face
457 'mouse-face 'highlight 459 'mouse-face 'highlight
458 'keymap xref--button-map 460 'keymap xref--button-map
459 'help-echo "mouse-2: display, RET or mouse-1: navigate") 461 'help-echo "mouse-2: display in another window, RET or mouse-1: navigate")
460 description)) 462 description))
461 (when (or more1 more2) 463 (when (or more1 more2)
462 (insert "\n"))))) 464 (insert "\n")))))
diff --git a/lisp/simple.el b/lisp/simple.el
index 25293edf88f..967fbc69cbc 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -1407,8 +1407,8 @@ display the result of expression evaluation."
1407 (minibuffer-with-setup-hook 1407 (minibuffer-with-setup-hook
1408 (lambda () 1408 (lambda ()
1409 ;; FIXME: call emacs-lisp-mode? 1409 ;; FIXME: call emacs-lisp-mode?
1410 (setq-local eldoc-documentation-function 1410 (add-function :before-until (local 'eldoc-documentation-function)
1411 #'elisp-eldoc-documentation-function) 1411 #'elisp-eldoc-documentation-function)
1412 (add-hook 'completion-at-point-functions 1412 (add-hook 'completion-at-point-functions
1413 #'elisp-completion-at-point nil t) 1413 #'elisp-completion-at-point nil t)
1414 (run-hooks 'eval-expression-minibuffer-setup-hook)) 1414 (run-hooks 'eval-expression-minibuffer-setup-hook))
diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el
index b18a93cd3e6..8bcc71ed531 100644
--- a/lisp/textmodes/paragraphs.el
+++ b/lisp/textmodes/paragraphs.el
@@ -168,11 +168,11 @@ to obtain the value of this variable."
168 :type '(choice regexp (const :tag "Use default value" nil))) 168 :type '(choice regexp (const :tag "Use default value" nil)))
169(put 'sentence-end 'safe-local-variable 'string-or-null-p) 169(put 'sentence-end 'safe-local-variable 'string-or-null-p)
170 170
171(defcustom sentence-end-base "[.?!][]\"'”)}]*" 171(defcustom sentence-end-base "[.?!…‽][]\"'”)}]*"
172 "Regexp matching the basic end of a sentence, not including following space." 172 "Regexp matching the basic end of a sentence, not including following space."
173 :group 'paragraphs 173 :group 'paragraphs
174 :type 'string 174 :type 'string
175 :version "22.1") 175 :version "25.1")
176(put 'sentence-end-base 'safe-local-variable 'stringp) 176(put 'sentence-end-base 'safe-local-variable 'stringp)
177 177
178(defun sentence-end () 178(defun sentence-end ()
diff --git a/lisp/textmodes/tildify.el b/lisp/textmodes/tildify.el
index 9382b32845d..0eae67ae83a 100644
--- a/lisp/textmodes/tildify.el
+++ b/lisp/textmodes/tildify.el
@@ -4,7 +4,7 @@
4 4
5;; Author: Milan Zamazal <pdm@zamazal.org> 5;; Author: Milan Zamazal <pdm@zamazal.org>
6;; Michal Nazarewicz <mina86@mina86.com> 6;; Michal Nazarewicz <mina86@mina86.com>
7;; Version: 4.5.7 7;; Version: 4.6.1
8;; Keywords: text, TeX, SGML, wp 8;; Keywords: text, TeX, SGML, wp
9 9
10;; This file is part of GNU Emacs. 10;; This file is part of GNU Emacs.
@@ -401,6 +401,109 @@ replacements done and response is one of symbols: t (all right), nil
401 (t t)))))) 401 (t t))))))
402 402
403 403
404;;; *** Tildify Mode ***
405
406(defcustom tildify-space-pattern "[,:;(][ \t]*[a]\\|\\<[AIKOSUVWZikosuvwz]"
407 "Pattern specifying whether to insert a hard space at point.
408
409If the pattern matches `looking-back', a hard space needs to be inserted instead
410of a space at point. The regexp is always case sensitive, regardless of the
411current `case-fold-search' setting."
412 :version "25.1"
413 :group 'tildify
414 :type 'string)
415
416(defcustom tildify-space-predicates '(tildify-space-region-predicate)
417 "A list of predicate functions for `tildify-space' function."
418 :version "25.1"
419 :group 'tildify
420 :type '(repeat 'function))
421
422(defcustom tildify-double-space-undos t
423 "Weather `tildify-space' should undo hard space when space is typed again."
424 :version "25.1"
425 :group 'tildify
426 :type 'boolean)
427
428;;;###autoload
429(defun tildify-space ()
430 "Convert space before point into a hard space if the context is right.
431
432If
433 * character before point is a space character,
434 * character before that has “w” character syntax (i.e. it's a word
435 constituent),
436 * `tildify-space-pattern' matches when `looking-back' (no more than 10
437 characters) from before the space character, and
438 * all predicates in `tildify-space-predicates' return non-nil,
439replace the space character with value of `tildify-space-string' and
440return t.
441
442Otherwise, if
443 * `tildify-double-space-undos' variable is non-nil,
444 * character before point is a space character, and
445 * text before that is a hard space as defined by
446 `tildify-space-string' variable,
447remove the hard space and leave only the space character.
448
449This function is meant to be used as a `post-self-insert-hook'."
450 (interactive)
451 (let* ((p (point)) (p-1 (1- p)) (n (- p (point-min)))
452 (l (length tildify-space-string)) (l+1 (1+ l))
453 case-fold-search)
454 (when (and (> n 2) (eq (preceding-char) ?\s))
455 (cond
456 ((and (eq (char-syntax (char-before p-1)) ?w)
457 (save-excursion
458 (goto-char p-1)
459 (looking-back tildify-space-pattern (max (point-min) (- p 10))))
460 (run-hook-with-args-until-failure 'tildify-space-predicates))
461 (delete-char -1)
462 (insert tildify-space-string)
463 t)
464 ((and tildify-double-space-undos
465 (> n l+1)
466 (string-equal tildify-space-string
467 (buffer-substring (- p l+1) p-1)))
468 (goto-char p-1)
469 (delete-char (- l))
470 (goto-char (1+ (point)))
471 nil)))))
472
473(defun tildify-space-region-predicate ()
474 "Check whether character before point should be tildified.
475Based on `tildify-foreach-region-function', check whether character before,
476which is assumed to be a space character, should be replaced with a hard space."
477 (catch 'found
478 (tildify--foreach-region (lambda (_b _e) (throw 'found t)) (1- (point)) (point))))
479
480;;;###autoload
481(define-minor-mode tildify-mode
482 "Adds electric behaviour to space character.
483
484When space is inserted into a buffer in a position where hard space is required
485instead (determined by `tildify-space-pattern' and `tildify-space-predicates'),
486that space character is replaced by a hard space specified by
487`tildify-space-string'. Converting of the space is done by `tildify-space'.
488
489When `tildify-mode' is enabled, if `tildify-string-alist' specifies a hard space
490representation for current major mode, the `tildify-space-string' buffer-local
491variable will be set to the representation."
492 nil " ~" nil
493 (when tildify-mode
494 (let ((space (tildify--pick-alist-entry tildify-string-alist)))
495 (if (not (string-equal " " (or space tildify-space-string)))
496 (when space
497 (setq tildify-space-string space))
498 (message (eval-when-compile
499 (concat "Hard space is a single space character, tildify-"
500 "mode won't have any effect, disabling.")))
501 (setq tildify-mode nil))))
502 (if tildify-mode
503 (add-hook 'post-self-insert-hook 'tildify-space nil t)
504 (remove-hook 'post-self-insert-hook 'tildify-space t)))
505
506
404;;; *** Announce *** 507;;; *** Announce ***
405 508
406(provide 'tildify) 509(provide 'tildify)
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 8bba79c111f..e050c947504 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -1241,7 +1241,7 @@ These are the commands available for use in the file status buffer:
1241 ;; Otherwise if you do C-x v d -> C-x C-f -> C-c v d 1241 ;; Otherwise if you do C-x v d -> C-x C-f -> C-c v d
1242 ;; you may get a new *vc-dir* buffer, different from the original 1242 ;; you may get a new *vc-dir* buffer, different from the original
1243 (file-truename (read-directory-name "VC status for directory: " 1243 (file-truename (read-directory-name "VC status for directory: "
1244 default-directory default-directory t 1244 (vc-root-dir) nil t
1245 nil)) 1245 nil))
1246 (if current-prefix-arg 1246 (if current-prefix-arg
1247 (intern 1247 (intern
diff --git a/src/ChangeLog b/src/ChangeLog
index f6a5f3837a3..e5e4fe9edb0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,57 @@
12015-01-20 Paul Eggert <eggert@cs.ucla.edu>
2
3 Undo port to hypothetical nonzero Qnil case
4 This mostly undoes the previous change in this area. See:
5 http://lists.gnu.org/archive/html/emacs-devel/2015-01/msg00570.html
6 * alloc.c (allocate_pseudovector):
7 * callint.c (Fcall_interactively):
8 * dispnew.c (realloc_glyph_pool):
9 * fringe.c (init_fringe):
10 * lisp.h (memsetnil):
11 * xdisp.c (init_iterator):
12 Simplify by assuming that Qnil is zero, but verify the assumption.
13 * lisp.h (NIL_IS_ZERO): Revert back to this symbol, removing
14 NIL_IS_NONZERO. All uses changed.
15
162015-01-20 Jan Djärv <jan.h.d@swipnet.se>
17
18 * nsterm.m (EV_TRAILER2): Set Vinhibit_quit to Qt (Bug#19531).
19
202015-01-20 Dmitry Antipov <dmantipov@yandex.ru>
21
22 Prefer xlispstrdup to avoid dumb calls to strlen.
23 * nsfont.m (ns_get_family):
24 * nsterm.m (ns_term_init):
25 * w32fns.c (w32_window):
26 * xfns.c (x_window, Fx_select_font): Use xlispstrdup.
27
282015-01-20 Paul Eggert <eggert@cs.ucla.edu>
29
30 Correct an old fix for GTK font selection
31 * gtkutil.c (xg_get_font): Fix off-by-2 typo.
32 Fixes: bug#3228
33
34 Fix minor bugs with printing null bytes
35 * minibuf.c (read_minibuf_noninteractive):
36 * xdisp.c (Ftrace_to_stderr) [GLYPH_DEBUG]:
37 Work even if the Lisp string contains a null byte.
38
39 Port to hypothetical case where Qnil is nonzero
40 * alloc.c (allocate_pseudovector):
41 * callint.c (Fcall_interactively):
42 * coding.c (syms_of_coding):
43 * dispnew.c (realloc_glyph_pool):
44 * fringe.c (init_fringe):
45 * lisp.h (memsetnil):
46 * xdisp.c (init_iterator):
47 Port to the currently-hypothetical case where Qnil is nonzero.
48 * dispnew.c (adjust_glyph_matrix): Remove unnecessary verification,
49 as there are no Lisp_Object values in the data here.
50 * lisp.h (NIL_IS_NONZERO): New symbol, replacing NIL_IS_ZERO.
51 All uses changed. Define only if not already defined, so that one
52 can debug with -DNIL_IS_NONZERO.
53 * xdisp.c (init_iterator): Remove unnecessary initializations to 0.
54
12015-01-19 Eli Zaretskii <eliz@gnu.org> 552015-01-19 Eli Zaretskii <eliz@gnu.org>
2 56
3 * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool): Verify that 57 * dispnew.c (adjust_glyph_matrix, realloc_glyph_pool): Verify that
diff --git a/src/alloc.c b/src/alloc.c
index 2c7b02f1158..bf0456c6862 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3175,9 +3175,9 @@ allocate_pseudovector (int memlen, int lisplen,
3175 eassert (lisplen <= (1 << PSEUDOVECTOR_SIZE_BITS) - 1); 3175 eassert (lisplen <= (1 << PSEUDOVECTOR_SIZE_BITS) - 1);
3176 3176
3177 /* Only the first LISPLEN slots will be traced normally by the GC. 3177 /* Only the first LISPLEN slots will be traced normally by the GC.
3178 But since Qnil == 0, we can memset Lisp_Object slots as well. */ 3178 Since Qnil == 0, we can memset Lisp and non-Lisp data at one go. */
3179 verify (NIL_IS_ZERO); 3179 verify (NIL_IS_ZERO);
3180 memset (v->contents, 0, zerolen * word_size); 3180 memsetnil (v->contents, zerolen);
3181 3181
3182 XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen); 3182 XSETPVECTYPESIZE (v, tag, lisplen, memlen - lisplen);
3183 return v; 3183 return v;
diff --git a/src/coding.c b/src/coding.c
index 77cea77cef5..b95c0a5f825 100644
--- a/src/coding.c
+++ b/src/coding.c
@@ -11272,8 +11272,8 @@ internal character representation. */);
11272 Vtranslation_table_for_input = Qnil; 11272 Vtranslation_table_for_input = Qnil;
11273 11273
11274 { 11274 {
11275 verify (NIL_IS_ZERO); 11275 Lisp_Object args[coding_arg_undecided_max];
11276 Lisp_Object args[coding_arg_undecided_max] = { LISP_INITIALLY_ZERO, }; 11276 memsetnil (args, ARRAYELTS (args));
11277 11277
11278 Lisp_Object plist[16]; 11278 Lisp_Object plist[16];
11279 plist[0] = intern_c_string (":name"); 11279 plist[0] = intern_c_string (":name");
diff --git a/src/dispnew.c b/src/dispnew.c
index abfdde6ef24..3c0f110446b 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -417,12 +417,6 @@ adjust_glyph_matrix (struct window *w, struct glyph_matrix *matrix, int x, int y
417 new_rows = dim.height - matrix->rows_allocated; 417 new_rows = dim.height - matrix->rows_allocated;
418 matrix->rows = xpalloc (matrix->rows, &matrix->rows_allocated, 418 matrix->rows = xpalloc (matrix->rows, &matrix->rows_allocated,
419 new_rows, INT_MAX, sizeof *matrix->rows); 419 new_rows, INT_MAX, sizeof *matrix->rows);
420 /* As a side effect, this sets the object of each glyph in the
421 row to nil, so verify we will indeed get that. Redisplay
422 relies on the object of special glyphs (truncation and
423 continuation glyps and also blanks used to extend each line
424 on a TTY) to be nil. */
425 verify (NIL_IS_ZERO);
426 memset (matrix->rows + old_alloc, 0, 420 memset (matrix->rows + old_alloc, 0,
427 (matrix->rows_allocated - old_alloc) * sizeof *matrix->rows); 421 (matrix->rows_allocated - old_alloc) * sizeof *matrix->rows);
428 } 422 }
@@ -1349,12 +1343,12 @@ realloc_glyph_pool (struct glyph_pool *pool, struct dim matrix_dim)
1349 ptrdiff_t old_nglyphs = pool->nglyphs; 1343 ptrdiff_t old_nglyphs = pool->nglyphs;
1350 pool->glyphs = xpalloc (pool->glyphs, &pool->nglyphs, 1344 pool->glyphs = xpalloc (pool->glyphs, &pool->nglyphs,
1351 needed - old_nglyphs, -1, sizeof *pool->glyphs); 1345 needed - old_nglyphs, -1, sizeof *pool->glyphs);
1352 /* As a side effect, this sets the object of each glyph to nil, 1346
1353 so verify we will indeed get that. Redisplay relies on the 1347 /* Redisplay relies on nil as the object of special glyphs
1354 object of special glyphs (truncation and continuation glyps 1348 (truncation and continuation glyphs and also blanks used to
1355 and also blanks used to extend each line on a TTY) to be 1349 extend each line on a TTY), so verify that memset does this. */
1356 nil. */
1357 verify (NIL_IS_ZERO); 1350 verify (NIL_IS_ZERO);
1351
1358 memset (pool->glyphs + old_nglyphs, 0, 1352 memset (pool->glyphs + old_nglyphs, 0,
1359 (pool->nglyphs - old_nglyphs) * sizeof *pool->glyphs); 1353 (pool->nglyphs - old_nglyphs) * sizeof *pool->glyphs);
1360 } 1354 }
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 694278a2b4c..da05742b0c6 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -2093,7 +2093,7 @@ xg_get_font (struct frame *f, const char *default_name)
2093 args[8] = QCtype; 2093 args[8] = QCtype;
2094 args[9] = Qxft; 2094 args[9] = Qxft;
2095 2095
2096 font = Ffont_spec (8, args); 2096 font = Ffont_spec (10, args);
2097 2097
2098 pango_font_description_free (desc); 2098 pango_font_description_free (desc);
2099 dupstring (&x_last_font_name, name); 2099 dupstring (&x_last_font_name, name);
diff --git a/src/lisp.h b/src/lisp.h
index 65e6c626527..f1e6945f43a 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1513,13 +1513,13 @@ gc_aset (Lisp_Object array, ptrdiff_t idx, Lisp_Object val)
1513 to find such assumptions later if we change Qnil to be nonzero. */ 1513 to find such assumptions later if we change Qnil to be nonzero. */
1514enum { NIL_IS_ZERO = XLI_BUILTIN_LISPSYM (iQnil) == 0 }; 1514enum { NIL_IS_ZERO = XLI_BUILTIN_LISPSYM (iQnil) == 0 };
1515 1515
1516/* Set a Lisp_Object array V's SIZE entries to nil. */ 1516/* Set a Lisp_Object array V's N entries to nil. */
1517INLINE void 1517INLINE void
1518memsetnil (Lisp_Object *v, ptrdiff_t size) 1518memsetnil (Lisp_Object *v, ptrdiff_t n)
1519{ 1519{
1520 eassert (0 <= size); 1520 eassert (0 <= n);
1521 verify (NIL_IS_ZERO); 1521 verify (NIL_IS_ZERO);
1522 memset (v, 0, size * sizeof *v); 1522 memset (v, 0, n * sizeof *v);
1523} 1523}
1524 1524
1525/* If a struct is made to look like a vector, this macro returns the length 1525/* If a struct is made to look like a vector, this macro returns the length
diff --git a/src/minibuf.c b/src/minibuf.c
index 07f489258e1..0d6e2c79813 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -217,7 +217,7 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial,
217 suppress_echo_on_tty (fileno (stdin)); 217 suppress_echo_on_tty (fileno (stdin));
218 } 218 }
219 219
220 fprintf (stdout, "%s", SDATA (prompt)); 220 fwrite (SDATA (prompt), 1, SBYTES (prompt), stdout);
221 fflush (stdout); 221 fflush (stdout);
222 222
223 val = Qnil; 223 val = Qnil;
diff --git a/src/nsfont.m b/src/nsfont.m
index f5e89d32bfc..683ab178836 100644
--- a/src/nsfont.m
+++ b/src/nsfont.m
@@ -93,7 +93,7 @@ ns_get_family (Lisp_Object font_spec)
93 return nil; 93 return nil;
94 else 94 else
95 { 95 {
96 char *tmp = xstrdup (SSDATA (SYMBOL_NAME (tem))); 96 char *tmp = xlispstrdup (SYMBOL_NAME (tem));
97 NSString *family; 97 NSString *family;
98 ns_unescape_name (tmp); 98 ns_unescape_name (tmp);
99 family = [NSString stringWithUTF8String: tmp]; 99 family = [NSString stringWithUTF8String: tmp];
diff --git a/src/nsterm.m b/src/nsterm.m
index bf3192bf432..ee1268ef850 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -373,8 +373,11 @@ static CGPoint menu_mouse_point;
373 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \ 373 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
374 if (q_event_ptr) \ 374 if (q_event_ptr) \
375 { \ 375 { \
376 Lisp_Object tem = Vinhibit_quit; \
377 Vinhibit_quit = Qt; \
376 n_emacs_events_pending++; \ 378 n_emacs_events_pending++; \
377 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \ 379 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
380 Vinhibit_quit = tem; \
378 } \ 381 } \
379 else \ 382 else \
380 hold_event (emacs_event); \ 383 hold_event (emacs_event); \
@@ -4313,7 +4316,7 @@ ns_term_init (Lisp_Object display_name)
4313 4316
4314 dpyinfo->name_list_element = Fcons (display_name, Qnil); 4317 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4315 4318
4316 terminal->name = xstrdup (SSDATA (display_name)); 4319 terminal->name = xlispstrdup (display_name);
4317 4320
4318 unblock_input (); 4321 unblock_input ();
4319 4322
diff --git a/src/w32fns.c b/src/w32fns.c
index 2dd92ff8a3a..55e58294629 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -4208,7 +4208,7 @@ w32_window (struct frame *f, long window_prompting, int minibuffer_only)
4208 for the window manager, so GC relocation won't bother it. 4208 for the window manager, so GC relocation won't bother it.
4209 4209
4210 Elsewhere we specify the window name for the window manager. */ 4210 Elsewhere we specify the window name for the window manager. */
4211 f->namebuf = xstrdup (SSDATA (Vx_resource_name)); 4211 f->namebuf = xlispstrdup (Vx_resource_name);
4212 4212
4213 my_create_window (f); 4213 my_create_window (f);
4214 4214
diff --git a/src/xdisp.c b/src/xdisp.c
index 208c1243e35..f6795415bcb 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -2753,19 +2753,17 @@ init_iterator (struct it *it, struct window *w,
2753 } 2753 }
2754 2754
2755 /* Clear IT. */ 2755 /* Clear IT. */
2756 /* As a side effect, this sets it->object to nil, so verify we will 2756
2757 indeed get that. */ 2757 /* The code assumes it->object and other Lisp_Object components are
2758 set to nil, so verify that memset does this. */
2758 verify (NIL_IS_ZERO); 2759 verify (NIL_IS_ZERO);
2759 memset (it, 0, sizeof *it); 2760 memset (it, 0, sizeof *it);
2761
2760 it->current.overlay_string_index = -1; 2762 it->current.overlay_string_index = -1;
2761 it->current.dpvec_index = -1; 2763 it->current.dpvec_index = -1;
2762 it->base_face_id = remapped_base_face_id; 2764 it->base_face_id = remapped_base_face_id;
2763 it->string = Qnil;
2764 IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; 2765 IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
2765 it->paragraph_embedding = L2R; 2766 it->paragraph_embedding = L2R;
2766 it->bidi_it.string.lstring = Qnil;
2767 it->bidi_it.string.s = NULL;
2768 it->bidi_it.string.bufpos = 0;
2769 it->bidi_it.w = w; 2767 it->bidi_it.w = w;
2770 2768
2771 /* The window in which we iterate over current_buffer: */ 2769 /* The window in which we iterate over current_buffer: */
@@ -2786,7 +2784,6 @@ init_iterator (struct it *it, struct window *w,
2786 * FRAME_LINE_HEIGHT (it->f)); 2784 * FRAME_LINE_HEIGHT (it->f));
2787 else if (it->f->extra_line_spacing > 0) 2785 else if (it->f->extra_line_spacing > 0)
2788 it->extra_line_spacing = it->f->extra_line_spacing; 2786 it->extra_line_spacing = it->f->extra_line_spacing;
2789 it->max_extra_line_spacing = 0;
2790 } 2787 }
2791 2788
2792 /* If realized faces have been removed, e.g. because of face 2789 /* If realized faces have been removed, e.g. because of face
@@ -2798,10 +2795,6 @@ init_iterator (struct it *it, struct window *w,
2798 if (FRAME_FACE_CACHE (it->f)->used == 0) 2795 if (FRAME_FACE_CACHE (it->f)->used == 0)
2799 recompute_basic_faces (it->f); 2796 recompute_basic_faces (it->f);
2800 2797
2801 /* Current value of the `slice', `space-width', and 'height' properties. */
2802 it->slice.x = it->slice.y = it->slice.width = it->slice.height = Qnil;
2803 it->space_width = Qnil;
2804 it->font_height = Qnil;
2805 it->override_ascent = -1; 2798 it->override_ascent = -1;
2806 2799
2807 /* Are control characters displayed as `^C'? */ 2800 /* Are control characters displayed as `^C'? */
@@ -2839,21 +2832,19 @@ init_iterator (struct it *it, struct window *w,
2839 it->tab_width = SANE_TAB_WIDTH (current_buffer); 2832 it->tab_width = SANE_TAB_WIDTH (current_buffer);
2840 2833
2841 /* Are lines in the display truncated? */ 2834 /* Are lines in the display truncated? */
2842 if (base_face_id != DEFAULT_FACE_ID 2835 if (TRUNCATE != 0)
2843 || it->w->hscroll
2844 || (! WINDOW_FULL_WIDTH_P (it->w)
2845 && ((!NILP (Vtruncate_partial_width_windows)
2846 && !INTEGERP (Vtruncate_partial_width_windows))
2847 || (INTEGERP (Vtruncate_partial_width_windows)
2848 /* PXW: Shall we do something about this? */
2849 && (WINDOW_TOTAL_COLS (it->w)
2850 < XINT (Vtruncate_partial_width_windows))))))
2851 it->line_wrap = TRUNCATE; 2836 it->line_wrap = TRUNCATE;
2852 else if (NILP (BVAR (current_buffer, truncate_lines))) 2837 if (base_face_id == DEFAULT_FACE_ID
2838 && !it->w->hscroll
2839 && (WINDOW_FULL_WIDTH_P (it->w)
2840 || NILP (Vtruncate_partial_width_windows)
2841 || (INTEGERP (Vtruncate_partial_width_windows)
2842 /* PXW: Shall we do something about this? */
2843 && (XINT (Vtruncate_partial_width_windows)
2844 <= WINDOW_TOTAL_COLS (it->w))))
2845 && NILP (BVAR (current_buffer, truncate_lines)))
2853 it->line_wrap = NILP (BVAR (current_buffer, word_wrap)) 2846 it->line_wrap = NILP (BVAR (current_buffer, word_wrap))
2854 ? WINDOW_WRAP : WORD_WRAP; 2847 ? WINDOW_WRAP : WORD_WRAP;
2855 else
2856 it->line_wrap = TRUNCATE;
2857 2848
2858 /* Get dimensions of truncation and continuation glyphs. These are 2849 /* Get dimensions of truncation and continuation glyphs. These are
2859 displayed as fringe bitmaps under X, but we need them for such 2850 displayed as fringe bitmaps under X, but we need them for such
@@ -18905,7 +18896,7 @@ usage: (trace-to-stderr STRING &rest OBJECTS) */)
18905 (ptrdiff_t nargs, Lisp_Object *args) 18896 (ptrdiff_t nargs, Lisp_Object *args)
18906{ 18897{
18907 Lisp_Object s = Fformat (nargs, args); 18898 Lisp_Object s = Fformat (nargs, args);
18908 fprintf (stderr, "%s", SDATA (s)); 18899 fwrite (SDATA (s), 1, SBYTES (s), stderr);
18909 return Qnil; 18900 return Qnil;
18910} 18901}
18911 18902
diff --git a/src/xfns.c b/src/xfns.c
index 936c769a2de..a09e4a6df63 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -2238,7 +2238,7 @@ x_window (struct frame *f, long window_prompting, int minibuffer_only)
2238 for the window manager, so GC relocation won't bother it. 2238 for the window manager, so GC relocation won't bother it.
2239 2239
2240 Elsewhere we specify the window name for the window manager. */ 2240 Elsewhere we specify the window name for the window manager. */
2241 f->namebuf = xstrdup (SSDATA (Vx_resource_name)); 2241 f->namebuf = xlispstrdup (Vx_resource_name);
2242 2242
2243 ac = 0; 2243 ac = 0;
2244 XtSetArg (al[ac], XtNallowShellResize, 1); ac++; 2244 XtSetArg (al[ac], XtNallowShellResize, 1); ac++;
@@ -5995,12 +5995,12 @@ nil, it defaults to the selected frame. */)
5995 XSETFONT (font, FRAME_FONT (f)); 5995 XSETFONT (font, FRAME_FONT (f));
5996 font_param = Ffont_get (font, intern (":name")); 5996 font_param = Ffont_get (font, intern (":name"));
5997 if (STRINGP (font_param)) 5997 if (STRINGP (font_param))
5998 default_name = xstrdup (SSDATA (font_param)); 5998 default_name = xlispstrdup (font_param);
5999 else 5999 else
6000 { 6000 {
6001 font_param = Fframe_parameter (frame, Qfont_param); 6001 font_param = Fframe_parameter (frame, Qfont_param);
6002 if (STRINGP (font_param)) 6002 if (STRINGP (font_param))
6003 default_name = xstrdup (SSDATA (font_param)); 6003 default_name = xlispstrdup (font_param);
6004 } 6004 }
6005 6005
6006 font = xg_get_font (f, default_name); 6006 font = xg_get_font (f, default_name);
diff --git a/test/ChangeLog b/test/ChangeLog
index 4b9e7a92621..dcce0bf3c39 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,29 @@
12015-01-20 Jorgen Schaefer <contact@jorgenschaefer.de>
2
3 * automated/package-test.el (package-test-install-prioritized):
4 Removed test due to unreproducable failures.
5
62015-01-20 Michal Nazarewicz <mina86@mina86.com>
7
8 * automated/descr-text-test.el: New file with tests for
9 `describe-char-eldoc--truncate', `describe-char-eldoc--format',
10 and `describe-char-eldoc'.
11
122015-01-20 Michal Nazarewicz <mina86@mina86.com>
13
14 * automated/tildify-tests.el (tildify-space-undo-test--test):
15 A new helper function for testing `tildify-double-space-undos'
16 behaviour in the `tildify-space' function.
17 (tildify-space-undo-test-html, tildify-space-undo-test-html-nbsp)
18 (tildify-space-undo-test-xml, tildify-space-undo-test-tex): New
19 tests for `tildify-doule-space-undos' behaviour.
20
21 * automated/tildify-tests.el (tildify-space-test--test):
22 A new helper function for testing `tildify-space' function.
23 (tildify-space-test-html, tildify-space-test-html-nbsp)
24 (tildify-space-test-xml, tildify-space-test-tex): New tests for
25 `tildify-space' function.
26
12015-01-18 Stefan Monnier <monnier@iro.umontreal.ca> 272015-01-18 Stefan Monnier <monnier@iro.umontreal.ca>
2 28
3 * automated/Makefile.in (EMACS_EXTRAOPT): New var. 29 * automated/Makefile.in (EMACS_EXTRAOPT): New var.
diff --git a/test/automated/descr-text-test.el b/test/automated/descr-text-test.el
new file mode 100644
index 00000000000..81ae727f076
--- /dev/null
+++ b/test/automated/descr-text-test.el
@@ -0,0 +1,94 @@
1;;; descr-text-test.el --- ERT tests for descr-text.el -*- lexical-binding: t -*-
2
3;; Copyright (C) 2014 Free Software Foundation, Inc.
4
5;; Author: Michal Nazarewicz <mina86@mina86.com>
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software: you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation, either version 3 of the License, or
12;; (at your option) any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
21
22;;; Commentary:
23
24;; This package defines regression tests for the descr-text package.
25
26;;; Code:
27
28(require 'ert)
29(require 'descr-text)
30
31
32(ert-deftest descr-text-test-truncate ()
33 "Tests describe-char-eldoc--truncate function."
34 (should (equal ""
35 (describe-char-eldoc--truncate " \t \n" 100)))
36 (should (equal "foo"
37 (describe-char-eldoc--truncate "foo" 1)))
38 (should (equal "foo..."
39 (describe-char-eldoc--truncate "foo wilma fred" 0)))
40 (should (equal "foo..."
41 (describe-char-eldoc--truncate
42 "foo wilma fred" (length "foo wilma"))))
43 (should (equal "foo wilma..."
44 (describe-char-eldoc--truncate
45 "foo wilma fred" (+ 3 (length "foo wilma")))))
46 (should (equal "foo wilma..."
47 (describe-char-eldoc--truncate
48 "foo wilma fred" (1- (length "foo wilma fred")))))
49 (should (equal "foo wilma fred"
50 (describe-char-eldoc--truncate
51 "foo wilma fred" (length "foo wilma fred"))))
52 (should (equal "foo wilma fred"
53 (describe-char-eldoc--truncate
54 " foo\t wilma \nfred\t " (length "foo wilma fred")))))
55
56(ert-deftest descr-text-test-format-desc ()
57 "Tests describe-char-eldoc--format function."
58 (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
59 (describe-char-eldoc--format ?…)))
60 (should (equal "U+2026: Horizontal ellipsis (Punctuation, Other)"
61 (describe-char-eldoc--format ?… 51)))
62 (should (equal "U+2026: Horizontal ellipsis (Po)"
63 (describe-char-eldoc--format ?… 40)))
64 (should (equal "Horizontal ellipsis (Po)"
65 (describe-char-eldoc--format ?… 30)))
66 (should (equal "Horizontal ellipsis"
67 (describe-char-eldoc--format ?… 20)))
68 (should (equal "Horizontal..."
69 (describe-char-eldoc--format ?… 10))))
70
71(ert-deftest descr-text-test-desc ()
72 "Tests describe-char-eldoc function."
73 (with-temp-buffer
74 (insert "a…")
75 (goto-char (point-min))
76 (should (eq ?a (following-char))) ; make sure we are where we think we are
77 ;; Function should return nil for an ASCII character.
78 (should (not (describe-char-eldoc)))
79
80 (goto-char (1+ (point)))
81 (should (eq ?… (following-char)))
82 (let ((eldoc-echo-area-use-multiline-p t))
83 ;; Function should return description of an Unicode character.
84 (should (equal "U+2026: Horizontal ellipsis (Po: Punctuation, Other)"
85 (describe-char-eldoc))))
86
87 (goto-char (point-max))
88 ;; At the end of the buffer, function should return nil and not blow up.
89 (should (not (describe-char-eldoc)))))
90
91
92(provide 'descr-text-test)
93
94;;; descr-text-test.el ends here
diff --git a/test/automated/package-test.el b/test/automated/package-test.el
index c33a1ba0232..27a71c528c6 100644
--- a/test/automated/package-test.el
+++ b/test/automated/package-test.el
@@ -230,23 +230,6 @@ Must called from within a `tar-mode' buffer."
230 (package-refresh-contents) 230 (package-refresh-contents)
231 (package-install 'simple-single))) 231 (package-install 'simple-single)))
232 232
233(ert-deftest package-test-install-prioritized ()
234 "Install a lower version from a higher-prioritized archive."
235 (with-package-test ()
236 (let* ((newer-version (expand-file-name "data/package/newer-versions"
237 package-test-file-dir))
238 (package-archives `(("older" . ,package-test-data-dir)
239 ("newer" . ,newer-version)))
240 (package-archive-priorities '(("newer" . 100))))
241
242 (package-initialize)
243 (package-refresh-contents)
244 (package-install 'simple-single)
245
246 (let ((installed (cadr (assq 'simple-single package-alist))))
247 (should (version-list-= '(1 3)
248 (package-desc-version installed)))))))
249
250(ert-deftest package-test-install-multifile () 233(ert-deftest package-test-install-multifile ()
251 "Check properties of the installed multi-file package." 234 "Check properties of the installed multi-file package."
252 (with-package-test (:basedir "data/package" :install '(multi-file)) 235 (with-package-test (:basedir "data/package" :install '(multi-file))
diff --git a/test/automated/tildify-tests.el b/test/automated/tildify-tests.el
index b1f3de94fc5..b53f58c279e 100644
--- a/test/automated/tildify-tests.el
+++ b/test/automated/tildify-tests.el
@@ -185,6 +185,77 @@ The function must terminate as soon as callback returns nil."
185 (+ (point-min) 10) (+ (point-min) 20)))) ; start at "3" end past "5" 185 (+ (point-min) 10) (+ (point-min) 20)))) ; start at "3" end past "5"
186 186
187 187
188(defun tildify-space-test--test (modes nbsp env-open &optional set-space-string)
189 (with-temp-buffer
190 (dolist (mode modes)
191 (funcall mode)
192 (when set-space-string
193 (setq-local tildify-space-string nbsp))
194 (let ((header (concat "Testing `tildify-space' in "
195 (symbol-name mode) "\n")))
196 ;; Replace space with hard space.
197 (erase-buffer)
198 (insert header "Lorem v ")
199 (should (tildify-space))
200 (should (string-equal (concat header "Lorem v" nbsp) (buffer-string)))
201 ;; Inside and ignore environment, replacing does not happen.
202 (erase-buffer)
203 (insert header env-open "Lorem v ")
204 (should (not (tildify-space)))
205 (should (string-equal (concat header env-open "Lorem v ")
206 (buffer-string)))))))
207
208(ert-deftest tildify-space-test-html ()
209 "Tests auto-tildification in an HTML document"
210 (tildify-space-test--test '(html-mode sgml-mode) " " "<pre>"))
211
212(ert-deftest tildify-space-test-html-nbsp ()
213 "Tests auto-tildification in an HTML document"
214 (tildify-space-test--test '(html-mode sgml-mode) "&nbsp;" "<pre>" t))
215
216(ert-deftest tildify-space-test-xml ()
217 "Tests auto-tildification in an XML document"
218 (tildify-space-test--test '(nxml-mode) " " "<! -- "))
219
220(ert-deftest tildify-space-test-tex ()
221 "Tests tildification in a TeX document"
222 (tildify-space-test--test '(tex-mode latex-mode plain-tex-mode)
223 "~" "\\verb# "))
224
225
226(defun tildify-space-undo-test--test
227 (modes nbsp env-open &optional set-space-string)
228 (with-temp-buffer
229 (dolist (mode modes)
230 (funcall mode)
231 (when set-space-string
232 (setq-local tildify-space-string nbsp))
233 (let ((header (concat "Testing double-space-undos in "
234 (symbol-name mode) "\n")))
235 (erase-buffer)
236 (insert header "Lorem v" nbsp " ")
237 (should (not (tildify-space)))
238 (should (string-equal (concat header "Lorem v ") (buffer-string)))))))
239
240(ert-deftest tildify-space-undo-test-html ()
241 "Tests auto-tildification in an HTML document"
242 (tildify-space-undo-test--test '(html-mode sgml-mode) " " "<pre>"))
243
244(ert-deftest tildify-space-undo-test-html-nbsp ()
245 "Tests auto-tildification in an HTML document"
246 (tildify-space-undo-test--test '(html-mode sgml-mode) "&nbsp;" "<pre>" t))
247
248(ert-deftest tildify-space-undo-test-xml ()
249 "Tests auto-tildification in an XML document"
250 (tildify-space-undo-test--test '(nxml-mode) " " "<! -- "))
251
252(ert-deftest tildify-space-undo-test-tex ()
253 "Tests tildification in a TeX document"
254 (tildify-space-undo-test--test '(tex-mode latex-mode plain-tex-mode)
255 "~" "\\verb# "))
256
257
258
188(provide 'tildify-tests) 259(provide 'tildify-tests)
189 260
190;;; tildify-tests.el ends here 261;;; tildify-tests.el ends here