From: Paul Eggert Date: Tue, 22 Mar 2016 18:01:30 +0000 (-0700) Subject: - X-Git-Tag: emacs-26.0.90~2307 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=37b9099068c10383e959ee366a52a22516846163;p=emacs.git - --- 37b9099068c10383e959ee366a52a22516846163 diff --cc doc/lispref/sequences.texi index 002a9ceceec,a54ab104ab5..f7d26e54d0b --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@@ -572,26 -576,12 +576,27 @@@ element of @var{sequence}. The returne @end example @end defun +@defun seq-map-indexed function sequence + This function returns the result of applying @var{function} to each +element of @var{sequence} and its index within @var{seq}. The +returned value is a list. + +@example +@group +(seq-map-indexed (lambda (elt idx) + (list idx elt)) + '(a b c)) +@result{} ((0 a) (b 1) (c 2)) +@end group +@end example +@end defun + @defun seq-mapn function &rest sequences This function returns the result of applying @var{function} to each - element of @var{sequences}. The arity of @var{function} must match - the number of sequences. Mapping stops at the shortest sequence, and - the returned value is a list. + element of @var{sequences}. The arity (@pxref{What Is a Function, + sub-arity}) of @var{function} must match the number of sequences. + Mapping stops at the end of the shortest sequence, and the returned + value is a list. @example @group diff --cc etc/NEWS index 4414625eacd,8ce194a69ca..366208b27da --- a/etc/NEWS +++ b/etc/NEWS @@@ -22,183 -22,6 +22,183 @@@ Temporary note When you add a new item, use the appropriate mark if you are sure it applies, otherwise leave it unmarked. + +* Installation Changes in Emacs 25.2 + ++++ - ** New configure option ‘--disable-build-details’ attempts to build an ++** New configure option '--disable-build-details' attempts to build an +Emacs that is more likely to be reproducible; that is, if you build +and install Emacs twice, the second Emacs is a copy of the first. +Deterministic builds omit the build date from the output of the +emacs-version and erc-cmd-SV functions, and the leave the following +variables nil: emacs-build-system, emacs-build-time, +erc-emacs-build-time. + +** Emacs no longer works on IRIX. We expect that Emacs users are not +affected by this, as SGI stopped supporting IRIX in December 2013. + + +* Startup Changes in Emacs 25.2 + + +* Changes in Emacs 25.2 + ++++ - ** A number of accessors for the value returned by `file-attributes' - has been added. They are: `file-attribute-type', - `file-attribute-link-number', `file-attribute-user-id', - `file-attribute-group-id', `file-attribute-access-time', - `file-attribute-modification-time', - `file-attribute-status-change-time', `file-attribute-size', - `file-attribute-modes', `file-attribute-inode-number', and - `file-attribute-device-number' ++** A number of accessors for the value returned by 'file-attributes' ++has been added. They are: 'file-attribute-type', ++'file-attribute-link-number', 'file-attribute-user-id', ++'file-attribute-group-id', 'file-attribute-access-time', ++'file-attribute-modification-time', ++'file-attribute-status-change-time', 'file-attribute-size', ++'file-attribute-modes', 'file-attribute-inode-number', and ++'file-attribute-device-number' + +--- - ** The locale language name `ca' is now mapped to the language - environment `Catalan', which has been added. ++** The locale language name 'ca' is now mapped to the language ++environment 'Catalan', which has been added. + +--- - ** `align-regexp' has a separate history for its interactive argument - `align-regexp' no longer shares its history with all other - history-less functions that use `read-string' ++** 'align-regexp' has a separate history for its interactive argument ++'align-regexp' no longer shares its history with all other ++history-less functions that use 'read-string' + ++++ +** The networking code has been reworked so that it's more +asynchronous than it was (when specifying :nowait t in - `make-network-process'). How asynchronous it is varies based on the ++'make-network-process'). How asynchronous it is varies based on the +capabilities of the system, but on a typical GNU/Linux system the DNS +resolution, the connection, and (for TLS streams) the TLS negotiation +are all done without blocking the main Emacs thread. To get +asynchronous TLS, the TLS boot parameters have to be passed in (see +the manual for details). + - Certain process oriented functions (like `process-datagram-address') ++Certain process oriented functions (like 'process-datagram-address') +will block until socket setup has been performed. The recommended way +to deal with asynchronous sockets is to avoid interacting with them +until they have changed status to "run". This is most easily done +from a process sentinel. + - ** ‘make-network-process’ and ‘open-network-stream’ sometimes allowed ++** 'make-network-process' and 'open-network-stream' sometimes allowed +:service to be an integer string (e.g., :service "993") and sometimes +required an integer (e.g., :service 993). This difference has been +eliminated, and integer strings work everywhere. + +** It is possible to disable attempted recovery on fatal signals + +Two new variables allow to disable attempts to recover from stack +overflow and to avoid automatic auto-save when Emacs is delivered a - fatal signal. `attempt-stack-overflow-recovery', if set to `nil', ++fatal signal. 'attempt-stack-overflow-recovery', if set to 'nil', +will disable attempts to recover from C stack overflows; Emacs will +then crash as with any other fatal signal. - `attempt-orderly-shutdown-on-fatal-signal', if set to `nil', will ++'attempt-orderly-shutdown-on-fatal-signal', if set to 'nil', will +disable attempts to auto-save the session and shut down in an orderly +fashion when Emacs receives a fatal signal; instead, Emacs will - terminate immediately. Both variables are non-`nil' by default. ++terminate immediately. Both variables are non-'nil' by default. +These variables are for users who would like to avoid the small +probability of data corruption due to techniques Emacs uses to recover +in these situations. + + +* Editing Changes in Emacs 25.2 + + +* Changes in Specialized Modes and Packages in Emacs 25.2 + +** eww + ++++ - *** A new `s' command for switching to another eww buffer via the minibuffer. ++*** A new 's' command for switching to another eww buffer via the minibuffer. + +--- - *** The `o' command (`shr-save-contents') has moved to `O' to avoid collision - with the `o' command from `image-map'. ++*** The 'o' command ('shr-save-contents') has moved to 'O' to avoid collision ++with the 'o' command from 'image-map'. + ++++ +** The commands that add ChangeLog entries now prefer a VCS root directory +for the ChangeLog file, if none already exists. Customize - `change-log-directory-files' to nil for the old behavior. ++'change-log-directory-files' to nil for the old behavior. + +--- - ** Support for non-string values of `time-stamp-format' has been removed. ++** Support for non-string values of 'time-stamp-format' has been removed. + +** Tramp + ++++ +*** New connection method "sg", which allows to edit files under +different group ID. + ++++ +*** New connection method "doas" for OpenBSD hosts. + +--- - ** `auto-revert-use-notify' is set back to t in `global-auto-revert-mode'. ++** 'auto-revert-use-notify' is set back to t in 'global-auto-revert-mode'. + + +* New Modes and Packages in Emacs 25.2 + + +* Incompatible Lisp Changes in Emacs 25.2 + ++++ - ** Resizing a frame no longer runs `window-configuration-change-hook'. - Put your function on `window-size-change-functions' instead. ++** Resizing a frame no longer runs 'window-configuration-change-hook'. ++Put your function on 'window-size-change-functions' instead. + + +* Lisp Changes in Emacs 25.2 + +** New var syntax-ppss-table to control the syntax-table used in syntax-ppss + +** Autoload files can be generated without timestamps, - by setting `autoload-timestamps' to nil. ++by setting 'autoload-timestamps' to nil. +FIXME As an experiment, nil is the current default. +If no insurmountable problems before next release, it can stay that way. + - ** `ert-with-function-mocked' of 'ert-x package allows mocking of functions ++** 'ert-with-function-mocked' of 'ert-x package allows mocking of functions +in unit tests. + +--- - ** `gnutls-boot' now takes a parameter :complete-negotiation that says ++** 'gnutls-boot' now takes a parameter :complete-negotiation that says +that negotiation should complete even on non-blocking sockets. + ++++ - ** New functions `window-pixel-width-before-size-change' and - `window-pixel-height-before-size-change' allow to detect which window - changed size when `window-size-change-functions' are run. ++** New functions 'window-pixel-width-before-size-change' and ++'window-pixel-height-before-size-change' allow to detect which window ++changed size when 'window-size-change-functions' are run. + ++++ - ** New function `display-buffer-reuse-mode-window' is an action function - suitable for use in `display-buffer-alist'. For example, to avoid creating ++** New function 'display-buffer-reuse-mode-window' is an action function ++suitable for use in 'display-buffer-alist'. For example, to avoid creating +a new window when opening man pages when there's already one, use +(add-to-list 'display-buffer-alist - '("\\`\\*Man .*\\*\\'" . ++ '("\\'\\*Man .*\\*\\'" . + (display-buffer-reuse-mode-window + (inhibit-same-window . nil) + (mode . Man-mode)))) + ++++ - ** `parse-partial-sexp' state has a new element. Element 10 is ++** 'parse-partial-sexp' state has a new element. Element 10 is +non-nil when the last character scanned might be the first character +of a two character construct, i.e. a comment delimiter or escaped +character. Its value is the syntax of that last character. + ++++ - ** `parse-partial-sexp''s state, element 9, has now been confirmed as ++** 'parse-partial-sexp''s state, element 9, has now been confirmed as +permanent and documented, and may be used by Lisp programs. Its value +is a list of currently open parenthesis positions, starting with the +outermost parenthesis. + + +* Changes in Emacs 25.2 on Non-Free Operating Systems + +** Intercepting hotkeys on Windows 7 and later now works better. +The new keyboard hooking code properly grabs system hotkeys such as +Win-* and Alt-TAB, in a way that Emacs can get at them before the - system. This makes the `w32-register-hot-key' functionality work ++system. This makes the 'w32-register-hot-key' functionality work +again on all versions of MS-Windows starting with Windows 7. On +Windows NT and later you can now register any hotkey combination. (On +Windows 9X, the previous limitations, spelled out in the Emacs manual, +still apply.) + * Installation Changes in Emacs 25.1 @@@ -354,36 -177,20 +354,35 @@@ object Loadable modules in Emacs are an experimental feature, and subject to change in future releases. For that reason, their support is disabled - by default, and must be enabled by using the `--with-modules' option + by default, and must be enabled by using the '--with-modules' option at configure time. ++++ +** A second dir-local file (.dir-locals-2.el) is now accepted. - See the variable `dir-locals-file-2' for more information. ++See the variable 'dir-locals-file-2' for more information. + +++ ** Network security (TLS/SSL certificate validity and the like) is added via the new Network Security Manager (NSM) and controlled via - the `network-security-level' variable. + the 'network-security-level' variable. +--- +** International domain names (IDNA) are now encoded via the new - puny.el library, so that one can visit web sites like - "http://méxico.icom.museum". ++puny.el library, so that one can visit web sites with non-ASCII URLs. + +++ ** C-h l now also lists the commands that were run. +** The new M-s M-w key binding uses eww to search the web for the +text in the region. + +++ - ** The new `timer-list' command lists all active timers in a buffer - where you can cancel them with the `c' command. -** x-select-enable-clipboard is renamed select-enable-clipboard -and x-select-enable-primary is renamed select-enable-primary. ++** The new 'timer-list' command lists all active timers in a buffer ++where you can cancel them with the 'c' command. + +** M-x suggests shorthands and ignores obsolete commands for completion. +** x-select-enable-clipboard is renamed select-enable-clipboard. +x-select-enable-primary and renamed select-enable-primary. Additionally they both now apply to all systems (OSX, GNUstep, Windows, you name it), with the proviso that on some systems (e.g. Windows) select-enable-primary is ineffective since the system doesn't @@@ -395,13 -202,9 +394,13 @@@ customize how 'switch-to-buffer' procee selected window is strongly dedicated to its buffer. +++ - ** The option `even-window-heights' has been renamed to - `even-window-sizes' and now handles window widths as well. + ** The option 'even-window-heights' has been renamed to + 'even-window-sizes' and now handles window widths as well. ++++ - ** New function `read-multiple-choice' use to prompt for ++** New function 'read-multiple-choice' use to prompt for +multiple-choice questions, with a handy way to display help texts. + +++ ** terpri gets an optional arg ENSURE to conditionally output a newline. @@@ -519,15 -323,10 +519,15 @@@ unsaved customizations and prompts use is intended for adding to 'kill-emacs-query-functions'. +++ - ** The old `C-x w' bindings in hi-lock-mode are officially deprecated - in favor of the global `M-s h' bindings introduced in Emacs-23.1. + ** The old 'C-x w' bindings in hi-lock-mode are officially deprecated + in favor of the global 'M-s h' bindings introduced in Emacs-23.1. They'll disappear soon. ++++ +** New bindings for 'query-replace-map'. - `undo', undo the last replacement; bound to `u'. - `undo-all', undo all replacements; bound to `U'. ++'undo', undo the last replacement; bound to 'u'. ++'undo-all', undo all replacements; bound to 'U'. + * Changes in Specialized Modes and Packages in Emacs 25.1 @@@ -654,13 -453,10 +654,13 @@@ obsolete alias for the new 'save-place- +++ *** ERC can now hide message types by network or channel. - `erc-hide-list' will hide all messages of the specified type, while - `erc-network-hide-list' and `erc-channel-hide-list' will only hide the + 'erc-hide-list' will hide all messages of the specified type, while + 'erc-network-hide-list' and 'erc-channel-hide-list' will only hide the specified message types for the respective specified targets. - *** New variable `erc-default-port-tls' used to connect to TLS IRC ++*** New variable 'erc-default-port-tls' used to connect to TLS IRC +servers. + --- *** Reconnection is now asynchronous. @@@ -905,31 -703,19 +907,31 @@@ using mono-spaced font *** HTML can now be rendered using variable-width fonts. +++ - *** A new command `F' (`eww-toggle-fonts') can be used to toggle + *** A new command 'F' ('eww-toggle-fonts') can be used to toggle whether to use variable-pitch fonts or not. The user can also - customize the `shr-use-fonts' variable. + customize the 'shr-use-fonts' variable. ++++ - *** A new command `C' (`eww-toggle-colors') can be used to toggle ++*** A new command 'C' ('eww-toggle-colors') can be used to toggle +whether to use the HTML-specified colors or not. The user can also - customize the `shr-use-colors' variable. ++customize the 'shr-use-colors' variable. + +++ - *** A new command `R' (`eww-readable') will try do identify the main + *** A new command 'R' ('eww-readable') will try do identify the main textual parts of a web page and display only that, leaving menus and the like off the page. +++ - *** A new command `D' (`eww-toggle-paragraph-direction') allows you to + *** A new command 'D' ('eww-toggle-paragraph-direction') allows you to toggle the paragraph direction between left-to-right and right-to-left. +--- +*** Images that are being loaded are now marked with grey +"placeholder" images of the size specified by the HTML. They are then +replaced by the real images asynchronously, which will also now +respect width/height HTML specs (unless they specify widths/heights +bigger than the current window). + --- *** You can now use several eww buffers in parallel by renaming eww buffers you want to keep separate. @@@ -969,17 -755,6 +971,17 @@@ invalid certificates are marked in red *** text/html messages that contain inline image parts will be transformed into multipart/related messages before sending. +--- - *** The `message-valid-fqdn-regexp' variable has been removed, since ++*** The 'message-valid-fqdn-regexp' variable has been removed, since +there are now top-level domains added all the time. Message will no +longer warn about sending emails to top-level domains it hasn't heard +about. + - *** `message-beginning-of-line' (bound to C-a) understands folded headers. - In `visual-line-mode' it will look for the true beginning of a header - while in non-`visual-line-mode' it will move the point to the indented - header’s value. ++*** 'message-beginning-of-line' (bound to C-a) understands folded headers. ++In 'visual-line-mode' it will look for the true beginning of a header ++while in non-'visual-line-mode' it will move the point to the indented ++header's value. + +++ ** In Show Paren Mode, a parenthesis can be highlighted when point stands inside it, and certain parens can be highlighted when point is @@@ -989,32 -764,8 +991,32 @@@ respectively, 'show-paren-when-point-in --- ** If gpg2 exists on the system, it is now used as the default value - of `epg-gpg-program' (instead of gpg). + of 'epg-gpg-program' (instead of gpg). +** Images + ++++ +*** Images are automatically scaled before displaying based on the - `image-scaling-factor' variable (if Emacs supports scaling the images ++'image-scaling-factor' variable (if Emacs supports scaling the images +in question). + ++++ - *** Images inserted with `insert-image' and related functions get a ++*** Images inserted with 'insert-image' and related functions get a +keymap put into the text properties (or overlays) that span the +image. This keymap binds keystrokes for manipulating size and +rotation, as well as saving the image to a file. These commands are - also available in `image-mode'. ++also available in 'image-mode'. + ++++ +*** A new library for creating and manipulating SVG images has been +added. See the "SVG Images" section in the lispref manual for +details. + ++++ +*** New setf-able function to access and set image parameters is - provided: `image-property'. ++provided: 'image-property'. + + ** Lisp mode --- @@@ -1186,13 -937,8 +1188,13 @@@ variable, meaning you can bind it aroun --- *** If URL is used with a https connection, the first callback argument plist will contain a :peer element that has the output of - `gnutls-peer-status' (if Emacs is built with GnuTLS support). + 'gnutls-peer-status' (if Emacs is built with GnuTLS support). ++++ - *** The new function `url-cookie-delete-cookie' can be used to ++*** The new function 'url-cookie-delete-cookie' can be used to +programmatically delete all cookies, or cookies from a specific +domain. + ** Tramp +++ @@@ -1242,14 -988,9 +1244,14 @@@ This command is useful when you perfor outside Emacs (e.g., from the shell prompt), or if you switch the VC back-end for the buffer's file, or remove it from version control. +--- +*** The VC state indicator in the mode line now defaults to more +colorful faces to make it more obvious to the user what the state is. - See the `vc-faces' customization group. ++See the 'vc-faces' customization group. + +++ - *** New option `vc-annotate-background-mode' controls whether - the color range from `vc-annotate-color-map' is applied to the + *** New option 'vc-annotate-background-mode' controls whether + the color range from 'vc-annotate-color-map' is applied to the background or to the foreground. +++ @@@ -1518,30 -1259,21 +1520,30 @@@ notification descriptor still correspon directories and decompress zip files. +++ - *** New command `dired-do-compress-to' bound to `c' can be used to + *** New command 'dired-do-compress-to' bound to 'c' can be used to compress many marked files into a single named archive. The compression command is determined from the new - `dired-compress-files-alist' variable. + 'dired-compress-files-alist' variable. +++ +*** In wdired, when editing files to contain slash characters, +the resulting directories are automatically created. Whether +to do this or not is controlled by the - `wdired-create-parent-directories' variable. ++'wdired-create-parent-directories' variable. + ++++ - *** `W' is now bound to `browse-url-of-dired-file', and is useful for ++*** 'W' is now bound to 'browse-url-of-dired-file', and is useful for +viewing HTML files and the like. + - *** New user interface for the `A' and `Q' commands. - These keys, now bound to `dired-do-find-regexp' and - `dired-do-find-regexp-and-replace', work similarly to `xref-find-apropos' - and `xref-query-replace-in-results': they present the matches - in the `*xref*' buffer and let you move through the matches. No need - to use `tags-loop-continue' to resume the search or replace loop. The - previous commands, `dired-do-search' and - `dired-do-query-replace-regexp', are still available, but not bound to - keys; rebind `A' and `Q' to invoke them if you want the old behavior + *** New user interface for the 'A' and 'Q' commands. + These keys, now bound to 'dired-do-find-regexp' and + 'dired-do-find-regexp-and-replace', work similarly to 'xref-find-apropos' + and 'xref-query-replace-in-results': they present the matches + in the '*xref*' buffer and let you move through the matches. No need + to use 'tags-loop-continue' to resume the search or replace loop. The + previous commands, 'dired-do-search' and + 'dired-do-query-replace-regexp', are still available, but not bound to + keys; rebind 'A' and 'Q' to invoke them if you want the old behavior back. We intend to obsolete the old commands in a future release. ** Tabulated List Mode @@@ -1675,24 -1407,16 +1677,24 @@@ symbol-function was changed not to sign ** Comint, term, and compile do not set the EMACS env var any more. Use the INSIDE_EMACS environment variable instead. - ** `C-up', `C-down', `C-left' and `C-right' are now defined in term ++** 'C-up', 'C-down', 'C-left' and 'C-right' are now defined in term +mode to send the same escape sequences that xterm does. This makes +things like forward-word in readline work. + +--- +** hideshow mode got four key bindings that are analogous to outline - mode bindings: `C-c @ C-a', `C-c @ C-t', `C-c @ C-d', and `C-c @ C-e.' ++mode bindings: 'C-c @ C-a', 'C-c @ C-t', 'C-c @ C-d', and 'C-c @ C-e.' + +++ - ** `save-excursion' does not save&restore the mark any more. - Use `save-mark-and-excursion' if you want the old behavior. + ** 'save-excursion' does not save&restore the mark any more. + Use 'save-mark-and-excursion' if you want the old behavior. +++ - ** `read-buffer' and `read-buffer-function' can now be called with a 4th - argument (`predicate'). + ** 'read-buffer' and 'read-buffer-function' can now be called with a 4th + argument ('predicate'). +++ - ** `completion-table-dynamic' by default stays in the minibuffer. + ** 'completion-table-dynamic' by default stays in the minibuffer. The minibuffer will be the current buffer when the function is called. If you want the old behavior of calling the function in the buffer from which the minibuffer was entered, use the new argument @@@ -1777,20 -1501,16 +1779,20 @@@ behavior, set 'diff-switches' to '-c' dynamically. Any third-party code that changes these templates should be updated accordingly. +** The grep/rgrep/lgrep functions will now ask about saving files - before running. This is controlled by the `grep-save-buffers' ++before running. This is controlled by the 'grep-save-buffers' +variable. + +++ - ** ‘(/ N)’ is now equivalent to ‘(/ 1 N)’ rather than to ‘(/ N 1)’. + ** '(/ N)' is now equivalent to '(/ 1 N)' rather than to '(/ N 1)'. The new behavior is compatible with Common Lisp and with XEmacs. This change does not affect Lisp code intended to be portable to - Emacs 24.2 and earlier, which did not support unary ‘/’. + Emacs 24.2 and earlier, which did not support unary '/'. +++ - ** The `default-directory' value doesn't have to end slash. To make - that happen, `unhandled-file-name-directory' now defaults to calling - `file-name-as-directory'. + ** The 'default-directory' value doesn't have to end slash. To make + that happen, 'unhandled-file-name-directory' now defaults to calling + 'file-name-as-directory'. * Lisp Changes in Emacs 25.1 @@@ -1886,10 -1606,6 +1888,10 @@@ details It should be placed right where the docstring would be, and FORM is then evaluated (and should return a string) when the closure is built. +--- - ** The new command `fortune-message' has been added, which displays ++** The new command 'fortune-message' has been added, which displays +fortunes in the echo area. + +++ ** define-inline provides a new way to define inlinable functions. @@@ -1914,16 -1630,10 +1916,16 @@@ preserve the collation order as defined by the system's locale(1) environment. For the time being this is implemented for modern POSIX systems and for MS-Windows, for other systems they fall back to their - counterparts `string-lessp' and `string-equal'. + counterparts 'string-lessp' and 'string-equal'. ++++ - ** The new function `string-version-lessp' compares strings by ++** The new function 'string-version-lessp' compares strings by +interpreting consecutive runs of numerical characters as numbers, and +compares their numerical values. According to this predicate, +"foo2.png" is smaller than "foo12.png". + --- - *** The ls-lisp package uses `string-collate-lessp' to sort file names. + *** The ls-lisp package uses 'string-collate-lessp' to sort file names. The effect is that, on systems that use ls-lisp for Dired, the default sort order of the files in Dired is now different from what it was in previous versions of Emacs. In particular, the file names are sorted @@@ -2100,25 -1810,17 +2102,25 @@@ if the terminal cannot display curved q +++ ** Standard output and error streams now transliterate characters via standard-display-table, and encode output using locale-coding-system. - To force a specific encoding, bind `coding-system-for-write' to the - coding-system of your choice when invoking functions like `prin1' and - `message'. + To force a specific encoding, bind 'coding-system-for-write' to the + coding-system of your choice when invoking functions like 'prin1' and + 'message'. +++ - ** New var `truncate-string-ellipsis' to choose how to indicate truncation. + ** New var 'truncate-string-ellipsis' to choose how to indicate truncation. +++ - ** New possible value for `system-type': `nacl'. + ** New possible value for 'system-type': 'nacl'. This is used by Google's Native Client (NaCl). +--- - ** `read-color' will now display the color names using the color itself ++** 'read-color' will now display the color names using the color itself +as the background color. + +--- - ** There is now a new variable `flyspell-sort-corrections-function' ++** There is now a new variable 'flyspell-sort-corrections-function' +that allows changing the way corrections are sorted. + ** Miscellaneous name change --- diff --cc lisp/gnus/mml-sec.el index 576eceecf4b,254c427299e..0e2d4381993 --- a/lisp/gnus/mml-sec.el +++ b/lisp/gnus/mml-sec.el @@@ -46,9 -46,9 +47,11 @@@ (autoload 'mml-smime-verify "mml-smime") (autoload 'mml-smime-verify-test "mml-smime") (autoload 'epa--select-keys "epa") +(autoload 'message-options-get "message") +(autoload 'message-options-set "message") + (declare-function message-options-set "message" (symbol value)) + (defvar mml-sign-alist '(("smime" mml-smime-sign-buffer mml-smime-sign-query) ("pgp" mml-pgp-sign-buffer list) diff --cc test/lisp/emacs-lisp/package-tests.el index 9afdfe67c26,00000000000..70e129cc4f5 mode 100644,000000..100644 --- a/test/lisp/emacs-lisp/package-tests.el +++ b/test/lisp/emacs-lisp/package-tests.el @@@ -1,626 -1,0 +1,626 @@@ +;;; package-test.el --- Tests for the Emacs package system + +;; Copyright (C) 2013-2016 Free Software Foundation, Inc. + +;; Author: Daniel Hackney +;; Version: 1.0 + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; You may want to run this from a separate Emacs instance from your +;; main one, because a bug in the code below could mess with your +;; installed packages. + +;; Run this in a clean Emacs session using: +;; +;; $ emacs -Q --batch -L . -l package-test.el -l ert -f ert-run-tests-batch-and-exit + +;;; Code: + +(require 'package) +(require 'ert) +(require 'cl-lib) + +(setq package-menu-async nil) + +(defvar package-test-user-dir nil + "Directory to use for installing packages during testing.") + +(defvar package-test-file-dir (file-name-directory (or load-file-name + buffer-file-name)) + "Directory of the actual \"package-test.el\" file.") + +(defvar simple-single-desc + (package-desc-create :name 'simple-single + :version '(1 3) + :summary "A single-file package with no dependencies" + :kind 'single + :extras '((:authors ("J. R. Hacker" . "jrh@example.com")) + (:maintainer "J. R. Hacker" . "jrh@example.com") + (:url . "http://doodles.au"))) + "Expected `package-desc' parsed from simple-single-1.3.el.") + +(defvar simple-depend-desc + (package-desc-create :name 'simple-depend + :version '(1 0) + :summary "A single-file package with a dependency." + :kind 'single + :reqs '((simple-single (1 3))) + :extras '((:authors ("J. R. Hacker" . "jrh@example.com")) + (:maintainer "J. R. Hacker" . "jrh@example.com"))) + "Expected `package-desc' parsed from simple-depend-1.0.el.") + +(defvar multi-file-desc + (package-desc-create :name 'multi-file + :version '(0 2 3) + :summary "Example of a multi-file tar package" + :kind 'tar + :extras '((:url . "http://puddles.li"))) + "Expected `package-desc' from \"multi-file-0.2.3.tar\".") + +(defvar new-pkg-desc + (package-desc-create :name 'new-pkg + :version '(1 0) + :kind 'single) + "Expected `package-desc' parsed from new-pkg-1.0.el.") + +(defvar simple-depend-desc-1 + (package-desc-create :name 'simple-depend-1 + :version '(1 0) + :summary "A single-file package with a dependency." + :kind 'single + :reqs '((simple-depend (1 0)) + (multi-file (0 1)))) + "`package-desc' used for testing dependencies.") + +(defvar simple-depend-desc-2 + (package-desc-create :name 'simple-depend-2 + :version '(1 0) + :summary "A single-file package with a dependency." + :kind 'single + :reqs '((simple-depend-1 (1 0)) + (multi-file (0 1)))) + "`package-desc' used for testing dependencies.") + +(defvar package-test-data-dir (expand-file-name "package-resources" package-test-file-dir) + "Base directory of package test files.") + +(defvar package-test-fake-contents-file + (expand-file-name "archive-contents" package-test-data-dir) + "Path to a static copy of \"archive-contents\".") + +(cl-defmacro with-package-test ((&optional &key file + basedir + install + location + update-news + upload-base) + &rest body) + "Set up temporary locations and variables for testing." + (declare (indent 1)) + `(let* ((package-test-user-dir (make-temp-file "pkg-test-user-dir-" t)) + (process-environment (cons (format "HOME=%s" package-test-user-dir) + process-environment)) + (package-user-dir package-test-user-dir) + (package-archives `(("gnu" . ,(or ,location package-test-data-dir)))) + (default-directory package-test-file-dir) + abbreviated-home-dir + package--initialized + package-alist + ,@(if update-news + '(package-update-news-on-upload t) + (list (cl-gensym))) + ,@(if upload-base + '((package-test-archive-upload-base (make-temp-file "pkg-archive-base-" t)) + (package-archive-upload-base package-test-archive-upload-base)) + (list (cl-gensym)))) ;; Dummy value so `let' doesn't try to bind nil + (let ((buf (get-buffer "*Packages*"))) + (when (buffer-live-p buf) + (kill-buffer buf))) + (unwind-protect + (progn + ,(if basedir `(cd ,basedir)) + (unless (file-directory-p package-user-dir) + (mkdir package-user-dir)) + (cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest r) t)) + ((symbol-function 'y-or-n-p) (lambda (&rest r) t))) + ,@(when install + `((package-initialize) + (package-refresh-contents) + (mapc 'package-install ,install))) + (with-temp-buffer + ,(if file + `(insert-file-contents ,file)) + ,@body))) + + (when (file-directory-p package-test-user-dir) + (delete-directory package-test-user-dir t)) + + (when (and (boundp 'package-test-archive-upload-base) + (file-directory-p package-test-archive-upload-base)) + (delete-directory package-test-archive-upload-base t))))) + +(defmacro with-fake-help-buffer (&rest body) + "Execute BODY in a temp buffer which is treated as the \"*Help*\" buffer." + `(with-temp-buffer + (help-mode) + ;; Trick `help-buffer' into using the temp buffer. + (let ((help-xref-following t)) + ,@body))) + +(defun package-test-strip-version (dir) + (replace-regexp-in-string "-pkg\\.el\\'" "" (package--description-file dir))) + +(defun package-test-suffix-matches (base suffix-list) + "Return file names matching BASE concatenated with each item in SUFFIX-LIST" + (cl-mapcan + '(lambda (item) (file-expand-wildcards (concat base item))) + suffix-list)) + +(defvar tar-parse-info) +(declare-function tar-header-name "tar-mode" (cl-x) t) ; defstruct + +(defun package-test-search-tar-file (filename) + "Search the current buffer's `tar-parse-info' variable for FILENAME. + +Must called from within a `tar-mode' buffer." + (cl-dolist (header tar-parse-info) + (let ((tar-name (tar-header-name header))) + (when (string= tar-name filename) + (cl-return t))))) + +(defun package-test-desc-version-string (desc) + "Return the package version as a string." + (package-version-join (package-desc-version desc))) + +(ert-deftest package-test-desc-from-buffer () + "Parse an elisp buffer to get a `package-desc' object." + (with-package-test (:basedir "package-resources" :file "simple-single-1.3.el") + (should (equal (package-buffer-info) simple-single-desc))) + (with-package-test (:basedir "package-resources" :file "simple-depend-1.0.el") + (should (equal (package-buffer-info) simple-depend-desc))) + (with-package-test (:basedir "package-resources" + :file "multi-file-0.2.3.tar") + (tar-mode) + (should (equal (package-tar-file-info) multi-file-desc)))) + +(ert-deftest package-test-install-single () + "Install a single file without using an archive." + (with-package-test (:basedir "package-resources" :file "simple-single-1.3.el") + (should (package-install-from-buffer)) + (package-initialize) + (should (package-installed-p 'simple-single)) + ;; Check if we properly report an "already installed". + (package-install 'simple-single) + (with-current-buffer "*Messages*" + (should (string-match "^[`‘']simple-single[’'] is already installed\n?\\'" + (buffer-string)))) + (should (package-installed-p 'simple-single)) + (let* ((simple-pkg-dir (file-name-as-directory + (expand-file-name + "simple-single-1.3" + package-test-user-dir))) + (autoloads-file (expand-file-name "simple-single-autoloads.el" + simple-pkg-dir))) + (should (file-directory-p simple-pkg-dir)) + (with-temp-buffer + (insert-file-contents (expand-file-name "simple-single-pkg.el" + simple-pkg-dir)) + (should (string= (buffer-string) + (concat ";;; -*- no-byte-compile: t -*-\n" + "(define-package \"simple-single\" \"1.3\" " + "\"A single-file package " + "with no dependencies\" 'nil " + ":authors '((\"J. R. Hacker\" . \"jrh@example.com\")) " + ":maintainer '(\"J. R. Hacker\" . \"jrh@example.com\") " + ":url \"http://doodles.au\"" + ")\n")))) + (should (file-exists-p autoloads-file)) + (should-not (get-file-buffer autoloads-file))))) + +(ert-deftest package-test-install-dependency () + "Install a package which includes a dependency." + (with-package-test () + (package-initialize) + (package-refresh-contents) + (package-install 'simple-depend) + (should (package-installed-p 'simple-single)) + (should (package-installed-p 'simple-depend)))) + +(ert-deftest package-test-macro-compilation () + "Install a package which includes a dependency." + (with-package-test (:basedir "package-resources") + (package-install-file (expand-file-name "macro-problem-package-1.0/")) + (require 'macro-problem) + ;; `macro-problem-func' uses a macro from `macro-aux'. + (should (equal (macro-problem-func) '(progn a b))) + (package-install-file (expand-file-name "macro-problem-package-2.0/")) + ;; After upgrading, `macro-problem-func' depends on a new version + ;; of the macro from `macro-aux'. + (should (equal (macro-problem-func) '(1 b))) + ;; `macro-problem-10-and-90' depends on an entirely new macro from `macro-aux'. + (should (equal (macro-problem-10-and-90) '(10 90))))) + +(ert-deftest package-test-install-two-dependencies () + "Install a package which includes a dependency." + (with-package-test () + (package-initialize) + (package-refresh-contents) + (package-install 'simple-two-depend) + (should (package-installed-p 'simple-single)) + (should (package-installed-p 'simple-depend)) + (should (package-installed-p 'simple-two-depend)))) + +(ert-deftest package-test-refresh-contents () + "Parse an \"archive-contents\" file." + (with-package-test () + (package-initialize) + (package-refresh-contents) + (should (eq 4 (length package-archive-contents))))) + +(ert-deftest package-test-install-single-from-archive () + "Install a single package from a package archive." + (with-package-test () + (package-initialize) + (package-refresh-contents) + (package-install 'simple-single))) + +(ert-deftest package-test-install-prioritized () + "Install a lower version from a higher-prioritized archive." + (with-package-test () + (let* ((newer-version (expand-file-name "package-resources/newer-versions" + package-test-file-dir)) + (package-archives `(("older" . ,package-test-data-dir) + ("newer" . ,newer-version))) + (package-archive-priorities '(("older" . 100)))) + + (package-initialize) + (package-refresh-contents) + (package-install 'simple-single) + + (let ((installed (cadr (assq 'simple-single package-alist)))) + (should (version-list-= '(1 3) + (package-desc-version installed))))))) + +(ert-deftest package-test-install-multifile () + "Check properties of the installed multi-file package." + (with-package-test (:basedir "package-resources" :install '(multi-file)) + (let ((autoload-file + (expand-file-name "multi-file-autoloads.el" + (expand-file-name + "multi-file-0.2.3" + package-test-user-dir))) + (installed-files '("dir" "multi-file.info" "multi-file-sub.elc" + "multi-file-autoloads.el" "multi-file.elc")) + (autoload-forms '("^(defvar multi-file-custom-var" + "^(custom-autoload 'multi-file-custom-var" + "^(autoload 'multi-file-mode")) + (pkg-dir (file-name-as-directory + (expand-file-name + "multi-file-0.2.3" + package-test-user-dir)))) + (package-refresh-contents) + (should (package-installed-p 'multi-file)) + (with-temp-buffer + (insert-file-contents-literally autoload-file) + (dolist (fn installed-files) + (should (file-exists-p (expand-file-name fn pkg-dir)))) + (dolist (re autoload-forms) + (goto-char (point-min)) + (should (re-search-forward re nil t))))))) + +(ert-deftest package-test-update-listing () + "Ensure installed package status is updated." + (with-package-test () + (let ((buf (package-list-packages))) + (search-forward-regexp "^ +simple-single") + (package-menu-mark-install) + (package-menu-execute) + (run-hooks 'post-command-hook) + (should (package-installed-p 'simple-single)) + (switch-to-buffer "*Packages*") + (goto-char (point-min)) + (should (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+installed" nil t)) + (goto-char (point-min)) + (should-not (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+\\(available\\|new\\)" nil t)) + (kill-buffer buf)))) + +(ert-deftest package-test-update-archives () + "Test updating package archives." + (with-package-test () + (let ((buf (package-list-packages))) + (package-menu-refresh) + (search-forward-regexp "^ +simple-single") + (package-menu-mark-install) + (package-menu-execute) + (should (package-installed-p 'simple-single)) + (let ((package-test-data-dir + (expand-file-name "package-resources/newer-versions" package-test-file-dir))) + (setq package-archives `(("gnu" . ,package-test-data-dir))) + (package-menu-refresh) + + ;; New version should be available and old version should be installed + (goto-char (point-min)) + (should (re-search-forward "^\\s-+simple-single\\s-+1.4\\s-+available" nil t)) + (should (re-search-forward "^\\s-+simple-single\\s-+1.3\\s-+installed" nil t)) + + (goto-char (point-min)) + (should (re-search-forward "^\\s-+new-pkg\\s-+1.0\\s-+\\(available\\|new\\)" nil t)) + + (package-menu-mark-upgrades) + (package-menu-execute) + (package-menu-refresh) + (should (package-installed-p 'simple-single '(1 4))))))) + +(ert-deftest package-test-update-archives-async () + "Test updating package archives asynchronously." + (skip-unless (executable-find "python2")) + ;; For some reason this test doesn't work reliably on hydra.nixos.org. + (skip-unless (not (getenv "NIX_STORE"))) + (with-package-test (:basedir + package-test-data-dir + :location "http://0.0.0.0:8000/") + (let* ((package-menu-async t) + (process (start-process + "package-server" "package-server-buffer" + (executable-find "python2") + (expand-file-name "package-test-server.py")))) + (unwind-protect + (progn + (list-packages) + (should package--downloads-in-progress) + (should mode-line-process) + (should-not + (with-timeout (10 'timeout) + (while package--downloads-in-progress + (accept-process-output nil 1)) + nil)) + ;; If the server process died, there's some non-Emacs problem. + ;; Eg maybe the port was already in use. + (skip-unless (process-live-p process)) + (goto-char (point-min)) + (should + (search-forward-regexp "^ +simple-single" nil t))) + (if (process-live-p process) (kill-process process)))))) + +(ert-deftest package-test-describe-package () + "Test displaying help for a package." + + (require 'finder-inf) + ;; Built-in + (with-fake-help-buffer + (describe-package '5x5) + (goto-char (point-min)) + (should (search-forward "5x5 is a built-in package." nil t)) + ;; Don't assume the descriptions are in any particular order. + (save-excursion (should (search-forward "Status: Built-in." nil t))) + (save-excursion (should (search-forward "Summary: simple little puzzle game" nil t))) + (should (search-forward "The aim of 5x5" nil t))) + + ;; Installed + (with-package-test () + (package-initialize) + (package-refresh-contents) + (package-install 'simple-single) + (with-fake-help-buffer + (describe-package 'simple-single) + (goto-char (point-min)) + (should (search-forward "simple-single is an installed package." nil t)) + (save-excursion (should (re-search-forward "Status: Installed in ['`‘]simple-single-1.3/['’] (unsigned)." nil t))) + (save-excursion (should (search-forward "Version: 1.3" nil t))) + (save-excursion (should (search-forward "Summary: A single-file package with no dependencies" nil t))) + (save-excursion (should (search-forward "Homepage: http://doodles.au" nil t))) + (save-excursion (should (re-search-forward "Keywords: \\[?frobnicate\\]?" nil t))) + ;; No description, though. Because at this point we don't know + ;; what archive the package originated from, and we don't have + ;; its readme file saved. + ))) + +(ert-deftest package-test-describe-non-installed-package () + "Test displaying of the readme for non-installed package." + + (with-package-test () + (package-initialize) + (package-refresh-contents) + (with-fake-help-buffer + (describe-package 'simple-single) + (goto-char (point-min)) + (should (search-forward "Homepage: http://doodles.au" nil t)) + (should (search-forward "This package provides a minor mode to frobnicate" + nil t))))) + +(ert-deftest package-test-describe-non-installed-multi-file-package () + "Test displaying of the readme for non-installed multi-file package." + + (with-package-test () + (package-initialize) + (package-refresh-contents) + (with-fake-help-buffer + (describe-package 'multi-file) + (goto-char (point-min)) + (should (search-forward "Homepage: http://puddles.li" nil t)) + (should (search-forward "This is a bare-bones readme file for the multi-file" + nil t))))) + +(ert-deftest package-test-signed () + "Test verifying package signature." + (skip-unless (ignore-errors + (let ((homedir (make-temp-file "package-test" t))) + (unwind-protect + (let ((process-environment + (cons (format "HOME=%s" homedir) + process-environment))) + (epg-check-configuration (epg-configuration)) - t) ++ (epg-find-configuration 'OpenPGP)) + (delete-directory homedir t))))) + (let* ((keyring (expand-file-name "key.pub" package-test-data-dir)) + (package-test-data-dir + (expand-file-name "package-resources/signed" package-test-file-dir))) + (with-package-test () + (package-initialize) + (package-import-keyring keyring) + (package-refresh-contents) + (should (package-install 'signed-good)) + (should-error (package-install 'signed-bad)) + ;; Check if the installed package status is updated. + (let ((buf (package-list-packages))) + (package-menu-refresh) + (should (re-search-forward + "^\\s-+signed-good\\s-+\\(\\S-+\\)\\s-+\\(\\S-+\\)\\s-" + nil t)) + (should (string-equal (match-string-no-properties 1) "1.0")) + (should (string-equal (match-string-no-properties 2) "installed"))) + ;; Check if the package description is updated. + (with-fake-help-buffer + (describe-package 'signed-good) + (goto-char (point-min)) + (should (re-search-forward "signed-good is an? \\(\\S-+\\) package." nil t)) + (should (string-equal (match-string-no-properties 1) "installed")) + (should (re-search-forward + "Status: Installed in ['`‘]signed-good-1.0/['’]." + nil t)))))) + + + +;;; Tests for package-x features. + +(require 'package-x) + +(defvar package-x-test--single-archive-entry-1-3 + (cons 'simple-single + (package-make-ac-desc '(1 3) nil + "A single-file package with no dependencies" + 'single + '((:authors ("J. R. Hacker" . "jrh@example.com")) + (:maintainer "J. R. Hacker" . "jrh@example.com") + (:url . "http://doodles.au")))) + "Expected contents of the archive entry from the \"simple-single\" package.") + +(defvar package-x-test--single-archive-entry-1-4 + (cons 'simple-single + (package-make-ac-desc '(1 4) nil + "A single-file package with no dependencies" + 'single + '((:authors ("J. R. Hacker" . "jrh@example.com")) + (:maintainer "J. R. Hacker" . "jrh@example.com")))) + "Expected contents of the archive entry from the updated \"simple-single\" package.") + +(ert-deftest package-x-test-upload-buffer () + "Test creating an \"archive-contents\" file" + (with-package-test (:basedir "package-resources" + :file "simple-single-1.3.el" + :upload-base t) + (package-upload-buffer) + (should (file-exists-p (expand-file-name "archive-contents" + package-archive-upload-base))) + (should (file-exists-p (expand-file-name "simple-single-1.3.el" + package-archive-upload-base))) + (should (file-exists-p (expand-file-name "simple-single-readme.txt" + package-archive-upload-base))) + + (let (archive-contents) + (with-temp-buffer + (insert-file-contents + (expand-file-name "archive-contents" + package-archive-upload-base)) + (setq archive-contents + (package-read-from-string + (buffer-substring (point-min) (point-max))))) + (should (equal archive-contents + (list 1 package-x-test--single-archive-entry-1-3)))))) + +(ert-deftest package-x-test-upload-new-version () + "Test uploading a new version of a package" + (with-package-test (:basedir "package-resources" + :file "simple-single-1.3.el" + :upload-base t) + (package-upload-buffer) + (with-temp-buffer + (insert-file-contents "newer-versions/simple-single-1.4.el") + (package-upload-buffer)) + + (let (archive-contents) + (with-temp-buffer + (insert-file-contents + (expand-file-name "archive-contents" + package-archive-upload-base)) + (setq archive-contents + (package-read-from-string + (buffer-substring (point-min) (point-max))))) + (should (equal archive-contents + (list 1 package-x-test--single-archive-entry-1-4)))))) + +(ert-deftest package-test-get-deps () + "Test `package--get-deps' with complex structures." + (let ((package-alist + (mapcar (lambda (p) (list (package-desc-name p) p)) + (list simple-single-desc + simple-depend-desc + multi-file-desc + new-pkg-desc + simple-depend-desc-1 + simple-depend-desc-2)))) + (should + (equal (package--get-deps 'simple-depend) + '(simple-single))) + (should + (equal (package--get-deps 'simple-depend 'indirect) + nil)) + (should + (equal (package--get-deps 'simple-depend 'direct) + '(simple-single))) + (should + (equal (package--get-deps 'simple-depend-2) + '(simple-depend-1 multi-file simple-depend simple-single))) + (should + (equal (package--get-deps 'simple-depend-2 'indirect) + '(simple-depend multi-file simple-single))) + (should + (equal (package--get-deps 'simple-depend-2 'direct) + '(simple-depend-1 multi-file))))) + +(ert-deftest package-test-sort-by-dependence () + "Test `package--sort-by-dependence' with complex structures." + (let ((package-alist + (mapcar (lambda (p) (list (package-desc-name p) p)) + (list simple-single-desc + simple-depend-desc + multi-file-desc + new-pkg-desc + simple-depend-desc-1 + simple-depend-desc-2))) + (delete-list + (list simple-single-desc + simple-depend-desc + multi-file-desc + new-pkg-desc + simple-depend-desc-1 + simple-depend-desc-2))) + (should + (equal (package--sort-by-dependence delete-list) + + (list simple-depend-desc-2 simple-depend-desc-1 new-pkg-desc + multi-file-desc simple-depend-desc simple-single-desc))) + (should + (equal (package--sort-by-dependence (reverse delete-list)) + (list new-pkg-desc simple-depend-desc-2 simple-depend-desc-1 + multi-file-desc simple-depend-desc simple-single-desc))))) + +(provide 'package-test) + +;;; package-test.el ends here diff --cc test/lisp/progmodes/ruby-mode-tests.el index 4fa7470218a,00000000000..7e85fb83edd mode 100644,000000..100644 --- a/test/lisp/progmodes/ruby-mode-tests.el +++ b/test/lisp/progmodes/ruby-mode-tests.el @@@ -1,730 -1,0 +1,738 @@@ +;;; ruby-mode-tests.el --- Test suite for ruby-mode + +;; Copyright (C) 2012-2016 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;;; Code: + +(require 'ert) +(require 'ruby-mode) + +(defmacro ruby-with-temp-buffer (contents &rest body) + (declare (indent 1) (debug t)) + `(with-temp-buffer + (insert ,contents) + (ruby-mode) + ,@body)) + +(defun ruby-should-indent (content column) + "Assert indentation COLUMN on the last line of CONTENT." + (ruby-with-temp-buffer content + (indent-according-to-mode) + (should (= (current-indentation) column)))) + +(defun ruby-should-indent-buffer (expected content) + "Assert that CONTENT turns into EXPECTED after the buffer is re-indented. + +The whitespace before and including \"|\" on each line is removed." + (ruby-with-temp-buffer (ruby-test-string content) + (indent-region (point-min) (point-max)) + (should (string= (ruby-test-string expected) (buffer-string))))) + +(defun ruby-test-string (s &rest args) + (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) + +(defun ruby-assert-state (content index value &optional point) + "Assert syntax state values at the end of CONTENT. + +VALUES-PLIST is a list with alternating index and value elements." + (ruby-with-temp-buffer content + (when point (goto-char point)) + (syntax-propertize (point)) + (should (eq (nth index + (parse-partial-sexp (point-min) (point))) + value)))) + +(defun ruby-assert-face (content pos face) + (ruby-with-temp-buffer content + (font-lock-ensure nil nil) + (should (eq face (get-text-property pos 'face))))) + +(ert-deftest ruby-indent-after-symbol-made-from-string-interpolation () + "It can indent the line after symbol made using string interpolation." + (ruby-should-indent "def foo(suffix)\n :\"bar#{suffix}\"\n" + ruby-indent-level)) + +(ert-deftest ruby-indent-after-js-style-symbol-with-block-beg-name () + "JS-style hash symbol can have keyword name." + (ruby-should-indent "link_to \"home\", home_path, class: \"foo\"\n" 0)) + +(ert-deftest ruby-discern-singleton-class-from-heredoc () + (ruby-assert-state "foo < 5 } + | .map { |str| str.downcase }" + "one.two.three + | .four + | + |my_array.select { |str| str.size > 5 } + | .map { |str| str.downcase }"))) + +(ert-deftest ruby-move-to-block-stops-at-indentation () + (ruby-with-temp-buffer "def f\nend" + (beginning-of-line) + (ruby-move-to-block -1) + (should (looking-at "^def")))) + +(ert-deftest ruby-toggle-block-to-do-end () + (ruby-with-temp-buffer "foo {|b|\n}" + (beginning-of-line) + (ruby-toggle-block) + (should (string= "foo do |b|\nend" (buffer-string))))) + +(ert-deftest ruby-toggle-block-to-brace () + (let ((pairs '((17 . "foo { |b| b + 2 }") + (16 . "foo { |b|\n b + 2\n}")))) + (dolist (pair pairs) + (with-temp-buffer + (let ((fill-column (car pair))) + (insert "foo do |b|\n b + 2\nend") + (ruby-mode) + (beginning-of-line) + (ruby-toggle-block) + (should (string= (cdr pair) (buffer-string)))))))) + +(ert-deftest ruby-toggle-block-to-multiline () + (ruby-with-temp-buffer "foo {|b| b + 1}" + (beginning-of-line) + (ruby-toggle-block) + (should (string= "foo do |b|\n b + 1\nend" (buffer-string))))) + +(ert-deftest ruby-toggle-block-with-interpolation () + (ruby-with-temp-buffer "foo do\n \"#{bar}\"\nend" + (beginning-of-line) + (ruby-toggle-block) + (should (string= "foo { \"#{bar}\" }" (buffer-string))))) + +(ert-deftest ruby-recognize-symbols-starting-with-at-character () + (ruby-assert-face ":@abc" 3 font-lock-constant-face)) + +(ert-deftest ruby-hash-character-not-interpolation () + (ruby-assert-face "\"This is #{interpolation}\"" 15 + font-lock-variable-name-face) + (ruby-assert-face "\"This is \\#{no interpolation} despite the #\"" + 15 font-lock-string-face) + (ruby-assert-face "\n#@comment, not ruby code" 5 font-lock-comment-face) + (ruby-assert-state "\n#@comment, not ruby code" 4 t) + (ruby-assert-face "# A comment cannot have #{an interpolation} in it" + 30 font-lock-comment-face) + (ruby-assert-face "# #{comment}\n \"#{interpolation}\"" 16 + font-lock-variable-name-face)) + +(ert-deftest ruby-interpolation-suppresses-quotes-inside () + (let ((s "\"
  • #{@files.join(\"
  • \")}
\"")) + (ruby-assert-state s 8 nil) + (ruby-assert-face s 9 font-lock-string-face) + (ruby-assert-face s 10 font-lock-variable-name-face) + (ruby-assert-face s 41 font-lock-string-face))) + +(ert-deftest ruby-interpolation-suppresses-one-double-quote () + (let ((s "\"foo#{'\"'}\"")) + (ruby-assert-state s 8 nil) + (ruby-assert-face s 8 font-lock-variable-name-face) + (ruby-assert-face s 11 font-lock-string-face))) + +(ert-deftest ruby-interpolation-suppresses-one-backtick () + (let ((s "`as#{'`'}das`")) + (ruby-assert-state s 8 nil))) + +(ert-deftest ruby-interpolation-keeps-non-quote-syntax () + (let ((s "\"foo#{baz.tee}bar\"")) + (ruby-with-temp-buffer s + (goto-char (point-min)) + (ruby-mode) + (syntax-propertize (point-max)) + (search-forward "tee") + (should (string= (thing-at-point 'symbol) "tee"))))) + +(ert-deftest ruby-interpolation-inside-percent-literal () + (let ((s "%( #{boo} )")) + (ruby-assert-face s 1 font-lock-string-face) + (ruby-assert-face s 4 font-lock-variable-name-face) + (ruby-assert-face s 10 font-lock-string-face) + (ruby-assert-state s 8 nil))) + +(ert-deftest ruby-interpolation-inside-percent-literal-with-paren () + :expected-result :failed + (let ((s "%(^#{\")\"}^)")) + (ruby-assert-face s 3 font-lock-string-face) + (ruby-assert-face s 4 font-lock-variable-name-face) + (ruby-assert-face s 10 font-lock-string-face) + ;; It's confused by the closing paren in the middle. + (ruby-assert-state s 8 nil))) + ++(ert-deftest ruby-interpolation-inside-another-interpolation () ++ :expected-result :failed ++ (let ((s "\"#{[a, b, c].map { |v| \"#{v}\" }.join}\"")) ++ (ruby-assert-face s 1 font-lock-string-face) ++ (ruby-assert-face s 2 font-lock-variable-name-face) ++ (ruby-assert-face s 38 font-lock-string-face) ++ (ruby-assert-state s 8 nil))) ++ +(ert-deftest ruby-interpolation-inside-double-quoted-percent-literals () + (ruby-assert-face "%Q{foo #@bar}" 8 font-lock-variable-name-face) + (ruby-assert-face "%W{foo #@bar}" 8 font-lock-variable-name-face) + (ruby-assert-face "%r{foo #@bar}" 8 font-lock-variable-name-face) + (ruby-assert-face "%x{foo #@bar}" 8 font-lock-variable-name-face)) + +(ert-deftest ruby-no-interpolation-in-single-quoted-literals () + (ruby-assert-face "'foo #@bar'" 7 font-lock-string-face) + (ruby-assert-face "%q{foo #@bar}" 8 font-lock-string-face) + (ruby-assert-face "%w{foo #@bar}" 8 font-lock-string-face) + (ruby-assert-face "%s{foo #@bar}" 8 font-lock-string-face)) + +(ert-deftest ruby-interpolation-after-dollar-sign () + (ruby-assert-face "\"$#{balance}\"" 2 'font-lock-string-face) + (ruby-assert-face "\"$#{balance}\"" 3 'font-lock-variable-name-face)) + +(ert-deftest ruby-no-unknown-percent-literals () + ;; No folding of case. + (ruby-assert-face "%S{foo}" 4 nil) + (ruby-assert-face "%R{foo}" 4 nil)) + +(ert-deftest ruby-no-nested-percent-literals () + (ruby-with-temp-buffer "a = %w[b %()]" + (syntax-propertize (point)) + (should (null (nth 8 (syntax-ppss)))) + (should (eq t (nth 3 (syntax-ppss (1- (point-max)))))) + (search-backward "[") + (should (eq t (nth 3 (syntax-ppss)))))) + +(ert-deftest ruby-add-log-current-method-examples () + (let ((pairs '(("foo" . "#foo") + ("C.foo" . ".foo") + ("self.foo" . ".foo")))) + (dolist (pair pairs) + (let ((name (car pair)) + (value (cdr pair))) + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | def %s + | _ + | end + | end + |end" + name) + (search-backward "_") + (forward-line) + (should (string= (ruby-add-log-current-method) + (format "M::C%s" value)))))))) + +(ert-deftest ruby-add-log-current-method-outside-of-method () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | def foo + | end + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method)"M::C")))) + +(ert-deftest ruby-add-log-current-method-in-singleton-class () + (ruby-with-temp-buffer (ruby-test-string + "class C + | class << self + | def foo + | _ + | end + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method) "C.foo")))) + +(ert-deftest ruby-add-log-current-method-namespace-shorthand () + (ruby-with-temp-buffer (ruby-test-string + "class C::D + | def foo + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method) "C::D#foo")))) + +(ert-deftest ruby-add-log-current-method-after-inner-class () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | class D + | end + | def foo + | _ + | end + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method) "M::C#foo")))) + +(defvar ruby-block-test-example + (ruby-test-string + "class C + | def foo + | 1 + | end + | + | def bar + | 2 + | end + | + | def baz + |some do + |3 + | end + | end + |end")) + +(defmacro ruby-deftest-move-to-block (name &rest body) + (declare (indent defun)) + `(ert-deftest ,(intern (format "ruby-move-to-block-%s" name)) () + (with-temp-buffer + (insert ruby-block-test-example) + (ruby-mode) + (goto-char (point-min)) + ,@body))) + +(ruby-deftest-move-to-block works-on-do + (forward-line 10) + (ruby-end-of-block) + (should (= 13 (line-number-at-pos))) + (ruby-beginning-of-block) + (should (= 11 (line-number-at-pos)))) + +(ruby-deftest-move-to-block zero-is-noop + (forward-line 4) + (ruby-move-to-block 0) + (should (= 5 (line-number-at-pos)))) + +(ruby-deftest-move-to-block ok-with-three + (forward-line 1) + (ruby-move-to-block 3) + (should (= 14 (line-number-at-pos)))) + +(ruby-deftest-move-to-block ok-with-minus-two + (forward-line 9) + (ruby-move-to-block -2) + (should (= 2 (line-number-at-pos)))) + +(ert-deftest ruby-move-to-block-skips-percent-literal () + (dolist (s (list (ruby-test-string + "foo do + | a = %%w( + | def yaa + | ) + |end") + (ruby-test-string + "foo do + | a = %%w| + | end + | | + |end"))) + (ruby-with-temp-buffer s + (goto-char (point-min)) + (ruby-end-of-block) + (should (= 5 (line-number-at-pos))) + (ruby-beginning-of-block) + (should (= 1 (line-number-at-pos)))))) + +(ert-deftest ruby-move-to-block-skips-heredoc () + (ruby-with-temp-buffer + (ruby-test-string + "if something_wrong? + | ActiveSupport::Deprecation.warn(<<-eowarn) + | boo hoo + | end + | eowarn + |end") + (goto-char (point-min)) + (ruby-end-of-block) + (should (= 6 (line-number-at-pos))) + (ruby-beginning-of-block) + (should (= 1 (line-number-at-pos))))) + +(ert-deftest ruby-move-to-block-does-not-fold-case () + (ruby-with-temp-buffer + (ruby-test-string + "foo do + | Module.to_s + |end") + (let ((case-fold-search t)) + (ruby-beginning-of-block)) + (should (= 1 (line-number-at-pos))))) + +(ert-deftest ruby-move-to-block-moves-from-else-to-if () + (ruby-with-temp-buffer (ruby-test-string + "if true + | nested_block do + | end + |else + |end") + (goto-char (point-min)) + (forward-line 3) + (ruby-beginning-of-block) + (should (= 1 (line-number-at-pos))))) + +(ert-deftest ruby-beginning-of-defun-does-not-fold-case () + (ruby-with-temp-buffer + (ruby-test-string + "class C + | def bar + | Class.to_s + | end + |end") + (goto-char (point-min)) + (forward-line 3) + (let ((case-fold-search t)) + (beginning-of-defun)) + (should (= 2 (line-number-at-pos))))) + +(ert-deftest ruby-end-of-defun-skips-to-next-line-after-the-method () + (ruby-with-temp-buffer + (ruby-test-string + "class D + | def tee + | 'ho hum' + | end + |end") + (goto-char (point-min)) + (forward-line 1) + (end-of-defun) + (should (= 5 (line-number-at-pos))))) + +(defvar ruby-sexp-test-example + (ruby-test-string + "class C + | def foo + | self.end + | D.new.class + | [1, 2, 3].map do |i| + | i + 1 + | end.sum + | end + |end")) + +(ert-deftest ruby-forward-sexp-skips-method-calls-with-keyword-names () + (ruby-with-temp-buffer ruby-sexp-test-example + (goto-line 2) + (ruby-forward-sexp) + (should (= 8 (line-number-at-pos))))) + +(ert-deftest ruby-backward-sexp-skips-method-calls-with-keyword-names () + (ruby-with-temp-buffer ruby-sexp-test-example + (goto-line 8) + (end-of-line) + (ruby-backward-sexp) + (should (= 2 (line-number-at-pos))))) + +(ert-deftest ruby--insert-coding-comment-ruby-style () + (with-temp-buffer + (let ((ruby-encoding-magic-comment-style 'ruby)) + (ruby--insert-coding-comment "utf-8") + (should (string= "# coding: utf-8\n" (buffer-string)))))) + +(ert-deftest ruby--insert-coding-comment-emacs-style () + (with-temp-buffer + (let ((ruby-encoding-magic-comment-style 'emacs)) + (ruby--insert-coding-comment "utf-8") + (should (string= "# -*- coding: utf-8 -*-\n" (buffer-string)))))) + +(ert-deftest ruby--insert-coding-comment-custom-style () + (with-temp-buffer + (let ((ruby-encoding-magic-comment-style 'custom) + (ruby-custom-encoding-magic-comment-template "# encoding: %s\n")) + (ruby--insert-coding-comment "utf-8") + (should (string= "# encoding: utf-8\n\n" (buffer-string)))))) + + +(provide 'ruby-mode-tests) + +;;; ruby-mode-tests.el ends here diff --cc test/manual/indent/ruby.rb index 585263d02a6,00000000000..b038512b114 mode 100644,000000..100644 --- a/test/manual/indent/ruby.rb +++ b/test/manual/indent/ruby.rb @@@ -1,433 -1,0 +1,477 @@@ +if something_wrong? # ruby-move-to-block-skips-heredoc + ActiveSupport::Deprecation.warn(<<-eowarn) + boo hoo + end + eowarn + foo + + foo(<<~squiggly) + end + squiggly +end + +def foo + %^bar^ +end + +# Percent literals. +b = %Q{This is a "string"} +c = %w!foo + bar + baz! +d = %(hello (nested) world) + +# Don't propertize percent literals inside strings. +"(%s, %s)" % [123, 456] + - "abc/#{def}ghi" - "abc\#{def}ghi" ++"abc/#{ddf}ghi" ++"abc\#{ddf}ghi" + +# Or inside comments. +x = # "tot %q/to"; = + y = 2 / 3 + +# Regexp after whitelisted method. +"abc".sub /b/, 'd' + +# Don't mis-match "sub" at the end of words. +a = asub / aslb + bsub / bslb; + +# Highlight the regexp after "if". +x = toto / foo if /do bar/ =~ "dobar" + +# Regexp options are highlighted. + +/foo/xi != %r{bar}mo.tee + +foo { /"tee/ + bar { |qux| /'fee"/ } # bug#20026 +} + +bar(class: XXX) do # ruby-indent-keyword-label + foo +end +bar + +foo = [1, # ruby-deep-indent + 2] + +foo = { # ruby-deep-indent-disabled + a: b +} + +foo = { a: b, + a1: b1 + } + +foo({ # bug#16118 + a: b, + c: d + }) + +bar = foo( + a, [ + 1, + ], + :qux => [ + 3 + ]) + +foo( + [ + { + a: b + }, + ], + { + c: d + } +) + +foo([{ + a: 2 + }, + { + b: 3 + }, + 4 + ]) + +foo = [ # ruby-deep-indent-disabled + 1 +] + +foo( # ruby-deep-indent-disabled + a +) + +# Multiline regexp. +/bars + tees # toots + nfoos/ + +def test1(arg) + puts "hello" +end + +def test2 (arg) + a = "apple" + + if a == 2 + puts "hello" + else + puts "there" + end + + if a == 2 then + puts "hello" + elsif a == 3 + puts "hello3" + elsif a == 3 then + puts "hello3" + else + puts "there" + end + + b = case a + when "a" + 6 + # Support for this syntax was removed in Ruby 1.9, so we + # probably don't need to handle it either. + # when "b" : + # 7 + # when "c" : 2 + when "d" then 4 + else 5 + end +end + +# Some Cucumber code: +Given /toto/ do + print "hello" +end + +# Bug#15208 +if something == :== + do_something + + return false unless method == :+ + x = y + z # Bug#16609 + + a = 1 ? 2 :( + 2 + 3 + ) +end + +# Bug#17097 +if x == :!= + something +end + +qux :+, + bar, + :[]=, + bar, + :a + +b = $: +c = ?? + +# Example from http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html +d = 4 + 5 + # no '\' needed + 6 + 7 + +# Example from http://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html +e = 8 + 9 \ + + 10 # '\' needed + +foo = obj.bar { |m| tee(m) } + + obj.qux { |m| hum(m) } + +begin + foo +ensure + bar +end + +# Bug#15369 +MSG = 'Separate every 3 digits in the integer portion of a number' \ + 'with underscores(_).' + +class C + def foo + self.end + D.new.class + end + + def begin + end +end + +a = foo(j, k) - + bar_tee + +while a < b do # "do" is optional + foo +end + +desc "foo foo" \ + "bar bar" + +foo. + bar + +# https://github.com/rails/rails/blob/17f5d8e062909f1fcae25351834d8e89967b645e/activesupport/lib/active_support/time_with_zone.rb#L206 - foo ++foo # comment intended to confuse the tokenizer + .bar + +z = { + foo: { + a: "aaa", + b: "bbb" + } +} + +foo if + bar + +fail "stuff" \ + unless all_fine? + +if foo? + bar +end + +method arg1, # bug#15594 + method2 arg2, + arg3 + +method? arg1, + arg2 + +method! arg1, + arg2 + +method !arg1, + arg2 + +method [], + arg2 + +method :foo, + :bar + +method (a + b), + c, :d => :e, + f: g + +desc "abc", + defg + +it "is a method call with block" do |asd| + foo +end + +it("is too!") { + bar + .qux +} + +and_this_one(has) { |block, parameters| + tee +} + +if foo && + bar +end + +foo + + bar + +foo and + bar + +foo > bar && + tee < qux + +zux do - foo == bar and ++ foo == bar && + tee == qux ++ ++ a = 3 and ++ b = 4 +end + ++foo + bar == ++ tee + qux ++ ++1 .. 2 && ++ 3 ++ ++3 < 4 + ++ 5 ++ ++10 << 4 ^ ++ 20 ++ ++100 + 2 >> ++ 3 ++ ++2 ** 10 / ++ 2 ++ +foo ^ + bar + +foo_bar_tee(1, 2, 3) - .qux.bar - .tee ++ .qux&.bar ++ .tee.bar ++ &.tee + +foo do + bar + .tee +end + +def bar + foo + .baz +end + ++abc(foo ++ .bar, ++ tee ++ .qux) ++ +# http://stackoverflow.com/questions/17786563/emacs-ruby-mode-if-expressions-indentation +tee = if foo + bar + else + tee + end + +a = b { + c +} + +aa = bb do + cc +end + +foo :bar do + qux +end + +foo do |*args| + tee +end + +bar do |&block| + tee +end + +foo = [1, 2, 3].map do |i| + i + 1 +end + +bar.foo do + bar +end + +bar.foo(tee) do + bar +end + +bar.foo(tee) { + bar +} + +bar 1 do + foo 2 do + tee + end +end + +foo | + bar + +def qux + foo ||= begin + bar + tee + rescue + oomph + end +end + +private def foo + bar +end + +%^abc^ +ddd + +qux = foo.fee ? + bar : + tee + +zoo.keep.bar!( + {x: y, + z: t}) + +zoo + .lose( + q, p) + +a.records().map(&:b).zip( + foo) + ++foo1 = ++ subject.update( ++ 1 ++ ) ++ ++foo2 = ++ subject. ++ update( ++ 2 ++ ) ++ +# FIXME: This is not consistent with the example below it, but this +# offset only happens if the colon is at eol, which wouldn't be often. +# Tokenizing `bar:' as `:bar =>' would be better, but it's hard to +# distinguish from a variable reference inside a ternary operator. +foo(bar: + tee) + +foo(:bar => + tee) + ++regions = foo( ++ OpenStruct.new(id: 0, name: "foo") => [ ++ 10 ++ ] ++) ++ +{'a' => { + 'b' => 'c', + 'd' => %w(e f) + } +} + +# Bug#17050 + +return render json: { + errors: { base: [message] }, + copying: copying + }, + status: 400 + +top test( + some, + top, + test) + +foo bar, { + tee: qux + }