diff --git a/admin/charsets/mule-charsets.el b/admin/charsets/mule-charsets.el index 8355af4488d..99a8c60d880 100644 --- a/admin/charsets/mule-charsets.el +++ b/admin/charsets/mule-charsets.el @@ -1,4 +1,4 @@ -;; mule-charsets.el -- Generate Mule-original charset maps. +;; mule-charsets.el -- Generate Mule-original charset maps. -*- lexical-binding: t -*- ;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 ;; National Institute of Advanced Industrial Science and Technology (AIST) ;; Registration Number H13PRO009 @@ -55,14 +55,14 @@ ("MULE-lviscii.map" . vietnamese-viscii-lower) ("MULE-uviscii.map" . vietnamese-viscii-upper))) -(defconst header +(defconst mule-charsets-header (format "# Generated by running admin/charsets/mule-charsets.el in Emacs %d.%d.\n" emacs-major-version emacs-minor-version)) (dolist (elt charset-alist) (with-temp-buffer - (insert header) + (insert mule-charsets-header) (map-charset-chars 'func (cdr elt) (cdr elt)) (sort-lines nil (point-min) (point-max)) (let ((coding-system-for-write 'unix)) diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi index 3e09f243226..91c749aa2d5 100644 --- a/doc/emacs/building.texi +++ b/doc/emacs/building.texi @@ -1092,13 +1092,12 @@ code that has already executed, in order to examine its execution in more detail. @vindex gdb-mi-decode-strings - If the file names of the source files are shown with octal escapes, -set the variable @code{gdb-mi-decode-strings} to the appropriate -coding-system, most probably @code{utf-8}. (This is @code{nil} by -default because GDB may emit octal escapes in situations where -decoding is undesirable, and also because the program being debugged -might use an encoding different from the one used to encode non-ASCII -file names on your system.) + By default, source file names and non-ASCII strings in the program +being debugged are decoded using the default coding-system. If you +prefer a different decoding, perhaps because the program being +debugged uses a different character encoding, set the variable +@code{gdb-mi-decode-strings} to the appropriate coding-system, or to +@code{nil} to leave non-ASCII characters as undecoded octal escapes. @node Breakpoints Buffer @subsubsection Breakpoints Buffer diff --git a/doc/emacs/custom.texi b/doc/emacs/custom.texi index 81874a04aa7..fb60caa773b 100644 --- a/doc/emacs/custom.texi +++ b/doc/emacs/custom.texi @@ -1582,6 +1582,13 @@ starts with @kbd{@key{ESC} [}.) If Emacs understands your terminal type properly, it automatically handles such sequences as single input events. + Key sequences that consist of @kbd{C-c} followed by a letter (upper +or lower case; @acronym{ASCII} or non-@acronym{ASCII}) are reserved +for users. Emacs itself will never bind those key sequences, and +Emacs extensions should avoid binding them. In other words, users can +bind key sequences like @kbd{C-c a} or @kbd{C-c ç} and rely on these +never being shadowed by other Emacs bindings. + @node Prefix Keymaps @subsection Prefix Keymaps diff --git a/doc/emacs/frames.texi b/doc/emacs/frames.texi index 1a44d8dc628..f5e2e8d1720 100644 --- a/doc/emacs/frames.texi +++ b/doc/emacs/frames.texi @@ -214,7 +214,11 @@ speed is linked to how fast you move the wheel. This mode also supports increasing or decreasing the height of the default face, by default bound to scrolling with the @key{Ctrl} modifier. -Emacs also supports horizontal scrolling with the @key{Shift} modifier. +@vindex mouse-wheel-scroll-amount-horizontal +Emacs also supports horizontal scrolling with the @key{Shift} +modifier. Typing a numeric prefix arg (e.g., @kbd{M-5}) before +starting horizontal scrolling changes its step value defined +by the user option @code{mouse-wheel-scroll-amount-horizontal}. @vindex mouse-wheel-tilt-scroll @vindex mouse-wheel-flip-direction diff --git a/doc/emacs/mini.texi b/doc/emacs/mini.texi index 54f046a7e05..ede95a28d4e 100644 --- a/doc/emacs/mini.texi +++ b/doc/emacs/mini.texi @@ -69,6 +69,17 @@ the minibuffer for a few seconds, or until you type something; then the minibuffer comes back. While the minibuffer is in use, Emacs does not echo keystrokes. +@vindex minibuffer-follows-selected-frame + While using the minibuffer, you can switch to a different frame, +perhaps to note text you need to enter (@pxref{Frame Commands}). By +default, the active minibuffer moves to this new frame. If you set +the user option @code{minibuffer-follows-selected-frame} to +@code{nil}, then the minibuffer stays in the frame where you opened +it, and you must switch back to that frame in order to complete (or +abort) the current command. Note that the effect of the command, when +you finally finish using the minibuffer, always takes place in the +frame where you first opened it. + @node Minibuffer File @section Minibuffers for File Names diff --git a/doc/emacs/mule.texi b/doc/emacs/mule.texi index b78019020a6..72ae7697677 100644 --- a/doc/emacs/mule.texi +++ b/doc/emacs/mule.texi @@ -578,6 +578,11 @@ Enable or disable use of the selected input method (@code{toggle-input-method}). @item C-x @key{RET} C-\ @var{method} @key{RET} Select a new input method for the current buffer (@code{set-input-method}). +@item C-x \ @var{method} @key{RET} +Temporarily enable the selected transient input method ; it will be +automatically disabled after inserting a single character +(@code{activate-transient-input-method}). + @item C-h I @var{method} @key{RET} @itemx C-h C-\ @var{method} @key{RET} @findex describe-input-method @@ -675,6 +680,21 @@ character. input methods. The list gives information about each input method, including the string that stands for it in the mode line. +@findex activate-transient-input-method +@kindex C-x \ +@anchor{transient input method} + Sometimes it can be convenient to enable an input method +@dfn{transiently}, for inserting only a single character. Typing +@kbd{C-x \} (@code{activate-transient-input-method}) will temporarily +enable an input method, let you insert a single character using the input +method rules, and then automatically disable the input method. If no +transient input method was selected yet, @kbd{C-x \} will prompt you +for an input method; subsequent invocations of this command will +enable the selected transient input method. To select a different +transient input method, type @kbd{C-u C-x \}. You can select a +transient method that is different from the input method which you +selected using @kbd{C-u C-\}. + @node Coding Systems @section Coding Systems @cindex coding systems diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index 91b433f1738..0612c134d1b 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -419,6 +419,7 @@ character into the search string, similar to the usual @kindex C-^ @r{(Incremental Search)} @findex isearch-toggle-input-method @findex isearch-toggle-specified-input-method +@findex isearch-transient-input-method Use an input method (@pxref{Input Methods}). If an input method is enabled in the current buffer when you start the search, the same method will be active in the minibuffer when you type the search @@ -437,7 +438,11 @@ I-search [@var{im}]: @noindent where @var{im} is the mnemonic of the active input method. Any input method you enable during incremental search remains enabled in the -current buffer afterwards. +current buffer afterwards. Finally, you can temporarily enable a +transient input method (@pxref{transient input method}) with +@kbd{C-x \} (@code{isearch-transient-input-method}) to insert a single +character to the search string using an input method, and +automatically disable the input method afterwards. @end itemize @kindex M-s o @r{(Incremental Search)} diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index fc66d1c085d..d49ac42bb46 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -2917,7 +2917,7 @@ or display the names in a buffer using the @code{ls} shell command. In the latter case, it can optionally display information about each file, depending on the options passed to the @code{ls} command. -@defun directory-files directory &optional full-name match-regexp nosort +@defun directory-files directory &optional full-name match-regexp nosort count This function returns a list of the names of the files in the directory @var{directory}. By default, the list is in alphabetical order. @@ -2937,6 +2937,10 @@ you want the utmost possible speed and don't care what order the files are processed in. If the order of processing is visible to the user, then the user will probably be happier if you do sort the names. +If @var{count} is non-@code{nil}, the function will return names of +first @var{count} number of files, or names of all files, whichever +occurs first. @var{count} has to be an integer greater than zero. + @example @group (directory-files "~lewis") @@ -2950,6 +2954,16 @@ An error is signaled if @var{directory} is not the name of a directory that can be read. @end defun +@defun directory-empty-p directory +This utility function returns @code{t} if given @var{directory} is an +accessible directory and it does not contain any files, i.e., is an +empty directory. It will ignore @samp{.} and @samp{..} on systems +that return them as files in a directory. + +Symbolic links to directories count as directories. +See @var{file-symlink-p} to distinguish symlinks. +@end defun + @cindex recursive traverse of directory tree @defun directory-files-recursively directory regexp &optional include-directories predicate follow-symlinks Return all files under @var{directory} whose names match @var{regexp}. @@ -2996,7 +3010,7 @@ is called with one argument (the file or directory) and should return non-@code{nil} if that directory is the one it is looking for. @end defun -@defun directory-files-and-attributes directory &optional full-name match-regexp nosort id-format +@defun directory-files-and-attributes directory &optional full-name match-regexp nosort id-format count This is similar to @code{directory-files} in deciding which files to report on and how to report their names. However, instead of returning a list of file names, it returns for each file a diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index e8e22078d9b..222a17fad4c 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -2368,6 +2368,8 @@ argument @var{fileonly} non-@code{nil} means check only that @var{file} exists, not that it actually defines @var{function}. @end defmac +@findex check-declare-file +@findex check-declare-directory To verify that these functions really are declared where @code{declare-function} says they are, use @code{check-declare-file} to check all @code{declare-function} calls in one source file, or use diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index e5a0233b3c7..b6a3434d15e 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi @@ -2586,10 +2586,12 @@ The minibuffer command @code{next-matching-history-element} (normally @node Minibuffer Misc @section Minibuffer Miscellany -@defun minibufferp &optional buffer-or-name +@defun minibufferp &optional buffer-or-name live This function returns non-@code{nil} if @var{buffer-or-name} is a -minibuffer. If @var{buffer-or-name} is omitted, it tests the current -buffer. +minibuffer. If @var{buffer-or-name} is omitted or @code{nil}, it +tests the current buffer. When @var{live} is non-@code{nil}, the +function returns non-@code{nil} only when @var{buffer-or-name} is an +active minibuffer. @end defun @defvar minibuffer-setup-hook diff --git a/doc/lispref/streams.texi b/doc/lispref/streams.texi index 2cd61ad04fc..0534afb67fa 100644 --- a/doc/lispref/streams.texi +++ b/doc/lispref/streams.texi @@ -902,3 +902,17 @@ variable. The string should hold a @samp{%}-specification to be used in the C function @code{sprintf}. For further restrictions on what you can use, see the variable's documentation string. @end defvar + +@defvar print-integers-as-characters +When this variable is non-@code{nil}, integers that represent +graphic base characters will be printed using Lisp character syntax +(@pxref{Basic Char Syntax}). Other numbers are printed the usual way. +For example, the list @code{(4 65 -1 10)} would be printed as +@samp{(4 ?A -1 ?\n)}. + +More precisely, values printed in character syntax are those +representing characters belonging to the Unicode general categories +Letter, Number, Punctuation, Symbol and Private-use +(@pxref{Character Properties}), as well as the control characters +having their own escape syntax such as newline. +@end defvar diff --git a/doc/lispref/tips.texi b/doc/lispref/tips.texi index 32836639a01..40d01d47468 100644 --- a/doc/lispref/tips.texi +++ b/doc/lispref/tips.texi @@ -283,8 +283,9 @@ implementing such clickable links. @cindex keys, reserved Don't define @kbd{C-c @var{letter}} as a key in Lisp programs. Sequences consisting of @kbd{C-c} and a letter (either upper or lower -case) are reserved for users; they are the @strong{only} sequences -reserved for users, so do not block them. +case; @acronym{ASCII} or non-@acronym{ASCII}) are reserved for users; +they are the @strong{only} sequences reserved for users, so do not +block them. Changing all the Emacs major modes to respect this convention was a lot of work; abandoning this convention would make that work go to diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index a35225256b6..cb2e83270e6 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -140,12 +140,12 @@ out. @item Connect to Freenode -Run @kbd{M-x erc}. Use ``irc.freenode.net'' as the IRC server, ``6667'' -as the port, and choose a nickname. +Run @kbd{M-x erc}. Use ``chat.freenode.net'' as the IRC server, +``6667'' as the port, and choose a nickname. @item Get used to the interface -Switch to the ``irc.freenode.net:6667'' buffer, if you're not already +Switch to the ``chat.freenode.net:6667'' buffer, if you're not already there. You will see first some messages about checking for ident, and then a bunch of other messages that describe the current IRC server. @@ -162,9 +162,10 @@ channel. If you would like to be able to talk with people privately on the Freenode network, you will have to ``register'' your nickname. To do -so, switch to the ``irc.freenode.net:6667'' buffer and type ``/msg +so, switch to the ``chat.freenode.net:6667'' buffer and type ``/msg NickServ register '', replacing ``'' with your -desired password. It should tell you that the operation was successful. +desired password. It should tell you that the operation was +successful. @item Talk to people in the channel @@ -518,7 +519,7 @@ That is, if called with the following arguments, @var{server} and parameters. @example -(erc :server "irc.freenode.net" :full-name "Harry S Truman") +(erc :server "chat.freenode.net" :full-name "Harry S Truman") @end example @end defun @@ -694,7 +695,8 @@ stuff, to the current ERC buffer." ;; This causes ERC to connect to the Freenode network upon hitting ;; C-c e f. Replace MYNICK with your IRC nick. (global-set-key "\C-cef" (lambda () (interactive) - (erc :server "irc.freenode.net" :port "6667" + (erc :server "chat.freenode.net" + :port "6667" :nick "MYNICK"))) ;; This causes ERC to connect to the IRC server on your own machine (if @@ -718,7 +720,7 @@ stuff, to the current ERC buffer." (setq erc-autojoin-channels-alist '(("freenode.net" "#emacs" "#erc"))) ;; Rename server buffers to reflect the current network name instead -;; of SERVER:PORT (e.g., "freenode" instead of "irc.freenode.net:6667"). +;; of SERVER:PORT (e.g., "freenode" instead of "chat.freenode.net:6667"). ;; This is useful when using a bouncer like ZNC where you have multiple ;; connections to the same server. (setq erc-rename-buffers t) diff --git a/doc/misc/gnus-faq.texi b/doc/misc/gnus-faq.texi index 6e2aedae716..adb812f5728 100644 --- a/doc/misc/gnus-faq.texi +++ b/doc/misc/gnus-faq.texi @@ -2144,7 +2144,7 @@ I need real-time help, where to find it? @subsubheading Answer -Point your IRC client to irc.freenode.net, channel #gnus. +Point your IRC client to chat.freenode.net, channel #gnus. @node FAQ 9 - Tuning Gnus @subsection Tuning Gnus diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index 69ac05d5aa9..c6ce129992d 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -795,19 +795,11 @@ Advanced Scoring Searching -* nnir:: Searching with various engines. +* Search Engines:: Selecting and configuring search engines. +* Creating Search Groups:: Creating search groups. +* Search Queries:: Gnus' built-in search syntax. * nnmairix:: Searching with Mairix. -nnir - -* What is nnir?:: What does nnir do. -* Basic Usage:: How to perform simple searches. -* Setting up nnir:: How to set up nnir. - -Setting up nnir - -* Associating Engines:: How to associate engines. - Various * Process/Prefix:: A convention used by many treatment commands. @@ -17919,12 +17911,11 @@ Or we may wish to create a group from the results of a search query: @lisp (nnselect-specs - (nnselect-function . nnir-run-query) + (nnselect-function . gnus-search-run-query) (nnselect-args - (nnir-query-spec - (query . "FLAGGED") - (criteria . "")) - (nnir-group-spec + (search-query-spec + (query . "mark:flag")) + (search-group-spec ("nnimap:home") ("nnimap:work")))) @end lisp @@ -17945,9 +17936,8 @@ find all message that have been received recently from certain groups: (days-to-time (car args))))) (cons 'criteria ""))) (group-spec (cadr args))) - (nnir-run-query (cons 'nnir-specs - (list (cons 'nnir-query-spec query-spec) - (cons 'nnir-group-spec group-spec)))))) + (gnus-search-run-query (list (cons 'search-query-spec query-spec) + (cons 'search-group-spec group-spec))))) @end lisp Then the following @code{nnselect-specs}: @@ -17970,18 +17960,13 @@ parameter of @code{nnselect-rescan} will allow automatic refreshing. A refresh can always be invoked manually through @code{gnus-group-get-new-news-this-group}. -The nnir interface (@pxref{nnir}) includes engines for searching a -variety of backends. While the details of each search engine vary, -the result of an nnir search is always a vector of the sort used by -the nnselect method, and the results of nnir queries are usually -viewed using an nnselect group. Indeed the standard search function -@code{gnus-group-read-ephemeral-search-group} just creates an -ephemeral nnselect group with the appropriate nnir query as the -@code{nnselect-specs}. nnir originally included both the search -engines and the glue to connect search results to gnus. Over time -this glue evolved into the nnselect method. The two had a mostly -amicable parting so that nnselect could pursue its dream of becoming a -fully functioning backend, but occasional conflicts may still linger. +Gnus includes engines for searching a variety of backends. While the +details of each search engine vary, the result of a search is always a +vector of the sort used by the nnselect method, and the results of +queries are usually viewed using an nnselect group. Indeed the +standard search function @code{gnus-group-read-ephemeral-search-group} +just creates an ephemeral nnselect group with the appropriate search +query as the @code{nnselect-specs}. @node Combined Groups @subsection Combined Groups @@ -21445,9 +21430,6 @@ four days, Gnus will decay the scores four times, for instance. @chapter Searching @cindex searching -FIXME: A brief comparison of nnir, nnmairix, contrib/gnus-namazu would -be nice. - Gnus has various ways of finding articles that match certain criteria (from a particular author, on a certain subject, etc.). The simplest method is to enter a group and then either "limit" the summary buffer @@ -21455,50 +21437,166 @@ to the desired articles using the limiting commands (@pxref{Limiting}), or searching through messages in the summary buffer (@pxref{Searching for Articles}). -Limiting commands and summary buffer searching work on subsets of the -articles already fetched from the servers, and these commands won't -query the server for additional articles. While simple, these methods -are therefore inadequate if the desired articles span multiple groups, -or if the group is so large that fetching all articles is impractical. -Many backends (such as imap, notmuch, namazu, etc.) provide their own -facilities to search for articles directly on the server and Gnus can -take advantage of these methods. This chapter describes tools for -searching groups and servers for articles matching a query. +Limiting commands and summary buffer searching work on articles +already fetched from the servers, and these commands won't query the +server for additional articles. While simple, these methods are +therefore inadequate if the desired articles span multiple groups, or +if the group is so large that fetching all articles is impractical. + +It's possible to search a backend more thoroughly using an associated +search engine. Some backends come with their own search engine: IMAP +servers, for instance, do their own searching. Other backends, for +example a local @code{nnmaildir} installation, might require the user +to manually set up some sort of search indexing. Default associations +between backends and engines can be defined in +@code{gnus-search-default-engines}, and engines can also be defined on +a per-backend basis (@pxref{Search Engines}). + +Once the search engines are set up, you can search for messages in +groups from one or more backends, and show the results in a group. +The groups that hold search results are created on the nnselect +backend, and can be either ephemeral or persistent (@pxref{Creating +Search Groups}). + +@vindex gnus-search-use-parsed-queries +Search queries can be specified one of two ways: either using the +syntax of the engine responsible for the group you're searching, or +using Gnus' generalized search syntax. Set the option +@code{gnus-search-use-parsed-queries} to a non-nil value to used the +generalized syntax. The advantage of this syntax is that, if you have +multiple backends indexed by different engines, you don't need to +remember which one you're searching---it's also possible to issue the +same query against multiple groups, indexed by different engines, at +the same time. It also provides a few other conveniences including +relative date parsing and tie-ins into other Emacs packages. For +details on Gnus' query language, see @ref{Search Queries}. @menu -* nnir:: Searching with various engines. -* nnmairix:: Searching with Mairix. +* Search Engines:: Selecting and configuring search engines. +* Creating Search Groups:: How and where. +* Search Queries:: Gnus' built-in search syntax. +* nnmairix:: Searching with Mairix. @end menu -@node nnir -@section nnir -@cindex nnir +@node Search Engines +@section Search Engines +@cindex search engines +@cindex configuring search -This section describes how to use @code{nnir} to search for articles -within gnus. +In order to search for messages from any given server, that server +must have a search engine associated with it. IMAP servers do their +own searching (theoretically it is possible to use a different engine +to search an IMAP store, but we don't recommend it), but in all other +cases the user will have to manually specify an engine to use. This +can be done at two different levels: by server type, or on a +per-server basis. -@menu -* What is nnir?:: What does @code{nnir} do? -* Basic Usage:: How to perform simple searches. -* Setting up nnir:: How to set up @code{nnir}. -@end menu +@vindex gnus-search-default-engines +The option @code{gnus-search-default-engines} assigns search engines +by server type. Its value is an alist mapping symbols indicating a +server type (e.g.@: @code{nnmaildir} or @code{nnml}) to symbols +indicating a search engine class. The built-in search engine symbols +are: -@node What is nnir? -@subsection What is nnir? +@itemize +@item +@code{gnus-search-imap} -@code{nnir} is a Gnus interface to a number of tools for searching -through mail and news repositories. Different backends (like -@code{nnimap} and @code{nntp}) work with different tools (called -@dfn{engines} in @code{nnir} lingo), but all use the same basic search -interface. +@item +@code{gnus-search-find-grep} -The @code{nnimap} search engine should work with no configuration. -Other engines may require a local index that needs to be created and -maintained outside of Gnus. +@item +@code{gnus-search-notmuch} +@item +@code{gnus-search-swish-e} -@node Basic Usage -@subsection Basic Usage +@item +@code{gnus-search-swish++} + +@item +@code{gnus-search-mairix} + +@item +@code{gnus-search-namazu} +@end itemize + +If you need more granularity, you can specify a search engine in the +server definition, using the @code{gnus-search-engine} key, whether +that be in your @file{.gnus.el} config file, or through Gnus' server +buffer. That might look like: + +@example +'(nnmaildir "My Mail" + (directory "/home/user/.mail") + (gnus-search-engine gnus-search-notmuch + (config-file "/home/user/.mail/.notmuch_config"))) +@end example + +Search engines like notmuch, namazu and mairix are similar in +behavior: they use a local executable to create an index of a message +store, and run command line search queries against those messages, +and return a list of absolute file names of matching messages. + +These engines have a handful of configuration parameters in common. +These common parameters are: + +@table @code +@item program +The name of the executable. Defaults to the plain +program name such as @command{notmuch} or @command{namazu}. + +@item config-file +The absolute filename of the configuration file for this search +engine. + +@item remove-prefix +The directory part to be removed from the filenames returned by the +search query. This absolute path should include everything up to the +top level of the message store. + +@item switches +Additional command-line switches to be fed to the search program. The +value of this parameter must be a list of strings, one string per +switch. +@end table + +The options above can be set in one of two ways: using a customization +option that is set for all engines of that type, or on a per-engine +basis in your server configuration files. + +The customization options are formed on the pattern +@code{gnus-search-@var{engine}-@var{parameter}}. For instance, to use a +non-standard notmuch program, you might set +@code{gnus-search-notmuch-program} to @file{/usr/local/bin/notmuch}. +This would apply to all notmuch engines. The engines that use these +options are: ``notmuch'', ``namazu'', ``mairix'', ``swish-e'' and +``swish++''. + +Alternately, the options can be set directly on your Gnus server +definitions, for instance, in the @code{nnmaildir} example above. +Note that the server options are part of the @code{gnus-search-engine} +sexp, and the option symbol and value form a two-element list, not a +cons cell. + +The namazu and swish-e engines each have one additional option, +specifying where to store their index files. For namazu it is +@code{index-directory}, and should be a single directory path. For +swish-e it is @code{index-files}, and should be a list of strings. + +All indexed search engines come with their own method of updating +their search indexes to include newly-arrived messages. Gnus +currently provides no convenient interface for this, and you'll have +to manage updates yourself, though this will likely change in the +future. + +Lastly, all search engines accept a @code{raw-queries-p} option. This +indicates that engines of this type (or this particular engine) should +always use raw queries, never parsed (@pxref{Search Queries}). + +@node Creating Search Groups +@section Creating Search Groups +@cindex creating search groups In the group buffer typing @kbd{G G} will search the group on the current line by calling @code{gnus-group-read-ephemeral-search-group}. @@ -21525,297 +21623,133 @@ in their original group. You can @emph{warp} (i.e., jump) to the original group for the article on the current line with @kbd{A W}, aka @code{gnus-warp-to-article}. -You say you want to search more than just the group on the current line? -No problem: just process-mark the groups you want to search. You want -even more? Calling for an nnir search with the cursor on a topic heading -will search all the groups under that heading. +You say you want to search more than just the group on the current +line? No problem: just process-mark the groups you want to search. +You want even more? Initiating a search with the cursor on a topic +heading will search all the groups under that topic. +@vindex gnus-search-ignored-newsgroups Still not enough? OK, in the server buffer -@code{gnus-group-read-ephemeral-search-group} (now bound to @kbd{G}) +@code{gnus-group-read-ephemeral-search-group} (here bound to @kbd{G}) will search all groups from the server on the current line. Too much? Want to ignore certain groups when searching, like spam groups? Just -customize @code{nnir-ignored-newsgroups}. +customize @code{gnus-search-ignored-newsgroups}: groups matching this +regexp will not be searched. -One more thing: individual search engines may have special search -features. You can access these special features by giving a -prefix-arg to @code{gnus-group-read-ephemeral-search-group}. If you -are searching multiple groups with different search engines you will -be prompted for the special search features for each engine -separately. +@node Search Queries +@section Search Queries +@cindex search queries +@cindex search syntax +Gnus provides an optional unified search syntax that can be used +across all supported search engines. This can be convenient in that +you don't have to remember different search syntaxes; it's also +possible to mark multiple groups indexed by different engines and +issue a single search against them. -@node Setting up nnir -@subsection Setting up nnir +@vindex gnus-search-use-parsed-queries +Set the option @code{gnus-search-use-parsed-queries} to non-@code{nil} +to enable this---it is @code{nil} by default. Even if it is +non-@code{nil}, it's still possible to turn off parsing for a class of +engines or a single engine (@pxref{Search Engines}), or a single +search by giving a prefix argument to any of the search commands. -To set up nnir you may need to do some prep work. Firstly, you may -need to configure the search engines you plan to use. Some of them, -like @code{imap}, need no special configuration. Others, like -@code{namazu} and @code{swish}, require configuration as described -below. Secondly, you need to associate a search engine with a server -or a backend. +The search syntax is fairly simple: keys and values are separated by a +colon, multi-word values must be quoted, ``and'' is implicit, ``or'' +is explicit, ``not'' will negate the following expression (or keys can +be prefixed with a ``-''),and parentheses can be used to group logical +sub-clauses. For example: -If you just want to use the @code{imap} engine to search @code{nnimap} -servers then you don't have to do anything. But you might want to -read the details of the query language anyway. +@example +(from:john or from:peter) subject:"lunch tomorrow" since:3d +@end example -@menu -* Associating Engines:: How to associate engines. -* The imap Engine:: Imap configuration and usage. -* The swish++ Engine:: Swish++ configuration and usage. -* The swish-e Engine:: Swish-e configuration and usage. -* The namazu Engine:: Namazu configuration and usage. -* The notmuch Engine:: Notmuch configuration and usage. -* The hyrex Engine:: Hyrex configuration and usage. -* Customizations:: User customizable settings. -@end menu +The syntax is made to be accepted by a wide range of engines, and thus +will happily accept most input, valid or not. Some terms will only be +meaningful to some engines; other engines will drop them silently. -@node Associating Engines -@subsubsection Associating Engines +Key completion is offered on @key{TAB}, but it's also possible to +enter the query with abbreviated keys, which will be expanded during +parsing. If a key is abbreviated to the point of ambiguity (for +instance, ``s:'' could be ``subject:'' or ``since:''), an error will +be raised. - -When searching a group, @code{nnir} needs to know which search engine to -use. You can configure a given server to use a particular engine by -setting the server variable @code{nnir-search-engine} to the engine -name. For example to use the @code{namazu} engine to search the server -named @code{home} you can use - -@lisp -(setq gnus-secondary-select-methods - '((nnml "home" - (nnimap-address "localhost") - (nnir-search-engine namazu)))) -@end lisp - -Alternatively you might want to use a particular engine for all servers -with a given backend. For example, you might want to use the @code{imap} -engine for all servers using the @code{nnimap} backend. In this case you -can customize the variable @code{nnir-method-default-engines}. This is -an alist of pairs of the form @code{(backend . engine)}. By default this -variable is set to use the @code{imap} engine for all servers using the -@code{nnimap} backend. But if you wanted to use @code{namazu} for all -your servers with an @code{nnimap} backend you could change this to - -@lisp -'((nnimap . namazu)) -@end lisp - -@node The imap Engine -@subsubsection The imap Engine - -The @code{imap} engine requires no configuration. - -Queries using the @code{imap} engine follow a simple query language. -The search is always case-insensitive and supports the following -features (inspired by the Google search input language): +Supported keys include all the usual mail headers: ``from'', +``subject'', ``cc'', etc. Other keys are: @table @samp - -@item Boolean query operators -AND, OR, and NOT are supported, and parentheses can be used to control -operator precedence, e.g., (emacs OR xemacs) AND linux. Note that -operators must be written with all capital letters to be -recognized. Also preceding a term with a @minus{} sign is equivalent -to NOT term. - -@item Automatic AND queries -If you specify multiple words then they will be treated as an AND -expression intended to match all components. - -@item Phrase searches -If you wrap your query in double-quotes then it will be treated as a -literal string. - +@item body +The body of the message. +@item recipient +Equivalent to @samp{to or cc or bcc}. +@item address +Equivalent to @samp{from or recipient}. +@item id +The keys @samp{message-id} and @samp{id} are equivalent. +@item mark +Accepts @samp{flag}, @samp{seen}, @samp{read} or @samp{replied}, or +any of Gnus' single-letter representations of those marks, e.g.@: +@samp{mark:R} for @samp{read}. +@item tag +This is interpreted as @samp{keyword} for IMAP and @samp{tag} for +notmuch. +@item attachment +Matches the attachment file name. +@item before +Date is exclusive; see below for date parsing. +@item after +Date is inclusive; can also use @samp{since}. +@item thread +Return entire message threads, not just individual messages. +@item raw +Do not parse this particular search. +@item limit +Limit the results to this many messages. When searching multiple +groups this may give undesired results, as the limiting happens before +sorting. +@item grep +Only applicable to ``local index'' engines such as mairix or notmuch. +On systems with a grep command, additionally filter the results by +using the value of this term as a grep regexp. @end table -By default the whole message will be searched. The query can be limited -to a specific part of a message by using a prefix-arg. After inputting -the query this will prompt (with completion) for a message part. -Choices include ``Whole message'', ``Subject'', ``From'', and -``To''. Any unrecognized input is interpreted as a header name. For -example, typing @kbd{Message-ID} in response to this prompt will limit -the query to the Message-ID header. +@vindex gnus-search-contact-tables +Elisp-based contact management packages (e.g.@: BBDB or EBDB) can push +completion tables onto the variable @code{gnus-search-contact-tables}, +allowing auto-completion of contact names and addresses for keys like +@samp{from} or @samp{to}. -Finally selecting ``Imap'' will interpret the query as a raw -@acronym{IMAP} search query. The format of such queries can be found in -RFC3501. +@subsection Date value parsing -If you don't like the default of searching whole messages you can -customize @code{nnir-imap-default-search-key}. For example to use -@acronym{IMAP} queries by default +@vindex gnus-search-date-keys +Date-type keys (see @code{gnus-search-date-keys}) will accept a wide +variety of values. First, anything that @code{parse-time-string} can +parse is acceptable. Dates with missing values will be interpreted as +the most recent occurrence thereof: for instance ``march 03'' is the +most recent March 3rd. Lastly, it's possible to use relative +specifications, such as ``3d'' (three days ago). This format also accepts +w, m and y. -@lisp -(setq nnir-imap-default-search-key "Imap") -@end lisp - -@node The swish++ Engine -@subsubsection The swish++ Engine - -FIXME: Say something more here. - -Documentation for swish++ may be found at the swish++ sourceforge page: -@uref{http://swishplusplus.sourceforge.net} - -@table @code - -@item nnir-swish++-program -The name of the swish++ executable. Defaults to @code{search} - -@item nnir-swish++-additional-switches -A list of strings to be given as additional arguments to -swish++. @code{nil} by default. - -@item nnir-swish++-remove-prefix -The prefix to remove from each file name returned by swish++ in order -to get a group name. By default this is @code{$HOME/Mail}. - -@end table - -@node The swish-e Engine -@subsubsection The swish-e Engine - -FIXME: Say something more here. - -@table @code - -@item nnir-swish-e-program -The name of the swish-e search program. Defaults to @code{swish-e}. - -@item nnir-swish-e-additional-switches -A list of strings to be given as additional arguments to -swish-e. @code{nil} by default. - -@item nnir-swish-e-remove-prefix -The prefix to remove from each file name returned by swish-e in order -to get a group name. By default this is @code{$HOME/Mail}. - -@end table - -@node The namazu Engine -@subsubsection The namazu Engine - -Using the namazu engine requires creating and maintaining index files. -One directory should contain all the index files, and nnir must be told -where to find them by setting the @code{nnir-namazu-index-directory} -variable. - -To work correctly the @code{nnir-namazu-remove-prefix} variable must -also be correct. This is the prefix to remove from each file name -returned by Namazu in order to get a proper group name (albeit with @samp{/} -instead of @samp{.}). - -For example, suppose that Namazu returns file names such as -@samp{/home/john/Mail/mail/misc/42}. For this example, use the -following setting: @code{(setq nnir-namazu-remove-prefix -"/home/john/Mail/")} Note the trailing slash. Removing this prefix from -the directory gives @samp{mail/misc/42}. @code{nnir} knows to remove -the @samp{/42} and to replace @samp{/} with @samp{.} to arrive at the -correct group name @samp{mail.misc}. - -Extra switches may be passed to the namazu search command by setting the -variable @code{nnir-namazu-additional-switches}. It is particularly -important not to pass any switches to namazu that will change the -output format. Good switches to use include @option{--sort}, -@option{--ascending}, @option{--early} and @option{--late}. -Refer to the Namazu documentation for further -information on valid switches. - -Mail must first be indexed with the @command{mknmz} program. Read the -documentation for namazu to create a configuration file. Here is an -example: - -@cartouche -@example - package conf; # Don't remove this line! - - # Paths which will not be indexed. Don't use '^' or '$' anchors. - $EXCLUDE_PATH = "spam|sent"; - - # Header fields which should be searchable. case-insensitive - $REMAIN_HEADER = "from|date|message-id|subject"; - - # Searchable fields. case-insensitive - $SEARCH_FIELD = "from|date|message-id|subject"; - - # The max length of a word. - $WORD_LENG_MAX = 128; - - # The max length of a field. - $MAX_FIELD_LENGTH = 256; -@end example -@end cartouche - -For this example, mail is stored in the directories @samp{~/Mail/mail/}, -@samp{~/Mail/lists/} and @samp{~/Mail/archive/}, so to index them go to -the index directory set in @code{nnir-namazu-index-directory} and issue -the following command: +When creating persistent search groups, the search is saved unparsed, +and re-parsed every time the group is updated. So a permanent search +group with a query like: @example -mknmz --mailnews ~/Mail/archive/ ~/Mail/mail/ ~/Mail/lists/ +from:"my boss" mark:flag since:1w @end example -For maximum searching efficiency you might want to have a cron job run -this command periodically, say every four hours. - - -@node The notmuch Engine -@subsubsection The notmuch Engine - -@table @code -@item nnir-notmuch-program -The name of the notmuch search executable. Defaults to -@samp{notmuch}. - -@item nnir-notmuch-additional-switches -A list of strings, to be given as additional arguments to notmuch. - -@item nnir-notmuch-remove-prefix -The prefix to remove from each file name returned by notmuch in order -to get a group name (albeit with @samp{/} instead of @samp{.}). This -is a regular expression. - -@item nnir-notmuch-filter-group-names-function -A function used to transform the names of groups being searched in, -for use as a ``path:'' search keyword for notmuch. If nil, the -default, ``path:'' keywords are not used. Otherwise, this should be a -callable which accepts a single group name and returns a transformed -name as notmuch expects to see it. In many mail backends, for -instance, dots in group names must be converted to forward slashes: to -achieve this, set this option to -@example -(lambda (g) (replace-regexp-in-string "\\." "/" g)) -@end example - -@end table - - -@node The hyrex Engine -@subsubsection The hyrex Engine -This engine is obsolete. - -@node Customizations -@subsubsection Customizations - -@table @code - -@item nnir-method-default-engines -Alist of pairs of server backends and search engines. The default -association is -@example -(nnimap . imap) -@end example - -@item nnir-ignored-newsgroups -A regexp to match newsgroups in the active file that should be skipped -when searching all groups on a server. - -@end table - +would always contain only messages from the past seven days. @node nnmairix @section nnmairix @cindex mairix @cindex nnmairix + +This section is now mostly obsolete, as mairix can be used as a regular +search engine, including persistent search groups, with +@code{nnselect}. + This paragraph describes how to set up mairix and the back end @code{nnmairix} for indexing and searching your mail from within Gnus. Additionally, you can create permanent ``smart'' groups which are diff --git a/doc/misc/rcirc.texi b/doc/misc/rcirc.texi index 75f9cc63a2e..2054ca5860d 100644 --- a/doc/misc/rcirc.texi +++ b/doc/misc/rcirc.texi @@ -126,7 +126,7 @@ Here's a typical example: @cindex redirection to random servers When you connect to the Freenode network (@code{http://freenode.net/}), you point your IRC client at the -server @code{irc.freenode.net}. That server will redirect your client +server @code{chat.freenode.net}. That server will redirect your client to a random server on the network, such as @code{zelazny.freenode.net}. @cindex channel name @@ -176,7 +176,7 @@ using a different nick. This will prompt you for four things: What server do you want to connect to? All the servers in a particular network are equivalent. Some networks use a round-robin system where a single server redirects new connections to a random server in the -network. @code{irc.freenode.net} is such a server for the Freenode +network. @code{chat.freenode.net} is such a server for the Freenode network. Freenode provides the network ``for the Free and Open Source Software communities, for not-for-profit organizations and for related communities and organizations.'' @@ -211,7 +211,7 @@ Emacs, or join @code{#rcirc}, the channel about @code{rcirc}. @cindex server buffer When you have answered these questions, @code{rcirc} will create a server -buffer, which will be named something like @file{*irc.freenode.net*}, +buffer, which will be named something like @file{*chat.freenode.net*}, and a channel buffer for each of the channels you wanted to join. @kindex RET @@ -482,7 +482,7 @@ Here's an example of how to set it: @end example By default you will be connected to the @code{rcirc} support channel: -@code{#rcirc} on @code{irc.freenode.net}. +@code{#rcirc} on @code{chat.freenode.net}. @table @code @item :nick diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index a7339bf2988..6738ed5123d 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -4511,6 +4511,21 @@ HISTFILE=/dev/null @end example +@item +Where are remote files trashed to? + +Emacs can trash file instead of deleting them, @ref{Misc File Ops, +Trashing , , emacs}. Remote files are always trashed to the local +trash, except remote encrypted files (@pxref{Keeping files +encrypted}), which are deleted anyway. + +If Emacs is configured to use the XDG conventions for the trash +directory, remote files cannot be restored with the respective tools, +because those conventions don't specify remote paths. Such files must +be restored by moving them manually from +@file{$@{XDG_DATA_HOME@}/Trash/files/}, if needed. + + @item How to shorten long file names when typing in @value{tramp}? diff --git a/etc/NEWS b/etc/NEWS index a52122bceaf..8b5acafe319 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -89,13 +89,25 @@ useful on systems such as FreeBSD which ships only with "etc/termcap". This is controlled by the new variable 'scroll-minibuffer-conservatively'. +++ -** New system for displaying documentation for groups of function. +** Improved handling of minibuffers on switching frames. +By default, when you switch to another frame, an active minibuffer now +moves to the newly selected frame. Nevertheless, the effect of what +you type in the minibuffer happens in the frame where the minibuffer +was first activated, even if it moved to another frame. An +alternative behavior is available by customizing +'minibuffer-follows-selected-frame' to nil. Here, the minibuffer +stays in the frame where you first opened it, and you must switch back +to this frame to continue or abort its command. The old, somewhat +unsystematic behavior, which mixed these two is no longer available. + ++++ +** New system for displaying documentation for groups of functions. This can either be used by saying 'M-x shortdoc-display-group' and choosing a group, or clicking a button in the *Help* buffers when looking at the doc string of a function that belongs to one of these groups. -** New var 'redisplay-skip-initial-frame' to enable batch redisplay tests. +** New variable 'redisplay-skip-initial-frame' to enable batch redisplay tests. Setting it to nil forces the redisplay to do its job even in the initial frame used in batch mode. @@ -132,11 +144,6 @@ Emacs to break lines after more characters than just whitespace characters. In particular, this significantly improves word-wrapping for CJK text mixed with Latin text. ---- -** Improved language transliteration in Malayalam input methods. -Added a new Mozhi scheme. The inapplicable ITRANS scheme is now -deprecated. Errors in the Inscript method were corrected. - --- ** Rudimentary support for the 'st' terminal emulator. Emacs now supports 256 color display on the 'st' terminal emulator. @@ -153,7 +160,9 @@ displays.) +++ ** Mouse wheel scrolling with Shift modifier now scrolls horizontally. -This works in text buffers and over images. +This works in text buffers and over images. Typing a numeric prefix arg +(e.g. 'M-5') before starting horizontal scrolling changes its step value. +The value is saved in the user option 'mouse-wheel-scroll-amount-horizontal'. --- ** The default value of 'frame-title-format' and 'icon-title-format' has changed. @@ -172,6 +181,12 @@ Previously, this was limited only to NO-BREAK-SPACE and hyphen characters. Now it also covers the rest of the non-ASCII Unicode space characters. +--- +** Prefer "chat.freenode.net" to "irc.freenode.net". +"chat.freenode.net" has been the preferred address for connecting to the +freenode IRC network for years now. Occurrences of "irc.freenode.net" +have been replaced with "chat.freenode.net" throughout Emacs. + * Editing Changes in Emacs 28.1 @@ -326,7 +341,7 @@ and variables. ** Archive mode --- -*** Archive Mode can now parse .squashfs files. +*** Archive Mode can now parse ".squashfs" files. *** Can now modify members of 'ar' archives. @@ -361,7 +376,7 @@ time zones will use a form like "+0100" instead of "CET". +++ *** New user option 'dired-switches-in-mode-line'. -This variable controls how 'ls' switches are displayed in the mode +This user option controls how 'ls' switches are displayed in the mode line, and allows truncating them (to preserve space on the mode line) or showing them literally, either instead of, or in addition to, displaying "by name" or "by date" sort order. @@ -450,6 +465,12 @@ tags to be considered as well. ** Gnus ++++ +*** New gnus-search library +A new unified search syntax which can be used across multiple +supported search engines. Set 'gnus-search-use-parsed-queries' to +non-nil to enable. + +++ *** New value for user option 'smiley-style' Smileys can now be rendered with emojis instead of small images when @@ -587,11 +608,12 @@ authentication mechanism by setting a value for the key 'smtp-auth'. ** Grep +++ -*** New variable 'grep-match-regexp' matches grep markers to highlight. -grep emits SGR ANSI escape sequences to color its output. The new variable -'grep-match-regexp' holds the regular expression to match the appropriate -markers in order to provide highlighting in the source buffer. The variable -can be customized to accommodate other grep-like tools. +*** New user option 'grep-match-regexp' matches grep markers to highlight. +Grep emits SGR ANSI escape sequences to color its output. The new +user option 'grep-match-regexp' holds the regular expression to match +the appropriate markers in order to provide highlighting in the source +buffer. The user option can be customized to accommodate other +grep-like tools. --- *** The 'lgrep' command now ignores directories. @@ -616,9 +638,31 @@ recorded for the purpose of 'view-lossage'. --- *** The command 'view-lossage' can now be invoked from the menu bar. -The menu-bar Help menu now has a "Show Recent Inputs" item under the +The menu bar "Help" menu now has a "Show Recent Inputs" item under the "Describe" sub-menu. +** Input methods + ++++ +*** Emacs now supports "transient" input methods. +A transient input method is enabled for inserting a single character, +and is then automatically disabled. 'C-x \' temporarily enables the +selected transient input method. Use 'C-u C-x \' to select a +transient input method (which can be different from the input method +enabled by 'C-\'). For example, 'C-u C-x \ compose RET' selects the +'compose' input method; then typing 'C-x \ 1 2' will insert the +character '½', and disable the 'compose' input method afterwards. +You can use 'C-x \' in incremental search to insert a single character +to the search string. + +--- +*** New input method 'compose' based on X Multi_key sequences. + +--- +*** Improved language transliteration in Malayalam input methods. +Added a new Mozhi scheme. The inapplicable ITRANS scheme is now +deprecated. Errors in the Inscript method were corrected. + ** Ispell +++ @@ -679,11 +723,11 @@ doc string functions are accessible to the user through the user option 'eldoc-documentation-strategy'. *** New hook 'eldoc-display-functions'. -This hook is intended to be used for displaying doc string. The -functions receive the docstrings composed according to -`eldoc-documentation-strategy' and are tasked with displaying it to +This hook is intended to be used for displaying doc strings. The +functions receive the doc string composed according to +'eldoc-documentation-strategy' and are tasked with displaying it to the user. Examples of such functions would use the echo area, a -separate buffer or a tooltip. +separate buffer, or a tooltip. +++ *** New user option 'eldoc-documentation-strategy'. @@ -731,6 +775,11 @@ preferred over the eudcb-mab.el backend. *** New connection method "media", which allows accessing media devices like cell phones, tablets or cameras. ++++ +*** Trashed remote files are moved to the local trash directory. +All remote files, which are trashed, are moved to the local trash +directory. Except remote encrypted files, which are always deleted. + +++ *** New command 'tramp-crypt-add-directory'. This command marks a remote directory to contain only encrypted files. @@ -806,6 +855,11 @@ Now GDB only uses one source window to display source file by default. Customize 'gdb-max-source-window-count' to use more than one window. Control source file display by 'gdb-display-source-buffer-action'. ++++ +*** The default value of gdb-mi-decode-strings is now t. +This means that the default coding-system is now used to decode strings +and source file names from GDB. + ** Gravatar --- @@ -1207,27 +1261,26 @@ window after starting). This variable defaults to nil. --- *** The 'editable-list' widget now supports moving items up and down. You can now move items up and down by deleting and then reinserting -them, using the DEL and INS buttons respectively. This is useful in -Custom buffers, for example, to change the order of the elements in a -list. +them, using the 'DEL' and 'INS' buttons respectively. This is useful +in Custom buffers, for example, to change the order of the elements in +a list. ** Diff --- *** New 'diff-mode' font locking face 'diff-error'. -This face is used for error messages from diff. +This face is used for error messages from 'diff'. +++ *** New command 'diff-refresh-hunk'. This new command (bound to 'C-c C-l') regenerates the current hunk. - ** Miscellaneous +++ *** 'format-seconds' can now be used for sub-second times. The new optional "," parameter has been added, and -(format-seconds "%mm %,1ss" 66.4) will now result in "1m 6.4s". +'(format-seconds "%mm %,1ss" 66.4)' will now result in "1m 6.4s". --- *** 'global-display-fill-column-indicator-mode' skips some buffers. @@ -1253,7 +1306,7 @@ visited errors, so you can have an overview what errors were already visited. +++ *** New user option 'tab-first-completion'. -If 'tab-always-indent' is 'complete', this new option can be used to +If 'tab-always-indent' is 'complete', this new user option can be used to further tweak whether to complete or indent. --- @@ -1383,10 +1436,10 @@ horizontal movements now stop at the edge of the board. --- *** TTY menu navigation is now supported in 'xterm-mouse-mode'. -TTY menus support mouse navigation and selection when xterm-mouse-mode +TTY menus support mouse navigation and selection when 'xterm-mouse-mode' is active. When run on a terminal, clicking on the menu bar with the mouse now pops up a TTY menu by default instead of running the command -'tmm-menubar'. To restore the old behavior, set the variable +'tmm-menubar'. To restore the old behavior, set the user option 'tty-menu-open-use-tmm' to non-nil. ** xwidget-webkit mode @@ -1467,10 +1520,10 @@ type symbols. Both functions propagate D-Bus errors. *** D-Bus errors, which have been converted from incoming D-Bus error messages, contain the error name of that message now. ---- ++++ *** D-Bus messages can be monitored with new function 'dbus-register-monitor'. ---- ++++ *** D-Bus events have changed their internal structure. They carry now the destination and the error-name of an event. They also keep the type information of their arguments. Use the @@ -1575,7 +1628,7 @@ This is no longer supported, and setting this variable has no effect. Use macro 'with-current-buffer-window' with action alist entry 'body-function'. +++ -** `byte-compile-file' optional argument LOAD is now obsolete. +** 'byte-compile-file' optional argument LOAD is now obsolete. To load the file after byte-compiling, add a call to 'load' from Lisp or use 'M-x emacs-lisp-byte-compile-and-load' interactively. @@ -1664,7 +1717,7 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el. * Lisp Changes in Emacs 28.1 +++ -** 'define-globalized-minor-mode' now takes a :predicate parameter. +** 'define-globalized-minor-mode' now takes a ':predicate' parameter. This can be used to control which major modes the minor mode should be used in. @@ -1675,37 +1728,49 @@ argument 'ellipsis', will now indicate truncation using '…' when the selected frame can display it, and using "..." otherwise. +++ -*** New command 'make-directory-autoloads'. +** New command 'make-directory-autoloads'. This does the same as the old command 'update-directory-autoloads', but has different semantics: Instead of passing in the output file via the dynamically bound 'generated-autoload-file' variable, the output file is now a explicit parameter. +++ -*** New function 'string-search'. +** New function 'string-search'. This function takes two string parameters and returns the position of the first instance of the former string in the latter. +++ -*** New function 'string-replace'. +** New function 'string-replace'. This function works along the line of 'replace-regexp-in-string', but matching on strings instead of regexps, and does not change the global match state. +++ -*** New function 'process-lines-ignore-status'. +** New function 'process-lines-ignore-status'. This is like 'process-lines', but does not signal an error if the return status is non-zero. 'process-lines-handling-status' has also been added, and takes a callback to handle the return status. --- -*** 'ascii' is now a coding system alias for 'us-ascii'. +** 'ascii' is now a coding system alias for 'us-ascii'. +++ -*** New function 'file-backup-file-names'. +** New function 'file-backup-file-names'. This function returns the list of file names of all the backup files of its file argument. ++++ +** New utility function 'directory-empty-p'. +This predicate tests whether a given filename is an accessible +directory and whether it contains no other directories or files. + ++++ +** 'directory-files' now takes an additional COUNT parameter. +The parameter makes 'directory-files' return COUNT first file names +from a directory. If MATCH is also given, the function will return +first COUNT file names that match the expression. The same COUNT +parameter has been added to 'directory-files-and-attributes'. + +++ ** The 'count-lines' function now takes an optional parameter to ignore invisible lines. @@ -1833,7 +1898,7 @@ menu handling. It is meant as an (experimental) aid for converting Emacs Lisp code to lexical binding, where dynamic (special) variables bound in one file can affect code in another. For details, see the manual section -'(Elisp) Converting to Lexical Binding'. +"(Elisp) Converting to Lexical Binding". --- ** 'unload-feature' now also tries to undo additions to buffer-local hooks. @@ -1843,6 +1908,11 @@ file can affect code in another. For details, see the manual section 'replace-regexp-in-string', 'catch', 'throw', 'error', 'signal' and 'play-sound-file'. ++++ +** New variable 'print-integers-as-characters' modifies integer printing. +If this variable is non-nil, character syntax is used for printing +numbers when this makes sense, such as '?A' for 65. + * Changes in Emacs 28.1 on Non-Free Operating Systems diff --git a/etc/NEWS.27 b/etc/NEWS.27 index f0b5dd088af..61f9c0e1fe2 100644 --- a/etc/NEWS.27 +++ b/etc/NEWS.27 @@ -35,10 +35,10 @@ This is a bug-fix release with no new features. * Lisp Changes in Emacs 27.2 -*** The behavior of the user option 'resize-mini-frames' has changed. -If set to non-nil, resize the mini frame using the new function -'fit-mini-frame-to-buffer' which won't skip leading or trailing empty -lines of the buffer. +** The behavior of the user option 'resize-mini-frames' has changed. +If set to a non-nil value which isn't a function, resize the mini +frame using the new function 'fit-mini-frame-to-buffer' which won't +skip leading or trailing empty lines of the buffer. * Editing Changes in Emacs 27.2 diff --git a/etc/schema/schemas.xml b/etc/schema/schemas.xml index f1e0ed7856f..40175b056b1 100644 --- a/etc/schema/schemas.xml +++ b/etc/schema/schemas.xml @@ -1,7 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lisp/apropos.el b/lisp/apropos.el index e7e8955afe8..9debdfb19ce 100644 --- a/lisp/apropos.el +++ b/lisp/apropos.el @@ -27,8 +27,7 @@ ;; The ideas for this package were derived from the C code in ;; src/keymap.c and elsewhere. The functions in this file should -;; always be byte-compiled for speed. Someone should rewrite this in -;; C (as part of src/keymap.c) for speed. +;; always be byte-compiled for speed. ;; The idea for super-apropos is based on the original implementation ;; by Lynn Slater . diff --git a/lisp/autoinsert.el b/lisp/autoinsert.el index 4af3d631a2c..9bb485f55dc 100644 --- a/lisp/autoinsert.el +++ b/lisp/autoinsert.el @@ -264,7 +264,7 @@ Foundation Web site at @url{https://www.gnu.org/licenses/fdl.html}. @end quotation The document was typeset with -@uref{http://www.texinfo.org/, GNU Texinfo}. +@uref{https://www.gnu.org/software/texinfo/, GNU Texinfo}. @end copying @@ -315,8 +315,7 @@ The document was typeset with @printindex cp @bye - -@c " (file-name-nondirectory (buffer-file-name)) " ends here\n")) +")) "A list specifying text to insert by default into a new file. Elements look like (CONDITION . ACTION) or ((CONDITION . DESCRIPTION) . ACTION). CONDITION may be a regexp that must match the new file's name, or it may be diff --git a/lisp/cedet/srecode.el b/lisp/cedet/srecode.el index eb7af1c2727..79c8afff348 100644 --- a/lisp/cedet/srecode.el +++ b/lisp/cedet/srecode.el @@ -1,4 +1,4 @@ -;;; srecode.el --- Semantic buffer evaluator. +;;; srecode.el --- Semantic buffer evaluator. -*- lexical-binding: t -*- ;;; Copyright (C) 2005, 2007-2020 Free Software Foundation, Inc. diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el index 769a69a50f2..d1077d367d5 100644 --- a/lisp/cus-edit.el +++ b/lisp/cus-edit.el @@ -730,48 +730,86 @@ groups after non-groups, if nil do not order groups at all." ;; `custom-buffer-create-internal' if `custom-buffer-verbose-help' is non-nil. (defvar custom-commands - '((" Apply " Custom-set t - "Apply settings (for the current session only)." - "index" - "Apply") - (" Apply and Save " Custom-save - (or custom-file user-init-file) - "Apply settings and save for future sessions." - "save" - "Save") + '((" Apply " Custom-set t "Apply settings (for the current session only)." + "index" "Apply" (modified)) + (" Apply and Save " Custom-save (or custom-file user-init-file) + "Apply settings and save for future sessions." "save" "Save" + (modified set changed rogue)) (" Undo Edits " Custom-reset-current t "Restore customization buffer to reflect existing settings." - "refresh" - "Undo") + "refresh" "Undo" (modified)) (" Reset Customizations " Custom-reset-saved t - "Undo any settings applied only for the current session." - "undo" - "Reset") + "Undo any settings applied only for the current session." "undo" "Reset" + (modified set changed rogue)) (" Erase Customizations " Custom-reset-standard (or custom-file user-init-file) - "Un-customize settings in this and future sessions." - "delete" - "Uncustomize") - (" Help for Customize " Custom-help t - "Get help for using Customize." - "help" - "Help") - (" Exit " Custom-buffer-done t "Exit Customize." "exit" "Exit"))) + "Un-customize settings in this and future sessions." "delete" "Uncustomize" + (modified set changed rogue saved)) + (" Help for Customize " Custom-help t "Get help for using Customize." + "help" "Help" t) + (" Exit " Custom-buffer-done t "Exit Customize." "exit" "Exit" t)) + "Alist of specifications for Customize menu items, tool bar icons and buttons. +Each member has the format (TAG COMMAND VISIBLE HELP ICON LABEL ENABLE). +TAG is a string, used as the :tag property of a widget. +COMMAND is the command that the item or button runs. +VISIBLE should be a form, suitable to pass as the :visible property for menu +or tool bar items. +HELP should be a string that can be used as the help echo property for tooltips +and the like. +ICON is a string that names the image to use for the tool bar item, like in the +first argument of `tool-bar-local-item'. +LABEL should be a string, used as the name of the menu items. +ENABLE should be a list of custom states or t. When ENABLE is t, the item is +always enabled. Otherwise, it is enabled only if at least one option displayed +in the Custom buffer is in a state present in ENABLE.") + +(defvar-local custom-command-buttons nil + "A list that holds the buttons that act on all settings in a Custom buffer. +`custom-buffer-create-internal' adds the buttons to this list. +Changes in the state of the custom options should notify the buttons via the +:notify property, so buttons can be enabled/disabled correctly at all times.") (defun Custom-help () "Read the node on Easy Customization in the Emacs manual." (interactive) (info "(emacs)Easy Customization")) -(defvar custom-reset-menu - '(("Undo Edits in Customization Buffer" . Custom-reset-current) - ("Revert This Session's Customizations" . Custom-reset-saved) - ("Erase Customizations" . Custom-reset-standard)) - "Alist of actions for the `Reset' button. +(defvar custom-reset-menu nil + "If non-nil, an alist of actions for the `Reset' button. + +This variable is kept for backward compatibility reasons, please use +`custom-reset-extended-menu' instead. + The key is a string containing the name of the action, the value is a Lisp function taking the widget as an element which will be called when the action is chosen.") +(defvar custom-reset-extended-menu + (let ((map (make-sparse-keymap))) + (define-key-after map [Custom-reset-current] + '(menu-item "Undo Edits in Customization Buffer" Custom-reset-current + :enable (seq-some (lambda (option) + (eq (widget-get option :custom-state) + 'modified)) + custom-options))) + (define-key-after map [Custom-reset-saved] + '(menu-item "Revert This Session's Customizations" Custom-reset-saved + :enable (seq-some (lambda (option) + (memq (widget-get option :custom-state) + '(modified set changed rogue))) + custom-options))) + (when (or custom-file user-init-file) + (define-key-after map [Custom-reset-standard] + '(menu-item "Erase Customizations" Custom-reset-standard + :enable (seq-some + (lambda (option) + (memq (widget-get option :custom-state) + '(modified set changed rogue saved))) + custom-options)))) + map) + "A menu for the \"Revert...\" button. +Used in `custom-reset' to show a menu to the user.") + (defvar custom-options nil "Customization widgets in the current buffer.") @@ -821,7 +859,8 @@ setting was merely edited before, this sets it then saves it." "Select item from reset menu." (let* ((completion-ignore-case t) (answer (widget-choose "Reset settings" - custom-reset-menu + (or custom-reset-menu + custom-reset-extended-menu) event))) (if answer (funcall answer)))) @@ -1555,7 +1594,10 @@ that option. DESCRIPTION is unused." (pop-to-buffer-same-window (custom-get-fresh-buffer (or name "*Customization*"))) - (custom-buffer-create-internal options)) + (custom-buffer-create-internal options) + ;; Notify the command buttons, to correctly enable/disable them. + (dolist (btn custom-command-buttons) + (widget-apply btn :notify))) ;;;###autoload (defun custom-buffer-create-other-window (options &optional name _description) @@ -1672,11 +1714,24 @@ or a regular expression.") (if custom-buffer-verbose-help (widget-insert " Operate on all settings in this buffer:\n")) - (let ((button (lambda (tag action active help _icon _label) + (let ((button (lambda (tag action visible help _icon _label active) (widget-insert " ") - (if (eval active) - (widget-create 'push-button :tag tag - :help-echo help :action action)))) + (if (eval visible) + (push (widget-create + 'push-button :tag tag + :help-echo help :action action + :notify + (lambda (widget) + (when (listp active) + (if (seq-some + (lambda (widget) + (memq + (widget-get widget :custom-state) + active)) + custom-options) + (widget-apply widget :activate) + (widget-apply widget :deactivate))))) + custom-command-buttons)))) (commands custom-commands)) (if custom-reset-button-menu (progn @@ -2215,7 +2270,11 @@ and `face'." (let ((state (widget-get widget :custom-state))) (unless (eq state 'modified) (unless (memq state '(nil unknown hidden)) - (widget-put widget :custom-state 'modified)) + (widget-put widget :custom-state 'modified) + ;; Tell our buttons and the tool bar that we changed the widget's state. + (force-mode-line-update) + (dolist (btn custom-command-buttons) + (widget-apply btn :notify))) ;; Update the status text (usually from "STANDARD" to "EDITED ;; bla bla" in the buffer after the command has run. Otherwise ;; commands like `M-u' (that work on a region in the buffer) @@ -2254,7 +2313,10 @@ and `face'." (custom-group-state-update widget))) (t (setq widget nil))))) - (widget-setup)) + (widget-setup) + (force-mode-line-update) + (dolist (btn custom-command-buttons) + (widget-apply btn :notify))) (defun custom-show (widget value) "Non-nil if WIDGET should be shown with VALUE by default." @@ -3931,7 +3993,12 @@ Optional EVENT is the location for the menu." (custom-face-mark-to-save widget) ;; The user is working on only a selected terminal type; ;; make sure we save the entire spec to `custom-file'. (Bug #40866) + ;; If recreating a widget that may have been edited by the user, remember + ;; to always save the edited value into the :shown-value property, so + ;; we use that value for the recreated widget. (Bug#44331) + (widget-put widget :shown-value (custom-face-widget-to-spec widget)) (custom-face-edit-all widget) + (widget-put widget :shown-value nil) ; Reset it after we used it. (custom-face-mark-to-save widget) (if (eq form 'selected) (custom-face-edit-selected widget) @@ -4016,7 +4083,7 @@ restoring it to the state of a face that has never been customized." (define-widget 'face 'symbol "A Lisp face name (with sample)." - :format "%f %{%t%}: (%{sample%}) %v" + :format "%{%t%}: %f (%{sample%}) %v" :tag "Face" :value 'default :sample-face-get 'widget-face-sample-face-get @@ -4940,9 +5007,19 @@ The format is suitable for use with `easy-menu-define'." (mapcar (lambda (arg) (let ((tag (nth 0 arg)) (command (nth 1 arg)) - (active (nth 2 arg)) - (help (nth 3 arg))) - (vector tag command :active (eval active) :help help))) + (visible (nth 2 arg)) + (help (nth 3 arg)) + (active (nth 6 arg))) + (vector tag command :visible (eval visible) + :active + `(or (eq t ',active) + (seq-some ,(lambda (widget) + (memq + (widget-get widget + :custom-state) + active)) + custom-options)) + :help help))) custom-commands))) (defvar tool-bar-map) diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 6927b6df6b8..04fb1dc6d06 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -394,6 +394,7 @@ Leaving \"Default\" unchecked is equivalent with specifying a default of ;; (directory :format "%v")))) (load-prefer-newer lisp boolean "24.4") ;; minibuf.c + (minibuffer-follows-selected-frame minibuffer boolean "28.1") (enable-recursive-minibuffers minibuffer boolean) (history-length minibuffer (choice (const :tag "Infinite" t) integer) diff --git a/lisp/custom.el b/lisp/custom.el index cc445fe765b..3f1e8cacb28 100644 --- a/lisp/custom.el +++ b/lisp/custom.el @@ -1010,7 +1010,10 @@ COMMENT is a comment string about SYMBOL." set) (when requests (put symbol 'custom-requests requests) - (mapc #'require requests)) + ;; Load any libraries that the setting has specified as + ;; being required, but don't error out if the package has + ;; been removed. + (mapc (lambda (lib) (require lib nil t)) requests)) (setq set (or (get symbol 'custom-set) #'custom-set-default)) (put symbol 'saved-value (list value)) (put symbol 'saved-variable-comment comment) @@ -1382,8 +1385,30 @@ function runs. To disable other themes, use `disable-theme'." ;; Loop through theme settings, recalculating vars/faces. (dolist (s settings) (let* ((prop (car s)) - (symbol (cadr s))) - (custom-push-theme prop symbol theme 'set (nth 3 s)) + (symbol (cadr s)) + (spec-list (get symbol prop)) + (sv (get symbol 'standard-value)) + (val (and (boundp symbol) (symbol-value symbol)))) + ;; We can't call `custom-push-theme' when enabling the theme: it's not + ;; that the theme settings have changed, it's just that we want to + ;; enable those settings. But we might need to save a user setting + ;; outside of Customize, in order to get back to it when disabling + ;; the theme, just like in `custom-push-theme'. + (when (and (custom--should-apply-setting theme) + ;; Only do it for variables; for faces, using + ;; `face-new-frame-defaults' is enough. + (eq prop 'theme-value) + (boundp symbol) + (not (or spec-list + ;; Only if the current value is different from + ;; the standard value. + (and sv (equal (eval (car sv)) val)) + ;; And only if the changed value is different + ;; from the new value under the user theme. + (and (eq theme 'user) + (equal (custom-quote val) (nth 3 s)))))) + (setq spec-list `((changed ,(custom-quote val))))) + (put symbol prop (cons (cddr s) (assq-delete-all theme spec-list))) (cond ((eq prop 'theme-face) (custom-theme-recalc-face symbol)) diff --git a/lisp/descr-text.el b/lisp/descr-text.el index ec9a9680137..677db2f68a9 100644 --- a/lisp/descr-text.el +++ b/lisp/descr-text.el @@ -54,10 +54,12 @@ (<= (length pp) (- (window-width) (current-column)))) (insert pp) (insert-text-button - "[Show]" 'action (lambda (&rest _ignore) - (with-output-to-temp-buffer - "*Pp Eval Output*" - (princ pp))) + "[Show]" + 'follow-link t + 'action (lambda (&rest _ignore) + (with-output-to-temp-buffer + "*Pp Eval Output*" + (princ pp))) 'help-echo "mouse-2, RET: pretty print value in another buffer")))) (defun describe-property-list (properties) @@ -687,7 +689,8 @@ The character information includes: (save-excursion (goto-char pos) (looking-at-p "[ \t]+$"))) 'trailing-whitespace) - ((and nobreak-char-display char (eq char '#xa0)) + ((and nobreak-char-display char + (eq (get-char-code-property char 'general-category) 'Zs)) 'nobreak-space) ((and nobreak-char-display char (memq char '(#xad #x2010 #x2011))) diff --git a/lisp/dframe.el b/lisp/dframe.el index efe2bc57d93..417477be27b 100644 --- a/lisp/dframe.el +++ b/lisp/dframe.el @@ -287,6 +287,9 @@ CREATE-HOOK is a hook to run after creating a frame." ;; Correct use of `temp-buffer-show-function': Bob Weiner (if (and (boundp 'temp-buffer-show-hook) (boundp 'temp-buffer-show-function)) + ;; FIXME: Doesn't this get us into an inf-loop when the + ;; `temp-buffer-show-function' runs `temp-buffer-show-hook' + ;; (as is normally the case)? (progn (make-local-variable 'temp-buffer-show-hook) (setq temp-buffer-show-hook temp-buffer-show-function))) (make-local-variable 'temp-buffer-show-function) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 1dc83dd3958..530a086b14b 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -1147,12 +1147,14 @@ (let ((side-effect-free-fns '(% * + - / /= 1+ 1- < <= = > >= abs acos append aref ash asin atan assq + bool-vector-count-consecutive bool-vector-count-population + bool-vector-subsetp boundp buffer-file-name buffer-local-variables buffer-modified-p buffer-substring byte-code-function-p capitalize car-less-than-car car cdr ceiling char-after char-before char-equal char-to-string char-width compare-strings compare-window-configurations concat coordinates-in-window-p - copy-alist copy-sequence copy-marker cos count-lines + copy-alist copy-sequence copy-marker copysign cos count-lines current-time-string current-time-zone decode-char decode-time default-boundp default-value documentation downcase @@ -1165,22 +1167,22 @@ frame-visible-p fround ftruncate get gethash get-buffer get-buffer-window getenv get-file-buffer hash-table-count - int-to-string intern-soft + int-to-string intern-soft isnan keymap-parent - length line-beginning-position line-end-position + lax-plist-get ldexp length line-beginning-position line-end-position local-variable-if-set-p local-variable-p locale-info log log10 logand logb logcount logior lognot logxor lsh make-byte-code make-list make-string make-symbol marker-buffer max - member memq min minibuffer-selected-window minibuffer-window + member memq memql min minibuffer-selected-window minibuffer-window mod multibyte-char-to-unibyte next-window nth nthcdr number-to-string parse-colon-path plist-get plist-member prefix-numeric-value previous-window prin1-to-string propertize degrees-to-radians - radians-to-degrees rassq rassoc read-from-string regexp-quote - region-beginning region-end reverse round + radians-to-degrees rassq rassoc read-from-string regexp-opt + regexp-quote region-beginning region-end reverse round sin sqrt string string< string= string-equal string-lessp string-search string-to-char - string-to-number substring + string-to-number string-to-syntax substring sxhash sxhash-equal sxhash-eq sxhash-eql symbol-function symbol-name symbol-plist symbol-value string-make-unibyte string-make-multibyte string-as-multibyte string-as-unibyte @@ -1230,7 +1232,7 @@ standard-case-table standard-syntax-table stringp subrp symbolp syntax-table syntax-table-p this-command-keys this-command-keys-vector this-single-command-keys - this-single-command-raw-keys + this-single-command-raw-keys type-of user-real-login-name user-real-uid user-uid vector vectorp visible-frame-list wholenump window-configuration-p window-live-p @@ -1262,7 +1264,7 @@ '(concat regexp-opt regexp-quote string-to-char string-to-syntax symbol-name eq eql - = /= < <= => > min max + = /= < <= >= > min max + - * / % mod abs ash 1+ 1- sqrt logand logior lognot logxor logcount copysign isnan ldexp float logb @@ -1270,7 +1272,7 @@ ffloor fceiling fround ftruncate string= string-equal string< string-lessp string-search - consp atom listp nlistp propert-list-p + consp atom listp nlistp proper-list-p sequencep arrayp vectorp stringp bool-vector-p hash-table-p null not numberp integerp floatp natnump characterp diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index 23c784f9f8e..d3159a37683 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el @@ -201,8 +201,11 @@ the elements themselves. ;;;###autoload (defun cl-some (cl-pred cl-seq &rest cl-rest) - "Return true if PREDICATE is true of any element of SEQ or SEQs. -If so, return the true (non-nil) value returned by PREDICATE. + "Say whether PREDICATE is true for any element in the SEQ sequences. +More specifically, the return value of this function will be the +same as the first return value of PREDICATE where PREDICATE has a +non-nil value. + \n(fn PREDICATE SEQ...)" (if (or cl-rest (nlistp cl-seq)) (catch 'cl-some diff --git a/lisp/emacs-lisp/easy-mmode.el b/lisp/emacs-lisp/easy-mmode.el index a707d204f8b..261f2508af7 100644 --- a/lisp/emacs-lisp/easy-mmode.el +++ b/lisp/emacs-lisp/easy-mmode.el @@ -84,10 +84,13 @@ replacing its case-insensitive matches with the literal string in LIGHTER." (defconst easy-mmode--arg-docstring " -If called interactively, enable %s if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, -also enable the mode if ARG is omitted or nil, and toggle it -if ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `%s'. If the prefix argument is +positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +Disable the mode if ARG is a negative number. The mode's hook is called both when the mode is enabled and when it is disabled.") @@ -301,13 +304,18 @@ or call the function `%s'.")))) ,(easy-mmode--mode-docstring doc pretty-name keymap-sym) ;; Use `toggle' rather than (if ,mode 0 1) so that using ;; repeat-command still does the toggling correctly. - (interactive (list (or current-prefix-arg 'toggle))) + (interactive (list (if current-prefix-arg + (prefix-numeric-value current-prefix-arg) + 'toggle))) (let ((,last-message (current-message))) (,@setter - (if (eq arg 'toggle) - (not ,getter) - ;; A nil argument also means ON now. - (> (prefix-numeric-value arg) 0))) + (cond ((eq arg 'toggle) + (not ,getter)) + ((and (numberp arg) + (< arg 1)) + nil) + (t + t))) ,@body ;; The on/off hooks are here for backward compatibility only. (run-hooks ',hook (if ,getter ',hook-on ',hook-off)) diff --git a/lisp/emacs-lisp/ert-x.el b/lisp/emacs-lisp/ert-x.el index abbff6da625..a8da2c413e0 100644 --- a/lisp/emacs-lisp/ert-x.el +++ b/lisp/emacs-lisp/ert-x.el @@ -363,18 +363,19 @@ convert it to a string and pass it to COLLECTOR first." ;; Has to be a macro for `load-file-name'. (defmacro ert-resource-directory () - "Return absolute file name of the resource directory for this file. + "Return absolute file name of the resource (test data) directory. The path to the resource directory is the \"resources\" directory -in the same directory as the test file. +in the same directory as the test file this is called from. -If that directory doesn't exist, use the directory named like the -test file but formatted by `ert-resource-directory-format' and trimmed -using `string-trim' with arguments +If that directory doesn't exist, find a directory based on the +test file name. If the file is named \"foo-tests.el\", return +the absolute file name for \"foo-resources\". If you want a +different resource directory naming scheme, set the variable +`ert-resource-directory-format'. Before formatting, the file +name will be trimmed using `string-trim' with arguments `ert-resource-directory-trim-left-regexp' and -`ert-resource-directory-trim-right-regexp'. The default values mean -that if called from a test file named \"foo-tests.el\", return -the absolute file name for \"foo-resources\"." +`ert-resource-directory-trim-right-regexp'." `(let* ((testfile ,(or (bound-and-true-p byte-compile-current-file) (and load-in-progress load-file-name) buffer-file-name)) diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el index 352210f859d..daf49670894 100644 --- a/lisp/emacs-lisp/lisp-mode.el +++ b/lisp/emacs-lisp/lisp-mode.el @@ -178,13 +178,16 @@ (defun lisp--match-hidden-arg (limit) (let ((res nil)) + (forward-line 0) (while - (let ((ppss (parse-partial-sexp (line-beginning-position) + (let ((ppss (parse-partial-sexp (point) (line-end-position) -1))) (skip-syntax-forward " )") (if (or (>= (car ppss) 0) - (looking-at ";\\|$")) + (eolp) + (looking-at ";") + (nth 8 (syntax-ppss))) ;Within a string or comment. (progn (forward-line 1) (< (point) limit)) @@ -478,7 +481,8 @@ This will generate compile-time constants from BINDINGS." (3 'font-lock-regexp-grouping-construct prepend)) (lisp--match-hidden-arg (0 '(face font-lock-warning-face - help-echo "Hidden behind deeper element; move to another line?"))) + help-echo "Hidden behind deeper element; move to another line?") + prepend)) (lisp--match-confusable-symbol-character 0 '(face font-lock-warning-face help-echo "Confusable character")) @@ -522,7 +526,8 @@ This will generate compile-time constants from BINDINGS." (1 font-lock-keyword-face)) (lisp--match-hidden-arg (0 '(face font-lock-warning-face - help-echo "Hidden behind deeper element; move to another line?"))) + help-echo "Hidden behind deeper element; move to another line?") + prepend)) )) "Gaudy level highlighting for Lisp modes."))) diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index d58216b18a9..a381ca01f33 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -982,7 +982,8 @@ untar into a directory named DIR; otherwise, signal an error." (write-region (concat ";;; Generated package description from " - (replace-regexp-in-string "-pkg\\.el\\'" ".el" pkg-file) + (replace-regexp-in-string "-pkg\\.el\\'" ".el" + (file-name-nondirectory pkg-file)) " -*- no-byte-compile: t -*-\n" (prin1-to-string (nconc diff --git a/lisp/emacs-lisp/tabulated-list.el b/lisp/emacs-lisp/tabulated-list.el index b13f609f882..30577679f24 100644 --- a/lisp/emacs-lisp/tabulated-list.el +++ b/lisp/emacs-lisp/tabulated-list.el @@ -269,42 +269,48 @@ Populated by `tabulated-list-init-header'.") ;; FIXME: Should share code with tabulated-list-print-col! (let ((x (max tabulated-list-padding 0)) (button-props `(help-echo "Click to sort by column" - mouse-face header-line-highlight - keymap ,tabulated-list-sort-button-map)) + mouse-face header-line-highlight + keymap ,tabulated-list-sort-button-map)) + (len (length tabulated-list-format)) (cols nil)) (if display-line-numbers (setq x (+ x (tabulated-list-line-number-width)))) (push (propertize " " 'display `(space :align-to ,x)) cols) - (dotimes (n (length tabulated-list-format)) + (dotimes (n len) (let* ((col (aref tabulated-list-format n)) + (not-last-col (< n (1- len))) (label (nth 0 col)) + (lablen (length label)) + (pname label) (width (nth 1 col)) (props (nthcdr 3 col)) (pad-right (or (plist-get props :pad-right) 1)) (right-align (plist-get props :right-align)) (next-x (+ x pad-right width))) + (when (and (>= lablen 3) (> lablen width) not-last-col) + (setq label (truncate-string-to-width label (- lablen 1) nil nil t))) (push (cond ;; An unsortable column ((not (nth 2 col)) - (propertize label 'tabulated-list-column-name label)) + (propertize label 'tabulated-list-column-name pname)) ;; The selected sort column ((equal (car col) (car tabulated-list-sort-key)) (apply 'propertize - (concat label - (cond - ((> (+ 2 (length label)) width) "") - ((cdr tabulated-list-sort-key) + (concat label + (cond + ((and (< lablen 3) not-last-col) "") + ((cdr tabulated-list-sort-key) (format " %c" tabulated-list-gui-sort-indicator-desc)) - (t (format " %c" + (t (format " %c" tabulated-list-gui-sort-indicator-asc)))) - 'face 'bold - 'tabulated-list-column-name label - button-props)) + 'face 'bold + 'tabulated-list-column-name pname + button-props)) ;; Unselected sortable column. (t (apply 'propertize label - 'tabulated-list-column-name label + 'tabulated-list-column-name pname button-props))) cols) (when right-align diff --git a/lisp/emacs-lisp/timer-list.el b/lisp/emacs-lisp/timer-list.el index 4bda9acebf7..024f0030629 100644 --- a/lisp/emacs-lisp/timer-list.el +++ b/lisp/emacs-lisp/timer-list.el @@ -95,8 +95,8 @@ (setq-local revert-buffer-function #'list-timers) (setq tabulated-list-format '[("Idle" 6 timer-list--idle-predicate) - (" Next" 12 timer-list--next-predicate) - (" Repeat" 12 timer-list--repeat-predicate) + ("Next" 12 timer-list--next-predicate :right-align t :pad-right 1) + ("Repeat" 12 timer-list--repeat-predicate :right-align t :pad-right 1) ("Function" 10 timer-list--function-predicate)])) (defun timer-list--idle-predicate (A B) @@ -121,7 +121,7 @@ (string< rA rB))) (defun timer-list--function-predicate (A B) - "Predicate to sort Timer-List by the Next column." + "Predicate to sort Timer-List by the Function column." (let ((fA (aref (cadr A) 3)) (fB (aref (cadr B) 3))) (string< fA fB))) diff --git a/lisp/emulation/edt-lk201.el b/lisp/emulation/edt-lk201.el index c922e00f8f6..f7b2c0c93ea 100644 --- a/lisp/emulation/edt-lk201.el +++ b/lisp/emulation/edt-lk201.el @@ -1,4 +1,4 @@ -;;; edt-lk201.el --- enhanced EDT keypad mode emulation for LK-201 keyboards +;;; edt-lk201.el --- enhanced EDT keypad mode emulation for LK-201 keyboards -*- lexical-binding: t -*- ;; Copyright (C) 1986, 1992-1993, 1995, 2001-2020 Free Software ;; Foundation, Inc. diff --git a/lisp/emulation/edt-pc.el b/lisp/emulation/edt-pc.el index aa31d5bc32a..53fc9886b77 100644 --- a/lisp/emulation/edt-pc.el +++ b/lisp/emulation/edt-pc.el @@ -1,4 +1,4 @@ -;;; edt-pc.el --- enhanced EDT keypad mode emulation for PC 101 keyboards +;;; edt-pc.el --- enhanced EDT keypad mode emulation for PC 101 keyboards -*- lexical-binding: t -*- ;; Copyright (C) 1986, 1994-1995, 2001-2020 Free Software Foundation, ;; Inc. diff --git a/lisp/emulation/edt-vt100.el b/lisp/emulation/edt-vt100.el index 199212d2227..420d29b6aab 100644 --- a/lisp/emulation/edt-vt100.el +++ b/lisp/emulation/edt-vt100.el @@ -1,4 +1,4 @@ -;;; edt-vt100.el --- enhanced EDT keypad mode emulation for VT series terminals +;;; edt-vt100.el --- enhanced EDT keypad mode emulation for VT series terminals -*- lexical-binding: t -*- ;; Copyright (C) 1986, 1992-1993, 1995, 2002-2020 Free Software ;; Foundation, Inc. diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index 2166123e674..de0a16ea3f0 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -267,7 +267,7 @@ The current buffer is given by BUFFER." (with-current-buffer buffer (auto-save-mode -1) (setq buffer-file-name nil) - (set (make-local-variable 'write-file-functions) '(erc-save-buffer-in-logs)) + (add-hook 'write-file-functions #'erc-save-buffer-in-logs nil t) (when erc-log-insert-log-on-open (ignore-errors (save-excursion diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 309a78865df..d957fcee056 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -190,9 +190,9 @@ ("Fraggers: Random server" Fraggers "irc.fraggers.co.uk" ((6661 6669) (7000 7001) )) ("FreedomChat: Random server" FreedomChat "chat.freedomchat.net" 6667) ("FreedomIRC: Random server" FreedomIRC "irc.freedomirc.net" 6667) - ("Freenode: Random server" freenode "irc.freenode.net" 6667) - ("Freenode: Random EU server" freenode "irc.eu.freenode.net" 6667) - ("Freenode: Random US server" freenode "irc.us.freenode.net" 6667) + ("Freenode: Random server" freenode "chat.freenode.net" 6667) + ("Freenode: Random EU server" freenode "chat.eu.freenode.net" 6667) + ("Freenode: Random US server" freenode "chat.us.freenode.net" 6667) ("FunNet: Random server" FunNet "irc.funnet.org" 6667) ("Galaxynet: Random server" GalaxyNet "irc.galaxynet.org" ((6662 6668) 7000 )) ("Galaxynet: AU, NZ, Auckland" GalaxyNet "auckland.nz.galaxynet.org" ((6661 6669))) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 6481446ba5e..e35ae0cfd87 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1500,7 +1500,7 @@ Defaults to the server buffer." ;; activation -(defconst erc-default-server "irc.freenode.net" +(defconst erc-default-server "chat.freenode.net" "IRC server to use if it cannot be detected otherwise.") (defconst erc-default-port 6667 @@ -2244,7 +2244,7 @@ Non-interactively, it takes the keyword arguments That is, if called with - (erc :server \"irc.freenode.net\" :full-name \"Harry S Truman\") + (erc :server \"chat.freenode.net\" :full-name \"Harry S Truman\") then the server and full-name will be set to those values, whereas `erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' will diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el index 5cee1bad364..bdc21c916c6 100644 --- a/lisp/eshell/em-hist.el +++ b/lisp/eshell/em-hist.el @@ -75,8 +75,7 @@ (defcustom eshell-hist-load-hook nil "A list of functions to call when loading `eshell-hist'." :version "24.1" ; removed eshell-hist-initialize - :type 'hook - :group 'eshell-hist) + :type 'hook) (defcustom eshell-hist-unload-hook (list @@ -84,8 +83,7 @@ (lambda () (remove-hook 'kill-emacs-hook 'eshell-save-some-history)))) "A hook that gets run when `eshell-hist' is unloaded." - :type 'hook - :group 'eshell-hist) + :type 'hook) (defcustom eshell-history-file-name (expand-file-name "history" eshell-directory-name) @@ -93,20 +91,17 @@ See also `eshell-read-history' and `eshell-write-history'. If it is nil, Eshell will use the value of HISTFILE." :type '(choice (const :tag "Use HISTFILE" nil) - file) - :group 'eshell-hist) + file)) (defcustom eshell-history-size 128 "Size of the input history ring. If nil, use envvar HISTSIZE." :type '(choice (const :tag "Use HISTSIZE" nil) - integer) - :group 'eshell-hist) + integer)) (defcustom eshell-hist-ignoredups nil "If non-nil, don't add input matching the last on the input ring. This mirrors the optional behavior of bash." - :type 'boolean - :group 'eshell-hist) + :type 'boolean) (defcustom eshell-save-history-on-exit t "Determine if history should be automatically saved. @@ -118,8 +113,7 @@ If set to `ask', ask if any Eshell buffers are open at exit time. If set to t, history will always be saved, silently." :type '(choice (const :tag "Never" nil) (const :tag "Ask" ask) - (const :tag "Always save" t)) - :group 'eshell-hist) + (const :tag "Always save" t))) (defcustom eshell-input-filter 'eshell-input-filter-default "Predicate for filtering additions to input history. @@ -128,8 +122,7 @@ the input history list. Default is to save anything that isn't all whitespace." :type '(radio (function-item eshell-input-filter-default) (function-item eshell-input-filter-initial-space) - (function :tag "Other function")) - :group 'eshell-hist) + (function :tag "Other function"))) (put 'eshell-input-filter 'risky-local-variable t) @@ -138,31 +131,26 @@ whitespace." Otherwise, typing and will always go to the next history element, regardless of any text on the command line. In that case, and still offer that functionality." - :type 'boolean - :group 'eshell-hist) + :type 'boolean) (defcustom eshell-hist-move-to-end t "If non-nil, move to the end of the buffer before cycling history." - :type 'boolean - :group 'eshell-hist) + :type 'boolean) (defcustom eshell-hist-event-designator "^!\\(!\\|-?[0-9]+\\|\\??[^:^$%*?]+\\??\\|#\\)" "The regexp used to identifier history event designators." - :type 'regexp - :group 'eshell-hist) + :type 'regexp) (defcustom eshell-hist-word-designator "^:?\\([0-9]+\\|[$^%*]\\)?\\(-[0-9]*\\|[$^%*]\\)?" "The regexp used to identify history word designators." - :type 'regexp - :group 'eshell-hist) + :type 'regexp) (defcustom eshell-hist-modifier "^\\(:\\([hretpqx&g]\\|s/\\([^/]*\\)/\\([^/]*\\)/\\)\\)*" "The regexp used to identity history modifiers." - :type 'regexp - :group 'eshell-hist) + :type 'regexp) (defcustom eshell-hist-rebind-keys-alist '(([(control ?p)] . eshell-previous-input) @@ -180,8 +168,7 @@ element, regardless of any text on the command line. In that case, "History keys to bind differently if point is in input text." :type '(repeat (cons (vector :tag "Keys to bind" (repeat :inline t sexp)) - (function :tag "Command"))) - :group 'eshell-hist) + (function :tag "Command")))) ;;; Internal Variables: @@ -308,7 +295,6 @@ Returns nil if INPUT is prepended by blank space, otherwise non-nil." (add-hook 'kill-emacs-hook #'eshell-save-some-history) - (make-local-variable 'eshell-input-filter-functions) (add-hook 'eshell-input-filter-functions #'eshell-add-to-history nil t)) (defun eshell-save-some-history () diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el index c26f654e278..59139da10db 100644 --- a/lisp/eshell/em-pred.el +++ b/lisp/eshell/em-pred.el @@ -73,18 +73,18 @@ ordinary strings." (?p . (eshell-pred-file-type ?p)) ; named pipes (?@ . (eshell-pred-file-type ?l)) ; symbolic links (?% . (eshell-pred-file-type ?%)) ; allow user to specify (c def.) - (?r . (eshell-pred-file-mode 0400)) ; owner-readable - (?w . (eshell-pred-file-mode 0200)) ; owner-writable - (?x . (eshell-pred-file-mode 0100)) ; owner-executable - (?A . (eshell-pred-file-mode 0040)) ; group-readable - (?I . (eshell-pred-file-mode 0020)) ; group-writable - (?E . (eshell-pred-file-mode 0010)) ; group-executable - (?R . (eshell-pred-file-mode 0004)) ; world-readable - (?W . (eshell-pred-file-mode 0002)) ; world-writable - (?X . (eshell-pred-file-mode 0001)) ; world-executable - (?s . (eshell-pred-file-mode 4000)) ; setuid - (?S . (eshell-pred-file-mode 2000)) ; setgid - (?t . (eshell-pred-file-mode 1000)) ; sticky bit + (?r . (eshell-pred-file-mode #o0400)) ; owner-readable + (?w . (eshell-pred-file-mode #o0200)) ; owner-writable + (?x . (eshell-pred-file-mode #o0100)) ; owner-executable + (?A . (eshell-pred-file-mode #o0040)) ; group-readable + (?I . (eshell-pred-file-mode #o0020)) ; group-writable + (?E . (eshell-pred-file-mode #o0010)) ; group-executable + (?R . (eshell-pred-file-mode #o0004)) ; world-readable + (?W . (eshell-pred-file-mode #o0002)) ; world-writable + (?X . (eshell-pred-file-mode #o0001)) ; world-executable + (?s . (eshell-pred-file-mode #o4000)) ; setuid + (?S . (eshell-pred-file-mode #o2000)) ; setgid + (?t . (eshell-pred-file-mode #o1000)) ; sticky bit (?U . #'(lambda (file) ; owned by effective uid (if (file-exists-p file) (= (file-attribute-user-id (file-attributes file)) @@ -478,7 +478,7 @@ that `ls -l' will show in the first column of its display." `(lambda (file) (let ((modes (file-modes file 'nofollow))) (if modes - (logand ,mode modes))))) + (not (zerop (logand ,mode modes))))))) (defun eshell-pred-file-links () "Return a predicate to test whether a file has a given number of links." diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index 68aa6803278..937b8bfa391 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -1007,18 +1007,17 @@ Show wall-clock time elapsed during execution of COMMAND.") (throw 'eshell-replace-command (eshell-parse-command "*diff" orig-args)))) (when (fboundp 'diff-mode) - (make-local-variable 'compilation-finish-functions) (add-hook 'compilation-finish-functions - `(lambda (buff msg) + (lambda (buff _msg) (with-current-buffer buff (diff-mode) - (set (make-local-variable 'eshell-diff-window-config) - ,config) - (local-set-key [?q] 'eshell-diff-quit) + (set (make-local-variable 'eshell-diff-window-config) config) + (local-set-key [?q] #'eshell-diff-quit) (if (fboundp 'turn-on-font-lock-if-enabled) (turn-on-font-lock-if-enabled)) - (goto-char (point-min)))))) + (goto-char (point-min)))) + nil t)) (pop-to-buffer (current-buffer)))))) nil) diff --git a/lisp/faces.el b/lisp/faces.el index 0ce95322703..728f8b0fe67 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2716,9 +2716,11 @@ used to display the prompt text." :group 'frames :group 'basic-faces) -(defface scroll-bar '((t nil)) +(defface scroll-bar + '((((background light)) :foreground "black") + (((background dark)) :foreground "white")) "Basic face for the scroll bar colors under X." - :version "21.1" + :version "28.1" :group 'frames :group 'basic-faces) diff --git a/lisp/files.el b/lisp/files.el index 67b3083df6a..92c9a63ef18 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -888,6 +888,16 @@ recursion." (push (concat dir "/" file) files))))) (nconc result (nreverse files)))) +(defun directory-empty-p (dir) + "Return t if DIR names an existing directory containing no other files. +Return nil if DIR does not name a directory, or if there was +trouble determining whether DIR is a directory or empty. + +Symbolic links to directories count as directories. +See `file-symlink-p' to distinguish symlinks." + (and (file-directory-p dir) + (null (directory-files dir nil directory-files-no-dot-files-regexp t 1)))) + (defvar module-file-suffix) (defun load-file (file) @@ -5862,10 +5872,7 @@ RECURSIVE if DIRECTORY is nonempty." ;; case, where the operation fails in delete-directory-internal. ;; As `move-file-to-trash' trashes directories (empty or ;; otherwise) as a unit, we do not need to recurse here. - (if (and (not recursive) - ;; Check if directory is empty apart from "." and "..". - (directory-files - directory 'full directory-files-no-dot-files-regexp)) + (if (not (or recursive (directory-empty-p directory))) (error "Directory is not empty, not moving to trash") (move-file-to-trash directory))) ;; Otherwise, call ourselves recursively if needed. diff --git a/lisp/finder.el b/lisp/finder.el index 820d6d0a3b9..a59a185cc9b 100644 --- a/lisp/finder.el +++ b/lisp/finder.el @@ -178,6 +178,9 @@ directory name and PACKAGE is the name of a package (a symbol). When generating `package--builtins', Emacs assumes any file in DIR is part of the package PACKAGE.") +(defconst finder-buffer "*Finder*" + "Name of the Finder buffer.") + (defun finder-compile-keywords (&rest dirs) "Regenerate list of built-in Emacs packages. This recomputes `package--builtins' and `finder-keywords-hash', @@ -338,9 +341,9 @@ not `finder-known-keywords'." (defun finder-list-keywords () "Display descriptions of the keywords in the Finder buffer." (interactive) - (if (get-buffer "*Finder*") - (pop-to-buffer "*Finder*") - (pop-to-buffer (get-buffer-create "*Finder*")) + (if (get-buffer finder-buffer) + (pop-to-buffer finder-buffer) + (pop-to-buffer (get-buffer-create finder-buffer)) (finder-mode) (let ((inhibit-read-only t)) (erase-buffer) @@ -460,10 +463,9 @@ finder directory, \\[finder-exit] = quit, \\[finder-summary] = help"))) "Exit Finder mode. Quit the window and kill all Finder-related buffers." (interactive) - (let ((buf "*Finder*")) - (if (equal (current-buffer) buf) - (quit-window t) - (and (get-buffer buf) (kill-buffer buf))))) + (quit-window t) + (dolist (buf (list finder-buffer "*Finder-package*")) + (and (get-buffer buf) (kill-buffer buf)))) (defun finder-unload-function () "Unload the Finder library." diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el index 1d614f8a8d4..c6f7e1c41ac 100644 --- a/lisp/gnus/gnus-group.el +++ b/lisp/gnus/gnus-group.el @@ -3165,29 +3165,27 @@ mail messages or news articles in files that have numeric names." (gnus-group-real-name group) (list 'nndir (gnus-group-real-name group) (list 'nndir-directory dir))))) - -(autoload 'nnir-read-parms "nnir") -(autoload 'nnir-server-to-search-engine "nnir") (autoload 'gnus-group-topic-name "gnus-topic") +(autoload 'gnus-search-make-spec "gnus-search") ;; Temporary to make group creation easier -(defun gnus-group-make-search-group (nnir-extra-parms &optional specs) +(defun gnus-group-make-search-group (no-parse &optional specs) "Make a group based on a search. Prompt for a search query and determine the groups to search as follows: if called from the *Server* buffer search all groups belonging to the server on the current line; if called from the *Group* buffer search any marked groups, or the group on the -current line, or all the groups under the current topic. Calling -with a prefix arg prompts for additional search-engine specific -constraints. A non-nil SPECS arg must be an alist with -`nnir-query-spec' and `nnir-group-spec' keys, and skips all -prompting." +current line, or all the groups under the current topic. A +prefix arg NO-PARSE means that Gnus should not parse the search +query before passing it to the underlying search engine. A +non-nil SPECS arg must be an alist with `search-query-spec' and +`search-group-spec' keys, and skips all prompting." (interactive "P") (let ((name (gnus-read-group "Group name: "))) (with-current-buffer gnus-group-buffer (let* ((group-spec (or - (cdr (assq 'nnir-group-spec specs)) + (cdr (assq 'search-group-spec specs)) (if (gnus-server-server-name) (list (list (gnus-server-server-name))) (seq-group-by @@ -3199,16 +3197,8 @@ prompting." (assoc (gnus-group-topic-name) gnus-topic-alist)))))))) (query-spec (or - (cdr (assq 'nnir-query-spec specs)) - (apply - 'append - (list (cons 'query - (read-string "Query: " nil 'nnir-search-history))) - (when nnir-extra-parms - (mapcar - (lambda (x) - (nnir-read-parms (nnir-server-to-search-engine (car x)))) - group-spec)))))) + (cdr (assq 'search-query-spec specs)) + (gnus-search-make-spec no-parse)))) (gnus-group-make-group name (list 'nnselect "nnselect") @@ -3216,29 +3206,29 @@ prompting." (list (cons 'nnselect-specs (list - (cons 'nnselect-function 'nnir-run-query) + (cons 'nnselect-function 'gnus-search-run-query) (cons 'nnselect-args - (list (cons 'nnir-query-spec query-spec) - (cons 'nnir-group-spec group-spec))))) + (list (cons 'search-query-spec query-spec) + (cons 'search-group-spec group-spec))))) (cons 'nnselect-artlist nil))))))) (define-obsolete-function-alias 'gnus-group-make-nnir-group 'gnus-group-read-ephemeral-search-group "28.1") -(defun gnus-group-read-ephemeral-search-group (nnir-extra-parms &optional specs) +(defun gnus-group-read-ephemeral-search-group (no-parse &optional specs) "Read an nnselect group based on a search. Prompt for a search query and determine the groups to search as follows: if called from the *Server* buffer search all groups belonging to the server on the current line; if called from the *Group* buffer search any marked groups, or the group on the -current line, or all the groups under the current topic. Calling -with a prefix arg prompts for additional search-engine specific -constraints. A non-nil SPECS arg must be an alist with -`nnir-query-spec' and `nnir-group-spec' keys, and skips all -prompting." +current line, or all the groups under the current topic. A +prefix arg NO-PARSE means that Gnus should not parse the search +query before passing it to the underlying search engine. A +non-nil SPECS arg must be an alist with `search-query-spec' and +`search-group-spec' keys, and skips all prompting." (interactive "P") (let* ((group-spec - (or (cdr (assq 'nnir-group-spec specs)) + (or (cdr (assq 'search-group-spec specs)) (if (gnus-server-server-name) (list (list (gnus-server-server-name))) (seq-group-by @@ -3249,16 +3239,8 @@ prompting." (cdr (assoc (gnus-group-topic-name) gnus-topic-alist)))))))) (query-spec - (or (cdr (assq 'nnir-query-spec specs)) - (apply - 'append - (list (cons 'query - (read-string "Query: " nil 'nnir-search-history))) - (when nnir-extra-parms - (mapcar - (lambda (x) - (nnir-read-parms (nnir-server-to-search-engine (car x)))) - group-spec)))))) + (or (cdr (assq 'search-query-spec specs)) + (gnus-search-make-spec no-parse)))) (gnus-group-read-ephemeral-group (concat "nnselect-" (message-unique-id)) (list 'nnselect "nnselect") @@ -3268,10 +3250,10 @@ prompting." (list (cons 'nnselect-specs (list - (cons 'nnselect-function 'nnir-run-query) + (cons 'nnselect-function 'gnus-search-run-query) (cons 'nnselect-args - (list (cons 'nnir-query-spec query-spec) - (cons 'nnir-group-spec group-spec))))) + (list (cons 'search-query-spec query-spec) + (cons 'search-group-spec group-spec))))) (cons 'nnselect-artlist nil))))) (defun gnus-group-add-to-virtual (n vgroup) diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el new file mode 100644 index 00000000000..07bd2bca1bb --- /dev/null +++ b/lisp/gnus/gnus-search.el @@ -0,0 +1,2137 @@ +;;; gnus-search.el --- Search facilities for Gnus -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Free Software Foundation, Inc. + +;; Author: Eric Abrahamsen + +;; This program 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. + +;; This program 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 this program. If not, see . + +;;; Commentary: + +;; This file defines a generalized search language, and search engines +;; that interface with various search programs. It is responsible for +;; parsing the user's search input, sending that query to the search +;; engines, and collecting results. Results are in the form of a +;; vector of vectors, each vector representing a found article. The +;; nnselect backend interprets that value to create a group containing +;; the search results. + +;; This file was formerly known as nnir. Later, the backend parts of +;; nnir became nnselect, and only the search functionality was left +;; here. + +;; See the Gnus manual for details of the search language. Tests are +;; in tests/gnus-search-test.el. + +;; The search parsing routines are responsible for accepting the +;; user's search query as a string and parsing it into a sexp +;; structure. The function `gnus-search-parse-query' is the entry +;; point for that. Once the query is in sexp form, it is passed to +;; the search engines themselves, which are responsible for +;; transforming the query into a form that the external program can +;; understand, and then filtering the search results into a format +;; that nnselect can understand. + +;; The general flow is: + +;; 1. The user calls one of `gnus-group-make-search-group' or +;; `gnus-group-make-permanent-search-group' (or a few other entry +;; points). These functions prompt for a search query, and collect +;; the groups to search, then create an nnselect group, setting an +;; 'nnselect-specs group parameter where 'nnselect-function is +;; `gnus-search-run-query', and 'nnselect-args is the search query and +;; groups to search. + +;; 2. `gnus-search-run-query' is called with 'nnselect-args. It looks +;; at the groups to search, categorizes them by server, and for each +;; server finds the search engine to use. It calls each engine's +;; `gnus-search-run-search' method with the query and groups passed as +;; arguments, and the results are collected and handed off to the +;; nnselect group. + +;; For information on writing new search engines, see the Gnus manual. + +;; TODO: Rewrite the query parser using syntax tables and +;; `parse-partial-sexp'. + +;; TODO: Refactor IMAP search so we can move code that uses nnimap-* +;; functions out into nnimap.el. + +;; TODO: Is there anything we can do about sorting results? + +;; TODO: Provide for returning a result count. This would probably +;; need a completely separate top-level command, since we wouldn't be +;; creating a group at all. + +;;; Code: + +(require 'gnus-group) +(require 'gnus-sum) +(require 'message) +(require 'gnus-util) +(require 'eieio) +(eval-when-compile (require 'cl-lib)) +(autoload 'eieio-build-class-alist "eieio-opt") +(autoload 'nnmaildir-base-name-to-article-number "nnmaildir") + +(defvar gnus-inhibit-demon) +(defvar gnus-english-month-names) + +;;; Internal Variables: + +(defvar gnus-search-memo-query nil + "Internal: stores current query.") + +(defvar gnus-search-memo-server nil + "Internal: stores current server.") + +(defvar gnus-search-history () + "Internal history of Gnus searches.") + +(define-error 'gnus-search-parse-error "Gnus search parsing error") + +;;; User Customizable Variables: + +(defgroup gnus-search nil + "Search groups in Gnus with assorted search engines." + :group 'gnus) + +(defcustom gnus-search-use-parsed-queries nil + "When t, use Gnus' generalized search language. +The generalized search language is a search language that can be +used across all search engines that Gnus supports. See the Gnus +manual for details. + +If this option is set to nil, search queries will be passed +directly to the search engines without being parsed or +transformed." + :version "28.1" + :type 'boolean + :group 'gnus-search) + +(define-obsolete-variable-alias 'nnir-ignored-newsgroups + 'gnus-search-ignored-newsgroups "28.1") + +(defcustom gnus-search-ignored-newsgroups "" + "A regexp to match newsgroups in the active file that should + be skipped when searching." + :version "24.1" + :type 'regexp + :group 'gnus-search) + +(make-obsolete-variable + 'nnir-imap-default-search-key + "specify imap search keys, or use parsed queries." "28.1") + +;; Engine-specific configuration options. + +(defcustom gnus-search-swish++-config-file + (expand-file-name "~/Mail/swish++.conf") + "Location of Swish++ configuration file. +This variable can also be set per-server." + :type 'file + :group 'gnus-search) + +(defcustom gnus-search-swish++-program "search" + "Name of swish++ search executable. +This variable can also be set per-server." + :type 'string + :group 'gnus-search) + +(defcustom gnus-search-swish++-switches '() + "A list of strings, to be given as additional arguments to swish++. +Note that this should be a list. I.e., do NOT use the following: + (setq gnus-search-swish++-switches \"-i -w\") ; wrong +Instead, use this: + (setq gnus-search-swish++-switches \\='(\"-i\" \"-w\")) + +This variable can also be set per-server." + :type '(repeat string) + :group 'gnus-search) + +(defcustom gnus-search-swish++-remove-prefix (concat (getenv "HOME") "/Mail/") + "The prefix to remove from each file name returned by swish++ +in order to get a group name (albeit with / instead of .). This is a +regular expression. + +This variable can also be set per-server." + :type 'regexp + :group 'gnus-search) + +(defcustom gnus-search-swish++-raw-queries-p nil + "If t, all Swish++ engines will only accept raw search query + strings." + :type 'boolean + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-swish-e-config-file + (expand-file-name "~/Mail/swish-e.conf") + "Configuration file for swish-e. +This variable can also be set per-server." + :type 'file + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-swish-e-program "search" + "Name of swish-e search executable. +This variable can also be set per-server." + :type 'string + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-swish-e-switches '() + "A list of strings, to be given as additional arguments to swish-e. +Note that this should be a list. I.e., do NOT use the following: + (setq gnus-search-swish-e-switches \"-i -w\") ; wrong +Instead, use this: + (setq gnus-search-swish-e-switches \\='(\"-i\" \"-w\")) + +This variable can also be set per-server." + :type '(repeat string) + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-swish-e-remove-prefix (concat (getenv "HOME") "/Mail/") + "The prefix to remove from each file name returned by swish-e +in order to get a group name (albeit with / instead of .). This is a +regular expression. + +This variable can also be set per-server." + :type 'regexp + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-swish-e-index-files '() + "A list of index files to use with this Swish-e instance. +This variable can also be set per-server." + :type '(repeat file) + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-swish-e-raw-queries-p nil + "If t, all Swish-e engines will only accept raw search query + strings." + :type 'boolean + :version "28.1" + :group 'gnus-search) + +;; Namazu engine, see + +(defcustom gnus-search-namazu-program "namazu" + "Name of Namazu search executable. +This variable can also be set per-server." + :type 'string + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-namazu-index-directory (expand-file-name "~/Mail/namazu/") + "Index directory for Namazu. +This variable can also be set per-server." + :type 'directory + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-namazu-switches '() + "A list of strings, to be given as additional arguments to namazu. +The switches `-q', `-a', and `-s' are always used, very few other switches +make any sense in this context. + +Note that this should be a list. I.e., do NOT use the following: + (setq gnus-search-namazu-switches \"-i -w\") ; wrong +Instead, use this: + (setq gnus-search-namazu-switches \\='(\"-i\" \"-w\")) + +This variable can also be set per-server." + :type '(repeat string) + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-namazu-remove-prefix (concat (getenv "HOME") "/Mail/") + "The prefix to remove from each file name returned by Namazu +in order to get a group name (albeit with / instead of .). + +For example, suppose that Namazu returns file names such as +\"/home/john/Mail/mail/misc/42\". For this example, use the following +setting: (setq gnus-search-namazu-remove-prefix \"/home/john/Mail/\") +Note the trailing slash. Removing this prefix gives \"mail/misc/42\". +Gnus knows to remove the \"/42\" and to replace \"/\" with \".\" to +arrive at the correct group name, \"mail.misc\". + +This variable can also be set per-server." + :type 'directory + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-namazu-raw-queries-p nil + "If t, all Namazu engines will only accept raw search query + strings." + :type 'boolean + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-notmuch-program "notmuch" + "Name of notmuch search executable. +This variable can also be set per-server." + :type '(string) + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-notmuch-config-file + (expand-file-name "~/.notmuch-config") + "Configuration file for notmuch. +This variable can also be set per-server." + :type 'file + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-notmuch-switches '() + "A list of strings, to be given as additional arguments to notmuch. +Note that this should be a list. I.e., do NOT use the following: + (setq gnus-search-notmuch-switches \"-i -w\") ; wrong +Instead, use this: + (setq gnus-search-notmuch-switches \\='(\"-i\" \"-w\")) + +This variable can also be set per-server." + :type '(repeat string) + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-notmuch-remove-prefix (concat (getenv "HOME") "/Mail/") + "The prefix to remove from each file name returned by notmuch +in order to get a group name (albeit with / instead of .). This is a +regular expression. + +This variable can also be set per-server." + :type 'regexp + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-notmuch-raw-queries-p nil + "If t, all Notmuch engines will only accept raw search query + strings." + :type 'boolean + :version "28.1" + :group 'gnus-search) + +(defcustom gnus-search-imap-raw-queries-p nil + "If t, all IMAP engines will only accept raw search query + strings." + :version "28.1" + :type 'boolean + :group 'gnus-search) + +(defcustom gnus-search-mairix-program "mairix" + "Name of mairix search executable. +This variable can also be set per-server." + :version "28.1" + :type 'string + :group 'gnus-search) + +(defcustom gnus-search-mairix-config-file + (expand-file-name "~/.mairixrc") + "Configuration file for mairix. +This variable can also be set per-server." + :version "28.1" + :type 'file + :group 'gnus-search) + +(defcustom gnus-search-mairix-switches '() + "A list of strings, to be given as additional arguments to mairix. +Note that this should be a list. I.e., do NOT use the following: + (setq gnus-search-mairix-switches \"-i -w\") ; wrong +Instead, use this: + (setq gnu-search-mairix-switches \\='(\"-i\" \"-w\")) + +This variable can also be set per-server." + :version "28.1" + :type '(repeat string) + :group 'gnus-search) + +(defcustom gnus-search-mairix-remove-prefix (concat (getenv "HOME") "/Mail/") + "The prefix to remove from each file name returned by mairix +in order to get a group name (albeit with / instead of .). This is a +regular expression. + +This variable can also be set per-server." + :version "28.1" + :type 'regexp + :group 'gnus-search) + +(defcustom gnus-search-mairix-raw-queries-p nil + "If t, all Mairix engines will only accept raw search query + strings." + :version "28.1" + :type 'boolean + :group 'gnus-search) + +;; Options for search language parsing. + +(defcustom gnus-search-expandable-keys + '("from" "subject" "to" "cc" "bcc" "body" "recipient" "date" + "mark" "before" "after" "larger" "smaller" "attachment" "text" + "since" "thread" "sender" "address" "tag" "size" "grep" "limit" + "raw" "message-id" "id") + "A list of strings representing expandable search keys. +\"Expandable\" simply means the key can be abbreviated while +typing in search queries, ie \"subject\" could be entered as +\"subj\" or even \"su\", though \"s\" is ambigous between +\"subject\" and \"since\". + +Ambiguous abbreviations will raise an error." + :group 'gnus-search + :version "28.1" + :type '(repeat string)) + +(defcustom gnus-search-date-keys + '("date" "before" "after" "on" "senton" "sentbefore" "sentsince" "since") + "A list of keywords whose value should be parsed as a date. +See the docstring of `gnus-search-parse-query' for information on +date parsing." + :group 'gnus-search + :version "26.1" + :type '(repeat string)) + +(defcustom gnus-search-contact-tables '() + "A list of completion tables used to search for messages from contacts. +Each list element should be a table or collection suitable to be +returned by `completion-at-point-functions'. That usually means +a list of strings, a hash table, or an alist." + :group 'gnus-search + :version "28.1" + :type '(repeat sexp)) + +;;; Search language + +;; This "language" was generalized from the original IMAP search query +;; parsing routine. + +(defun gnus-search-parse-query (string) + "Turn STRING into an s-expression based query. +The resulting query structure is passed to the various search +backends, each of which adapts it as needed. + +The search \"language\" is essentially a series of key:value +expressions. Key is most often a mail header, but there are +other keys. Value is a string, quoted if it contains spaces. +Key and value are separated by a colon, no space. Expressions +are implictly ANDed; the \"or\" keyword can be used to +OR. \"not\" will negate the following expression, or keys can be +prefixed with a \"-\". The \"near\" operator will work for +engines that understand it; other engines will convert it to +\"or\". Parenthetical groups work as expected. + +A key that matches the name of a mail header will search that +header. + +Search keys can be expanded with TAB during entry, or left +abbreviated so long as they remain unambiguous, ie \"f\" will +search the \"from\" header. \"s\" will raise an error. + +Other keys: + +\"address\" will search all sender and recipient headers. + +\"recipient\" will search \"To\", \"Cc\", and \"Bcc\". + +\"before\" will search messages sent before the specified +date (date specifications to come later). Date is exclusive. + +\"after\" (or its synonym \"since\") will search messages sent +after the specified date. Date is inclusive. + +\"mark\" will search messages that have some sort of mark. +Likely values include \"flag\", \"seen\", \"read\", \"replied\". +It's also possible to use Gnus' internal marks, ie \"mark:R\" +will be interpreted as mark:read. + +\"tag\" will search tags -- right now that's translated to +\"keyword\" in IMAP, and left as \"tag\" for notmuch. At some +point this should also be used to search marks in the Gnus +registry. + +Other keys can be specified, provided that the search backends +know how to interpret them. + +External contact-management packages can push completion tables +onto the list variable `gnus-search-contact-tables', to provide +auto-completion of contact names and addresses for keys like +\"from\" and \"to\". + +Date values (any key in `gnus-search-date-keys') can be provided +in any format that `parse-time-string' can parse (note that this +can produce weird results). Dates with missing bits will be +interpreted as the most recent occurance thereof (ie \"march 03\" +is the most recent March 3rd). Lastly, relative specifications +such as 1d (one day ago) are understood. This also accepts w, m, +and y. m is assumed to be 30 days. + +This function will accept pretty much anything as input. Its +only job is to parse the query into a sexp, and pass that on -- +it is the job of the search backends to make sense of the +structured query. Malformed, unusable or invalid queries will +typically be silently ignored." + (with-temp-buffer + ;; Set up the parsing environment. + (insert string) + (goto-char (point-min)) + ;; Now, collect the output terms and return them. + (let (out) + (while (not (gnus-search-query-end-of-input)) + (push (gnus-search-query-next-expr) out)) + (reverse out)))) + +(defun gnus-search-query-next-expr (&optional count halt) + "Return the next expression from the current buffer." + (let ((term (gnus-search-query-next-term count)) + (next (gnus-search-query-peek-symbol))) + ;; Deal with top-level expressions. And, or, not, near... What + ;; else? Notmuch also provides xor and adj. It also provides a + ;; "nearness" parameter for near and adj. + (cond + ;; Handle 'expr or expr' + ((and (eq next 'or) + (null halt)) + (list 'or term (gnus-search-query-next-expr 2))) + ;; Handle 'near operator. + ((eq next 'near) + (let ((near-next (gnus-search-query-next-expr 2))) + (if (and (stringp term) + (stringp near-next)) + (list 'near term near-next) + (signal 'gnus-search-parse-error + (list "\"Near\" keyword must appear between two plain strings."))))) + ;; Anything else + (t term)))) + +(defun gnus-search-query-next-term (&optional count) + "Return the next TERM from the current buffer." + (let ((term (gnus-search-query-next-symbol count))) + ;; What sort of term is this? + (cond + ;; negated term + ((eq term 'not) (list 'not (gnus-search-query-next-expr nil 'halt))) + ;; generic term + (t term)))) + +(defun gnus-search-query-peek-symbol () + "Return the next symbol from the current buffer, but don't consume it." + (save-excursion + (gnus-search-query-next-symbol))) + +(defun gnus-search-query-next-symbol (&optional count) + "Return the next symbol from the current buffer, or nil if we are +at the end of the buffer. If supplied COUNT skips some symbols before +returning the one at the supplied position." + (when (and (numberp count) (> count 1)) + (gnus-search-query-next-symbol (1- count))) + (let ((case-fold-search t)) + ;; end of input stream? + (unless (gnus-search-query-end-of-input) + ;; No, return the next symbol from the stream. + (cond + ;; Negated expression -- return it and advance one char. + ((looking-at "-") (forward-char 1) 'not) + ;; List expression -- we parse the content and return this as a list. + ((looking-at "(") + (gnus-search-parse-query (gnus-search-query-return-string ")" t))) + ;; Keyword input -- return a symbol version. + ((looking-at "\\band\\b") (forward-char 3) 'and) + ((looking-at "\\bor\\b") (forward-char 2) 'or) + ((looking-at "\\bnot\\b") (forward-char 3) 'not) + ((looking-at "\\bnear\\b") (forward-char 4) 'near) + ;; Plain string, no keyword + ((looking-at "[\"/]?\\b[^:]+\\([[:blank:]]\\|\\'\\)") + (gnus-search-query-return-string + (when (looking-at-p "[\"/]") t))) + ;; Assume a K:V expression. + (t (let ((key (gnus-search-query-expand-key + (buffer-substring + (point) + (progn + (re-search-forward ":" (point-at-eol) t) + (1- (point)))))) + (value (gnus-search-query-return-string + (when (looking-at-p "[\"/]") t)))) + (gnus-search-query-parse-kv key value))))))) + +(defun gnus-search-query-parse-kv (key value) + "Handle KEY and VALUE, parsing and expanding as necessary. +This may result in (key value) being turned into a larger query +structure. + +In the simplest case, they are simply consed together. String +KEY is converted to a symbol." + (let (return) + (cond + ((member key gnus-search-date-keys) + (when (string= "after" key) + (setq key "since")) + (setq value (gnus-search-query-parse-date value))) + ((equal key "mark") + (setq value (gnus-search-query-parse-mark value))) + ((string= "message-id" key) + (setq key "id"))) + (or return + (cons (intern key) value)))) + +(defun gnus-search-query-parse-date (value &optional rel-date) + "Interpret VALUE as a date specification. +See the docstring of `gnus-search-parse-query' for details. + +The result is a list of (dd mm yyyy); individual elements can be +nil. + +If VALUE is a relative time, interpret it as relative to +REL-DATE, or (current-time) if REL-DATE is nil." + ;; Time parsing doesn't seem to work with slashes. + (let ((value (replace-regexp-in-string "/" "-" value)) + (now (append '(0 0 0) + (seq-subseq (decode-time (or rel-date + (current-time))) + 3)))) + ;; Check for relative time parsing. + (if (string-match "\\([[:digit:]]+\\)\\([dwmy]\\)" value) + (seq-subseq + (decode-time + (time-subtract + (apply #'encode-time now) + (days-to-time + (* (string-to-number (match-string 1 value)) + (cdr (assoc (match-string 2 value) + '(("d" . 1) + ("w" . 7) + ("m" . 30) + ("y" . 365)))))))) + 3 6) + ;; Otherwise check the value of `parse-time-string'. + + ;; (SEC MIN HOUR DAY MON YEAR DOW DST TZ) + (let ((d-time (parse-time-string value))) + ;; Did parsing produce anything at all? + (if (seq-some #'integerp (seq-subseq d-time 3 7)) + (seq-subseq + ;; If DOW is given, handle that specially. + (if (and (seq-elt d-time 6) (null (seq-elt d-time 3))) + (decode-time + (time-subtract (apply #'encode-time now) + (days-to-time + (+ (if (> (seq-elt d-time 6) + (seq-elt now 6)) + 7 0) + (- (seq-elt now 6) (seq-elt d-time 6)))))) + d-time) + 3 6) + ;; `parse-time-string' failed to produce anything, just + ;; return the string. + value))))) + +(defun gnus-search-query-parse-mark (mark) + "Possibly transform MARK. +If MARK is a single character, assume it is one of the +gnus-*-mark marks, and return an appropriate string." + (if (= 1 (length mark)) + (let ((m (aref mark 0))) + ;; Neither pcase nor cl-case will work here. + (cond + ((eql m gnus-ticked-mark) "flag") + ((eql m gnus-read-mark) "read") + ((eql m gnus-replied-mark) "replied") + ((eql m gnus-recent-mark) "recent") + (t mark))) + mark)) + +(defun gnus-search-query-expand-key (key) + (cond ((test-completion key gnus-search-expandable-keys) + ;; We're done! + key) + ;; There is more than one possible completion. + ((consp (cdr (completion-all-completions + key gnus-search-expandable-keys #'stringp 0))) + (signal 'gnus-search-parse-error + (list (format "Ambiguous keyword: %s" key)))) + ;; Return KEY, either completed or untouched. + ((car-safe (completion-try-completion + key gnus-search-expandable-keys + #'stringp 0))))) + +(defun gnus-search-query-return-string (&optional delimited trim) + "Return a string from the current buffer. +If DELIMITED is non-nil, assume the next character is a delimiter +character, and return everything between point and the next +occurance of the delimiter, including the delimiters themselves. +If TRIM is non-nil, do not return the delimiters. Otherwise, +return one word." + ;; This function cannot handle nested delimiters, as it's not a + ;; proper parser. Ie, you cannot parse "to:bob or (from:bob or + ;; (cc:bob or bcc:bob))". + (let ((start (point)) + (delimiter (if (stringp delimited) + delimited + (when delimited + (char-to-string (char-after))))) + end) + (if delimiter + (progn + (when trim + ;; Skip past first delimiter if we're trimming. + (forward-char 1)) + (while (not end) + (unless (search-forward delimiter nil t (unless trim 2)) + (signal 'gnus-search-parse-error + (list (format "Unmatched delimited input with %s in query" delimiter)))) + (let ((here (point))) + (unless (equal (buffer-substring (- here 2) (- here 1)) "\\") + (setq end (if trim (1- (point)) (point)) + start (if trim (1+ start) start)))))) + (setq end (progn (re-search-forward "\\([[:blank:]]+\\|$\\)" (point-max) t) + (match-beginning 0)))) + (buffer-substring-no-properties start end))) + +(defun gnus-search-query-end-of-input () + "Are we at the end of input?" + (skip-chars-forward "[:blank:]") + (looking-at "$")) + +;;; Search engines + +;; Search engines are implemented as classes. This is good for two +;; things: encapsulating things like indexes and search prefixes, and +;; transforming search queries. + +(defclass gnus-search-engine () + ((raw-queries-p + :initarg :raw-queries-p + :initform nil + :type boolean + :custom boolean + :documentation + "When t, searches through this engine will never be parsed or + transformed, and must be entered \"raw\".")) + :abstract t + :documentation "Abstract base class for Gnus search engines.") + +(defclass gnus-search-grep () + ((grep-program + :initarg :grep-program + :initform "grep" + :type string + :documentation "Grep executable to use for second-pass grep + searches.") + (grep-options + :initarg :grep-options + :initform nil + :type list + :documentation "Additional options, in the form of a list, + passed to the second-pass grep search, when present.")) + :abstract t + :documentation "An abstract mixin class that can be added to + local-filesystem search engines, providing an additional grep: + search key. After the base engine returns a list of search + results (as local filenames), an external grep process is used + to further filter the results.") + +(cl-defgeneric gnus-search-grep-search (engine artlist criteria) + "Run a secondary grep search over a list of preliminary results. + +ARTLIST is a list of (filename score) pairs, produced by one of +the other search engines. CRITERIA is a grep-specific search +key. This method uses an external grep program to further filter +the files in ARTLIST by that search key.") + +(cl-defmethod gnus-search-grep-search ((engine gnus-search-grep) + artlist criteria) + (with-slots (grep-program grep-options) engine + (if (executable-find grep-program) + ;; Don't catch errors -- allow them to propagate. + (let ((matched-files + (apply + #'process-lines + grep-program + `("-l" ,@grep-options + "-e" ,(shell-quote-argument criteria) + ,@(mapcar #'car artlist))))) + (seq-filter (lambda (a) (member (car a) matched-files)) + artlist)) + (nnheader-report 'search "invalid grep program: %s" grep-program)))) + +(defclass gnus-search-process () + ((proc-buffer + :initarg :proc-buffer + :type buffer + :documentation "A temporary buffer this engine uses for its + search process, and for munging its search results.")) + :abstract t + :documentation + "A mixin class for engines that do their searching in a single + process launched for this purpose, which returns at the end of + the search. Subclass instances are safe to be run in + threads.") + +(cl-defmethod shared-initialize ((engine gnus-search-process) + slots) + (setq slots (plist-put slots :proc-buffer + (get-buffer-create + (generate-new-buffer-name " *gnus-search-")))) + (cl-call-next-method engine slots)) + +(defclass gnus-search-imap (gnus-search-engine) + ((literal-plus + :initarg :literal-plus + :initform nil + :type boolean + :documentation + "Can this search engine handle literal+ searches? This slot + is set automatically by the imap server, and cannot be + set manually. Only the LITERAL+ capability is handled.") + (multisearch + :initarg :multisearch + :initform nil + :type boolean + :documentation + "Can this search engine handle the MULTISEARCH capability? + This slot is set automatically by the imap server, and cannot + be set manually. Currently unimplemented.") + (fuzzy + :initarg :fuzzy + :initform nil + :type boolean + :documentation + "Can this search engine handle the FUZZY search capability? + This slot is set automatically by the imap server, and cannot + be set manually. Currently only partially implemented.") + (raw-queries-p + :initform (symbol-value 'gnus-search-imap-raw-queries-p))) + :documentation + "The base IMAP search engine, using an IMAP server's search capabilites. +This backend may be subclassed to handle particular IMAP servers' +quirks.") + +(defclass gnus-search-find-grep (gnus-search-engine + gnus-search-process + gnus-search-grep) + nil) + +;;; The "indexed" search engine. + +;; These are engines that use an external program, with indexes kept +;; on disk, to search messages usually kept in some local directory. +;; They have several slots in common, for instance program name or +;; configuration file. Many of the subclasses also allow +;; distinguishing multiple databases or indexes. These slots can be +;; set using a global default, or on a per-server basis. + +(defclass gnus-search-indexed (gnus-search-engine + gnus-search-process + gnus-search-grep) + ((program + :initarg :program + :type string + :documentation + "The executable used for indexing and searching.") + (config-file + :init-arg :config-file + :type string + :custom file + :documentation "Location of the config file, if any.") + (remove-prefix + :initarg :remove-prefix + :initform (concat (getenv "HOME") "/Mail/") + :type string + :documentation + "The path to the directory where the indexed mails are + kept. This path is removed from the search results.") + (switches + :initarg :switches + :type list + :documentation + "Additional switches passed to the search engine command-line + program.")) + :abstract t + :allow-nil-initform t + :documentation "A base search engine class that assumes a local search index + accessed by a command line program.") + +(defclass gnus-search-swish-e (gnus-search-indexed) + ((index-files + :init-arg :index-files + :initform (symbol-value 'gnus-search-swish-e-index-files) + :type list) + (program + :initform (symbol-value 'gnus-search-swish-e-program)) + (remove-prefix + :initform (symbol-value 'gnus-search-swish-e-remove-prefix)) + (switches + :initform (symbol-value 'gnus-search-swish-e-switches)) + (raw-queries-p + :initform (symbol-value 'gnus-search-swish-e-raw-queries-p)))) + +(defclass gnus-search-swish++ (gnus-search-indexed) + ((program + :initform (symbol-value 'gnus-search-swish++-program)) + (remove-prefix + :initform (symbol-value 'gnus-search-swish++-remove-prefix)) + (switches + :initform (symbol-value 'gnus-search-swish++-switches)) + (config-file + :initform (symbol-value 'gnus-search-swish++-config-file)) + (raw-queries-p + :initform (symbol-value 'gnus-search-swish++-raw-queries-p)))) + +(defclass gnus-search-mairix (gnus-search-indexed) + ((program + :initform (symbol-value 'gnus-search-mairix-program)) + (remove-prefix + :initform (symbol-value 'gnus-search-mairix-remove-prefix)) + (switches + :initform (symbol-value 'gnus-search-mairix-switches)) + (config-file + :initform (symbol-value 'gnus-search-mairix-config-file)) + (raw-queries-p + :initform (symbol-value 'gnus-search-mairix-raw-queries-p)))) + +(defclass gnus-search-namazu (gnus-search-indexed) + ((index-directory + :initarg :index-directory + :type string + :custom directory) + (program + :initform (symbol-value 'gnus-search-namazu-program)) + (remove-prefix + :initform (symbol-value 'gnus-search-namazu-remove-prefix)) + (switches + :initform (symbol-value 'gnus-search-namazu-switches)) + (raw-queries-p + :initform (symbol-value 'gnus-search-namazu-raw-queries-p)))) + +(defclass gnus-search-notmuch (gnus-search-indexed) + ((program + :initform (symbol-value 'gnus-search-notmuch-program)) + (remove-prefix + :initform (symbol-value 'gnus-search-notmuch-remove-prefix)) + (switches + :initform (symbol-value 'gnus-search-notmuch-switches)) + (config-file + :initform (symbol-value 'gnus-search-notmuch-config-file)) + (raw-queries-p + :initform (symbol-value 'gnus-search-notmuch-raw-queries-p)))) + +(define-obsolete-variable-alias 'nnir-method-default-engines + 'gnus-search-default-engines "28.1") + +(defcustom gnus-search-default-engines '((nnimap . gnus-search-imap)) + "Alist of default search engines keyed by server method." + :version "26.1" + :group 'gnus-search + :type `(repeat (cons (choice (const nnimap) (const nntp) (const nnspool) + (const nneething) (const nndir) (const nnmbox) + (const nnml) (const nnmh) (const nndraft) + (const nnfolder) (const nnmaildir)) + (choice + ,@(mapcar + (lambda (el) (list 'const (intern (car el)))) + (eieio-build-class-alist 'gnus-search-engine t)))))) + +;;; Transforming and running search queries. + +(cl-defgeneric gnus-search-run-search (engine server query groups) + "Run QUERY in GROUPS against SERVER, using search ENGINE. +Should return results as a vector of vectors.") + +(cl-defgeneric gnus-search-transform (engine expression) + "Transform sexp EXPRESSION into a string search query usable by ENGINE. +Responsible for handling and, or, and parenthetical expressions.") + +(cl-defgeneric gnus-search-transform-expression (engine expression) + "Transform a basic EXPRESSION into a string usable by ENGINE.") + +(cl-defgeneric gnus-search-make-query-string (engine query-spec) + "Extract the actual query string to use from QUERY-SPEC.") + +;; Methods that are likely to be the same for all engines. + +(cl-defmethod gnus-search-make-query-string ((engine gnus-search-engine) + query-spec) + (if (and gnus-search-use-parsed-queries + (null (alist-get 'raw query-spec)) + (null (slot-value engine 'raw-queries-p))) + (gnus-search-transform + engine (alist-get 'parsed-query query-spec)) + (alist-get 'query query-spec))) + +(defsubst gnus-search-single-p (query) + "Return t if QUERY is a search for a single message." + (let ((q (alist-get 'parsed-query query))) + (and (= (length q ) 1) + (consp (car-safe q)) + (eq (caar q) 'id)))) + +(cl-defmethod gnus-search-transform ((engine gnus-search-engine) + (query list)) + (let (clauses) + (mapc + (lambda (item) + (when-let ((expr (gnus-search-transform-expression engine item))) + (push expr clauses))) + query) + (mapconcat #'identity (reverse clauses) " "))) + +;; Most search engines just pass through plain strings. +(cl-defmethod gnus-search-transform-expression ((_ gnus-search-engine) + (expr string)) + expr) + +;; Most search engines use implicit ANDs. +(cl-defmethod gnus-search-transform-expression ((_ gnus-search-engine) + (_expr (eql and))) + nil) + +;; Most search engines use explicit infixed ORs. +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-engine) + (expr (head or))) + (let ((left (gnus-search-transform-expression engine (nth 1 expr))) + (right (gnus-search-transform-expression engine (nth 2 expr)))) + ;; Unhandled keywords return a nil; don't create an "or" expression + ;; unless both sub-expressions are non-nil. + (if (and left right) + (format "%s or %s" left right) + (or left right)))) + +;; Most search engines just use the string "not" +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-engine) + (expr (head not))) + (let ((next (gnus-search-transform-expression engine (cadr expr)))) + (when next + (format "not %s" next)))) + +;;; Search Engine Interfaces: + +(autoload 'nnimap-change-group "nnimap") +(declare-function nnimap-buffer "nnimap" ()) +(declare-function nnimap-command "nnimap" (&rest args)) + +;; imap interface +(cl-defmethod gnus-search-run-search ((engine gnus-search-imap) + srv query groups) + (save-excursion + (let ((server (cadr (gnus-server-to-method srv))) + (gnus-inhibit-demon t) + ;; We're using the message id to look for a single message. + (single-search (gnus-search-single-p query)) + (grouplist (or groups (gnus-search-get-active srv))) + q-string artlist group) + (message "Opening server %s" server) + ;; We should only be doing this once, in + ;; `nnimap-open-connection', but it's too frustrating to try to + ;; get to the server from the process buffer. + (with-current-buffer (nnimap-buffer) + (setf (slot-value engine 'literal-plus) + (when (nnimap-capability "LITERAL+") t)) + ;; MULTISEARCH not yet implemented. + (setf (slot-value engine 'multisearch) + (when (nnimap-capability "MULTISEARCH") t)) + ;; FUZZY only partially supported: the command is sent to the + ;; server (and presumably acted upon), but we don't yet + ;; request a RELEVANCY score as part of the response. + (setf (slot-value engine 'fuzzy) + (when (nnimap-capability "SEARCH=FUZZY") t))) + + (setq q-string + (gnus-search-make-query-string engine query)) + + ;; If it's a thread query, make sure that all message-id + ;; searches are also references searches. + (when (alist-get 'thread query) + (setq q-string + (replace-regexp-in-string + "HEADER Message-Id \\([^ )]+\\)" + "(OR HEADER Message-Id \\1 HEADER References \\1)" + q-string))) + + (while (and (setq group (pop grouplist)) + (or (null single-search) (null artlist))) + (when (nnimap-change-group + (gnus-group-short-name group) server) + (with-current-buffer (nnimap-buffer) + (message "Searching %s..." group) + (let ((result + (gnus-search-imap-search-command engine q-string))) + (when (car result) + (setq artlist + (vconcat + (mapcar + (lambda (artnum) + (let ((artn (string-to-number artnum))) + (when (> artn 0) + (vector group artn 100)))) + (cdr (assoc "SEARCH" (cdr result)))) + artlist)))) + (message "Searching %s...done" group)))) + (nreverse artlist)))) + +(cl-defmethod gnus-search-imap-search-command ((engine gnus-search-imap) + (query string)) + "Create the IMAP search command for QUERY. +Currenly takes into account support for the LITERAL+ capability. +Other capabilities could be tested here." + (with-slots (literal-plus) engine + (when literal-plus + (setq query (split-string query "\n"))) + (cond + ((consp query) + ;; We're not really streaming, just need to prevent + ;; `nnimap-send-command' from waiting for a response. + (let* ((nnimap-streaming t) + (call + (nnimap-send-command + "UID SEARCH CHARSET UTF-8 %s" + (pop query)))) + (dolist (l query) + (process-send-string (get-buffer-process (current-buffer)) l) + (process-send-string (get-buffer-process (current-buffer)) + (if (nnimap-newlinep nnimap-object) + "\n" + "\r\n"))) + (nnimap-get-response call))) + (t (nnimap-command "UID SEARCH %s" query))))) + +;; TODO: Don't exclude booleans and date keys, just check for them +;; before checking for general keywords. +(defvar gnus-search-imap-search-keys + '(body cc bcc from header keyword larger smaller subject text to uid) + "Known IMAP search keys, excluding booleans and date keys.") + +(cl-defmethod gnus-search-transform ((_ gnus-search-imap) + (_query null)) + "ALL") + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-imap) + (expr string)) + (unless (string-match-p "\\`/.+/\\'" expr) + ;; Also need to check for fuzzy here. Or better, do some + ;; refactoring of this stuff. + (format "TEXT %s" + (gnus-search-imap-handle-string engine expr)))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-imap) + (expr (head or))) + (let ((left (gnus-search-transform-expression engine (nth 1 expr))) + (right (gnus-search-transform-expression engine (nth 2 expr)))) + (if (and left right) + (format "(OR %s %s)" + left (format (if (eq 'or (car-safe (nth 2 expr))) + "(%s)" "%s") + right)) + (or left right)))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-imap) + (expr (head near))) + "Imap searches interpret \"near\" as \"or\"." + (setcar expr 'or) + (gnus-search-transform-expression engine expr)) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-imap) + (expr (head not))) + "Transform IMAP NOT. +If the term to be negated is a flag, then use the appropriate UN* +boolean instead." + (if (eql (caadr expr) 'mark) + (if (string= (cdadr expr) "new") + "OLD" + (format "UN%s" (gnus-search-imap-handle-flag (cdadr expr)))) + (format "NOT %s" + (gnus-search-transform-expression engine (cadr expr))))) + +(cl-defmethod gnus-search-transform-expression ((_ gnus-search-imap) + (expr (head mark))) + (gnus-search-imap-handle-flag (cdr expr))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-imap) + (expr list)) + "Handle a search keyword for IMAP. +All IMAP search keywords that take a value are supported +directly. Keywords that are boolean are supported through other +means (usually the \"mark\" keyword)." + (let ((fuzzy-supported (slot-value engine 'fuzzy)) + (fuzzy "")) + (cl-case (car expr) + (date (setcar expr 'on)) + (tag (setcar expr 'keyword)) + (sender (setcar expr 'from)) + (attachment (setcar expr 'body))) + ;; Allow sizes specified as KB or MB. + (let ((case-fold-search t) + unit) + (when (and (memq (car expr) '(larger smaller)) + (string-match "\\(kb?\\|mb?\\)\\'" (cdr expr))) + (setq unit (match-string 1 (cdr expr))) + (setcdr expr + (number-to-string + (* (string-to-number + (string-replace unit "" (cdr expr))) + (if (string-prefix-p "k" unit) + 1024 + 1048576)))))) + (cond + ((consp (car expr)) + (format "(%s)" (gnus-search-transform engine expr))) + ((eq (car expr) 'recipient) + (gnus-search-transform + engine (gnus-search-parse-query + (format + "to:%s or cc:%s or bcc:%s" + (cdr expr) (cdr expr) (cdr expr))))) + ((eq (car expr) 'address) + (gnus-search-transform + engine (gnus-search-parse-query + (format + "from:%s or to:%s or cc:%s or bcc:%s" + (cdr expr) (cdr expr) (cdr expr) (cdr expr))))) + ((memq (car expr) '(before since on sentbefore senton sentsince)) + ;; Ignore dates given as strings. + (when (listp (cdr expr)) + (format "%s %s" + (upcase (symbol-name (car expr))) + (gnus-search-imap-handle-date engine (cdr expr))))) + ((stringp (cdr expr)) + ;; If the search term starts or ends with "*", remove the + ;; asterisk. If the engine supports FUZZY, then additionally make + ;; the search fuzzy. + (when (string-match "\\`\\*\\|\\*\\'" (cdr expr)) + (setcdr expr (replace-regexp-in-string + "\\`\\*\\|\\*\\'" "" (cdr expr))) + (when fuzzy-supported + (setq fuzzy "FUZZY "))) + ;; If the search term is a regexp, drop the expression altogether. + (unless (string-match-p "\\`/.+/\\'" (cdr expr)) + (cond + ((memq (car expr) gnus-search-imap-search-keys) + (format "%s%s %s" + fuzzy + (upcase (symbol-name (car expr))) + (gnus-search-imap-handle-string engine (cdr expr)))) + ((eq (car expr) 'id) + (format "HEADER Message-ID \"%s\"" (cdr expr))) + ;; Treat what can't be handled as a HEADER search. Probably a bad + ;; idea. + (t (format "%sHEADER %s %s" + fuzzy + (car expr) + (gnus-search-imap-handle-string engine (cdr expr)))))))))) + +(cl-defmethod gnus-search-imap-handle-date ((_engine gnus-search-imap) + (date list)) + "Turn DATE into a date string recognizable by IMAP. +While other search engines can interpret partially-qualified +dates such as a plain \"January\", IMAP requires an absolute +date. + +DATE is a list of (dd mm yyyy), any element of which could be +nil. Massage those numbers into the most recent past occurrence +of whichever date elements are present." + (let ((now (decode-time (current-time)))) + ;; Set nil values to 1, current-month, current-year, or else 1, 1, + ;; current-year, depending on what we think the user meant. + (unless (seq-elt date 1) + (setf (seq-elt date 1) + (if (seq-elt date 0) + (seq-elt now 4) + 1))) + (unless (seq-elt date 0) + (setf (seq-elt date 0) 1)) + (unless (seq-elt date 2) + (setf (seq-elt date 2) + (seq-elt now 5))) + ;; Fiddle with the date until it's in the past. There + ;; must be a way to combine all these steps. + (unless (< (seq-elt date 2) + (seq-elt now 5)) + (when (< (seq-elt now 3) + (seq-elt date 0)) + (cl-decf (seq-elt date 1))) + (cond ((zerop (seq-elt date 1)) + (setf (seq-elt date 1) 1) + (cl-decf (seq-elt date 2))) + ((< (seq-elt now 4) + (seq-elt date 1)) + (cl-decf (seq-elt date 2)))))) + (format-time-string "%e-%b-%Y" (apply #'encode-time + (append '(0 0 0) + date)))) + +(cl-defmethod gnus-search-imap-handle-string ((engine gnus-search-imap) + (str string)) + (with-slots (literal-plus) engine + (if (multibyte-string-p str) + ;; If LITERAL+ is available, use it and encode string as + ;; UTF-8. + (if literal-plus + (format "{%d+}\n%s" + (string-bytes str) + (encode-coding-string str 'utf-8)) + ;; Otherwise, if the user hasn't already quoted the string, + ;; quote it for them. + (if (string-prefix-p "\"" str) + str + (format "\"%s\"" str))) + str))) + +(defun gnus-search-imap-handle-flag (flag) + "Make sure string FLAG is something IMAP will recognize." + ;; What else? What about the KEYWORD search key? + (setq flag + (pcase flag + ("flag" "flagged") + ("read" "seen") + (_ flag))) + (if (member flag '("seen" "answered" "deleted" "draft" "flagged")) + (upcase flag) + "")) + +;;; Methods for the indexed search engines. + +;; First, some common methods. + +(cl-defgeneric gnus-search-indexed-parse-output (engine server &optional groups) + "Parse the results of ENGINE's query against SERVER in GROUPS. +Locally-indexed search engines return results as a list of +filenames, sometimes with additional information. Returns a list +of viable results, in the form of a list of [group article score] +vectors.") + +(cl-defgeneric gnus-search-index-extract (engine) + "Extract a single article result from the current buffer. +Returns a list of two values: a file name, and a relevancy score. +Advances point to the beginning of the next result.") + +(cl-defmethod gnus-search-run-search ((engine gnus-search-indexed) + server query groups) + "Run QUERY against SERVER using ENGINE. +This method is common to all indexed search engines. + +Returns a list of [group article score] vectors." + + (save-excursion + (let* ((qstring (gnus-search-make-query-string engine query)) + (program (slot-value engine 'program)) + (buffer (slot-value engine 'proc-buffer)) + (cp-list (gnus-search-indexed-search-command + engine qstring query groups)) + proc exitstatus) + (set-buffer buffer) + (erase-buffer) + + (if groups + (message "Doing %s query on %s..." program groups) + (message "Doing %s query..." program)) + (setq proc (apply #'start-process (format "search-%s" server) + buffer program cp-list)) + (while (process-live-p proc) + (accept-process-output proc)) + (setq exitstatus (process-exit-status proc)) + (if (zerop exitstatus) + ;; The search results have been put into the current buffer; + ;; `parse-output' finds them there and returns the article + ;; list. + (gnus-search-indexed-parse-output engine server query groups) + (nnheader-report 'search "%s error: %s" program exitstatus) + ;; Failure reason is in this buffer, show it if the user + ;; wants it. + (when (> gnus-verbose 6) + (display-buffer buffer)) + nil)))) + +(cl-defmethod gnus-search-indexed-parse-output ((engine gnus-search-indexed) + server query &optional groups) + (let ((prefix (slot-value engine 'remove-prefix)) + (group-regexp (when groups + (regexp-opt + (mapcar + (lambda (x) (gnus-group-real-name x)) + groups)))) + artlist vectors article group) + (goto-char (point-min)) + (while (not (eobp)) + (pcase-let ((`(,f-name ,score) (gnus-search-indexed-extract engine))) + (when (and (file-readable-p f-name) + (null (file-directory-p f-name)) + (or (null groups) + (and (gnus-search-single-p query) + (alist-get 'thread query)) + (string-match-p group-regexp f-name))) + (push (list f-name score) artlist)))) + ;; Are we running an additional grep query? + (when-let ((grep-reg (alist-get 'grep query))) + (setq artlist (gnus-search-grep-search engine artlist grep-reg))) + ;; Turn (file-name score) into [group article score]. + (pcase-dolist (`(,f-name ,score) artlist) + (setq article (file-name-nondirectory f-name)) + ;; Remove prefix. + (when (and prefix + (file-name-absolute-p prefix) + (string-match (concat "^" + (file-name-as-directory prefix)) + f-name)) + (setq group (replace-match "" t t (file-name-directory f-name)))) + ;; Break the directory name down until it's something that + ;; (probably) can be used as a group name. + (setq group + (replace-regexp-in-string + "[/\\]" "." + (replace-regexp-in-string + "/?\\(cur\\|new\\|tmp\\)?/\\'" "" + (replace-regexp-in-string + "^[./\\]" "" + group nil t) + nil t) + nil t)) + + (push (vector (gnus-group-full-name group server) + (if (string-match-p "\\`[[:digit:]]+\\'" article) + (string-to-number article) + (nnmaildir-base-name-to-article-number + (substring article 0 (string-match ":" article)) + group nil)) + (if (numberp score) + score + (string-to-number score))) + vectors)) + vectors)) + +(cl-defmethod gnus-search-indexed-extract ((_engine gnus-search-indexed)) + "Base implementation treats the whole line as a filename, and +fudges a relevancy score of 100." + (prog1 + (list (buffer-substring-no-properties (line-beginning-position) + (line-end-position)) + 100) + (forward-line 1))) + +;; Swish++ + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-swish++) + (expr (head near))) + (format "%s near %s" + (gnus-search-transform-expression engine (nth 1 expr)) + (gnus-search-transform-expression engine (nth 2 expr)))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-swish++) + (expr list)) + (cond + ((listp (car expr)) + (format "(%s)" (gnus-search-transform engine expr))) + ;; Untested and likely wrong. + ((and (stringp (cdr expr)) + (string-prefix-p "(" (cdr expr))) + (format "%s = %s" (car expr) (gnus-search-transform + engine + (gnus-search-parse-query (cdr expr))))) + (t (format "%s = %s" (car expr) (cdr expr))))) + +(cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-swish++) + (qstring string) + _query &optional _groups) + (with-slots (config-file switches) engine + `("--config-file" ,config-file + ,@switches + ,qstring + ))) + +(cl-defmethod gnus-search-indexed-extract ((_engine gnus-search-swish++)) + (when (re-search-forward + "\\(^[0-9]+\\) \\([^ ]+\\) [0-9]+ \\(.*\\)$" nil t) + (list (match-string 2) + (match-string 1)))) + +;; Swish-e + +;; I didn't do the query transformation for Swish-e, because the +;; program seems no longer to exist. + +(cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-swish-e) + (qstring string) + _query &optional _groups) + (with-slots (index-files switches) engine + `("-f" ,@index-files + ,@switches + "-w" + ,qstring + ))) + +(cl-defmethod gnus-search-indexed-extract ((_engine gnus-search-swish-e)) + (when (re-search-forward + "\\(^[0-9]+\\) \\([^ ]+\\) \"\\([^\"]+\\)\" [0-9]+$" nil t) + (list (match-string 3) + (match-string 1)))) + +;; Namazu interface + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-namazu) + (expr list)) + (cond + ((listp (car expr)) + (format "(%s)" (gnus-search-transform engine expr))) + ((eql (car expr) 'body) + (cadr expr)) + ;; I have no idea which fields namazu can handle. Just do these + ;; for now. + ((memq (car expr) '(subject from to)) + (format "+%s:%s" (car expr) (cdr expr))) + ((eql (car expr) 'address) + (gnus-search-transform engine `((or (from . ,(cdr expr)) + (to . ,(cdr expr)))))) + ((eq (car expr) 'id) + (format "+message-id:%s" (cdr expr))) + (t (ignore-errors (cl-call-next-method))))) + +;; I can't tell if this is actually necessary. +(cl-defmethod gnus-search-run-search :around ((_e gnus-search-namazu) + _server _query _groups) + (let ((process-environment (copy-sequence process-environment))) + (setenv "LC_MESSAGES" "C") + (cl-call-next-method))) + +(cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-namazu) + (qstring string) + query &optional _groups) + (let ((max (alist-get 'limit query))) + (with-slots (switches index-directory) engine + (append + (list "-q" ; don't be verbose + "-a" ; show all matches + "-s") ; use short format + (when max (list (format "--max=%d" max))) + switches + (list qstring index-directory))))) + +(cl-defmethod gnus-search-indexed-extract ((_engine gnus-search-namazu)) + "Extract a single message result for Namazu. +Namazu provides a little more information, for instance a score." + + (when (re-search-forward + "^\\([0-9,]+\\.\\).*\\((score: \\([0-9]+\\)\\))\n\\([^ ]+\\)" + nil t) + (list (match-string 4) + (match-string 3)))) + +;;; Notmuch interface + +(cl-defmethod gnus-search-transform ((_engine gnus-search-notmuch) + (_query null)) + "*") + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-notmuch) + (expr (head near))) + (format "%s near %s" + (gnus-search-transform-expression engine (nth 1 expr)) + (gnus-search-transform-expression engine (nth 2 expr)))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-notmuch) + (expr list)) + ;; Swap keywords as necessary. + (cl-case (car expr) + (sender (setcar expr 'from)) + ;; Notmuch's "to" is already equivalent to our "recipient". + (recipient (setcar expr 'to)) + (mark (setcar expr 'tag))) + ;; Then actually format the results. + (cl-flet ((notmuch-date (date) + (if (stringp date) + date + (pcase date + (`(nil ,m nil) + (nth (1- m) gnus-english-month-names)) + (`(nil nil ,y) + (number-to-string y)) + (`(,d ,m nil) + (format "%02d-%02d" d m)) + (`(nil ,m ,y) + (format "%02d-%d" m y)) + (`(,d ,m ,y) + (format "%d/%d/%d" m d y)))))) + (cond + ((consp (car expr)) + (format "(%s)" (gnus-search-transform engine expr))) + ((eql (car expr) 'address) + (gnus-search-transform engine `((or (from . ,(cdr expr)) + (to . ,(cdr expr)))))) + ((eql (car expr) 'body) + (cdr expr)) + ((memq (car expr) '(from to subject attachment mimetype tag id + thread folder path lastmod query property)) + ;; Notmuch requires message-id with no angle brackets. + (when (eql (car expr) 'id) + (setcdr + expr (replace-regexp-in-string "\\`<\\|>\\'" "" (cdr expr)))) + (format "%s:%s" (car expr) + (if (string-match "\\`\\*" (cdr expr)) + ;; Notmuch can only handle trailing asterisk + ;; wildcards, so strip leading asterisks. + (replace-match "" nil nil (cdr expr)) + (cdr expr)))) + ((eq (car expr) 'date) + (format "date:%s" (notmuch-date (cdr expr)))) + ((eq (car expr) 'before) + (format "date:..%s" (notmuch-date (cdr expr)))) + ((eq (car expr) 'since) + (format "date:%s.." (notmuch-date (cdr expr)))) + (t (ignore-errors (cl-call-next-method)))))) + +(cl-defmethod gnus-search-run-search :around ((engine gnus-search-notmuch) + server query groups) + "Handle notmuch's thread-search routine." + ;; Notmuch allows for searching threads, but only using its own + ;; thread ids. That means a thread search is a \"double-bounce\": + ;; once to find the relevant thread ids, and again to find the + ;; actual messages. This method performs the first \"bounce\". + (if (alist-get 'thread query) + (with-slots (program proc-buffer) engine + (let* ((qstring + (gnus-search-make-query-string engine query)) + (cp-list (gnus-search-indexed-search-command + engine qstring query groups)) + thread-ids proc) + (set-buffer proc-buffer) + (erase-buffer) + (setq proc (apply #'start-process (format "search-%s" server) + proc-buffer program cp-list)) + (while (process-live-p proc) + (accept-process-output proc)) + (while (re-search-forward "^thread:\\([^ ]+\\)" (point-max) t) + (push (match-string 1) thread-ids)) + (cl-call-next-method + engine server + ;; Completely replace the query with our new thread-based one. + (mapconcat (lambda (thrd) (concat "thread:" thrd)) + thread-ids " or ") + nil))) + (cl-call-next-method engine server query groups))) + +(cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-notmuch) + (qstring string) + query &optional _groups) + ;; Theoretically we could use the GROUPS parameter to pass a + ;; --folder switch to notmuch, but I'm not confident of getting the + ;; format right. + (let ((limit (alist-get 'limit query)) + (thread (alist-get 'thread query))) + (with-slots (switches config-file) engine + `(,(format "--config=%s" config-file) + "search" + ,(if thread + "--output=threads" + "--output=files") + "--duplicate=1" ; I have found this necessary, I don't know why. + ,@switches + ,(if limit (format "--limit=%d" limit) "") + ,qstring + )))) + +;;; Mairix interface + +;; See the Gnus manual for why mairix searching is a bit weird. + +(cl-defmethod gnus-search-transform ((engine gnus-search-mairix) + (query list)) + "Transform QUERY for a Mairix engine. +Because Mairix doesn't accept parenthesized expressions, nor +\"or\" statements between different keys, results may differ from +other engines. We unpeel parenthesized expressions, and just +cross our fingers for the rest of it." + (let (clauses) + (mapc + (lambda (item) + (when-let ((expr (if (consp (car-safe item)) + (gnus-search-transform engine item) + (gnus-search-transform-expression engine item)))) + (push expr clauses))) + query) + (mapconcat #'identity (reverse clauses) " "))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-mairix) + (expr (head not))) + "Transform Mairix \"not\". +Mairix negation requires a \"~\" preceding string search terms, +and \"-\" before marks." + (let ((next (gnus-search-transform-expression engine (cadr expr)))) + (replace-regexp-in-string + ":" + (if (eql (caadr expr) 'mark) + ":-" + ":~") + next))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-mairix) + (expr (head or))) + "Handle Mairix \"or\" statement. +Mairix only accepts \"or\" expressions on homogenous keys. We +cast \"or\" expressions on heterogenous keys as \"and\", which +isn't quite right, but it's the best we can do. For date keys, +only keep one of the terms." + (let ((term1 (caadr expr)) + (term2 (caaddr expr)) + (val1 (gnus-search-transform-expression engine (nth 1 expr))) + (val2 (gnus-search-transform-expression engine (nth 2 expr)))) + (cond + ((or (listp term1) (listp term2)) + (concat val1 " " val2)) + ((and (member (symbol-name term1) gnus-search-date-keys) + (member (symbol-name term2) gnus-search-date-keys)) + (or val1 val2)) + ((eql term1 term2) + (if (and val1 val2) + (format "%s/%s" + val1 + (nth 1 (split-string val2 ":"))) + (or val1 val2))) + (t (concat val1 " " val2))))) + + +(cl-defmethod gnus-search-transform-expression ((_ gnus-search-mairix) + (expr (head mark))) + (gnus-search-mairix-handle-mark (cdr expr))) + +(cl-defmethod gnus-search-transform-expression ((engine gnus-search-mairix) + (expr list)) + (let ((key (cl-case (car expr) + (sender "f") + (from "f") + (to "t") + (cc "c") + (subject "s") + (id "m") + (body "b") + (address "a") + (recipient "tc") + (text "bs") + (attachment "n") + (t nil)))) + (cond + ((consp (car expr)) + (gnus-search-transform engine expr)) + ((member (symbol-name (car expr)) gnus-search-date-keys) + (gnus-search-mairix-handle-date expr)) + ((memq (car expr) '(size smaller larger)) + (gnus-search-mairix-handle-size expr)) + ;; Drop regular expressions. + ((string-match-p "\\`/" (cdr expr)) + nil) + ;; Turn parenthesized phrases into multiple word terms. Again, + ;; this isn't quite what the user is asking for, but better to + ;; return false positives. + ((and key (string-match-p "[[:blank:]]" (cdr expr))) + (mapconcat + (lambda (s) (format "%s:%s" key s)) + (split-string (gnus-search-mairix-treat-string + (cdr expr))) + " ")) + (key (format "%s:%s" key + (gnus-search-mairix-treat-string + (cdr expr)))) + (t nil)))) + +(defun gnus-search-mairix-treat-string (str) + "Treat string for wildcards. +Mairix accepts trailing wildcards, but not leading. Also remove +double quotes." + (replace-regexp-in-string + "\\`\\*\\|\"" "" + (replace-regexp-in-string "\\*\\'" "=" str))) + +(defun gnus-search-mairix-handle-size (expr) + "Format a mairix size search. +Assume \"size\" key is equal to \"larger\"." + (format + (if (eql (car expr) 'smaller) + "z:-%s" + "z:%s-") + (cdr expr))) + +(defun gnus-search-mairix-handle-mark (expr) + "Format a mairix mark search." + (let ((mark + (pcase (cdr expr) + ("flag" "f") + ("read" "s") + ("seen" "s") + ("replied" "r") + (_ nil)))) + (when mark + (format "F:%s" mark)))) + +(defun gnus-search-mairix-handle-date (expr) + (let ((str + (pcase (cdr expr) + (`(nil ,m nil) + (substring + (nth (1- m) gnus-english-month-names) + 0 3)) + (`(nil nil ,y) + (number-to-string y)) + (`(,d ,m nil) + (format "%s%02d" + (substring + (nth (1- m) gnus-english-month-names) + 0 3) + d)) + (`(nil ,m ,y) + (format "%d%s" + y (substring + (nth (1- m) gnus-english-month-names) + 0 3))) + (`(,d ,m ,y) + (format "%d%02d%02d" y m d))))) + (format + (pcase (car expr) + ('date "d:%s") + ('since "d:%s-") + ('after "d:%s-") + ('before "d:-%s")) + str))) + +(cl-defmethod gnus-search-indexed-search-command ((engine gnus-search-mairix) + (qstring string) + query &optional _groups) + (with-slots (switches config-file) engine + (append `("--rcfile" ,config-file "-r") + switches + (when (alist-get 'thread query) (list "-t")) + (list qstring)))) + +;;; Find-grep interface + +(cl-defmethod gnus-search-transform-expression ((_engine gnus-search-find-grep) + (_ list)) + ;; Drop everything that isn't a plain string. + nil) + +(cl-defmethod gnus-search-run-search ((engine gnus-search-find-grep) + server query + &optional groups) + "Run find and grep to obtain matching articles." + (let* ((method (gnus-server-to-method server)) + (sym (intern + (concat (symbol-name (car method)) "-directory"))) + (directory (cadr (assoc sym (cddr method)))) + (regexp (alist-get 'grep query)) + (grep-options (slot-value engine 'grep-options)) + (grouplist (or groups (gnus-search-get-active server))) + (buffer (slot-value engine 'proc-buffer))) + (unless directory + (error "No directory found in method specification of server %s" + server)) + (apply + 'vconcat + (mapcar (lambda (x) + (let ((group x) + artlist) + (message "Searching %s using find-grep..." + (or group server)) + (save-window-excursion + (set-buffer buffer) + (if (> gnus-verbose 6) + (pop-to-buffer (current-buffer))) + (cd directory) ; Using relative paths simplifies + ; postprocessing. + (let ((group + (if (not group) + "." + ;; Try accessing the group literally as + ;; well as interpreting dots as directory + ;; separators so the engine works with + ;; plain nnml as well as the Gnus Cache. + (let ((group (gnus-group-real-name group))) + ;; Replace cl-func find-if. + (if (file-directory-p group) + group + (if (file-directory-p + (setq group + (replace-regexp-in-string + "\\." "/" + group nil t))) + group)))))) + (unless group + (error "Cannot locate directory for group")) + (save-excursion + (apply + 'call-process "find" nil t + "find" group "-maxdepth" "1" "-type" "f" + "-name" "[0-9]*" "-exec" + (slot-value engine 'grep-program) + `("-l" ,@(and grep-options + (split-string grep-options "\\s-" t)) + "-e" ,regexp "{}" "+")))) + + ;; Translate relative paths to group names. + (while (not (eobp)) + (let* ((path (split-string + (buffer-substring + (point) + (line-end-position)) "/" t)) + (art (string-to-number (car (last path))))) + (while (string= "." (car path)) + (setq path (cdr path))) + (let ((group (mapconcat #'identity + (cl-subseq path 0 -1) + "."))) + (push + (vector (gnus-group-full-name group server) art 0) + artlist)) + (forward-line 1))) + (message "Searching %s using find-grep...done" + (or group server)) + artlist))) + grouplist)))) + +;;; Util Code: + +(defun gnus-search-run-query (specs) + "Invoke appropriate search engine function." + ;; For now, run the searches synchronously. At some point + ;; multiple-server searches can each be run in their own thread, + ;; allowing concurrent searches of multiple backends. At present + ;; this causes problems when searching more than one server that + ;; uses `nntp-server-buffer', as their return values are written + ;; interleaved into that buffer. Anyway, that's the reason for the + ;; `mapc'. + (let* ((results []) + (prepared-query (gnus-search-prepare-query + (alist-get 'search-query-spec specs))) + (limit (alist-get 'limit prepared-query))) + (mapc + (pcase-lambda (`(,server . ,groups)) + (let ((search-engine (gnus-search-server-to-engine server))) + (setq results + (vconcat + (gnus-search-run-search + search-engine server prepared-query groups) + results)))) + (alist-get 'search-group-spec specs)) + ;; Some search engines do their own limiting, but some don't, so + ;; do it again here. This is bad because, if the user is + ;; searching multiple groups, they would reasonably expect the + ;; limiting to apply to the search results *after sorting*. Doing + ;; it this way is liable to, for instance, eliminate all results + ;; from a later group entirely. + (if limit + (seq-subseq results 0 (min limit (length results))) + results))) + +(defun gnus-search-prepare-query (query-spec) + "Accept a search query in raw format, and prepare it. +QUERY-SPEC is an alist produced by functions such as +`gnus-group-make-search-group', and contains at least a 'query +key, and possibly some meta keys. This function extracts any +additional meta keys from the 'query string, and parses the +remaining string, then adds all that to the top-level spec." + (let ((query (alist-get 'query query-spec)) + val) + (when (stringp query) + ;; Look for these meta keys: + (while (string-match + "\\(thread\\|grep\\|limit\\|raw\\):\\([^ ]+\\)" + query) + (setq val (match-string 2 query)) + (setf (alist-get (intern (match-string 1 query)) query-spec) + ;; This is stupid. + (cond + ((equal val "t")) + ((null (zerop (string-to-number val))) + (string-to-number val)) + (t val))) + (setq query + (string-trim (replace-match "" t t query 0))) + (setf (alist-get 'query query-spec) query))) + (when gnus-search-use-parsed-queries + (setf (alist-get 'parsed-query query-spec) + (gnus-search-parse-query query))) + query-spec)) + +;; This should be done once at Gnus startup time, when the servers are +;; first opened, and the resulting engine instance attached to the +;; server. +(defun gnus-search-server-to-engine (srv) + (let* ((method (gnus-server-to-method srv)) + (engine-config (assoc 'gnus-search-engine (cddr method))) + (server + (or (nth 1 engine-config) + (cdr-safe (assoc (car method) gnus-search-default-engines)) + (when-let ((old (assoc 'nnir-search-engine + (cddr method)))) + (nnheader-message + 8 "\"nnir-search-engine\" is no longer a valid parameter") + (pcase (nth 1 old) + ('notmuch 'gnus-search-notmuch) + ('namazu 'gnus-search-namazu) + ('find-grep 'gnus-search-find-grep))))) + (inst + (cond + ((null server) nil) + ((eieio-object-p server) + server) + ((class-p server) + (make-instance server)) + (t nil)))) + (if inst + (when (cddr engine-config) + ;; We're not being completely backward-compatible here, + ;; because we're not checking for nnir-specific config + ;; options in the server definition. + (pcase-dolist (`(,key ,value) (cddr engine-config)) + (condition-case nil + (setf (slot-value inst key) value) + ((invalid-slot-name invalid-slot-type) + (nnheader-message + 5 "Invalid search engine parameter: (%s %s)" + key value))))) + (nnheader-message 5 "No search engine defined for %s" srv)) + inst)) + +(declare-function gnus-registry-get-id-key "gnus-registry" (id key)) + +(defun gnus-search-thread (header) + "Make an nnselect group based on the thread containing the article +header. The current server will be searched. If the registry is +installed, the server that the registry reports the current +article came from is also searched." + (let* ((ids (cons (mail-header-id header) + (split-string + (or (mail-header-references header) + "")))) + (query + (list (cons 'query (mapconcat (lambda (i) + (format "id:%s" i)) + ids " or ")) + (cons 'thread t))) + (server + (list (list (gnus-method-to-server + (gnus-find-method-for-group gnus-newsgroup-name))))) + (registry-group (and + (bound-and-true-p gnus-registry-enabled) + (car (gnus-registry-get-id-key + (mail-header-id header) 'group)))) + (registry-server + (and registry-group + (gnus-method-to-server + (gnus-find-method-for-group registry-group))))) + (when registry-server + (cl-pushnew (list registry-server) server :test #'equal)) + (gnus-group-make-search-group nil (list + (cons 'search-query-spec query) + (cons 'search-group-spec server))) + (gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header))))) + +(defun gnus-search-get-active (srv) + (let ((method (gnus-server-to-method srv)) + groups) + (gnus-request-list method) + (with-current-buffer nntp-server-buffer + (let ((cur (current-buffer))) + (goto-char (point-min)) + (unless (or (null gnus-search-ignored-newsgroups) + (string= gnus-search-ignored-newsgroups "")) + (delete-matching-lines gnus-search-ignored-newsgroups)) + (if (eq (car method) 'nntp) + (while (not (eobp)) + (ignore-errors + (push (gnus-group-decoded-name + (gnus-group-full-name + (buffer-substring + (point) + (progn + (skip-chars-forward "^ \t") + (point))) + method)) + groups)) + (forward-line)) + (while (not (eobp)) + (ignore-errors + (push (gnus-group-decoded-name + (if (eq (char-after) ?\") + (gnus-group-full-name (read cur) method) + (let ((p (point)) (name "")) + (skip-chars-forward "^ \t\\\\") + (setq name (buffer-substring p (point))) + (while (eq (char-after) ?\\) + (setq p (1+ (point))) + (forward-char 2) + (skip-chars-forward "^ \t\\\\") + (setq name (concat name (buffer-substring + p (point))))) + (gnus-group-full-name name method)))) + groups)) + (forward-line))))) + groups)) + +(defvar gnus-search-minibuffer-map + (let ((km (make-sparse-keymap))) + (set-keymap-parent km minibuffer-local-map) + (define-key km (kbd "TAB") #'completion-at-point) + km)) + +(defun gnus-search--complete-key-data () + "Potentially return completion data for a search key or value." + (let* ((key-start (save-excursion + (if (re-search-backward " " (minibuffer-prompt-end) t) + (1+ (point)) + (minibuffer-prompt-end)))) + (after-colon (save-excursion + (when (re-search-backward ":" key-start t) + (1+ (point))))) + in-string) + (if after-colon + ;; We're in the value part of a key:value pair, which we + ;; only handle in a contact-completion context. + (when (and gnus-search-contact-tables + (save-excursion + (re-search-backward "\\<\\(\\w+\\):" key-start t) + (member (match-string 1) + '("from" "to" "cc" + "bcc" "recipient" "address")))) + (setq in-string (nth 3 (syntax-ppss))) + (list (if in-string (1+ after-colon) after-colon) + (point) (apply #'completion-table-merge + gnus-search-contact-tables) + :exit-function + (lambda (str status) + ;; If the value contains spaces, make sure it's + ;; quoted. + (when (and (memql status '(exact finished)) + (string-match-p " " str)) + (unless (looking-at-p "\\s\"") + (insert "\"")) + ;; Unless we already have an opening quote... + (unless in-string + (save-excursion + (goto-char after-colon) + (insert "\""))))))) + (list + key-start (point) gnus-search-expandable-keys + :exit-function (lambda (_s status) + (when (memql status '(exact finished)) + (insert ":"))))))) + +(defun gnus-search-make-spec (arg) + (list (cons 'query + (minibuffer-with-setup-hook + (lambda () + (add-hook 'completion-at-point-functions + #'gnus-search--complete-key-data)) + (read-from-minibuffer + "Query: " nil gnus-search-minibuffer-map + nil 'gnus-search-history))) + (cons 'raw arg))) + +(provide 'gnus-search) +;;; gnus-search.el ends here diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el index 8a88e0e6e64..7984998d214 100644 --- a/lisp/gnus/nnimap.el +++ b/lisp/gnus/nnimap.el @@ -365,7 +365,7 @@ textual parts.") (mm-disable-multibyte) (buffer-disable-undo) (gnus-add-buffer) - (set (make-local-variable 'after-change-functions) nil) + (set (make-local-variable 'after-change-functions) nil) ;FIXME: Why? (set (make-local-variable 'nnimap-object) (make-nnimap :server (nnoo-current-server 'nnimap) :initial-resync 0)) diff --git a/lisp/gnus/nnselect.el b/lisp/gnus/nnselect.el index 21206b683cf..ce2e99de05a 100644 --- a/lisp/gnus/nnselect.el +++ b/lisp/gnus/nnselect.el @@ -36,10 +36,10 @@ ;; sorting. Most functions will just chose a fixed number, such as ;; 100, for this score. -;; For example the search function `nnir-run-query' applied to -;; arguments specifying a search query (see "nnir.el") can be used to -;; return a list of articles from a search. Or the function can be the -;; identity and the args a vector of articles. +;; For example the search function `gnus-search-run-query' applied to +;; arguments specifying a search query (see "gnus-search.el") can be +;; used to return a list of articles from a search. Or the function +;; can be the identity and the args a vector of articles. ;;; Code: @@ -47,7 +47,7 @@ ;;; Setup: (require 'gnus-art) -(require 'nnir) +(require 'gnus-search) (eval-when-compile (require 'cl-lib)) @@ -372,25 +372,25 @@ If this variable is nil, or if the provided function returns nil, ;; find the servers for a pseudo-article (if (eq 'nnselect (car (gnus-server-to-method server))) (with-current-buffer gnus-summary-buffer - (let ((thread (gnus-id-to-thread article))) + (let ((thread (gnus-id-to-thread article))) (when thread (mapc - #'(lambda (x) - (when (and x (> x 0)) - (cl-pushnew - (list - (gnus-method-to-server - (gnus-find-method-for-group - (nnselect-article-group x)))) servers :test 'equal))) + (lambda (x) + (when (and x (> x 0)) + (cl-pushnew + (list + (gnus-method-to-server + (gnus-find-method-for-group + (nnselect-article-group x)))) servers :test 'equal))) (gnus-articles-in-thread thread))))) (setq servers (list (list server)))) (setq artlist - (nnir-run-query + (gnus-search-run-query (list - (cons 'nnir-query-spec - (list (cons 'query (format "HEADER Message-ID %s" article)) - (cons 'criteria "") (cons 'shortcut t))) - (cons 'nnir-group-spec servers)))) + (cons 'search-query-spec + (list (cons 'query `((id . ,article))) + (cons 'criteria "") (cons 'shortcut t))) + (cons 'search-group-spec servers)))) (unless (zerop (nnselect-artlist-length artlist)) (setq group-art @@ -603,26 +603,35 @@ If this variable is nil, or if the provided function returns nil, (cl-some #'(lambda (x) (when (and x (> x 0)) x)) (gnus-articles-in-thread thread))))))))) - ;; Check if we are dealing with an imap backend. - (if (eq 'nnimap - (car (gnus-find-method-for-group artgroup))) + ;; Check if search-based thread referral is permitted, and + ;; available. + (if (and gnus-refer-thread-use-search + (gnus-search-server-to-engine + (gnus-method-to-server + (gnus-find-method-for-group artgroup)))) ;; If so we perform the query, massage the result, and return ;; the new headers back to the caller to incorporate into the ;; current summary buffer. (let* ((group-spec (list (delq nil (list (or server (gnus-group-server artgroup)) - (unless gnus-refer-thread-use-search + (unless gnus-refer-thread-use-search artgroup))))) + (ids (cons (mail-header-id header) + (split-string + (or (mail-header-references header) + "")))) (query-spec - (list (cons 'query (nnimap-make-thread-query header)) - (cons 'criteria ""))) + (list (cons 'query (mapconcat (lambda (i) + (format "id:%s" i)) + ids " or ")) + (cons 'thread t))) (last (nnselect-artlist-length gnus-newsgroup-selection)) (first (1+ last)) (new-nnselect-artlist - (nnir-run-query - (list (cons 'nnir-query-spec query-spec) - (cons 'nnir-group-spec group-spec)))) + (gnus-search-run-query + (list (cons 'search-query-spec query-spec) + (cons 'search-group-spec group-spec)))) old-arts seq headers) (mapc @@ -670,7 +679,7 @@ If this variable is nil, or if the provided function returns nil, group (cons 1 (nnselect-artlist-length gnus-newsgroup-selection)))) headers) - ;; If not an imap backend just warp to the original article + ;; If we can't or won't use search, just warp to the original ;; group and punt back to gnus-summary-refer-thread. (and (gnus-warp-to-article) (gnus-summary-refer-thread)))))) @@ -768,9 +777,15 @@ Return an article list." The current server will be searched. If the registry is installed, the server that the registry reports the current article came from is also searched." - (let* ((query - (list (cons 'query (nnimap-make-thread-query header)) - (cons 'criteria ""))) + (let* ((ids (cons (mail-header-id header) + (split-string + (or (mail-header-references header) + "")))) + (query + (list (cons 'query (mapconcat (lambda (i) + (format "id:%s" i)) + ids " or ")) + (cons 'thread t))) (server (list (list (gnus-method-to-server (gnus-find-method-for-group gnus-newsgroup-name))))) @@ -794,10 +809,10 @@ article came from is also searched." (list (cons 'nnselect-specs (list - (cons 'nnselect-function 'nnir-run-query) + (cons 'nnselect-function 'gnus-search-run-query) (cons 'nnselect-args - (list (cons 'nnir-query-spec query) - (cons 'nnir-group-spec server))))) + (list (cons 'search-query-spec query) + (cons 'search-group-spec server))))) (cons 'nnselect-artlist nil))) (gnus-summary-goto-subject (gnus-id-to-article (mail-header-id header))))) @@ -929,18 +944,18 @@ article came from is also searched." (declare-function gnus-registry-get-id-key "gnus-registry" (id key)) -(defun gnus-summary-make-search-group (nnir-extra-parms) +(defun gnus-summary-make-search-group (no-parse) "Search a group from the summary buffer. -Pass NNIR-EXTRA-PARMS on to the search engine." +Pass NO-PARSE on to the search engine." (interactive "P") (gnus-warp-to-article) (let ((spec (list - (cons 'nnir-group-spec + (cons 'search-group-spec (list (list (gnus-group-server gnus-newsgroup-name) gnus-newsgroup-name)))))) - (gnus-group-make-search-group nnir-extra-parms spec))) + (gnus-group-make-search-group no-parse spec))) ;; The end. diff --git a/lisp/help.el b/lisp/help.el index c42e4b4fe67..6399a128e09 100644 --- a/lisp/help.el +++ b/lisp/help.el @@ -1013,8 +1013,7 @@ Otherwise, return a new string (without any text properties)." (insert string) (goto-char (point-min)) (while (< (point) (point-max)) - (let ((standard-output (current-buffer)) - (orig-point (point)) + (let ((orig-point (point)) end-point active-maps close generate-summary) (cond @@ -1169,14 +1168,14 @@ Any inserted text ends in two newlines (used by (print-title (or maps always-title))) ;; Print title. (when print-title - (princ (concat (if title - (concat title - (if prefix - (concat " Starting With " - (key-description prefix))) - ":\n")) - "key binding\n" - "--- -------\n"))) + (insert (concat (if title + (concat title + (if prefix + (concat " Starting With " + (key-description prefix))) + ":\n")) + "key binding\n" + "--- -------\n"))) ;; Describe key bindings. (setq help--keymaps-seen nil) (while (consp maps) @@ -1190,8 +1189,8 @@ Any inserted text ends in two newlines (used by ;; map. (or (keymapp sub-shadows) (null sub-shadows) - (consp sub-shadows) - (not (keymapp (car sub-shadows))))) + (and (consp sub-shadows) + (keymapp (car sub-shadows))))) ;; Maps we have already listed in this loop shadow this map. (let ((tail orig-maps)) (while (not (equal tail maps)) @@ -1202,7 +1201,7 @@ Any inserted text ends in two newlines (used by sub-shadows no-menu mention-shadow))) (setq maps (cdr maps))) (when print-title - (princ "\n")))) + (insert "\n")))) (defun help--shadow-lookup (keymap key accept-default remap) "Like `lookup-key', but with command remapping. diff --git a/lisp/ielm.el b/lisp/ielm.el index b3654b91d37..91d025dd5dd 100644 --- a/lisp/ielm.el +++ b/lisp/ielm.el @@ -533,9 +533,10 @@ Customized bindings may be defined in `ielm-map', which currently contains: (set (make-local-variable 'paragraph-start) comint-prompt-regexp) (setq comint-input-sender 'ielm-input-sender) (setq comint-process-echoes nil) - (set (make-local-variable 'completion-at-point-functions) - '(comint-replace-by-expanded-history - ielm-complete-filename elisp-completion-at-point)) + (dolist (f '(elisp-completion-at-point + ielm-complete-filename + comint-replace-by-expanded-history)) + (add-hook 'completion-at-point-functions f nil t)) (add-hook 'eldoc-documentation-functions #'elisp-eldoc-var-docstring nil t) (add-hook 'eldoc-documentation-functions diff --git a/lisp/international/isearch-x.el b/lisp/international/isearch-x.el index d77234ec77b..f50f86a035f 100644 --- a/lisp/international/isearch-x.el +++ b/lisp/international/isearch-x.el @@ -51,6 +51,17 @@ (setq input-method-function nil) (isearch-update)) +;;;###autoload +(defun isearch-transient-input-method () + "Activate transient input method in interactive search." + (interactive) + (let ((overriding-terminal-local-map nil)) + (activate-transient-input-method)) + (setq isearch-input-method-function input-method-function + isearch-input-method-local-p t) + (setq input-method-function nil) + (isearch-update)) + (defvar isearch-minibuffer-local-map (let ((map (copy-keymap minibuffer-local-map))) (define-key map [with-keyboard-coding] 'isearch-with-keyboard-coding) @@ -117,6 +128,7 @@ (cons last-char unread-command-events)) ;; Inherit current-input-method in a minibuffer. str (read-string prompt isearch-message 'junk-hist nil t)) + (deactivate-transient-input-method) (if (or (not str) (< (length str) (length isearch-message))) ;; All inputs were deleted while the input method ;; was working. diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el index e3155dfc52c..439843aaf8e 100644 --- a/lisp/international/mule-cmds.el +++ b/lisp/international/mule-cmds.el @@ -55,6 +55,7 @@ ;; Keep "C-x C-m ..." for mule specific commands. (define-key ctl-x-map "\C-m" mule-keymap) +(define-key ctl-x-map "\\" 'activate-transient-input-method) (defvar describe-language-environment-map (let ((map (make-sparse-keymap "Describe Language Environment"))) @@ -139,8 +140,8 @@ `(menu-item "Set Coding Systems" ,set-coding-system-map)) (bindings--define-key map [separator-input-method] menu-bar-separator) - (bindings--define-key map [describe-input-method] - '(menu-item "Describe Input Method" describe-input-method)) + (bindings--define-key map [activate-transient-input-method] + '(menu-item "Transient Input Method" activate-transient-input-method)) (bindings--define-key map [set-input-method] '(menu-item "Select Input Method..." set-input-method)) (bindings--define-key map [toggle-input-method] @@ -1344,6 +1345,29 @@ This is the input method activated automatically by the command mule-input-method-string) :set-after '(current-language-environment)) +(defcustom default-transient-input-method nil + "Default transient input method. +This is the input method activated by the command +`activate-transient-input-method' (\\[activate-transient-input-method])." + :link '(custom-manual "(emacs)Input Methods") + :group 'mule + :type '(choice (const nil) + mule-input-method-string) + :set-after '(current-language-environment) + :version "28.1") + +(defvar current-transient-input-method nil + "The current input method temporarily enabled by `activate-transient-input-method'. +If nil, that means no transient input method is active now.") +(make-variable-buffer-local 'current-transient-input-method) +(put 'current-transient-input-method 'permanent-local t) + +(defvar previous-transient-input-method nil + "The input method that was active before enabling the transient input method. +If nil, that means no previous input method was active.") +(make-variable-buffer-local 'previous-transient-input-method) +(put 'previous-transient-input-method 'permanent-local t) + (put 'input-method-function 'permanent-local t) (defvar input-method-history nil @@ -1478,7 +1502,8 @@ If INPUT-METHOD is nil, deactivate any current input method." (defun deactivate-input-method () "Turn off the current input method." (when current-input-method - (add-to-history 'input-method-history current-input-method) + (unless current-transient-input-method + (add-to-history 'input-method-history current-input-method)) (unwind-protect (progn (setq input-method-function nil @@ -1540,7 +1565,9 @@ which marks the variable `default-input-method' as set for Custom buffers." (if toggle-input-method-active (error "Recursive use of `toggle-input-method'")) (if (and current-input-method (not arg)) - (deactivate-input-method) + (if current-transient-input-method + (deactivate-transient-input-method) + (deactivate-input-method)) (let ((toggle-input-method-active t) (default (or (car input-method-history) default-input-method))) (if (and arg default (equal current-input-method default) @@ -1559,6 +1586,42 @@ which marks the variable `default-input-method' as set for Custom buffers." (when interactive (customize-mark-as-set 'default-input-method))))))) +(defun activate-transient-input-method (&optional arg interactive) + "Select and enable a transient input method for the current buffer. +If `default-transient-input-method' was not yet defined, prompt for it." + (interactive "P\np") + (when (or arg (not default-transient-input-method)) + (let* ((default (or (car input-method-history) default-input-method)) + (input-method + (read-input-method-name + (format-prompt "Transient input method" default) + default t))) + (setq default-transient-input-method input-method) + (when interactive + (customize-mark-as-set 'default-transient-input-method)))) + (let* ((clearfun (make-symbol "clear-transient-input-method")) + (exitfun + (lambda () + (deactivate-transient-input-method) + (remove-hook 'input-method-after-insert-chunk-hook clearfun)))) + (fset clearfun (lambda () (funcall exitfun))) + (add-hook 'input-method-after-insert-chunk-hook clearfun) + (setq previous-transient-input-method current-input-method) + (when previous-transient-input-method + (deactivate-input-method)) + (activate-input-method default-transient-input-method) + (setq current-transient-input-method default-transient-input-method) + exitfun)) + +(defun deactivate-transient-input-method () + "Disable currently active transient input method for the current buffer." + (when current-transient-input-method + (deactivate-input-method) + (when previous-transient-input-method + (activate-input-method previous-transient-input-method) + (setq previous-transient-input-method nil)) + (setq current-transient-input-method nil))) + (autoload 'help-buffer "help-mode") (defun describe-input-method (input-method) diff --git a/lisp/isearch.el b/lisp/isearch.el index c3d5ff2d313..4fba4370d98 100644 --- a/lisp/isearch.el +++ b/lisp/isearch.el @@ -565,6 +565,10 @@ This is like `describe-bindings', but displays only Isearch keys." :help "Highlight all matches for current search string")) (define-key map [isearch-search-replace-separator] '(menu-item "--")) + (define-key map [isearch-transient-input-method] + '(menu-item "Turn on transient input method" + isearch-transient-input-method + :help "Turn on transient input method for search")) (define-key map [isearch-toggle-specified-input-method] '(menu-item "Turn on specific input method" isearch-toggle-specified-input-method @@ -747,6 +751,7 @@ This is like `describe-bindings', but displays only Isearch keys." ;; For searching multilingual text. (define-key map "\C-\\" 'isearch-toggle-input-method) (define-key map "\C-^" 'isearch-toggle-specified-input-method) + (define-key map "\C-x\\" 'isearch-transient-input-method) ;; People expect to be able to paste with the mouse. (define-key map [mouse-2] #'isearch-mouse-2) @@ -1078,6 +1083,8 @@ To use a different input method for searching, type \ \\[isearch-toggle-specified-input-method], and specify an input method you want to use. +To activate a transient input method, type \\[isearch-transient-input-method]. + The above keys, bound in `isearch-mode-map', are often controlled by options; do \\[apropos] on search-.* to find them. Other control and meta characters terminate the search @@ -3262,6 +3269,8 @@ the word mode." (< (point) isearch-opoint))) "over") (if isearch-wrapped "wrapped ") + (if (and (not isearch-success) (buffer-narrowed-p) widen-automatically) + "narrowed " "") (if (and (not isearch-success) (not isearch-case-fold-search)) "case-sensitive ") (let ((prefix "")) diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el index 3260b67a993..f5ae3adf2eb 100644 --- a/lisp/ldefs-boot.el +++ b/lisp/ldefs-boot.el @@ -511,10 +511,13 @@ Return t if `allout-mode' is active in current buffer." nil t) (autoload 'allout-mode "allout" "\ Toggle Allout outline mode. -If called interactively, enable Allout mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Allout mode'. If the prefix argument +is positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -829,10 +832,13 @@ See `allout-widgets-mode' for allout widgets mode features.") (autoload 'allout-widgets-mode "allout-widgets" "\ Toggle Allout Widgets mode. -If called interactively, enable Allout-Widgets mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Allout-Widgets mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1246,15 +1252,17 @@ Entering array mode calls the function `array-mode-hook'. ;;;### (autoloads nil "artist" "textmodes/artist.el" (0 0 0 0)) ;;; Generated autoloads from textmodes/artist.el -(push (purecopy '(artist 1 2 6)) package--builtin-versions) (autoload 'artist-mode "artist" "\ Toggle Artist mode. -If called interactively, enable Artist mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Artist mode'. If the prefix argument +is positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1528,7 +1536,7 @@ ENTRY is the name of a password-store entry. The key used to retrieve the password is the symbol `secret'. The convention used as the format for a password-store file is -the following (see https://www.passwordstore.org/#organization): +the following (see http://www.passwordstore.org/#organization): secret key1: value1 @@ -1586,10 +1594,13 @@ or call the function `autoarg-kp-mode'.") (autoload 'autoarg-kp-mode "autoarg" "\ Toggle Autoarg-KP mode, a global minor mode. -If called interactively, enable Autoarg-Kp mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Autoarg-Kp mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1645,10 +1656,13 @@ or call the function `auto-insert-mode'.") (autoload 'auto-insert-mode "autoinsert" "\ Toggle Auto-insert mode, a global minor mode. -If called interactively, enable Auto-Insert mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Auto-Insert mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1696,14 +1710,29 @@ The function does NOT recursively descend into subdirectories of the directory or directories specified. In an interactive call, prompt for a default output file for the -autoload definitions, and temporarily bind the variable -`generated-autoload-file' to this value. When called from Lisp, -use the existing value of `generated-autoload-file'. If any Lisp -file binds `generated-autoload-file' as a file-local variable, -write its autoloads into the specified file instead. +autoload definitions. When called from Lisp, use the existing +value of `generated-autoload-file'. If any Lisp file binds +`generated-autoload-file' as a file-local variable, write its +autoloads into the specified file instead. \(fn &rest DIRS)" t nil) +(make-obsolete 'update-directory-autoloads 'make-directory-autoloads '"28.1") + +(autoload 'make-directory-autoloads "autoload" "\ +Update autoload definitions for Lisp files in the directories DIRS. +DIR can be either a single directory or a list of +directories. (The latter usage is discouraged.) + +The autoloads will be written to OUTPUT-FILE. If any Lisp file +binds `generated-autoload-file' as a file-local variable, write +its autoloads into the specified file instead. + +The function does NOT recursively descend into subdirectories of the +directory or directories specified. + +\(fn DIR OUTPUT-FILE)" t nil) + (autoload 'batch-update-autoloads "autoload" "\ Update loaddefs.el autoloads in batch mode. Calls `update-directory-autoloads' on the command line arguments. @@ -1720,10 +1749,13 @@ should be non-nil)." nil nil) (autoload 'auto-revert-mode "autorevert" "\ Toggle reverting buffer when the file changes (Auto-Revert Mode). -If called interactively, enable Auto-Revert mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Auto-Revert mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1750,10 +1782,13 @@ This function is designed to be added to hooks, for example: (autoload 'auto-revert-tail-mode "autorevert" "\ Toggle reverting tail of buffer when the file grows. -If called interactively, enable Auto-Revert-Tail mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Auto-Revert-Tail mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1794,10 +1829,13 @@ or call the function `global-auto-revert-mode'.") (autoload 'global-auto-revert-mode "autorevert" "\ Toggle Global Auto-Revert Mode. -If called interactively, enable Global Auto-Revert mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Global Auto-Revert mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -1928,10 +1966,13 @@ or call the function `display-battery-mode'.") (autoload 'display-battery-mode "battery" "\ Toggle battery status display in mode line (Display Battery mode). -If called interactively, enable Display-Battery mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Display-Battery mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -2907,10 +2948,13 @@ columns on its right towards the left. (autoload 'bug-reference-mode "bug-reference" "\ Toggle hyperlinking bug references in the buffer (Bug Reference mode). -If called interactively, enable Bug-Reference mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Bug-Reference mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -2920,10 +2964,13 @@ disabled. (autoload 'bug-reference-prog-mode "bug-reference" "\ Like `bug-reference-mode', but only buttonize in comments and strings. -If called interactively, enable Bug-Reference-Prog mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Bug-Reference-Prog mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -2998,11 +3045,14 @@ that already has a `.elc' file. Compile a file of Lisp code named FILENAME into a file of byte code. The output file's name is generated by passing FILENAME to the function `byte-compile-dest-file' (which see). -With prefix arg (noninteractively: 2nd arg), LOAD the file after compiling. The value is non-nil if there were no errors, nil if errors. +See also `emacs-lisp-byte-compile-and-load'. + \(fn FILENAME &optional LOAD)" t nil) +(set-advertised-calling-convention 'byte-compile-file '(filename) '"28.1") + (autoload 'compile-defun "bytecomp" "\ Compile and evaluate the current top-level form. Print the result in the echo area. @@ -3293,14 +3343,6 @@ See Info node `(calc)Defining Functions'. (register-definition-prefixes "calc" '("calc" "defcalcmodevar" "inexact-result" "math-" "var-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "calc-aent" "calc/calc-aent.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from calc/calc-aent.el - -(register-definition-prefixes "calc-aent" '("calc" "math-")) - ;;;*** ;;;### (autoloads nil "calc-alg" "calc/calc-alg.el" (0 0 0 0)) @@ -3336,14 +3378,6 @@ See Info node `(calc)Defining Functions'. (register-definition-prefixes "calc-cplx" '("calc" "math-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "calc-embed" "calc/calc-embed.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from calc/calc-embed.el - -(register-definition-prefixes "calc-embed" '("calc-")) - ;;;*** ;;;### (autoloads nil "calc-ext" "calc/calc-ext.el" (0 0 0 0)) @@ -3442,14 +3476,6 @@ See Info node `(calc)Defining Functions'. (register-definition-prefixes "calc-menu" '("calc-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "calc-misc" "calc/calc-misc.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from calc/calc-misc.el - -(register-definition-prefixes "calc-misc" '("math-iipow")) - ;;;*** ;;;### (autoloads nil "calc-mode" "calc/calc-mode.el" (0 0 0 0)) @@ -3560,14 +3586,6 @@ See Info node `(calc)Defining Functions'. (register-definition-prefixes "calc-vec" '("calc" "math-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "calc-yank" "calc/calc-yank.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from calc/calc-yank.el - -(register-definition-prefixes "calc-yank" '("calc-" "math-number-regexp")) - ;;;*** ;;;### (autoloads nil "calcalg2" "calc/calcalg2.el" (0 0 0 0)) @@ -4499,7 +4517,6 @@ from which to start. ;;;### (autoloads nil "chart" "emacs-lisp/chart.el" (0 0 0 0)) ;;; Generated autoloads from emacs-lisp/chart.el -(push (purecopy '(chart 0 2)) package--builtin-versions) (register-definition-prefixes "chart" '("chart")) @@ -4692,10 +4709,13 @@ Prefix argument is the same as for `checkdoc-defun'." t nil) (autoload 'checkdoc-minor-mode "checkdoc" "\ Toggle automatic docstring checking (Checkdoc minor mode). -If called interactively, enable Checkdoc minor mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Checkdoc minor mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -4786,14 +4806,6 @@ and runs the normal hook `command-history-hook'." t nil) (register-definition-prefixes "chistory" '("command-history-" "default-command-history-filter" "list-command-history-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "cl-extra" "emacs-lisp/cl-extra.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emacs-lisp/cl-extra.el - -(register-definition-prefixes "cl-extra" '("cl-")) - ;;;*** ;;;### (autoloads nil "cl-font-lock" "progmodes/cl-font-lock.el" @@ -4813,10 +4825,13 @@ or call the function `cl-font-lock-built-in-mode'.") (autoload 'cl-font-lock-built-in-mode "cl-font-lock" "\ Highlight built-in functions, variables, and types in `lisp-mode'. -If called interactively, enable Cl-Font-Lock-Built-In mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Cl-Font-Lock-Built-In mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -5028,10 +5043,13 @@ This can be needed when using code byte-compiled using the old macro-expansion of `cl-defstruct' that used vectors objects instead of record objects. -If called interactively, enable Cl-Old-Struct-Compat mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Cl-Old-Struct-Compat mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -5040,14 +5058,6 @@ disabled. (register-definition-prefixes "cl-lib" '("cl-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "cl-macs" "emacs-lisp/cl-macs.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emacs-lisp/cl-macs.el - -(register-definition-prefixes "cl-macs" '("cl-")) - ;;;*** ;;;### (autoloads nil "cl-print" "emacs-lisp/cl-print.el" (0 0 0 @@ -5104,14 +5114,6 @@ limit. (register-definition-prefixes "cl-print" '("cl-print-" "help-byte-code")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "cl-seq" "emacs-lisp/cl-seq.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emacs-lisp/cl-seq.el - -(register-definition-prefixes "cl-seq" '("cl--")) - ;;;*** ;;;### (autoloads nil "cmacexp" "progmodes/cmacexp.el" (0 0 0 0)) @@ -5480,10 +5482,13 @@ Runs `compilation-mode-hook' with `run-mode-hooks' (which see). (autoload 'compilation-shell-minor-mode "compile" "\ Toggle Compilation Shell minor mode. -If called interactively, enable Compilation-Shell minor mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Compilation-Shell minor mode'. If +the prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -5498,10 +5503,13 @@ See `compilation-mode'. (autoload 'compilation-minor-mode "compile" "\ Toggle Compilation minor mode. -If called interactively, enable Compilation minor mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Compilation minor mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -5538,10 +5546,13 @@ or call the function `dynamic-completion-mode'.") (autoload 'dynamic-completion-mode "completion" "\ Toggle dynamic word-completion on or off. -If called interactively, enable Dynamic-Completion mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Dynamic-Completion mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -6102,10 +6113,13 @@ or call the function `cua-mode'.") (autoload 'cua-mode "cua-base" "\ Toggle Common User Access style editing (CUA mode). -If called interactively, enable Cua mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Cua mode'. If the prefix argument is +positive, enable the mode, and if it is zero or negative, disable the +mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -6153,10 +6167,13 @@ Enable CUA selection mode without the C-z/C-x/C-c/C-v bindings. Toggle the region as rectangular. Activates the region if needed. Only lasts until the region is deactivated. -If called interactively, enable Cua-Rectangle-Mark mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Cua-Rectangle-Mark mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -6179,10 +6196,13 @@ By convention, this is a list of symbols where each symbol stands for the (autoload 'cursor-intangible-mode "cursor-sensor" "\ Keep cursor outside of any `cursor-intangible' text property. -If called interactively, enable Cursor-Intangible mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Cursor-Intangible mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -6197,10 +6217,13 @@ where WINDOW is the affected window, OLDPOS is the last known position of the cursor and DIR can be `entered' or `left' depending on whether the cursor is entering the area covered by the text-property property or leaving it. -If called interactively, enable Cursor-Sensor mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Cursor-Sensor mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -6523,7 +6546,7 @@ The format is suitable for use with `easy-menu-define'. \(fn SYMBOL &optional NAME)" nil nil) -(register-definition-prefixes "cus-edit" '("Custom-" "custom" "widget-")) +(register-definition-prefixes "cus-edit" '("Custom-" "cus" "widget-")) ;;;*** @@ -6580,10 +6603,13 @@ Mode used for cvs status output. (autoload 'cwarn-mode "cwarn" "\ Minor mode that highlights suspicious C and C++ constructions. -If called interactively, enable Cwarn mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Cwarn mode'. If the prefix argument +is positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -6618,7 +6644,9 @@ ARG is omitted or nil. Cwarn mode is enabled in all buffers where `turn-on-cwarn-mode-if-enabled' would do it. -See `cwarn-mode' for more information on Cwarn mode. + +See `cwarn-mode' for more information on +Cwarn mode. \(fn &optional ARG)" t nil) @@ -6824,8 +6852,7 @@ Variables controlling indentation style and extra features: dcl-imenu-label-call Change the text that is used as sub-listing labels in imenu. -Loading this package calls the value of the variable -`dcl-mode-load-hook' with no args, if that value is non-nil. +To run code after DCL mode has loaded, use `with-eval-after-load'. Turning on DCL mode calls the value of the variable `dcl-mode-hook' with no args, if that value is non-nil. @@ -6971,7 +6998,6 @@ The most useful commands are: ;;;### (autoloads nil "delim-col" "delim-col.el" (0 0 0 0)) ;;; Generated autoloads from delim-col.el -(push (purecopy '(delim-col 2 1)) package--builtin-versions) (autoload 'delimit-columns-customize "delim-col" "\ Customize the `columns' group." t nil) @@ -7032,10 +7058,13 @@ or call the function `delete-selection-mode'.") (autoload 'delete-selection-mode "delsel" "\ Toggle Delete Selection mode. -If called interactively, enable Delete-Selection mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Delete-Selection mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -7204,10 +7233,13 @@ or call the function `desktop-save-mode'.") (autoload 'desktop-save-mode "desktop" "\ Toggle desktop saving (Desktop Save mode). -If called interactively, enable Desktop-Save mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Desktop-Save mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -7600,10 +7632,13 @@ a diff with \\[diff-reverse-direction]. (autoload 'diff-minor-mode "diff-mode" "\ Toggle Diff minor mode. -If called interactively, enable Diff minor mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Diff minor mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -7781,22 +7816,6 @@ Like \\[dired-jump] (`dired-jump') but in other window. (register-definition-prefixes "dired" '("dired-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "dired-aux" "dired-aux.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from dired-aux.el - -(register-definition-prefixes "dired-aux" '("dired-" "minibuffer-default-add-dired-shell-commands")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "dired-x" "dired-x.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from dired-x.el - -(register-definition-prefixes "dired-x" '("dired-" "virtual-dired")) - ;;;*** ;;;### (autoloads nil "dirtrack" "dirtrack.el" (0 0 0 0)) @@ -7805,10 +7824,13 @@ Like \\[dired-jump] (`dired-jump') but in other window. (autoload 'dirtrack-mode "dirtrack" "\ Toggle directory tracking in shell buffers (Dirtrack mode). -If called interactively, enable Dirtrack mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Dirtrack mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -7979,10 +8001,13 @@ in `.emacs'. Toggle display of fill-column indicator. This uses `display-fill-column-indicator' internally. -If called interactively, enable Display-Fill-Column-Indicator mode if -ARG is positive, and disable it if ARG is zero or negative. If called -from Lisp, also enable the mode if ARG is omitted or nil, and toggle -it if ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Display-Fill-Column-Indicator mode'. +If the prefix argument is positive, enable the mode, and if it is zero +or negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -7990,6 +8015,8 @@ disabled. To change the position of the column displayed by default customize `display-fill-column-indicator-column'. You can change the character for the indicator setting `display-fill-column-indicator-character'. +The globalized version is `global-display-fill-column-indicator-mode', +which see. See Info node `Displaying Boundaries' for details. \(fn &optional ARG)" t nil) @@ -8014,10 +8041,31 @@ ARG is omitted or nil. Display-Fill-Column-Indicator mode is enabled in all buffers where `display-fill-column-indicator--turn-on' would do it. -See `display-fill-column-indicator-mode' for more information on Display-Fill-Column-Indicator mode. + +See `display-fill-column-indicator-mode' for more information on +Display-Fill-Column-Indicator mode. + +`global-display-fill-column-indicator-modes' is used to control which modes +this minor mode is used in. \(fn &optional ARG)" t nil) +(defvar global-display-fill-column-indicator-modes '((not special-mode) t) "\ +Which major modes `display-fill-column-indicator-mode' is switched on in. +This variable can be either t (all major modes), nil (no major modes), +or a list of modes and (not modes) to switch use this minor mode or +not. For instance + + (c-mode (not message-mode mail-mode) text-mode) + +means \"use this mode in all modes derived from `c-mode', don't use in +modes derived from `message-mode' or `mail-mode', but do use in other +modes derived from `text-mode'\". An element with value t means \"use\" +and nil means \"don't use\". There's an implicit nil at the end of the +list.") + +(custom-autoload 'global-display-fill-column-indicator-modes "display-fill-column-indicator" t) + (register-definition-prefixes "display-fill-column-indicator" '("display-fill-column-indicator--turn-on")) ;;;*** @@ -8030,10 +8078,13 @@ See `display-fill-column-indicator-mode' for more information on Display-Fill-Co Toggle display of line numbers in the buffer. This uses `display-line-numbers' internally. -If called interactively, enable Display-Line-Numbers mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Display-Line-Numbers mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -8064,7 +8115,9 @@ ARG is omitted or nil. Display-Line-Numbers mode is enabled in all buffers where `display-line-numbers--turn-on' would do it. -See `display-line-numbers-mode' for more information on Display-Line-Numbers mode. + +See `display-line-numbers-mode' for more information on +Display-Line-Numbers mode. \(fn &optional ARG)" t nil) @@ -8168,10 +8221,13 @@ to the next best mode." nil nil) (autoload 'doc-view-minor-mode "doc-view" "\ Toggle displaying buffer via Doc View (Doc View minor mode). -If called interactively, enable Doc-View minor mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Doc-View minor mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -8233,10 +8289,13 @@ Switch to *doctor* buffer and start giving psychotherapy." t nil) (autoload 'double-mode "double" "\ Toggle special insertion on double keypresses (Double mode). -If called interactively, enable Double mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Double mode'. If the prefix argument +is positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -8252,7 +8311,6 @@ strings when pressed twice. See `double-map' for details. ;;;### (autoloads nil "dunnet" "play/dunnet.el" (0 0 0 0)) ;;; Generated autoloads from play/dunnet.el -(push (purecopy '(dunnet 2 2)) package--builtin-versions) (autoload 'dunnet "dunnet" "\ Switch to *dungeon* buffer and start game." t nil) @@ -8297,6 +8355,10 @@ appear in DOC, a paragraph is added to DOC explaining usage of the mode argument. Optional INIT-VALUE is the initial value of the mode's variable. + Note that the minor mode function won't be called by setting + this option, so the value *reflects* the minor mode's natural + initial state, rather than *setting* it. + In the vast majority of cases it should be nil. Optional LIGHTER is displayed in the mode line when the mode is on. Optional KEYMAP is the default keymap bound to the mode keymap. If non-nil, it should be a variable name (whose value is a keymap), @@ -8354,18 +8416,21 @@ For example, you could write (autoload 'define-globalized-minor-mode "easy-mmode" "\ Make a global mode GLOBAL-MODE corresponding to buffer-local minor MODE. TURN-ON is a function that will be called with no args in every buffer - and that should try to turn MODE on if applicable for that buffer. -Each of KEY VALUE is a pair of CL-style keyword arguments. As - the minor mode defined by this function is always global, any - :global keyword is ignored. Other keywords have the same - meaning as in `define-minor-mode', which see. In particular, - :group specifies the custom group. The most useful keywords - are those that are passed on to the `defcustom'. It normally - makes no sense to pass the :lighter or :keymap keywords to - `define-globalized-minor-mode', since these are usually passed - to the buffer-local version of the minor mode. +and that should try to turn MODE on if applicable for that buffer. + +Each of KEY VALUE is a pair of CL-style keyword arguments. :predicate +specifies which major modes the globalized minor mode should be switched on +in. As the minor mode defined by this function is always global, any +:global keyword is ignored. Other keywords have the same meaning as in +`define-minor-mode', which see. In particular, :group specifies the custom +group. The most useful keywords are those that are passed on to the +`defcustom'. It normally makes no sense to pass the :lighter or :keymap +keywords to `define-globalized-minor-mode', since these are usually passed +to the buffer-local version of the minor mode. + BODY contains code to execute each time the mode is enabled or disabled. - It is executed after toggling the mode, and before running GLOBAL-MODE-hook. +It is executed after toggling the mode, and before running +GLOBAL-MODE-hook. If MODE's set-up depends on the major mode in effect when it was enabled, then disabling and reenabling MODE should make MODE work @@ -9074,10 +9139,13 @@ or call the function `global-ede-mode'.") (autoload 'global-ede-mode "ede" "\ Toggle global EDE (Emacs Development Environment) mode. -If called interactively, enable Global Ede mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Global Ede mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -9104,38 +9172,6 @@ an EDE controlled project. (register-definition-prefixes "ede/autoconf-edit" '("autoconf-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/base" "cedet/ede/base.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/base.el - -(register-definition-prefixes "ede/base" '("ede-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/config" "cedet/ede/config.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/config.el - -(register-definition-prefixes "ede/config" '("ede-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/cpp-root" -;;;;;; "cedet/ede/cpp-root.el" (0 0 0 0)) -;;; Generated autoloads from cedet/ede/cpp-root.el - -(register-definition-prefixes "ede/cpp-root" '("ede-cpp-root-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/custom" "cedet/ede/custom.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/custom.el - -(register-definition-prefixes "ede/custom" '("ede-" "eieio-ede-old-variables")) - ;;;*** ;;;### (autoloads nil "ede/detect" "cedet/ede/detect.el" (0 0 0 0)) @@ -9143,62 +9179,6 @@ an EDE controlled project. (register-definition-prefixes "ede/detect" '("ede-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/dired" "cedet/ede/dired.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/dired.el - -(register-definition-prefixes "ede/dired" '("ede-dired-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/emacs" "cedet/ede/emacs.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/emacs.el - -(register-definition-prefixes "ede/emacs" '("ede-emacs-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/files" "cedet/ede/files.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/files.el - -(register-definition-prefixes "ede/files" '("ede-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/generic" -;;;;;; "cedet/ede/generic.el" (0 0 0 0)) -;;; Generated autoloads from cedet/ede/generic.el - -(register-definition-prefixes "ede/generic" '("ede-generic-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/linux" "cedet/ede/linux.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/linux.el - -(register-definition-prefixes "ede/linux" '("ede-linux-" "project-linux-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/locate" "cedet/ede/locate.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/locate.el - -(register-definition-prefixes "ede/locate" '("ede-locate-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/make" "cedet/ede/make.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/make.el - -(register-definition-prefixes "ede/make" '("ede-")) - ;;;*** ;;;### (autoloads nil "ede/makefile-edit" "cedet/ede/makefile-edit.el" @@ -9316,14 +9296,6 @@ an EDE controlled project. (register-definition-prefixes "ede/project-am" '("project-am-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/shell" "cedet/ede/shell.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/shell.el - -(register-definition-prefixes "ede/shell" '("ede-shell-run-command")) - ;;;*** ;;;### (autoloads nil "ede/simple" "cedet/ede/simple.el" (0 0 0 0)) @@ -9338,14 +9310,6 @@ an EDE controlled project. (register-definition-prefixes "ede/source" '("ede-source")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/speedbar" -;;;;;; "cedet/ede/speedbar.el" (0 0 0 0)) -;;; Generated autoloads from cedet/ede/speedbar.el - -(register-definition-prefixes "ede/speedbar" '("ede-")) - ;;;*** ;;;### (autoloads nil "ede/srecode" "cedet/ede/srecode.el" (0 0 0 @@ -9354,14 +9318,6 @@ an EDE controlled project. (register-definition-prefixes "ede/srecode" '("ede-srecode-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "ede/util" "cedet/ede/util.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from cedet/ede/util.el - -(register-definition-prefixes "ede/util" '("ede-make-buffer-writable")) - ;;;*** ;;;### (autoloads nil "edebug" "emacs-lisp/edebug.el" (0 0 0 0)) @@ -9829,7 +9785,6 @@ To change the default, set the variable `ediff-use-toolbar-p', which see." t nil ;;;### (autoloads nil "edmacro" "edmacro.el" (0 0 0 0)) ;;; Generated autoloads from edmacro.el -(push (purecopy '(edmacro 2 1)) package--builtin-versions) (autoload 'edit-kbd-macro "edmacro" "\ Edit a keyboard macro. @@ -9979,14 +9934,6 @@ BUFFER is put back into its original major mode. (register-definition-prefixes "eieio-base" '("eieio-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "eieio-compat" -;;;;;; "emacs-lisp/eieio-compat.el" (0 0 0 0)) -;;; Generated autoloads from emacs-lisp/eieio-compat.el - -(register-definition-prefixes "eieio-compat" '("eieio--generic-static-symbol-specializers" "generic-p" "next-method-p" "no-")) - ;;;*** ;;;### (autoloads nil "eieio-core" "emacs-lisp/eieio-core.el" (0 @@ -10006,14 +9953,6 @@ It creates an autoload function for CNAME's constructor. (register-definition-prefixes "eieio-core" '("class-" "eieio-" "inconsistent-class-hierarchy" "invalid-slot-" "unbound-slot")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "eieio-custom" -;;;;;; "emacs-lisp/eieio-custom.el" (0 0 0 0)) -;;; Generated autoloads from emacs-lisp/eieio-custom.el - -(register-definition-prefixes "eieio-custom" '("eieio-")) - ;;;*** ;;;### (autoloads nil "eieio-datadebug" "emacs-lisp/eieio-datadebug.el" @@ -10022,14 +9961,6 @@ It creates an autoload function for CNAME's constructor. (register-definition-prefixes "eieio-datadebug" '("data-debug-insert-object-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "eieio-opt" "emacs-lisp/eieio-opt.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from emacs-lisp/eieio-opt.el - -(register-definition-prefixes "eieio-opt" '("eieio-")) - ;;;*** ;;;### (autoloads nil "eieio-speedbar" "emacs-lisp/eieio-speedbar.el" @@ -10042,7 +9973,7 @@ It creates an autoload function for CNAME's constructor. ;;;### (autoloads nil "eldoc" "emacs-lisp/eldoc.el" (0 0 0 0)) ;;; Generated autoloads from emacs-lisp/eldoc.el -(push (purecopy '(eldoc 1 10 0)) package--builtin-versions) +(push (purecopy '(eldoc 1 11 0)) package--builtin-versions) ;;;*** @@ -10062,10 +9993,13 @@ or call the function `electric-pair-mode'.") (autoload 'electric-pair-mode "elec-pair" "\ Toggle automatic parens pairing (Electric Pair mode). -If called interactively, enable Electric-Pair mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Electric-Pair mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -10083,10 +10017,13 @@ To toggle the mode in a single buffer, use `electric-pair-local-mode'. (autoload 'electric-pair-local-mode "elec-pair" "\ Toggle `electric-pair-mode' only in this buffer. -If called interactively, enable Electric-Pair-Local mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Electric-Pair-Local mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -10180,142 +10117,6 @@ displayed." t nil) (register-definition-prefixes "elp" '("elp-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-alias" "eshell/em-alias.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-alias.el - -(register-definition-prefixes "em-alias" '("eshell" "pcomplete/eshell-mode/alias")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-banner" "eshell/em-banner.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-banner.el - -(register-definition-prefixes "em-banner" '("eshell-banner-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-basic" "eshell/em-basic.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-basic.el - -(register-definition-prefixes "em-basic" '("eshell")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-cmpl" "eshell/em-cmpl.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-cmpl.el - -(register-definition-prefixes "em-cmpl" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-dirs" "eshell/em-dirs.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-dirs.el - -(register-definition-prefixes "em-dirs" '("eshell")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-glob" "eshell/em-glob.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-glob.el - -(register-definition-prefixes "em-glob" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-hist" "eshell/em-hist.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-hist.el - -(register-definition-prefixes "em-hist" '("eshell")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-ls" "eshell/em-ls.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-ls.el - -(register-definition-prefixes "em-ls" '("eshell")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-pred" "eshell/em-pred.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-pred.el - -(register-definition-prefixes "em-pred" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-prompt" "eshell/em-prompt.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-prompt.el - -(register-definition-prefixes "em-prompt" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-rebind" "eshell/em-rebind.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-rebind.el - -(register-definition-prefixes "em-rebind" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-script" "eshell/em-script.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-script.el - -(register-definition-prefixes "em-script" '("eshell")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-smart" "eshell/em-smart.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-smart.el - -(register-definition-prefixes "em-smart" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-term" "eshell/em-term.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-term.el - -(register-definition-prefixes "em-term" '("eshell-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-tramp" "eshell/em-tramp.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-tramp.el - -(register-definition-prefixes "em-tramp" '("eshell")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-unix" "eshell/em-unix.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-unix.el - -(register-definition-prefixes "em-unix" '("eshell" "nil-blank-string")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "em-xtra" "eshell/em-xtra.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from eshell/em-xtra.el - -(register-definition-prefixes "em-xtra" '("eshell/")) - ;;;*** ;;;### (autoloads nil "emacs-lock" "emacs-lock.el" (0 0 0 0)) @@ -10439,10 +10240,13 @@ Minor mode for editing text/enriched files. These are files with embedded formatting information in the MIME standard text/enriched format. -If called interactively, enable Enriched mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Enriched mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -10701,10 +10505,13 @@ Encrypt marked files." t nil) (autoload 'epa-mail-mode "epa-mail" "\ A minor-mode for composing encrypted/clearsigned mails. -If called interactively, enable epa-mail mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `epa-mail mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -10768,10 +10575,13 @@ or call the function `epa-global-mail-mode'.") (autoload 'epa-global-mail-mode "epa-mail" "\ Minor mode to hook EasyPG into Mail mode. -If called interactively, enable Epa-Global-Mail mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Epa-Global-Mail mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -10857,7 +10667,7 @@ Non-interactively, it takes the keyword arguments That is, if called with - (erc :server \"irc.freenode.net\" :full-name \"Harry S Truman\") + (erc :server \"chat.freenode.net\" :full-name \"Harry S Truman\") then the server and full-name will be set to those values, whereas `erc-compute-port', `erc-compute-nick' and `erc-compute-full-name' will @@ -10882,14 +10692,6 @@ Otherwise, connect to HOST:PORT as USER and /join CHANNEL. (register-definition-prefixes "erc" '("define-erc-module" "erc-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-autoaway" -;;;;;; "erc/erc-autoaway.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-autoaway.el - -(register-definition-prefixes "erc-autoaway" '("erc-auto")) - ;;;*** ;;;### (autoloads nil "erc-backend" "erc/erc-backend.el" (0 0 0 0)) @@ -10897,54 +10699,6 @@ Otherwise, connect to HOST:PORT as USER and /join CHANNEL. (register-definition-prefixes "erc-backend" '("erc-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-button" "erc/erc-button.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-button.el - -(register-definition-prefixes "erc-button" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-capab" "erc/erc-capab.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-capab.el - -(register-definition-prefixes "erc-capab" '("erc-capab-identify-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-dcc" "erc/erc-dcc.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-dcc.el - -(register-definition-prefixes "erc-dcc" '("erc-" "pcomplete/erc-mode/")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-desktop-notifications" -;;;;;; "erc/erc-desktop-notifications.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-desktop-notifications.el - -(register-definition-prefixes "erc-desktop-notifications" '("erc-notifications-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-ezbounce" -;;;;;; "erc/erc-ezbounce.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-ezbounce.el - -(register-definition-prefixes "erc-ezbounce" '("erc-ezb-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-fill" "erc/erc-fill.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-fill.el - -(register-definition-prefixes "erc-fill" '("erc-")) - ;;;*** ;;;### (autoloads nil "erc-goodies" "erc/erc-goodies.el" (0 0 0 0)) @@ -10959,30 +10713,6 @@ Otherwise, connect to HOST:PORT as USER and /join CHANNEL. (register-definition-prefixes "erc-ibuffer" '("erc-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-identd" "erc/erc-identd.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-identd.el - -(register-definition-prefixes "erc-identd" '("erc-identd-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-imenu" "erc/erc-imenu.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-imenu.el - -(register-definition-prefixes "erc-imenu" '("erc-unfill-notice")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-join" "erc/erc-join.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-join.el - -(register-definition-prefixes "erc-join" '("erc-")) - ;;;*** ;;;### (autoloads nil "erc-lang" "erc/erc-lang.el" (0 0 0 0)) @@ -10990,46 +10720,6 @@ Otherwise, connect to HOST:PORT as USER and /join CHANNEL. (register-definition-prefixes "erc-lang" '("erc-cmd-LANG" "iso-638-languages" "language")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-list" "erc/erc-list.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-list.el - -(register-definition-prefixes "erc-list" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-log" "erc/erc-log.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-log.el - -(register-definition-prefixes "erc-log" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-match" "erc/erc-match.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-match.el - -(register-definition-prefixes "erc-match" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-menu" "erc/erc-menu.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-menu.el - -(register-definition-prefixes "erc-menu" '("erc-menu-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-netsplit" -;;;;;; "erc/erc-netsplit.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-netsplit.el - -(register-definition-prefixes "erc-netsplit" '("erc-")) - ;;;*** ;;;### (autoloads nil "erc-networks" "erc/erc-networks.el" (0 0 0 @@ -11046,118 +10736,6 @@ Interactively select a server to connect to using `erc-server-alist'." t nil) (register-definition-prefixes "erc-networks" '("erc-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-notify" "erc/erc-notify.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-notify.el - -(register-definition-prefixes "erc-notify" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-page" "erc/erc-page.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-page.el - -(register-definition-prefixes "erc-page" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-pcomplete" -;;;;;; "erc/erc-pcomplete.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-pcomplete.el - -(register-definition-prefixes "erc-pcomplete" '("erc-pcomplet" "pcomplete")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-replace" -;;;;;; "erc/erc-replace.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-replace.el - -(register-definition-prefixes "erc-replace" '("erc-replace-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-ring" "erc/erc-ring.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-ring.el - -(register-definition-prefixes "erc-ring" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-services" -;;;;;; "erc/erc-services.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-services.el - -(register-definition-prefixes "erc-services" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-sound" "erc/erc-sound.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-sound.el - -(register-definition-prefixes "erc-sound" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-speedbar" -;;;;;; "erc/erc-speedbar.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-speedbar.el - -(register-definition-prefixes "erc-speedbar" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-spelling" -;;;;;; "erc/erc-spelling.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-spelling.el - -(register-definition-prefixes "erc-spelling" '("erc-spelling-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-stamp" "erc/erc-stamp.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-stamp.el - -(register-definition-prefixes "erc-stamp" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-status-sidebar" -;;;;;; "erc/erc-status-sidebar.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-status-sidebar.el - -(register-definition-prefixes "erc-status-sidebar" '("erc-status-sidebar-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-track" "erc/erc-track.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-track.el - -(register-definition-prefixes "erc-track" '("erc-")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-truncate" -;;;;;; "erc/erc-truncate.el" (0 0 0 0)) -;;; Generated autoloads from erc/erc-truncate.el - -(register-definition-prefixes "erc-truncate" '("erc-max-buffer-size")) - -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "erc-xdcc" "erc/erc-xdcc.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from erc/erc-xdcc.el - -(register-definition-prefixes "erc-xdcc" '("erc-")) - ;;;*** ;;;### (autoloads nil "ert" "emacs-lisp/ert.el" (0 0 0 0)) @@ -12067,11 +11645,11 @@ Render FILE using EWW. \(fn FILE)" t nil) (autoload 'eww-search-words "eww" "\ -Search the web for the text between BEG and END. +Search the web for the text in the region. If region is active (and not whitespace), search the web for -the text between BEG and END. Else, prompt the user for a search -string. See the `eww-search-prefix' variable for the search -engine used." t nil) +the text between region beginning and end. Else, prompt the +user for a search string. See the variable `eww-search-prefix' +for the search engine used." t nil) (autoload 'eww-mode "eww" "\ Mode for browsing the web. @@ -12380,10 +11958,13 @@ a top-level keymap, `text-scale-increase' or (autoload 'buffer-face-mode "face-remap" "\ Minor mode for a buffer-specific default face. -If called interactively, enable Buffer-Face mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Buffer-Face mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -13299,10 +12880,13 @@ region is invalid. (autoload 'flymake-mode "flymake" "\ Toggle Flymake mode on or off. -If called interactively, enable Flymake mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Flymake mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -13384,10 +12968,13 @@ Turn on `flyspell-mode' for comments and strings." t nil) (autoload 'flyspell-mode "flyspell" "\ Toggle on-the-fly spell checking (Flyspell mode). -If called interactively, enable Flyspell mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Flyspell mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -13412,7 +12999,7 @@ invoking `ispell-change-dictionary'. Consider using the `ispell-parser' to check your text. For instance consider adding: -\(add-hook \\='tex-mode-hook (function (lambda () (setq ispell-parser \\='tex)))) +\(add-hook \\='tex-mode-hook (lambda () (setq ispell-parser \\='tex))) in your init file. \\[flyspell-region] checks all words inside a region. @@ -13464,10 +13051,13 @@ Turn off Follow mode. Please see the function `follow-mode'." nil nil) (autoload 'follow-mode "follow" "\ Toggle Follow mode. -If called interactively, enable Follow mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Follow mode'. If the prefix argument +is positive, enable the mode, and if it is zero or negative, disable +the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -13587,15 +13177,17 @@ selected if the original window is the first one in the frame. ;;;### (autoloads nil "footnote" "mail/footnote.el" (0 0 0 0)) ;;; Generated autoloads from mail/footnote.el -(push (purecopy '(footnote 0 19)) package--builtin-versions) (autoload 'footnote-mode "footnote" "\ Toggle Footnote mode. -If called interactively, enable Footnote mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Footnote mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -14026,7 +13618,6 @@ Interactively, reads the register using `register-read-with-preview'. ;;;### (autoloads nil "gamegrid" "play/gamegrid.el" (0 0 0 0)) ;;; Generated autoloads from play/gamegrid.el -(push (purecopy '(gamegrid 1 2)) package--builtin-versions) (register-definition-prefixes "gamegrid" '("gamegrid-")) @@ -14057,10 +13648,13 @@ being transferred. This list may grow up to a size of `gdb-debug-log-max' after which the oldest element (at the end of the list) is deleted every time a new one is added (at the front). -If called interactively, enable Gdb-Enable-Debug mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Gdb-Enable-Debug mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -14238,10 +13832,13 @@ regular expression that can be used as an element of (autoload 'glasses-mode "glasses" "\ Minor mode for making identifiers likeThis readable. -If called interactively, enable Glasses mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Glasses mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -14850,10 +14447,13 @@ If FORCE is non-nil, replace the old ones. (autoload 'gnus-mailing-list-mode "gnus-ml" "\ Minor mode for providing mailing-list commands. -If called interactively, enable Gnus-Mailing-List mode if ARG is -positive, and disable it if ARG is zero or negative. If called -from Lisp, also enable the mode if ARG is omitted or nil, and -toggle it if ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Gnus-Mailing-List mode'. If the +prefix argument is positive, enable the mode, and if it is zero +or negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. +Enable the mode if ARG is nil, omitted, or is a positive number. +All other values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -15304,10 +14904,13 @@ Also fontifies the buffer appropriately (see `goto-address-fontify-p' and (autoload 'goto-address-mode "goto-addr" "\ Minor mode to buttonize URLs and e-mail addresses in the current buffer. -If called interactively, enable Goto-Address mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Goto-Address mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -15334,17 +14937,22 @@ ARG is omitted or nil. Goto-Address mode is enabled in all buffers where `goto-addr-mode--turn-on' would do it. -See `goto-address-mode' for more information on Goto-Address mode. + +See `goto-address-mode' for more information on +Goto-Address mode. \(fn &optional ARG)" t nil) (autoload 'goto-address-prog-mode "goto-addr" "\ Like `goto-address-mode', but only for comments and strings. -If called interactively, enable Goto-Address-Prog mode if ARG is -positive, and disable it if ARG is zero or negative. If called from -Lisp, also enable the mode if ARG is omitted or nil, and toggle it if -ARG is `toggle'; disable the mode otherwise. +If called interactively, toggle `Goto-Address-Prog mode'. If the +prefix argument is positive, enable the mode, and if it is zero or +negative, disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -15678,10 +15286,13 @@ or call the function `gud-tooltip-mode'.") (autoload 'gud-tooltip-mode "gud" "\ Toggle the display of GUD tooltips. -If called interactively, enable Gud-Tooltip mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Gud-Tooltip mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -16388,14 +15999,6 @@ This discards the buffer's undo information." t nil) (register-definition-prefixes "hexl" '("dehexlify-buffer" "hexl-")) -;;;*** - -;;;### (autoloads "actual autoloads are elsewhere" "hfy-cmap" "hfy-cmap.el" -;;;;;; (0 0 0 0)) -;;; Generated autoloads from hfy-cmap.el - -(register-definition-prefixes "hfy-cmap" '("hfy-" "htmlfontify-unload-rgb-file")) - ;;;*** ;;;### (autoloads nil "hi-lock" "hi-lock.el" (0 0 0 0)) @@ -16404,10 +16007,13 @@ This discards the buffer's undo information." t nil) (autoload 'hi-lock-mode "hi-lock" "\ Toggle selective highlighting of patterns (Hi Lock mode). -If called interactively, enable Hi-Lock mode if ARG is positive, and -disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Hi-Lock mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -16494,7 +16100,9 @@ ARG is omitted or nil. Hi-Lock mode is enabled in all buffers where `turn-on-hi-lock-if-enabled' would do it. -See `hi-lock-mode' for more information on Hi-Lock mode. + +See `hi-lock-mode' for more information on +Hi-Lock mode. \(fn &optional ARG)" t nil) @@ -16598,6 +16206,9 @@ Interactively added patterns are those normally specified using `highlight-regexp' and `highlight-lines-matching-regexp'; they can be found in variable `hi-lock-interactive-patterns'." t nil) +(autoload 'hi-lock-find-patterns "hi-lock" "\ +Add patterns from the current buffer to the list of hi-lock patterns." t nil) + (register-definition-prefixes "hi-lock" '("hi-lock-" "turn-on-hi-lock-if-enabled")) ;;;*** @@ -16608,10 +16219,13 @@ be found in variable `hi-lock-interactive-patterns'." t nil) (autoload 'hide-ifdef-mode "hideif" "\ Toggle features to hide/show #ifdef blocks (Hide-Ifdef mode). -If called interactively, enable Hide-Ifdef mode if ARG is positive, -and disable it if ARG is zero or negative. If called from Lisp, also -enable the mode if ARG is omitted or nil, and toggle it if ARG is -`toggle'; disable the mode otherwise. +If called interactively, toggle `Hide-Ifdef mode'. If the prefix +argument is positive, enable the mode, and if it is zero or negative, +disable the mode. + +If called from Lisp, toggle the mode if if ARG is `toggle'. Enable +the mode if ARG is nil, omitted, or is a positive number. All other +values will disable the mode. The mode's hook is called both when the mode is enabled and when it is disabled. @@ -16659,7 +16273,7 @@ Several variables affect how the hiding is done: ;;;### (autoloads nil "hideshow" "progmodes/hideshow.el" (0 0 0 0)) ;;; Generated autoloads from progmodes/hideshow.el -(defvar hs-special-modes-alist (mapcar 'purecopy '((c-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) (bibtex-mode ("@\\S(*\\(\\s(\\)" 1)) (java-mode "{" "}" "/[*/]" nil nil) (js-mode "{" "}" "/[*/]" nil))) "\ +(defvar hs-special-modes-alist (mapcar 'purecopy '((c-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) (bibtex-mode ("@\\S(*\\(\\s(\\)" 1)) (java-mode "{" "}" "/[*/]" nil nil) (js-mode "{" "}" "/[*/]" nil) (mhtml-mode "{\\|<[^/>]*?" "}\\|]*[^/]>" "