diff options
| author | Joakim Verona | 2015-01-21 00:26:56 +0100 |
|---|---|---|
| committer | Joakim Verona | 2015-01-21 00:26:56 +0100 |
| commit | 8628a48fec7fcd8bdbbf6ce5808fc574631d1541 (patch) | |
| tree | 3dfc3b71850123e7514ddb149a0ba768618cfddf | |
| parent | ffd9ee1d6412a6e61383930562e6167a458f0d5f (diff) | |
| parent | 0dd19ac82662c5710e73852f438fd55e1d9225b7 (diff) | |
| download | emacs-8628a48fec7fcd8bdbbf6ce5808fc574631d1541.tar.gz emacs-8628a48fec7fcd8bdbbf6ce5808fc574631d1541.zip | |
Merge branch 'master' into xwidget
39 files changed, 983 insertions, 1044 deletions
| @@ -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 |
| 213 | Bury the buffer at the head of `ido-matches', analogous to how C-k | 215 | Bury the buffer at the head of `ido-matches', analogous to how C-k |
| @@ -238,8 +240,12 @@ typing RET. | |||
| 238 | result of the calculation into the current buffer. | 240 | result 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, | ||
| 246 | and can be used as a default value of `eldoc-documentation-function'. It is | ||
| 247 | useful 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 |
| 495 | let-bind the values stored in an alist. | 501 | let-bind the values stored in an alist. |
| 496 | 502 | ||
| 503 | ** `tildify-mode' allows to automatically insert hard spaces as one | ||
| 504 | types the text. Breaking line after a single-character words is | ||
| 505 | forbidden by Czech and Polish typography (and may be discouraged in | ||
| 506 | other languages), so `auto-tildify-mode' makes it easier to create | ||
| 507 | a 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 @@ | |||
| 1 | 2015-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 | |||
| 14 | 2015-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 | |||
| 34 | 2015-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 | |||
| 40 | 2015-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 | |||
| 60 | 2015-01-20 Daniel Colascione <dancol@dancol.org> | ||
| 61 | |||
| 62 | * vc/vc-dir.el (vc-dir): Default to repository root, not | ||
| 63 | default-directory. | ||
| 64 | |||
| 65 | 2015-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 | |||
| 1 | 2015-01-19 Dmitry Gutov <dgutov@yandex.ru> | 75 | 2015-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 | ||
| 80 | 2015-01-18 Stefan Monnier <monnier@iro.umontreal.ca> | 154 | 2015-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 | |||
| 833 | Split NAME on white space character and return string with as | ||
| 834 | many leading words of NAME as possible without exceeding WIDTH | ||
| 835 | characters. If NAME consists of white space characters only, | ||
| 836 | return an empty string. Three dots (\"...\") are appended to | ||
| 837 | returned string if some of the words from NAME have been omitted. | ||
| 838 | |||
| 839 | NB: Function may return string longer than WIDTH if name consists | ||
| 840 | of a single word, or it's first word is longer than WIDTH | ||
| 841 | characters." | ||
| 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 | |||
| 858 | Full description message has a \"U+HEX: NAME (GC: GENERAL-CATEGORY)\" | ||
| 859 | format 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 | |||
| 868 | If WIDTH is non-nil some elements of the description may be | ||
| 869 | omitted to accommodate the length restriction. Under certain | ||
| 870 | condition, 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 | |||
| 908 | Return nil if character at point is a printable ASCII | ||
| 909 | character (i.e. codepoint between 32 and 127 inclusively). | ||
| 910 | Otherwise return a description formatted by | ||
| 911 | `describe-char-eldoc--format' function taking into account value | ||
| 912 | of `eldoc-echo-area-use-multiline-p' variable and width of | ||
| 913 | minibuffer window for width limit. | ||
| 914 | |||
| 915 | This 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. | ||
| 53 | More specifically, it has no side-effects at all when the new function | ||
| 54 | definition 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. | ||
| 66 | DOC-STRING is the base documentation for this class. A generic | ||
| 67 | function has no body, as its purpose is to decide which method body | ||
| 68 | is appropriate to use. Uses `defmethod' to create methods, and calls | ||
| 69 | `defgeneric' for you. With this implementation the ARGS are | ||
| 70 | currently ignored. You can use `defgeneric' to apply specialized | ||
| 71 | top 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 | |||
| 82 | The optional second argument KEY is a specifier that | ||
| 83 | modifies 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 | ||
| 88 | The next argument is the ARGLIST. The ARGLIST specifies the arguments | ||
| 89 | to the method as with `defun'. The first argument can have a type | ||
| 90 | specifier, such as: | ||
| 91 | ((VARNAME CLASS) ARG2 ...) | ||
| 92 | where VARNAME is the name of the local variable for the method being | ||
| 93 | created. The CLASS is a class symbol for a class made with `defclass'. | ||
| 94 | A DOCSTRING comes after the ARGLIST, and is optional. | ||
| 95 | All the rest of the args are the BODY of the method. A method will | ||
| 96 | return the value of the last form in the BODY. | ||
| 97 | |||
| 98 | Summary: | ||
| 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. | ||
| 1030 | This is for testing if the class currently in scope is the class that defines SLOT | ||
| 1031 | so 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. |
| 1044 | The slot is a symbol which is installed in CLASS by the `defclass' | 1030 | The 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" "\ | ||
| 1265 | Like `defalias', but with less side-effects. | ||
| 1266 | More specifically, it has no side-effects at all when the new function | ||
| 1267 | definition is the same (`eq') as the old one. | ||
| 1268 | |||
| 1269 | \(fn NAME BODY)" nil nil) | ||
| 1270 | |||
| 1271 | (autoload 'defgeneric "eieio-compat" "\ | ||
| 1272 | Create a generic function METHOD. | ||
| 1273 | DOC-STRING is the base documentation for this class. A generic | ||
| 1274 | function has no body, as its purpose is to decide which method body | ||
| 1275 | is appropriate to use. Uses `defmethod' to create methods, and calls | ||
| 1276 | `defgeneric' for you. With this implementation the ARGS are | ||
| 1277 | currently ignored. You can use `defgeneric' to apply specialized | ||
| 1278 | top 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" "\ | ||
| 1287 | Create a new METHOD through `defgeneric' with ARGS. | ||
| 1288 | |||
| 1289 | The optional second argument KEY is a specifier that | ||
| 1290 | modifies 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 | ||
| 1295 | The next argument is the ARGLIST. The ARGLIST specifies the arguments | ||
| 1296 | to the method as with `defun'. The first argument can have a type | ||
| 1297 | specifier, such as: | ||
| 1298 | ((VARNAME CLASS) ARG2 ...) | ||
| 1299 | where VARNAME is the name of the local variable for the method being | ||
| 1300 | created. The CLASS is a class symbol for a class made with `defclass'. | ||
| 1301 | A DOCSTRING comes after the ARGLIST, and is optional. | ||
| 1302 | All the rest of the args are the BODY of the method. A method will | ||
| 1303 | return the value of the last form in the BODY. | ||
| 1304 | |||
| 1305 | Summary: | ||
| 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. | ||
| 40 | More specifically, it has no side-effects at all when the new function | ||
| 41 | definition 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. | ||
| 69 | Only 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. | ||
| 75 | Only methods have the symbol `eieio-method-hashtable' as a property (which | ||
| 76 | contains a list of all bindings to that method type.) | ||
| 77 | Methods 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. | ||
| 91 | Only methods have the symbol `eieio-method-hashtable' as a property (which | ||
| 92 | contains a list of all bindings to that method type.) | ||
| 93 | Methods 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. | ||
| 125 | All methods should call the same EIEIO function for dispatch. | ||
| 126 | DOC-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. | ||
| 132 | All methods should call the same EIEIO function for dispatch. | ||
| 133 | DOC-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. | ||
| 141 | Keys 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'. | ||
| 144 | During executions, the list is first generated, then as each next method | ||
| 145 | is 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. | ||
| 149 | All methods should call the same EIEIO function for dispatch. | ||
| 150 | CLASS is the class symbol needed for private method access. | ||
| 151 | IMPL 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. | ||
| 181 | It will leave the original generic function in place, | ||
| 182 | but 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. | ||
| 249 | The hook function must accept one argument, the list of forms | ||
| 250 | about to be executed.") | ||
| 251 | |||
| 252 | (defun eieio--generic-call (method args) | ||
| 253 | "Call METHOD with ARGS. | ||
| 254 | ARGS provides the context on which implementation to use. | ||
| 255 | This 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. | ||
| 384 | ARGS provides the context on which implementation to use. | ||
| 385 | This should only be called from a generic function. | ||
| 386 | |||
| 387 | This method is like `eieio--generic-call', but only | ||
| 388 | implementations in the :PRIMARY slot are queried. After many | ||
| 389 | years of use, it appears that over 90% of methods in use | ||
| 390 | have :PRIMARY implementations only. We can therefore optimize | ||
| 391 | for 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. | ||
| 453 | METHOD is the method name. | ||
| 454 | KEY represents either :before, or :after methods. | ||
| 455 | CLASS is the starting class to search from in the method tree. | ||
| 456 | If 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. | ||
| 505 | Do 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. | ||
| 519 | METHOD-NAME is the name created by a call to `defgeneric'. | ||
| 520 | METHOD are the forms for a given implementation. | ||
| 521 | KEY is an integer (see comment in eieio.el near this function) which | ||
| 522 | is associated with the :static :before :primary and :after tags. | ||
| 523 | It also indicates if CLASS is defined or not. | ||
| 524 | CLASS 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. | ||
| 559 | If CLASS is a superclass, return variable `eieio-default-superclass'. | ||
| 560 | If CLASS is variable `eieio-default-superclass' then return nil. | ||
| 561 | This is different from function `class-parent' as class parent returns | ||
| 562 | nil 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. | ||
| 586 | If CLASS is not a class then use `generic' instead. If class has | ||
| 587 | no form, but has a parent class, then trace to that parent class. | ||
| 588 | The first time a form is requested from a symbol, an optimized path | ||
| 589 | is 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. | ||
| 638 | DOC-STRING is the base documentation for this class. A generic | ||
| 639 | function has no body, as its purpose is to decide which method body | ||
| 640 | is appropriate to use. Uses `defmethod' to create methods, and calls | ||
| 641 | `defgeneric' for you. With this implementation the ARGS are | ||
| 642 | currently ignored. You can use `defgeneric' to apply specialized | ||
| 643 | top 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 | |||
| 653 | The optional second argument KEY is a specifier that | ||
| 654 | modifies 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 | ||
| 659 | The next argument is the ARGLIST. The ARGLIST specifies the arguments | ||
| 660 | to the method as with `defun'. The first argument can have a type | ||
| 661 | specifier, such as: | ||
| 662 | ((VARNAME CLASS) ARG2 ...) | ||
| 663 | where VARNAME is the name of the local variable for the method being | ||
| 664 | created. The CLASS is a class symbol for a class made with `defclass'. | ||
| 665 | A DOCSTRING comes after the ARGLIST, and is optional. | ||
| 666 | All the rest of the args are the BODY of the method. A method will | ||
| 667 | return the value of the last form in the BODY. | ||
| 668 | |||
| 669 | Summary: | ||
| 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. | ||
| 705 | Returns a list of lambda expressions which is the `next-method' | ||
| 706 | order." | ||
| 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. | ||
| 711 | The superclass method is specified in the current method list, | ||
| 712 | and is called the next method. | ||
| 713 | |||
| 714 | If REPLACEMENT-ARGS is non-nil, then use them instead of | ||
| 715 | `eieio--generic-call-arglst'. The generic arg list are the | ||
| 716 | arguments passed in at the top level. | ||
| 717 | |||
| 718 | Use `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. | ||
| 740 | OBJECT is the object which has no method implementation. | ||
| 741 | ARGS are the arguments that were passed to METHOD. | ||
| 742 | |||
| 743 | Implement this for a class to block this signal. The return | ||
| 744 | value 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. | ||
| 752 | OBJECT is othe object being called on `call-next-method'. | ||
| 753 | ARGS are the arguments it is called by. | ||
| 754 | This method signals `no-next-method' by default. Override this | ||
| 755 | method to not throw an error, and its return value becomes the | ||
| 756 | return 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', | |||
| 336 | and the face `eldoc-highlight-function-argument', if they are to have any | 336 | and the face `eldoc-highlight-function-argument', if they are to have any |
| 337 | effect. | 337 | effect. |
| 338 | 338 | ||
| 339 | This variable is expected to be set buffer-locally by modes that support ElDoc.") | 339 | Major modes should modify this variable using `add-function', for example: |
| 340 | (add-function :before-until (local 'eldoc-documentation-function) | ||
| 341 | #'foo-mode-eldoc-function) | ||
| 342 | so that the global documentation function (i.e. the default value of the | ||
| 343 | variable) is taken into account if the major mode specific function does not | ||
| 344 | return 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. |
| 173 | This is an internal version of `macroexpand-all'. | 193 | This 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 | |||
| 409 | If the pattern matches `looking-back', a hard space needs to be inserted instead | ||
| 410 | of a space at point. The regexp is always case sensitive, regardless of the | ||
| 411 | current `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 | |||
| 432 | If | ||
| 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, | ||
| 439 | replace the space character with value of `tildify-space-string' and | ||
| 440 | return t. | ||
| 441 | |||
| 442 | Otherwise, 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, | ||
| 447 | remove the hard space and leave only the space character. | ||
| 448 | |||
| 449 | This 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. | ||
| 475 | Based on `tildify-foreach-region-function', check whether character before, | ||
| 476 | which 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 | |||
| 484 | When space is inserted into a buffer in a position where hard space is required | ||
| 485 | instead (determined by `tildify-space-pattern' and `tildify-space-predicates'), | ||
| 486 | that space character is replaced by a hard space specified by | ||
| 487 | `tildify-space-string'. Converting of the space is done by `tildify-space'. | ||
| 488 | |||
| 489 | When `tildify-mode' is enabled, if `tildify-string-alist' specifies a hard space | ||
| 490 | representation for current major mode, the `tildify-space-string' buffer-local | ||
| 491 | variable 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 @@ | |||
| 1 | 2015-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 | |||
| 16 | 2015-01-20 Jan Djärv <jan.h.d@swipnet.se> | ||
| 17 | |||
| 18 | * nsterm.m (EV_TRAILER2): Set Vinhibit_quit to Qt (Bug#19531). | ||
| 19 | |||
| 20 | 2015-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 | |||
| 28 | 2015-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 | |||
| 1 | 2015-01-19 Eli Zaretskii <eliz@gnu.org> | 55 | 2015-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. */ |
| 1514 | enum { NIL_IS_ZERO = XLI_BUILTIN_LISPSYM (iQnil) == 0 }; | 1514 | enum { 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. */ |
| 1517 | INLINE void | 1517 | INLINE void |
| 1518 | memsetnil (Lisp_Object *v, ptrdiff_t size) | 1518 | memsetnil (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 @@ | |||
| 1 | 2015-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 | |||
| 6 | 2015-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 | |||
| 12 | 2015-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 | |||
| 1 | 2015-01-18 Stefan Monnier <monnier@iro.umontreal.ca> | 27 | 2015-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) " " "<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) " " "<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 |