forked from Github/emacs
Compare commits
78 commits
master
...
scratch/gn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a40b1be061 | ||
|
|
3d333b146a | ||
|
|
5e786dc28b | ||
|
|
da6675fdb5 | ||
|
|
9dae21a631 | ||
|
|
79597457a9 | ||
|
|
7d34930785 | ||
|
|
d249e6bc4a | ||
|
|
1f821aee7f | ||
|
|
b23fe432f0 | ||
|
|
353288d9e3 | ||
|
|
039df5e777 | ||
|
|
7f21251a56 | ||
|
|
9965b9b340 | ||
|
|
64bf8de675 | ||
|
|
09aff5299d | ||
|
|
79b5546079 | ||
|
|
2ae25496a1 | ||
|
|
8ea8644653 | ||
|
|
371748dbdc | ||
|
|
9eebc881e9 | ||
|
|
66a7735817 | ||
|
|
37e044feb6 | ||
|
|
a4fe929956 | ||
|
|
32a328f83e | ||
|
|
9e61dd3148 | ||
|
|
9c57f16b44 | ||
|
|
cc541ba3f8 | ||
|
|
a43c41064a | ||
|
|
ede46affca | ||
|
|
c89e129223 | ||
|
|
fcf327bcdc | ||
|
|
6a4dc138ab | ||
|
|
e39079c74c | ||
|
|
b086d9a818 | ||
|
|
5e80a4da88 | ||
|
|
c7cf2127d8 | ||
|
|
31514a043a | ||
|
|
ad83eabc85 | ||
|
|
a80b6f9da4 | ||
|
|
a1cfb383e7 | ||
|
|
f723102b32 | ||
|
|
ac63735def | ||
|
|
ddfd397305 | ||
|
|
046785e5b7 | ||
|
|
7f263d8a9d | ||
|
|
0e2516b72c | ||
|
|
232de89341 | ||
|
|
c838fe43cf | ||
|
|
28f6e8a04b | ||
|
|
0f36c34ad2 | ||
|
|
57a86e5b2c | ||
|
|
ba7b51f27f | ||
|
|
55c5e699d8 | ||
|
|
7c3595470d | ||
|
|
cab358ed19 | ||
|
|
02c66f38bb | ||
|
|
2f67fadd86 | ||
|
|
9e9fdd950d | ||
|
|
130bba8a69 | ||
|
|
5e7a373f2c | ||
|
|
cbe6a2b998 | ||
|
|
1af8d59c6b | ||
|
|
6c64891e88 | ||
|
|
8a96272dde | ||
|
|
01a97228ed | ||
|
|
48dad784a2 | ||
|
|
e7fd7245e8 | ||
|
|
66d1ec0818 | ||
|
|
bcf49f627d | ||
|
|
e528a750da | ||
|
|
5d21c627f7 | ||
|
|
7bbc43ec77 | ||
|
|
ec5a24989f | ||
|
|
6ff9a4f22e | ||
|
|
fd548f570b | ||
|
|
bbd2b1fbee | ||
|
|
163313049b |
20 changed files with 3679 additions and 2288 deletions
|
|
@ -404,33 +404,26 @@ This manual corresponds to Gnus v5.13
|
|||
@end iftex
|
||||
|
||||
@menu
|
||||
* Starting Up:: Finding news can be a pain.
|
||||
* Group Buffer:: Selecting, subscribing and killing groups.
|
||||
* Summary Buffer:: Reading, saving and posting articles.
|
||||
* Article Buffer:: Displaying and handling articles.
|
||||
* Composing Messages:: Information on sending mail and news.
|
||||
* Select Methods:: Gnus reads all messages from various select methods.
|
||||
* Scoring:: Assigning values to articles.
|
||||
* Searching:: Mail and News search engines.
|
||||
* Various:: General purpose settings.
|
||||
* The End:: Farewell and goodbye.
|
||||
* Appendices:: Terminology, Emacs intro, @acronym{FAQ}, History, Internals.
|
||||
* GNU Free Documentation License:: The license for this documentation.
|
||||
* Index:: Variable, function and concept index.
|
||||
* Key Index:: Key Index.
|
||||
* Starting Up:: Finding news can be a pain.
|
||||
* Group Buffer:: Selecting, subscribing and killing groups.
|
||||
* Summary Buffer:: Reading, saving and posting articles.
|
||||
* Article Buffer:: Displaying and handling articles.
|
||||
* Composing Messages:: Information on sending mail and news.
|
||||
* Select Methods:: Gnus reads all messages from various select methods.
|
||||
* Scoring:: Assigning values to articles.
|
||||
* Searching:: Mail and News search engines.
|
||||
* Various:: General purpose settings.
|
||||
* The End:: Farewell and goodbye.
|
||||
* Appendices:: Terminology, Emacs intro, @acronym{FAQ}, History, Internals.
|
||||
* GNU Free Documentation License:: The license for this documentation.
|
||||
* Index:: Variable, function and concept index.
|
||||
* Key Index:: Key Index.
|
||||
|
||||
@c Doesn't work right in html.
|
||||
@c FIXME Do this in a more standard way.
|
||||
@ifinfo
|
||||
Other related manuals
|
||||
|
||||
* Message:(message). Composing messages.
|
||||
* Emacs-MIME:(emacs-mime). Composing messages; @acronym{MIME}-specific parts.
|
||||
* Sieve:(sieve). Managing Sieve scripts in Emacs.
|
||||
* EasyPG:(epa). @acronym{PGP/MIME} with Gnus.
|
||||
* SASL:(sasl). @acronym{SASL} authentication in Emacs.
|
||||
@end ifinfo
|
||||
|
||||
@detailmenu
|
||||
--- The Detailed Node Listing ---
|
||||
|
||||
|
|
@ -439,7 +432,6 @@ Starting Gnus
|
|||
* Finding the News:: Choosing a method for getting news.
|
||||
* The Server is Down:: How can I read my mail then?
|
||||
* Slave Gnusae:: You can have more than one Gnus active at a time.
|
||||
* Fetching a Group:: Starting Gnus just to read a group.
|
||||
* New Groups:: What is Gnus supposed to do with new groups?
|
||||
* Changing Servers:: You may want to move from one server to another.
|
||||
* Startup Files:: Those pesky startup files---@file{.newsrc}.
|
||||
|
|
@ -597,7 +589,8 @@ Article Treatment
|
|||
* Article Buttons:: Click on URLs, Message-IDs, addresses and the like.
|
||||
* Article Button Levels:: Controlling appearance of buttons.
|
||||
* Article Date:: Grumble, UT!
|
||||
* Article Display:: Display various stuff---X-Face, Picons, Smileys, Gravatars
|
||||
* Article Display:: Display various stuff:
|
||||
X-Face, Picons, Gravatars, Smileys.
|
||||
* Article Signature:: What is a signature?
|
||||
* Article Miscellanea:: Various other stuff.
|
||||
|
||||
|
|
@ -661,12 +654,19 @@ Getting News
|
|||
* NNTP:: Reading news from an @acronym{NNTP} server.
|
||||
* News Spool:: Reading news from the local spool.
|
||||
|
||||
@acronym{NNTP}
|
||||
NNTP
|
||||
|
||||
* Direct Functions:: Connecting directly to the server.
|
||||
* Indirect Functions:: Connecting indirectly to the server.
|
||||
* Common Variables:: Understood by several connection functions.
|
||||
|
||||
Using IMAP
|
||||
|
||||
* Connecting to an IMAP Server:: Getting started with @acronym{IMAP}.
|
||||
* Customizing the IMAP Connection:: Variables for @acronym{IMAP} connection.
|
||||
* Client-Side IMAP Splitting:: Put mail in the correct mail box.
|
||||
* Support for IMAP Extensions:: Getting extensions and labels from servers.
|
||||
|
||||
Getting Mail
|
||||
|
||||
* Mail in a Newsreader:: Important introductory notes.
|
||||
|
|
@ -686,6 +686,7 @@ Getting Mail
|
|||
Mail Sources
|
||||
|
||||
* Mail Source Specifiers:: How to specify what a mail source is.
|
||||
* Mail Source Functions::
|
||||
* Mail Source Customization:: Some variables that influence things.
|
||||
* Fetching Mail:: Using the mail source specifiers.
|
||||
|
||||
|
|
@ -696,6 +697,10 @@ Choosing a Mail Back End
|
|||
* Mail Spool:: Store your mail in a private spool?
|
||||
* MH Spool:: An mhspool-like back end.
|
||||
* Maildir:: Another one-file-per-message format.
|
||||
* nnmaildir Group Parameters::
|
||||
* Article Identification::
|
||||
* NOV Data::
|
||||
* Article Marks::
|
||||
* Mail Folders:: Having one file for each group.
|
||||
* Comparing Mail Back Ends:: An in-depth looks at pros and cons.
|
||||
|
||||
|
|
@ -735,10 +740,10 @@ The NNDiary Back End
|
|||
|
||||
The Gnus Diary Library
|
||||
|
||||
* Diary Summary Line Format:: A nicer summary buffer line format.
|
||||
* Diary Articles Sorting:: A nicer way to sort messages.
|
||||
* Diary Headers Generation:: Not doing it manually.
|
||||
* Diary Group Parameters:: Not handling them manually.
|
||||
* Diary Summary Line Format:: A nicer summary buffer line format.
|
||||
* Diary Articles Sorting:: A nicer way to sort messages.
|
||||
* Diary Headers Generation:: Not doing it manually.
|
||||
* Diary Group Parameters:: Not handling them manually.
|
||||
|
||||
Gnus Unplugged
|
||||
|
||||
|
|
@ -796,18 +801,37 @@ Advanced Scoring
|
|||
|
||||
Searching
|
||||
|
||||
* nnir:: Searching with various engines.
|
||||
* Specifying Search Engines::
|
||||
* nnmairix:: Searching with Mairix.
|
||||
|
||||
nnir
|
||||
Specifying Search Engines
|
||||
|
||||
* What is nnir?:: What does nnir do.
|
||||
* What is nnir?:: What does @code{nnir} do?
|
||||
* Basic Usage:: How to perform simple searches.
|
||||
* Setting up nnir:: How to set up nnir.
|
||||
* Setting up nnir:: How to set up @code{nnir}.
|
||||
|
||||
Setting up nnir
|
||||
|
||||
* Associating Engines:: How to associate engines.
|
||||
* The imap Engine:: Imap configuration and usage.
|
||||
* The gmane Engine:: Gmane 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.
|
||||
* Customizations:: User customizable settings.
|
||||
|
||||
nnmairix
|
||||
|
||||
* About mairix:: About the mairix mail search engine
|
||||
* nnmairix requirements:: What you will need for using nnmairix
|
||||
* What nnmairix does:: What does nnmairix actually do?
|
||||
* Setting up mairix:: Set up your mairix installation
|
||||
* Configuring nnmairix:: Set up the nnmairix back end
|
||||
* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
|
||||
* Propagating marks:: How to propagate marks from nnmairix groups
|
||||
* nnmairix tips and tricks:: Some tips, tricks and examples
|
||||
* nnmairix caveats:: Some more stuff you might want to know
|
||||
|
||||
Various
|
||||
|
||||
|
|
@ -823,6 +847,7 @@ Various
|
|||
* Undo:: Some actions can be undone.
|
||||
* Predicate Specifiers:: Specifying predicates.
|
||||
* Moderation:: What to do if you're a moderator.
|
||||
* Fetching a Group:: Starting Gnus just to read a group.
|
||||
* Image Enhancements:: Modern versions of Emacs/XEmacs can display images.
|
||||
* Fuzzy Matching:: What's the big fuzz?
|
||||
* Thwarting Email Spam:: Simple ways to avoid unsolicited commercial email.
|
||||
|
|
@ -847,8 +872,7 @@ Image Enhancements
|
|||
|
||||
* X-Face:: Display a funky, teensy black-and-white image.
|
||||
* Face:: Display a funkier, teensier colored image.
|
||||
* Smileys:: Show all those happy faces the way they were
|
||||
meant to be shown.
|
||||
* Smileys:: Show all those happy faces the way they were meant to be shown.
|
||||
* Picons:: How to display pictures of what you're reading.
|
||||
* Gravatars:: Display the avatar of people you read.
|
||||
* XVarious:: Other XEmacsy Gnusey variables.
|
||||
|
|
@ -871,23 +895,50 @@ Spam Package
|
|||
* Extending the Spam package::
|
||||
* Spam Statistics Package::
|
||||
|
||||
Spam Back Ends
|
||||
|
||||
* Blacklists and Whitelists::
|
||||
* BBDB Whitelists::
|
||||
* Gmane Spam Reporting::
|
||||
* Anti-spam Hashcash Payments::
|
||||
* Blackholes::
|
||||
* Regular Expressions Header Matching::
|
||||
* Bogofilter::
|
||||
* SpamAssassin back end::
|
||||
* ifile spam filtering::
|
||||
* Spam Statistics Filtering::
|
||||
* SpamOracle::
|
||||
|
||||
Spam Statistics Package
|
||||
|
||||
* Creating a spam-stat dictionary::
|
||||
* Splitting mail using spam-stat::
|
||||
* Low-level interface to the spam-stat dictionary::
|
||||
|
||||
The Gnus Registry
|
||||
|
||||
* Gnus Registry Setup::
|
||||
* Registry Article Refer Method::
|
||||
* Fancy splitting to parent::
|
||||
* Store custom flags and keywords::
|
||||
* Store arbitrary data::
|
||||
|
||||
The Gnus Cloud
|
||||
|
||||
* Gnus Cloud Setup::
|
||||
* Gnus Cloud Usage::
|
||||
|
||||
Appendices
|
||||
|
||||
* XEmacs:: Requirements for installing under XEmacs.
|
||||
* History:: How Gnus got where it is today.
|
||||
* The Manual::
|
||||
* On Writing Manuals:: Why this is not a beginner's guide.
|
||||
* Terminology:: We use really difficult, like, words here.
|
||||
* Customization:: Tailoring Gnus to your needs.
|
||||
* Troubleshooting:: What you might try if things do not work.
|
||||
* Gnus Reference Guide:: Rilly, rilly technical stuff.
|
||||
* Emacs for Heathens:: A short introduction to Emacsian terms.
|
||||
* Frequently Asked Questions:: The Gnus FAQ
|
||||
|
||||
History
|
||||
|
||||
|
|
@ -908,7 +959,7 @@ New Features
|
|||
* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
|
||||
* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
|
||||
* Oort Gnus:: It's big. It's far out. Gnus 5.10/5.11.
|
||||
* No Gnus:: Very punny. Gnus 5.12/5.13
|
||||
* No Gnus:: Very punny. Gnus 5.12/5.13.
|
||||
* Ma Gnus:: Celebrating 25 years of Gnus.
|
||||
|
||||
Customization
|
||||
|
|
@ -981,15 +1032,15 @@ If you puzzle at any terms used in this manual, please refer to the
|
|||
terminology section (@pxref{Terminology}).
|
||||
|
||||
@menu
|
||||
* Finding the News:: Choosing a method for getting news.
|
||||
* The Server is Down:: How can I read my mail then?
|
||||
* Slave Gnusae:: You can have more than one Gnus active at a time.
|
||||
* New Groups:: What is Gnus supposed to do with new groups?
|
||||
* Changing Servers:: You may want to move from one server to another.
|
||||
* Startup Files:: Those pesky startup files---@file{.newsrc}.
|
||||
* Auto Save:: Recovering from a crash.
|
||||
* The Active File:: Reading the active file over a slow line Takes Time.
|
||||
* Startup Variables:: Other variables you might change.
|
||||
* Finding the News:: Choosing a method for getting news.
|
||||
* The Server is Down:: How can I read my mail then?
|
||||
* Slave Gnusae:: You can have more than one Gnus active at a time.
|
||||
* New Groups:: What is Gnus supposed to do with new groups?
|
||||
* Changing Servers:: You may want to move from one server to another.
|
||||
* Startup Files:: Those pesky startup files---@file{.newsrc}.
|
||||
* Auto Save:: Recovering from a crash.
|
||||
* The Active File:: Reading the active file over a slow line Takes Time.
|
||||
* Startup Variables:: Other variables you might change.
|
||||
@end menu
|
||||
|
||||
|
||||
|
|
@ -13871,6 +13922,7 @@ installed. You then define a server as follows:
|
|||
(nntp-address "snews.bar.com"))
|
||||
@end lisp
|
||||
|
||||
@c FIXME openssl s_client should be deprecated in favor of gnutls.
|
||||
@findex nntp-open-ssl-stream
|
||||
@item nntp-open-ssl-stream
|
||||
Opens a connection to a server over a @dfn{secure} channel. To use
|
||||
|
|
@ -14190,10 +14242,10 @@ This means that it's a convenient choice when you're reading your mail
|
|||
from different locations, or with different user agents.
|
||||
|
||||
@menu
|
||||
* Connecting to an IMAP Server:: Getting started with @acronym{IMAP}.
|
||||
* Connecting to an IMAP Server:: Getting started with @acronym{IMAP}.
|
||||
* Customizing the IMAP Connection:: Variables for @acronym{IMAP} connection.
|
||||
* Client-Side IMAP Splitting:: Put mail in the correct mail box.
|
||||
* Support for IMAP Extensions:: Getting extensions and labels from servers.
|
||||
* Client-Side IMAP Splitting:: Put mail in the correct mail box.
|
||||
* Support for IMAP Extensions:: Getting extensions and labels from servers.
|
||||
@end menu
|
||||
|
||||
|
||||
|
|
@ -18002,10 +18054,10 @@ useful things for you.
|
|||
|
||||
|
||||
@menu
|
||||
* Diary Summary Line Format:: A nicer summary buffer line format.
|
||||
* Diary Articles Sorting:: A nicer way to sort messages.
|
||||
* Diary Headers Generation:: Not doing it manually.
|
||||
* Diary Group Parameters:: Not handling them manually.
|
||||
* Diary Summary Line Format:: A nicer summary buffer line format.
|
||||
* Diary Articles Sorting:: A nicer way to sort messages.
|
||||
* Diary Headers Generation:: Not doing it manually.
|
||||
* Diary Group Parameters:: Not handling them manually.
|
||||
@end menu
|
||||
|
||||
@node Diary Summary Line Format
|
||||
|
|
@ -21091,123 +21143,62 @@ four days, Gnus will decay the scores four times, for instance.
|
|||
@chapter Searching
|
||||
@cindex searching
|
||||
|
||||
FIXME: Add a brief overview of Gnus search capabilities. A brief
|
||||
comparison of nnir, nnmairix, contrib/gnus-namazu would be nice
|
||||
as well.
|
||||
Gnus allows you to search for messages from one or more backends, and
|
||||
to show the results in group summary buffers. The groups that hold
|
||||
search results are created on the nnselect backend (@xref{nnselect}),
|
||||
and can be either ephemeral or persistent (@xref{Creating Search
|
||||
Groups}).
|
||||
|
||||
This chapter describes tools for searching groups and servers for
|
||||
articles matching a query and then retrieving those articles. Gnus
|
||||
provides a simpler mechanism for searching through articles in a summary buffer
|
||||
to find those matching a pattern. @xref{Searching for Articles}.
|
||||
Each backend has a search engine associated with it. 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 (@xref{Specifying Search Engines}).
|
||||
|
||||
Gnus uses a generalized search query language, which is translated
|
||||
appropriately across all the backends being searched. For instance,
|
||||
if you mark one group from an IMAP backend, and another group from an
|
||||
nnmaildir backend indexed using notmuch, you can enter a single query,
|
||||
using Gnus' general search syntax, and that query will be translated
|
||||
appropriately for the IMAP and notmuch engines, returning relevant
|
||||
results from both backends. For details on Gnus' query language,
|
||||
@xref{Search Queries}.
|
||||
|
||||
If you're already in a summary buffer, Gnus provides a simpler
|
||||
mechanism for searching through the articles in that buffer.
|
||||
@xref{Searching for Articles}.
|
||||
|
||||
@menu
|
||||
* nnir:: Searching with various engines.
|
||||
* nnmairix:: Searching with Mairix.
|
||||
* Specifying Search Engines:: Which engines for which backends?
|
||||
* nnmairix:: Searching with Mairix.
|
||||
@end menu
|
||||
|
||||
@node nnir
|
||||
@section nnir
|
||||
@cindex nnir
|
||||
@node Search Engines
|
||||
@section Search Engines
|
||||
@cindex search engines
|
||||
|
||||
This section describes how to use @code{nnir} to search for articles
|
||||
within gnus.
|
||||
Each backend can have a search engine associated with it. Some
|
||||
backends don't provide much flexibility in this regard: imap servers
|
||||
generally provide their own search functionality, for instance. Other
|
||||
backends, like nnml or nnmaildir, don't come with any search
|
||||
capabilities at all, and it is up to the user to create and maintain
|
||||
search indexes using some external program. See below for details on
|
||||
the various search programs Gnus supports.
|
||||
|
||||
@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
|
||||
There are two ways to associate a search engine with a backend: either
|
||||
by creating default associations using
|
||||
@code{gnus-search-default-engines}, or on a per-backend basis in the
|
||||
backend declaration.
|
||||
|
||||
@node What is nnir?
|
||||
@subsection What is nnir?
|
||||
@table @code
|
||||
|
||||
@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-default-engines}
|
||||
@vindex gnus-search-default-engines
|
||||
An alist of pairs of the form @code{(backend . engine)}.
|
||||
Backends are a symbol like @code{nnimap} or @code{nnml}.
|
||||
Engines are the symbol name of a search engine class, for
|
||||
instance @code{gnus-search-imap} or @code{gnus-search-mairix}.
|
||||
@end table
|
||||
|
||||
The @code{nnimap} and @code{gmane} search engines should work with no
|
||||
configuration. Other engines require a local index that needs to be
|
||||
created and maintained outside of Gnus.
|
||||
|
||||
|
||||
@node Basic Usage
|
||||
@subsection Basic Usage
|
||||
|
||||
In the group buffer typing @kbd{G G} will search the group on the
|
||||
current line by calling @code{gnus-group-make-nnir-group}. This prompts
|
||||
for a query string, creates an ephemeral @code{nnir} group containing
|
||||
the articles that match this query, and takes you to a summary buffer
|
||||
showing these articles. Articles may then be read, moved and deleted
|
||||
using the usual commands.
|
||||
|
||||
The @code{nnir} group made in this way is an @code{ephemeral} group,
|
||||
and some changes are not permanent: aside from reading, moving, and
|
||||
deleting, you can't act on the original article. But there is an
|
||||
alternative: 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}. Even better, the function
|
||||
@code{gnus-summary-refer-thread}, bound by default in summary buffers
|
||||
to @kbd{A T}, will first warp to the original group before it works
|
||||
its magic and includes all the articles in the thread. From here you
|
||||
can read, move and delete articles, but also copy them, alter article
|
||||
marks, whatever. Go nuts.
|
||||
|
||||
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.
|
||||
|
||||
Still not enough? OK, in the server buffer
|
||||
@code{gnus-group-make-nnir-group} (now 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}.
|
||||
|
||||
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-make-nnir-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 Setting up nnir
|
||||
@subsection Setting up nnir
|
||||
|
||||
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} and @code{gmane}, 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.
|
||||
|
||||
If you just want to use the @code{imap} engine to search @code{nnimap}
|
||||
servers, and the @code{gmane} engine to search @code{gmane} then you
|
||||
don't have to do anything. But you might want to read the details of the
|
||||
query language anyway.
|
||||
|
||||
@menu
|
||||
* Associating Engines:: How to associate engines.
|
||||
* The imap Engine:: Imap configuration and usage.
|
||||
* The gmane Engine:: Gmane 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
|
||||
|
||||
@node Associating Engines
|
||||
@subsubsection Associating Engines
|
||||
|
||||
|
||||
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
|
||||
|
|
@ -21216,22 +21207,27 @@ named @code{home} you can use
|
|||
(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, and the @code{gmane} backend for @code{nntp}
|
||||
servers. (Don't worry, the @code{gmane} search engine won't actually try
|
||||
to search non-gmane @code{nntp} servers.) But if you wanted to use
|
||||
@code{namazu} for all your servers with an @code{nnimap} backend you
|
||||
could change this to
|
||||
Search engines are implemented as classes in Gnus, an implementation
|
||||
detail that users can usually ignore. The class names all begin with
|
||||
@samp{gnus-search-*}, see below for the full list. Many of the
|
||||
classes accept options changing their behavior: for instance,
|
||||
command-line search programs mostly accept a @samp{switches} option
|
||||
specifying extra switches to be passed on the command line.
|
||||
|
||||
@lisp
|
||||
'((nnimap . namazu)
|
||||
(nntp . gmane))
|
||||
@end lisp
|
||||
These options can be set either generally, for a whole class of search
|
||||
engine, or specifically for a single engine instance.
|
||||
|
||||
@node Supported Engines
|
||||
@subsection Supported Engines
|
||||
|
||||
@menu
|
||||
* The imap Engine:: Imap configuration and usage.
|
||||
* The gmane Engine:: Gmane 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.
|
||||
@end menu
|
||||
|
||||
@node The imap Engine
|
||||
@subsubsection The imap Engine
|
||||
|
|
@ -21445,54 +21441,93 @@ is a regular expression.
|
|||
|
||||
@end table
|
||||
|
||||
@node Creating Search Groups
|
||||
@section Creating Search Groups
|
||||
@cindex search groups
|
||||
|
||||
@node The hyrex Engine
|
||||
@subsubsection The hyrex Engine
|
||||
This engine is obsolete.
|
||||
In the group buffer typing @kbd{G G} will search the group on the
|
||||
current line by calling @code{gnus-group-make-search-group}. This
|
||||
prompts for a query string, creates an ephemeral @code{nnselect} group
|
||||
containing the articles that match this query, and takes you to a
|
||||
summary buffer showing these articles. Articles may then be read,
|
||||
moved and deleted using the usual commands.
|
||||
|
||||
The @code{nnir} group made in this way is an @code{ephemeral} group,
|
||||
and some changes are not permanent: aside from reading, moving, and
|
||||
deleting, you can't act on the original article. But there is an
|
||||
alternative: 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}. Even better, the function
|
||||
@code{gnus-summary-refer-thread}, bound by default in summary buffers
|
||||
to @kbd{A T}, will first warp to the original group before it works
|
||||
its magic and includes all the articles in the thread. From here you
|
||||
can read, move and delete articles, but also copy them, alter article
|
||||
marks, whatever. Go nuts.
|
||||
|
||||
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.
|
||||
|
||||
Still not enough? OK, in the server buffer
|
||||
@code{gnus-group-make-search-group} (now 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{gnus-search-ignored-newsgroups}.
|
||||
|
||||
@node Search Queries
|
||||
@section Search Queries
|
||||
@cindex search queries
|
||||
|
||||
Gnus provides a generalized search query language that can be used to
|
||||
search many engines at once. The language is meant to be as flexible
|
||||
as possible, with the expectation that the search engines will
|
||||
interpret the queries as best they can, and ignore any terms or
|
||||
expressions that cannot be interpreted.
|
||||
|
||||
The language is built on a simple @samp{key:value} pattern. The keys
|
||||
are defined below; many engines can also accept arbitrary keys,
|
||||
typically interpreting them as mail header names. Values are words,
|
||||
occasionally numbers, or quote-delimited phrases.
|
||||
|
||||
Keys can be arbitrarily abbreviated, for convenience in typing. For
|
||||
instance, @samp{subject} could also be written as @samp{subj}, or even
|
||||
@samp{su}. Abbreviated keywords will be expanded at parse time,
|
||||
though if a keyword is so abbreviated as to become ambiguous (@samp{s}
|
||||
could expand to either @samp{subject} or @samp{since}, for instance),
|
||||
an error will be raised.
|
||||
|
||||
Multiple terms are implicitly ANDed. The infixed @samp{or} keyword
|
||||
performs the OR function. The @samp{near} keyword is understood by
|
||||
some engines; by others it is treated as an AND. Parentheses can be
|
||||
used to group and/or nest sub-expressions.
|
||||
|
||||
@table @samp
|
||||
|
||||
@end table
|
||||
|
||||
@node Customizations
|
||||
@subsubsection Customizations
|
||||
@section Customizations
|
||||
|
||||
@table @code
|
||||
|
||||
@item nnir-method-default-engines
|
||||
@item gnus-search-use-parsed-queries
|
||||
When non-nil, the default, Gnus will parse string queries into sexp
|
||||
form, and allow search engines to transform those sexps into
|
||||
understandable formats. If you want to always send raw, unparsed queries to the engines,
|
||||
|
||||
@item gnus-search-default-engines
|
||||
Alist of pairs of server backends and search engines. The default
|
||||
associations are
|
||||
@example
|
||||
(nnimap . imap)
|
||||
(nntp . gmane)
|
||||
(nnimap . gnus-search-imap)
|
||||
(nntp . gnus-search-gmane)
|
||||
@end example
|
||||
|
||||
@item nnir-ignored-newsgroups
|
||||
@item gnus-search-ignored-newsgroups
|
||||
A regexp to match newsgroups in the active file that should be skipped
|
||||
when searching all groups on a server.
|
||||
|
||||
@item nnir-summary-line-format
|
||||
The format specification to be used for lines in an nnir summary buffer.
|
||||
All the items from @code{gnus-summary-line-format} are available, along with
|
||||
three items unique to nnir summary buffers:
|
||||
|
||||
@example
|
||||
%Z Search retrieval score value (integer)
|
||||
%G Article original full group name (string)
|
||||
%g Article original short group name (string)
|
||||
@end example
|
||||
|
||||
If @code{nil} (the default) this will use @code{gnus-summary-line-format}.
|
||||
|
||||
@item nnir-retrieve-headers-override-function
|
||||
If non-@code{nil}, a function that retrieves article headers rather than using
|
||||
the gnus built-in function. This function takes an article list and
|
||||
group as arguments and populates the @code{nntp-server-buffer} with the
|
||||
retrieved headers. It should then return either 'nov or 'headers
|
||||
indicating the retrieved header format. Failure to retrieve headers
|
||||
should return @code{nil}.
|
||||
|
||||
If this variable is @code{nil}, or if the provided function returns
|
||||
@code{nil} for a search result, @code{gnus-retrieve-headers} will be
|
||||
called instead."
|
||||
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
|
|
@ -21512,7 +21547,7 @@ bound to mairix searches and are automatically updated.
|
|||
* What nnmairix does:: What does nnmairix actually do?
|
||||
* Setting up mairix:: Set up your mairix installation
|
||||
* Configuring nnmairix:: Set up the nnmairix back end
|
||||
* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
|
||||
* nnmairix keyboard shortcuts:: List of available keyboard shortcuts
|
||||
* Propagating marks:: How to propagate marks from nnmairix groups
|
||||
* nnmairix tips and tricks:: Some tips, tricks and examples
|
||||
* nnmairix caveats:: Some more stuff you might want to know
|
||||
|
|
@ -26465,13 +26500,13 @@ but at the common table.@*
|
|||
@menu
|
||||
* XEmacs:: Requirements for installing under XEmacs.
|
||||
* History:: How Gnus got where it is today.
|
||||
* The Manual::
|
||||
* On Writing Manuals:: Why this is not a beginner's guide.
|
||||
* Terminology:: We use really difficult, like, words here.
|
||||
* Customization:: Tailoring Gnus to your needs.
|
||||
* Troubleshooting:: What you might try if things do not work.
|
||||
* Gnus Reference Guide:: Rilly, rilly technical stuff.
|
||||
* Emacs for Heathens:: A short introduction to Emacsian terms.
|
||||
* Frequently Asked Questions:: The Gnus FAQ
|
||||
@end menu
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -110,12 +110,14 @@ buffer, or a filename. If SOMETHING is nil return nil."
|
|||
(semantic-file-tag-table something))
|
||||
;; A Semanticdb table
|
||||
((and (featurep 'semantic/db)
|
||||
(require 'semantic/db-mode)
|
||||
(semanticdb-minor-mode-p)
|
||||
(semanticdb-abstract-table-child-p something))
|
||||
(semanticdb-refresh-table something)
|
||||
(semanticdb-get-tags something))
|
||||
;; Semanticdb find-results
|
||||
((and (featurep 'semantic/db)
|
||||
(require 'semantic/db-mode)
|
||||
(semanticdb-minor-mode-p)
|
||||
(require 'semantic/db-find)
|
||||
(semanticdb-find-results-p something))
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
;; CONTENTS --- `erc-response.contents'
|
||||
;; SENDER --- `erc-response.sender'
|
||||
;; LINE --- `erc-response.unparsed'
|
||||
;; TAGS --- `erc-response.tags'
|
||||
;;
|
||||
;; WARNING, WARNING!!
|
||||
;; It's probably not a good idea to destructively modify the list
|
||||
|
|
@ -115,7 +116,8 @@
|
|||
(sender "" :type string)
|
||||
(command "" :type string)
|
||||
(command-args '() :type list)
|
||||
(contents "" :type string))
|
||||
(contents "" :type string)
|
||||
(tags '() :type list))
|
||||
|
||||
;;; User data
|
||||
|
||||
|
|
@ -955,16 +957,34 @@ See also `erc-server-send'."
|
|||
|
||||
;;;; Handling responses
|
||||
|
||||
(defun erc-parse-tags (string)
|
||||
"Parse IRCv3 tags list in STRING to a (tag . value) alist."
|
||||
(let ((tags)
|
||||
(tag-strings (split-string string ";")))
|
||||
(dolist (tag-string tag-strings tags)
|
||||
(let ((pair (split-string tag-string "=")))
|
||||
(push (if (consp pair)
|
||||
pair
|
||||
`(,pair))
|
||||
tags)))))
|
||||
|
||||
(defun erc-parse-server-response (proc string)
|
||||
"Parse and act upon a complete line from an IRC server.
|
||||
PROC is the process (connection) from which STRING was received.
|
||||
PROCs `process-buffer' is `current-buffer' when this function is called."
|
||||
(unless (string= string "") ;; Ignore empty strings
|
||||
(save-match-data
|
||||
(let ((posn (if (eq (aref string 0) ?:)
|
||||
(string-match " " string)
|
||||
0))
|
||||
(msg (make-erc-response :unparsed string)))
|
||||
(let* ((tag-list (when (eq (aref string 0) ?@)
|
||||
(substring string 1 (string-match " " string))))
|
||||
(msg (make-erc-response :unparsed string :tags (when tag-list
|
||||
(erc-parse-tags
|
||||
tag-list))))
|
||||
(string (if tag-list
|
||||
(substring string (+ 1 (string-match " " string)))
|
||||
string))
|
||||
(posn (if (eq (aref string 0) ?:)
|
||||
(string-match " " string)
|
||||
0)))
|
||||
|
||||
(setf (erc-response.sender msg)
|
||||
(if (eq posn 0)
|
||||
|
|
|
|||
|
|
@ -2700,7 +2700,10 @@ See also `erc-format-message' and `erc-display-line'."
|
|||
(unless (erc-hide-current-message-p parsed)
|
||||
(erc-put-text-property 0 (length string) 'erc-parsed parsed string)
|
||||
(erc-put-text-property 0 (length string) 'rear-sticky t string)
|
||||
(erc-display-line string buffer)))))
|
||||
(when (erc-response.tags parsed)
|
||||
(erc-put-text-property 0 (length string) 'tags (erc-response.tags parsed)
|
||||
string))
|
||||
(erc-display-line string buffer)))))
|
||||
|
||||
(defun erc-message-type-member (position list)
|
||||
"Return non-nil if the erc-parsed text-property at POSITION is in LIST.
|
||||
|
|
|
|||
|
|
@ -6993,10 +6993,10 @@ If given a prefix, show the hidden text instead."
|
|||
((memq article gnus-newsgroup-sparse)
|
||||
;; This is a sparse gap article.
|
||||
(setq do-update-line article)
|
||||
(setq article (mail-header-id header))
|
||||
(setq sparse-header (gnus-read-header article))
|
||||
(setq gnus-newsgroup-sparse
|
||||
(delq article gnus-newsgroup-sparse)))
|
||||
(delq article gnus-newsgroup-sparse))
|
||||
(setq article (mail-header-id header))
|
||||
(setq sparse-header (gnus-read-header article)))
|
||||
((vectorp header)
|
||||
;; It's a real article.
|
||||
(setq article (mail-header-id header)))
|
||||
|
|
|
|||
|
|
@ -49,10 +49,11 @@
|
|||
(autoload 'gnus-agent-total-fetched-for "gnus-agent")
|
||||
(autoload 'gnus-cache-total-fetched-for "gnus-cache")
|
||||
|
||||
(autoload 'gnus-group-make-nnir-group "nnir")
|
||||
|
||||
(autoload 'gnus-cloud-upload-all-data "gnus-cloud")
|
||||
(autoload 'gnus-cloud-download-all-data "gnus-cloud")
|
||||
(autoload 'gnus-registry-get-id-key "gnus-registry")
|
||||
|
||||
(declare-function 'gnus-group-topic-name "gnus-topic")
|
||||
|
||||
(defcustom gnus-no-groups-message "No news is good news"
|
||||
"Message displayed by Gnus when no groups are available."
|
||||
|
|
@ -671,7 +672,8 @@ simple manner."
|
|||
"D" gnus-group-enter-directory
|
||||
"f" gnus-group-make-doc-group
|
||||
"w" gnus-group-make-web-group
|
||||
"G" gnus-group-make-nnir-group
|
||||
"G" gnus-group-read-ephemeral-search-group
|
||||
"g" gnus-group-make-search-group
|
||||
"M" gnus-group-read-ephemeral-group
|
||||
"r" gnus-group-rename-group
|
||||
"R" gnus-group-make-rss-group
|
||||
|
|
@ -917,7 +919,8 @@ simple manner."
|
|||
["Add the help group" gnus-group-make-help-group t]
|
||||
["Make a doc group..." gnus-group-make-doc-group t]
|
||||
["Make a web group..." gnus-group-make-web-group t]
|
||||
["Make a search group..." gnus-group-make-nnir-group t]
|
||||
["Read a search group..." gnus-group-read-ephemeral-search-group t]
|
||||
["Make a search group..." gnus-group-make-search-group t]
|
||||
["Make a virtual group..." gnus-group-make-empty-virtual t]
|
||||
["Add a group to a virtual..." gnus-group-add-to-virtual t]
|
||||
["Make an ephemeral group..." gnus-group-read-ephemeral-group t]
|
||||
|
|
@ -3193,6 +3196,51 @@ 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 'gnus-search-make-specs "gnus-search")
|
||||
(autoload 'gnus-group-topic-name "gnus-topic")
|
||||
|
||||
;; Temporary to make group creation easier
|
||||
(defun gnus-group-make-search-group (arg &optional specs)
|
||||
(interactive "P")
|
||||
(let ((name (read-string "Group name: " nil)))
|
||||
(with-current-buffer gnus-group-buffer
|
||||
(gnus-group-make-group
|
||||
name
|
||||
(list 'nnselect "nnselect")
|
||||
nil
|
||||
(list
|
||||
(cons 'nnselect-specs
|
||||
(list
|
||||
(cons 'nnselect-function 'gnus-search-run-query)
|
||||
(cons 'nnselect-args
|
||||
(gnus-search-make-specs arg specs)))))))))
|
||||
|
||||
(defun gnus-group-read-ephemeral-search-group (arg &optional specs)
|
||||
"Create 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
|
||||
prevents parsing of the query. A non-nil `specs' arg must be an
|
||||
alist with `search-query-spec' and `search-group-spec' keys, and
|
||||
skips all prompting."
|
||||
(interactive "P")
|
||||
(gnus-group-read-ephemeral-group
|
||||
(concat "nnselect-" (message-unique-id))
|
||||
(list 'nnselect "nnselect")
|
||||
nil
|
||||
(cons (current-buffer) gnus-current-window-configuration)
|
||||
; nil
|
||||
nil nil
|
||||
(list
|
||||
(cons 'nnselect-specs
|
||||
(list
|
||||
(cons 'nnselect-function 'gnus-search-run-query)
|
||||
(cons 'nnselect-args
|
||||
(gnus-search-make-specs arg specs))))
|
||||
(cons 'nnselect-artlist nil))))
|
||||
|
||||
(defun gnus-group-add-to-virtual (n vgroup)
|
||||
"Add the current group to a virtual group."
|
||||
(interactive
|
||||
|
|
@ -4728,6 +4776,7 @@ you the groups that have both dormant articles and cached articles."
|
|||
group 'expire (list article))))))
|
||||
|
||||
|
||||
|
||||
;;;
|
||||
;;; Group compaction. -- dvl
|
||||
;;;
|
||||
|
|
|
|||
|
|
@ -414,10 +414,9 @@ Thank you for your help in stamping out bugs.
|
|||
(gnus-inews-make-draft-meta-information
|
||||
,(gnus-group-decoded-name gnus-newsgroup-name) ',articles)))
|
||||
|
||||
(autoload 'nnir-article-number "nnir" nil nil 'macro)
|
||||
(autoload 'nnir-article-group "nnir" nil nil 'macro)
|
||||
(autoload 'gnus-nnir-group-p "nnir")
|
||||
|
||||
(autoload 'nnselect-article-number "nnselect" nil nil 'macro)
|
||||
(autoload 'nnselect-article-group "nnselect" nil nil 'macro)
|
||||
(autoload 'gnus-nnselect-group-p "nnselect")
|
||||
|
||||
(defvar gnus-article-reply nil)
|
||||
(defmacro gnus-setup-message (config &rest forms)
|
||||
|
|
@ -425,22 +424,24 @@ Thank you for your help in stamping out bugs.
|
|||
(winconf-name (make-symbol "gnus-setup-message-winconf-name"))
|
||||
(buffer (make-symbol "gnus-setup-message-buffer"))
|
||||
(article (make-symbol "gnus-setup-message-article"))
|
||||
(oarticle (make-symbol "gnus-setup-message-oarticle"))
|
||||
(yanked (make-symbol "gnus-setup-yanked-articles"))
|
||||
(group (make-symbol "gnus-setup-message-group")))
|
||||
`(let ((,winconf (current-window-configuration))
|
||||
(,winconf-name gnus-current-window-configuration)
|
||||
(,buffer (buffer-name (current-buffer)))
|
||||
(,article (if (and (gnus-nnir-group-p gnus-newsgroup-name)
|
||||
gnus-article-reply)
|
||||
(nnir-article-number (or (car-safe gnus-article-reply)
|
||||
gnus-article-reply))
|
||||
gnus-article-reply))
|
||||
(,article (when gnus-article-reply
|
||||
(or (nnselect-article-number
|
||||
(or (car-safe gnus-article-reply)
|
||||
gnus-article-reply))
|
||||
gnus-article-reply)))
|
||||
(,oarticle gnus-article-reply)
|
||||
(,yanked gnus-article-yanked-articles)
|
||||
(,group (if (and (gnus-nnir-group-p gnus-newsgroup-name)
|
||||
gnus-article-reply)
|
||||
(nnir-article-group (or (car-safe gnus-article-reply)
|
||||
gnus-article-reply))
|
||||
gnus-newsgroup-name))
|
||||
(,group (when gnus-article-reply
|
||||
(or (nnselect-article-group
|
||||
(or (car-safe gnus-article-reply)
|
||||
gnus-article-reply))
|
||||
gnus-newsgroup-name)))
|
||||
(message-header-setup-hook
|
||||
(copy-sequence message-header-setup-hook))
|
||||
(mbl mml-buffer-list)
|
||||
|
|
@ -481,24 +482,23 @@ Thank you for your help in stamping out bugs.
|
|||
(unwind-protect
|
||||
(progn
|
||||
,@forms)
|
||||
(gnus-inews-add-send-actions ,winconf ,buffer ,article ,config
|
||||
(gnus-inews-add-send-actions ,winconf ,buffer ,oarticle ,config
|
||||
,yanked ,winconf-name)
|
||||
(setq gnus-message-buffer (current-buffer))
|
||||
(set (make-local-variable 'gnus-message-group-art)
|
||||
(cons ,group ,article))
|
||||
(set (make-local-variable 'gnus-newsgroup-name) ,group)
|
||||
;; Enable highlighting of different citation levels
|
||||
(when gnus-message-highlight-citation
|
||||
(gnus-message-citation-mode 1))
|
||||
(gnus-run-hooks 'gnus-message-setup-hook)
|
||||
(if (eq major-mode 'message-mode)
|
||||
(let ((mbl1 mml-buffer-list))
|
||||
(setq mml-buffer-list mbl) ;; Global value
|
||||
(set (make-local-variable 'mml-buffer-list) mbl1);; Local value
|
||||
(add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
|
||||
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
|
||||
(mml-destroy-buffers)
|
||||
(setq mml-buffer-list mbl)))
|
||||
;; Enable highlighting of different citation levels
|
||||
(when gnus-message-highlight-citation
|
||||
(gnus-message-citation-mode 1))
|
||||
(gnus-run-hooks 'gnus-message-setup-hook)
|
||||
(if (eq major-mode 'message-mode)
|
||||
(let ((mbl1 mml-buffer-list))
|
||||
(setq mml-buffer-list mbl) ;; Global value
|
||||
(set (make-local-variable 'mml-buffer-list) mbl1);; Local value
|
||||
(add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
|
||||
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
|
||||
(mml-destroy-buffers)
|
||||
(setq mml-buffer-list mbl)))
|
||||
(message-hide-headers)
|
||||
(gnus-add-buffer)
|
||||
(gnus-configure-windows ,config t)
|
||||
|
|
@ -542,12 +542,10 @@ instead."
|
|||
mail-buf)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq gnus-newsgroup-name "")
|
||||
(let ((gnus-newsgroup-name ""))
|
||||
(gnus-setup-message 'message
|
||||
(message-mail to subject other-headers continue
|
||||
nil yank-action send-actions return-action)))
|
||||
(with-current-buffer buf
|
||||
(setq gnus-newsgroup-name group-name)))
|
||||
nil yank-action send-actions return-action)))))
|
||||
(when switch-action
|
||||
(setq mail-buf (current-buffer))
|
||||
(switch-to-buffer buf)
|
||||
|
|
@ -638,18 +636,15 @@ If ARG is 1, prompt for a group name to find the posting style."
|
|||
(buffer (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq gnus-newsgroup-name
|
||||
(if arg
|
||||
(if (= 1 (prefix-numeric-value arg))
|
||||
(gnus-group-completing-read
|
||||
"Use posting style of group"
|
||||
nil (gnus-read-active-file-p))
|
||||
(gnus-group-group-name))
|
||||
""))
|
||||
;; #### see comment in gnus-setup-message -- drv
|
||||
(gnus-setup-message 'message (message-mail)))
|
||||
(with-current-buffer buffer
|
||||
(setq gnus-newsgroup-name group)))))
|
||||
(let ((gnus-newsgroup-name
|
||||
(if arg
|
||||
(if (= 1 (prefix-numeric-value arg))
|
||||
(gnus-group-completing-read
|
||||
"Use posting style of group"
|
||||
nil (gnus-read-active-file-p))
|
||||
(gnus-group-group-name))
|
||||
"")))
|
||||
(gnus-setup-message 'message (message-mail)))))))
|
||||
|
||||
(defun gnus-group-news (&optional arg)
|
||||
"Start composing a news.
|
||||
|
|
@ -668,19 +663,16 @@ network. The corresponding back end must have a 'request-post method."
|
|||
(buffer (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq gnus-newsgroup-name
|
||||
(let ((gnus-newsgroup-name
|
||||
(if arg
|
||||
(if (= 1 (prefix-numeric-value arg))
|
||||
(gnus-group-completing-read "Use group"
|
||||
nil
|
||||
(gnus-read-active-file-p))
|
||||
(gnus-group-group-name))
|
||||
""))
|
||||
;; #### see comment in gnus-setup-message -- drv
|
||||
"")))
|
||||
(gnus-setup-message 'message
|
||||
(message-news (gnus-group-real-name gnus-newsgroup-name))))
|
||||
(with-current-buffer buffer
|
||||
(setq gnus-newsgroup-name group)))))
|
||||
(message-news (gnus-group-real-name gnus-newsgroup-name))))))))
|
||||
|
||||
(defun gnus-group-post-news (&optional arg)
|
||||
"Start composing a message (a news by default).
|
||||
|
|
@ -715,18 +707,15 @@ posting style."
|
|||
(buffer (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq gnus-newsgroup-name
|
||||
(let ((gnus-newsgroup-name
|
||||
(if arg
|
||||
(if (= 1 (prefix-numeric-value arg))
|
||||
(gnus-group-completing-read "Use group"
|
||||
nil
|
||||
(gnus-read-active-file-p))
|
||||
"")
|
||||
gnus-newsgroup-name))
|
||||
;; #### see comment in gnus-setup-message -- drv
|
||||
(gnus-setup-message 'message (message-mail)))
|
||||
(with-current-buffer buffer
|
||||
(setq gnus-newsgroup-name group)))))
|
||||
gnus-newsgroup-name)))
|
||||
(gnus-setup-message 'message (message-mail)))))))
|
||||
|
||||
(defun gnus-summary-news-other-window (&optional arg)
|
||||
"Start composing a news in another window.
|
||||
|
|
@ -745,24 +734,21 @@ network. The corresponding back end must have a 'request-post method."
|
|||
(buffer (current-buffer)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(setq gnus-newsgroup-name
|
||||
(let ((gnus-newsgroup-name
|
||||
(if arg
|
||||
(if (= 1 (prefix-numeric-value arg))
|
||||
(gnus-group-completing-read "Use group"
|
||||
nil
|
||||
(gnus-read-active-file-p))
|
||||
"")
|
||||
gnus-newsgroup-name))
|
||||
;; #### see comment in gnus-setup-message -- drv
|
||||
gnus-newsgroup-name)))
|
||||
(gnus-setup-message 'message
|
||||
(progn
|
||||
(message-news (gnus-group-real-name gnus-newsgroup-name))
|
||||
(set (make-local-variable 'gnus-discouraged-post-methods)
|
||||
(remove
|
||||
(car (gnus-find-method-for-group gnus-newsgroup-name))
|
||||
gnus-discouraged-post-methods)))))
|
||||
(with-current-buffer buffer
|
||||
(setq gnus-newsgroup-name group)))))
|
||||
gnus-discouraged-post-methods)))))))))
|
||||
|
||||
(defun gnus-summary-post-news (&optional arg)
|
||||
"Start composing a message. Post to the current group by default.
|
||||
|
|
|
|||
|
|
@ -380,6 +380,8 @@ This is not required after changing `gnus-registry-cache-file'."
|
|||
(gnus-message 4 "Removed %d ignored entries from the Gnus registry"
|
||||
(- old-size (registry-size db)))))
|
||||
|
||||
(declare-function gnus-nnselect-group-p "nnselect" (group))
|
||||
(declare-function nnselect-article-group "nnselect" (article))
|
||||
;; article move/copy/spool/delete actions
|
||||
(defun gnus-registry-action (action data-header from &optional to method)
|
||||
(let* ((id (mail-header-id data-header))
|
||||
|
|
@ -390,7 +392,10 @@ This is not required after changing `gnus-registry-cache-file'."
|
|||
(or (cdr-safe (assq 'To extra)) "")))
|
||||
(sender (nth 0 (gnus-registry-extract-addresses
|
||||
(mail-header-from data-header))))
|
||||
(from (gnus-group-guess-full-name-from-command-method from))
|
||||
(from (gnus-group-guess-full-name-from-command-method
|
||||
(if (gnus-nnselect-group-p from)
|
||||
(nnselect-article-group (mail-header-number data-header))
|
||||
from)))
|
||||
(to (if to (gnus-group-guess-full-name-from-command-method to) nil)))
|
||||
(gnus-message 7 "Gnus registry: article %s %s from %s to %s"
|
||||
id (if method "respooling" "going") from to)
|
||||
|
|
@ -737,7 +742,7 @@ Consults `gnus-registry-unfollowed-groups' and
|
|||
Consults `gnus-registry-ignored-groups' and
|
||||
`nnmail-split-fancy-with-parent-ignore-groups'."
|
||||
(and group
|
||||
(or (gnus-grep-in-list
|
||||
(or (gnus-virtual-group-p group) (gnus-grep-in-list
|
||||
group
|
||||
(delq nil (mapcar (lambda (g)
|
||||
(cond
|
||||
|
|
@ -1175,7 +1180,7 @@ is `ask', ask the user; or if `gnus-registry-install' is non-nil, enable it."
|
|||
(gnus-registry-initialize)))
|
||||
gnus-registry-enabled)
|
||||
|
||||
;; largely based on nnir-warp-to-article
|
||||
;; largely based on nnselect-warp-to-article
|
||||
(defun gnus-try-warping-via-registry ()
|
||||
"Try to warp via the registry.
|
||||
This will be done via the current article's source group based on
|
||||
|
|
@ -1199,7 +1204,7 @@ data stored in the registry."
|
|||
(gnus-ephemeral-group-p group) ;; any ephemeral group
|
||||
(memq (car (gnus-find-method-for-group group))
|
||||
;; Specific methods; this list may need to expand.
|
||||
'(nnir)))
|
||||
'(nnselect)))
|
||||
|
||||
;; remember that we've seen this group already
|
||||
(push group seen-groups)
|
||||
|
|
|
|||
2254
lisp/gnus/gnus-search.el
Normal file
2254
lisp/gnus/gnus-search.el
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -34,7 +34,8 @@
|
|||
(require 'gnus-range)
|
||||
(require 'gnus-cloud)
|
||||
|
||||
(autoload 'gnus-group-make-nnir-group "nnir")
|
||||
(autoload 'gnus-group-make-search-group "nnselect")
|
||||
(autoload 'gnus-group-make-permanent-search-group "nnselect")
|
||||
|
||||
(defcustom gnus-server-mode-hook nil
|
||||
"Hook run in `gnus-server-mode' buffers."
|
||||
|
|
@ -184,7 +185,7 @@ If nil, a faster, but more primitive, buffer is used instead."
|
|||
|
||||
"g" gnus-server-regenerate-server
|
||||
|
||||
"G" gnus-group-make-nnir-group
|
||||
"G" gnus-group-read-ephemeral-search-group
|
||||
|
||||
"z" gnus-server-compact-server
|
||||
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@
|
|||
(autoload 'gnus-article-outlook-unwrap-lines "deuglify" nil t)
|
||||
(autoload 'gnus-article-outlook-repair-attribution "deuglify" nil t)
|
||||
(autoload 'gnus-article-outlook-rearrange-citation "deuglify" nil t)
|
||||
(autoload 'nnir-article-rsv "nnir" nil nil 'macro)
|
||||
(autoload 'nnir-article-group "nnir" nil nil 'macro)
|
||||
(autoload 'nnselect-article-rsv "nnselect" nil nil)
|
||||
(autoload 'nnselect-article-group "nnselect" nil nil)
|
||||
|
||||
(defcustom gnus-kill-summary-on-exit t
|
||||
"If non-nil, kill the summary buffer when you exit from it.
|
||||
|
|
@ -111,8 +111,8 @@ If t, fetch all the available old headers."
|
|||
:type '(choice number
|
||||
(sexp :menu-tag "other" t)))
|
||||
|
||||
(defcustom gnus-refer-thread-use-nnir nil
|
||||
"Use nnir to search an entire server when referring threads. A
|
||||
(defcustom gnus-refer-thread-use-search nil
|
||||
"Search an entire server when referring threads. A
|
||||
nil value will only search for thread-related articles in the
|
||||
current group."
|
||||
:version "24.1"
|
||||
|
|
@ -844,6 +844,7 @@ controls how articles are sorted."
|
|||
(function-item gnus-article-sort-by-subject)
|
||||
(function-item gnus-article-sort-by-date)
|
||||
(function-item gnus-article-sort-by-score)
|
||||
(function-item gnus-article-sort-by-rsv)
|
||||
(function-item gnus-article-sort-by-random)
|
||||
(function :tag "other"))
|
||||
(boolean :tag "Reverse order"))))
|
||||
|
|
@ -887,6 +888,7 @@ subthreads, customize `gnus-subthread-sort-functions'."
|
|||
(function-item gnus-thread-sort-by-subject)
|
||||
(function-item gnus-thread-sort-by-date)
|
||||
(function-item gnus-thread-sort-by-score)
|
||||
(function-item gnus-thread-sort-by-rsv)
|
||||
(function-item gnus-thread-sort-by-most-recent-number)
|
||||
(function-item gnus-thread-sort-by-most-recent-date)
|
||||
(function-item gnus-thread-sort-by-random)
|
||||
|
|
@ -1388,12 +1390,12 @@ the normal Gnus MIME machinery."
|
|||
(?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
|
||||
(?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
|
||||
(?L gnus-tmp-lines ?s)
|
||||
(?Z (or (nnir-article-rsv (mail-header-number gnus-tmp-header))
|
||||
(?Z (or (nnselect-article-rsv (mail-header-number gnus-tmp-header))
|
||||
0) ?d)
|
||||
(?G (or (nnir-article-group (mail-header-number gnus-tmp-header))
|
||||
(?G (or (nnselect-article-group (mail-header-number gnus-tmp-header))
|
||||
"") ?s)
|
||||
(?g (or (gnus-group-short-name
|
||||
(nnir-article-group (mail-header-number gnus-tmp-header)))
|
||||
(nnselect-article-group (mail-header-number gnus-tmp-header)))
|
||||
"") ?s)
|
||||
(?O gnus-tmp-downloaded ?c)
|
||||
(?I gnus-tmp-indentation ?s)
|
||||
|
|
@ -1568,6 +1570,8 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
|
|||
|
||||
(defvar gnus-newsgroup-sparse nil)
|
||||
|
||||
(defvar gnus-newsgroup-selection nil)
|
||||
|
||||
(defvar gnus-current-article nil)
|
||||
(defvar gnus-article-current nil)
|
||||
(defvar gnus-current-headers nil)
|
||||
|
|
@ -1602,6 +1606,8 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
|
|||
gnus-newsgroup-undownloaded
|
||||
gnus-newsgroup-unsendable
|
||||
|
||||
gnus-newsgroup-selection
|
||||
|
||||
gnus-newsgroup-begin gnus-newsgroup-end
|
||||
gnus-newsgroup-last-rmail gnus-newsgroup-last-mail
|
||||
gnus-newsgroup-last-folder gnus-newsgroup-last-file
|
||||
|
|
@ -5022,6 +5028,17 @@ using some other form will lead to serious barfage."
|
|||
(gnus-article-sort-by-date
|
||||
(gnus-thread-header h1) (gnus-thread-header h2)))
|
||||
|
||||
(defsubst gnus-article-sort-by-rsv (h1 h2)
|
||||
"Sort articles by rsv."
|
||||
(when gnus-newsgroup-selection
|
||||
(< (nnselect-article-rsv (mail-header-number h1))
|
||||
(nnselect-article-rsv (mail-header-number h2)))))
|
||||
|
||||
(defun gnus-thread-sort-by-rsv (h1 h2)
|
||||
"Sort threads by root article rsv."
|
||||
(gnus-article-sort-by-rsv
|
||||
(gnus-thread-header h1) (gnus-thread-header h2)))
|
||||
|
||||
(defsubst gnus-article-sort-by-score (h1 h2)
|
||||
"Sort articles by root article score.
|
||||
Unscored articles will be counted as having a score of zero."
|
||||
|
|
@ -9007,9 +9024,9 @@ Return the number of articles fetched."
|
|||
(defun gnus-summary-refer-thread (&optional limit)
|
||||
"Fetch all articles in the current thread. For backends that
|
||||
know how to search for threads (currently only 'nnimap) a
|
||||
non-numeric prefix arg will use nnir to search the entire
|
||||
non-numeric prefix arg will search the entire
|
||||
server; without a prefix arg only the current group is
|
||||
searched. If the variable `gnus-refer-thread-use-nnir' is
|
||||
searched. If the variable `gnus-refer-thread-use-search' is
|
||||
non-nil the prefix arg has the reverse meaning. If no
|
||||
backend-specific 'request-thread function is available fetch
|
||||
LIMIT (the numerical prefix) old headers. If LIMIT is
|
||||
|
|
@ -9021,9 +9038,9 @@ non-numeric or nil fetch the number specified by the
|
|||
(gnus-inhibit-demon t)
|
||||
(gnus-summary-ignore-duplicates t)
|
||||
(gnus-read-all-available-headers t)
|
||||
(gnus-refer-thread-use-nnir
|
||||
(gnus-refer-thread-use-search
|
||||
(if (and (not (null limit)) (listp limit))
|
||||
(not gnus-refer-thread-use-nnir) gnus-refer-thread-use-nnir))
|
||||
(not gnus-refer-thread-use-search) gnus-refer-thread-use-search))
|
||||
(new-headers
|
||||
(if (gnus-check-backend-function
|
||||
'request-thread gnus-newsgroup-name)
|
||||
|
|
@ -9162,9 +9179,9 @@ non-numeric or nil fetch the number specified by the
|
|||
(dolist (method gnus-refer-article-method)
|
||||
(push (if (eq 'current method)
|
||||
gnus-current-select-method
|
||||
(if (eq 'nnir (car method))
|
||||
(if (eq 'nnselect (car method))
|
||||
(list
|
||||
'nnir
|
||||
'nnselect
|
||||
(or (cadr method)
|
||||
(gnus-method-to-server gnus-current-select-method)))
|
||||
method))
|
||||
|
|
|
|||
|
|
@ -1868,7 +1868,7 @@ total number of articles in the group.")
|
|||
:variable-default (mapcar
|
||||
(lambda (g) (list g t))
|
||||
'("delayed$" "drafts$" "queue$" "INBOX$"
|
||||
"^nnmairix:" "^nnir:" "archive"))
|
||||
"^nnmairix:" "^nnselect:" "archive"))
|
||||
:variable-document
|
||||
"Groups in which the registry should be turned off."
|
||||
:variable-group gnus-registry
|
||||
|
|
|
|||
|
|
@ -1797,17 +1797,17 @@ If LIMIT, first try to limit the search to the N last articles."
|
|||
(setq nnimap-status-string "Read-only server")
|
||||
nil)
|
||||
|
||||
(defvar gnus-refer-thread-use-nnir) ;; gnus-sum.el
|
||||
(defvar gnus-refer-thread-use-search) ;; gnus-sum.el
|
||||
(declare-function gnus-fetch-headers "gnus-sum"
|
||||
(articles &optional limit force-new dependencies))
|
||||
|
||||
(autoload 'nnir-search-thread "nnir")
|
||||
(autoload 'nnselect-search-thread "nnselect")
|
||||
|
||||
(deffoo nnimap-request-thread (header &optional group server)
|
||||
(when group
|
||||
(setq group (nnimap-decode-gnus-group group)))
|
||||
(if gnus-refer-thread-use-nnir
|
||||
(nnir-search-thread header)
|
||||
(if gnus-refer-thread-use-search
|
||||
(nnselect-search-thread header)
|
||||
(when (nnimap-change-group group server)
|
||||
(let* ((cmd (nnimap-make-thread-query header))
|
||||
(result (with-current-buffer (nnimap-buffer)
|
||||
|
|
@ -1819,6 +1819,20 @@ If LIMIT, first try to limit the search to the N last articles."
|
|||
(cdr (assoc "SEARCH" (cdr result))))))
|
||||
nil t))))))
|
||||
|
||||
(defun nnimap-make-thread-query (header)
|
||||
(let* ((id (mail-header-id header))
|
||||
(refs (split-string
|
||||
(or (mail-header-references header)
|
||||
"")))
|
||||
(value
|
||||
(format
|
||||
"(OR HEADER REFERENCES %S HEADER Message-Id %S)"
|
||||
id id)))
|
||||
(dolist (refid refs value)
|
||||
(setq value (format
|
||||
"(OR (OR HEADER Message-Id %S HEADER REFERENCES %S) %s)"
|
||||
refid refid value)))))
|
||||
|
||||
(defun nnimap-change-group (group &optional server no-reconnect read-only)
|
||||
"Change group to GROUP if non-nil.
|
||||
If SERVER is set, check that server is connected, otherwise retry
|
||||
|
|
@ -2212,21 +2226,6 @@ Return the server's response to the SELECT or EXAMINE command."
|
|||
group-art))
|
||||
nnimap-incoming-split-list)))
|
||||
|
||||
(defun nnimap-make-thread-query (header)
|
||||
(let* ((id (mail-header-id header))
|
||||
(refs (split-string
|
||||
(or (mail-header-references header)
|
||||
"")))
|
||||
(value
|
||||
(format
|
||||
"(OR HEADER REFERENCES %S HEADER Message-Id %S)"
|
||||
id id)))
|
||||
(dolist (refid refs value)
|
||||
(setq value (format
|
||||
"(OR (OR HEADER Message-Id %S HEADER REFERENCES %S) %s)"
|
||||
refid refid value)))))
|
||||
|
||||
|
||||
(provide 'nnimap)
|
||||
|
||||
;;; nnimap.el ends here
|
||||
|
|
|
|||
1927
lisp/gnus/nnir.el
1927
lisp/gnus/nnir.el
File diff suppressed because it is too large
Load diff
826
lisp/gnus/nnselect.el
Normal file
826
lisp/gnus/nnselect.el
Normal file
|
|
@ -0,0 +1,826 @@
|
|||
;;; nnselect.el --- a virtual group backend -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Andrew Cohen <cohen@andy.bu.edu>
|
||||
;; Keywords: news mail
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; GNU Emacs is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; GNU Emacs is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; This is a "virtual" backend that allows an aribtrary list of
|
||||
;; articles to be treated as a gnus group. An nnselect group uses an
|
||||
;; nnselect-spec group parameter to specify this list of
|
||||
;; articles. nnselect-spec is an alist with two keys:
|
||||
;; nnselect-function, whose value should be a function that returns
|
||||
;; the list of articles, and nnselect-args. The function will be
|
||||
;; applied to the arguments to generate the list of articles. The
|
||||
;; return value should be a vector, each element of which should in
|
||||
;; turn be a vector of three elements: a real prefixed group name, an
|
||||
;; article number in that group, and an integer score. The score is
|
||||
;; not used by nnselect but may be used by other code to help in
|
||||
;; sorting. Most functions will just chose a fixed number, such as
|
||||
;; 100, for this score.
|
||||
|
||||
;; 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:
|
||||
|
||||
;;; Setup:
|
||||
|
||||
|
||||
(require 'gnus-art)
|
||||
(require 'gnus-search)
|
||||
|
||||
(eval-when-compile (require 'cl-lib))
|
||||
|
||||
;; Set up the backend
|
||||
|
||||
(nnoo-declare nnselect)
|
||||
|
||||
(nnoo-define-basics nnselect)
|
||||
|
||||
(gnus-declare-backend "nnselect" 'post-mail 'virtual)
|
||||
|
||||
;;; Internal Variables:
|
||||
|
||||
(defvar gnus-inhibit-demon)
|
||||
(defvar gnus-message-group-art)
|
||||
|
||||
(defvar nnselect-artlist nil
|
||||
"Internal: stores the list of articles.")
|
||||
|
||||
|
||||
;; For future use
|
||||
(defvoo nnselect-directory gnus-directory
|
||||
"Directory for the nnselect backend.")
|
||||
|
||||
(defvoo nnselect-active-file
|
||||
(expand-file-name "nnselect-active" nnselect-directory)
|
||||
"nnselect active file.")
|
||||
|
||||
(defvoo nnselect-groups-file
|
||||
(expand-file-name "nnselect-newsgroups" nnselect-directory)
|
||||
"nnselect groups description file.")
|
||||
|
||||
;;; Helper routines.
|
||||
|
||||
(defun nnselect-group-server (group)
|
||||
(gnus-group-server group))
|
||||
|
||||
;; Data type article list.
|
||||
|
||||
(define-inline nnselect-artlist-length (artlist)
|
||||
(inline-quote (length ,artlist)))
|
||||
|
||||
(define-inline nnselect-artlist-article (artlist n)
|
||||
"Return from ARTLIST the Nth artitem (counting starting at 1)."
|
||||
(inline-quote (when (> ,n 0)
|
||||
(elt ,artlist (1- ,n)))))
|
||||
|
||||
(define-inline nnselect-artitem-group (artitem)
|
||||
"Return the group from the ARTITEM."
|
||||
(inline-quote (elt ,artitem 0)))
|
||||
|
||||
(define-inline nnselect-artitem-number (artitem)
|
||||
"Return the number from the ARTITEM."
|
||||
(inline-quote (elt ,artitem 1)))
|
||||
|
||||
(define-inline nnselect-artitem-rsv (artitem)
|
||||
"Return the Retrieval Status Value (RSV, score) from the ARTITEM."
|
||||
(inline-quote (elt ,artitem 2)))
|
||||
|
||||
(define-inline nnselect-article-group (article)
|
||||
"Return the group for ARTICLE."
|
||||
(inline-quote
|
||||
(nnselect-artitem-group (nnselect-artlist-article
|
||||
gnus-newsgroup-selection ,article))))
|
||||
|
||||
(define-inline nnselect-article-number (article)
|
||||
"Return the number for ARTICLE."
|
||||
(inline-quote (nnselect-artitem-number
|
||||
(nnselect-artlist-article
|
||||
gnus-newsgroup-selection ,article))))
|
||||
|
||||
(define-inline nnselect-article-rsv (article)
|
||||
"Return the rsv for ARTICLE."
|
||||
(inline-quote (nnselect-artitem-rsv
|
||||
(nnselect-artlist-article
|
||||
gnus-newsgroup-selection ,article))))
|
||||
|
||||
(define-inline nnselect-article-id (article)
|
||||
"Return the pair `(nnselect id . real id)' of ARTICLE."
|
||||
(inline-quote (cons ,article (nnselect-article-number ,article))))
|
||||
|
||||
(define-inline nnselect-categorize (sequence keyfunc &optional valuefunc)
|
||||
"Sorts a sequence into categories and returns a list of the form
|
||||
`((key1 (element11 element12)) (key2 (element21 element22))'.
|
||||
The category key for a member of the sequence is obtained
|
||||
as `(keyfunc member)' and the corresponding element is just
|
||||
`member' (or `(valuefunc member)' if `valuefunc' is non-nil)."
|
||||
(inline-letevals (sequence keyfunc valuefunc)
|
||||
(inline-quote (let ((valuefunc (or ,valuefunc 'identity))
|
||||
result)
|
||||
(unless (null ,sequence)
|
||||
(mapc
|
||||
(lambda (member)
|
||||
(let* ((key (funcall ,keyfunc member))
|
||||
(value (funcall valuefunc member))
|
||||
(kr (assoc key result)))
|
||||
(if kr
|
||||
(push value (cdr kr))
|
||||
(push (list key value) result))))
|
||||
(reverse ,sequence))
|
||||
result)))))
|
||||
|
||||
|
||||
;; (defmacro nnselect-categorize (sequence keyfunc &optional valuefunc)
|
||||
;; "Sorts a sequence into categories and returns a list of the form
|
||||
;; `((key1 (element11 element12)) (key2 (element21 element22))'.
|
||||
;; The category key for a member of the sequence is obtained
|
||||
;; as `(keyfunc member)' and the corresponding element is just
|
||||
;; `member' (or `(valuefunc member)' if `valuefunc' is non-nil)."
|
||||
;; (let ((key (make-symbol "key"))
|
||||
;; (value (make-symbol "value"))
|
||||
;; (result (make-symbol "result"))
|
||||
;; (valuefunc (or valuefunc 'identity)))
|
||||
;; `(unless (null ,sequence)
|
||||
;; (let (,result)
|
||||
;; (mapc
|
||||
;; (lambda (member)
|
||||
;; (let* ((,key (,keyfunc member))
|
||||
;; (,value (,valuefunc member))
|
||||
;; (kr (assoc ,key ,result)))
|
||||
;; (if kr
|
||||
;; (push ,value (cdr kr))
|
||||
;; (push (list ,key ,value) ,result))))
|
||||
;; (reverse ,sequence))
|
||||
;; ,result))))
|
||||
|
||||
(define-inline ids-by-group (articles)
|
||||
(inline-quote
|
||||
(nnselect-categorize ,articles 'nnselect-article-group
|
||||
'nnselect-article-id)))
|
||||
|
||||
(define-inline numbers-by-group (articles)
|
||||
(inline-quote
|
||||
(nnselect-categorize
|
||||
,articles 'nnselect-article-group 'nnselect-article-number)))
|
||||
|
||||
|
||||
;;; User Customizable Variables:
|
||||
|
||||
(defgroup nnselect nil
|
||||
"Virtual groups in Gnus with arbitrary selection methods."
|
||||
:group 'gnus)
|
||||
|
||||
(defcustom nnselect-retrieve-headers-override-function nil
|
||||
"A function that retrieves article headers for ARTICLES from GROUP.
|
||||
The retrieved headers should populate the `nntp-server-buffer'.
|
||||
Returns either the retrieved header format 'nov or 'headers.
|
||||
|
||||
If this variable is nil, or if the provided function returns nil,
|
||||
`gnus-retrieve-headers' will be called instead."
|
||||
:version "24.1" :type '(function) :group 'nnselect)
|
||||
|
||||
|
||||
;; Gnus backend interface functions.
|
||||
|
||||
(deffoo nnselect-open-server (server &optional definitions)
|
||||
;; Just set the server variables appropriately.
|
||||
(let ((backend (or (car (gnus-server-to-method server)) 'nnselect)))
|
||||
(nnoo-change-server backend server definitions)))
|
||||
|
||||
;; (deffoo nnselect-server-opened (&optional server)
|
||||
;; "Is SERVER the current virtual server?"
|
||||
;; (if (string-empty-p server)
|
||||
;; t
|
||||
;; (let ((backend (car (gnus-server-to-method server))))
|
||||
;; (nnoo-current-server-p (or backend 'nnselect) server))))
|
||||
|
||||
(deffoo nnselect-server-opened (&optional _server)
|
||||
t)
|
||||
|
||||
|
||||
(deffoo nnselect-request-group (group &optional server dont-check info)
|
||||
(let ((group (nnselect-possibly-change-group group server))
|
||||
length)
|
||||
;; Check for cached select result or run the selection and cache
|
||||
;; the result.
|
||||
(unless (and nnselect-artlist dont-check)
|
||||
(gnus-group-set-parameter
|
||||
group 'nnselect-artlist
|
||||
(setq nnselect-artlist
|
||||
(nnselect-run
|
||||
(gnus-group-get-parameter group 'nnselect-specs t))))
|
||||
(nnselect-request-update-info
|
||||
group (or info (gnus-get-info group))))
|
||||
(if (zerop (setq length (nnselect-artlist-length nnselect-artlist)))
|
||||
(progn
|
||||
(nnheader-report 'nnselect "Selection produced empty results.")
|
||||
(nnheader-insert ""))
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(nnheader-insert "211 %d %d %d %s\n"
|
||||
length ; total #
|
||||
1 ; first #
|
||||
length ; last #
|
||||
group)))) ; group name
|
||||
nnselect-artlist)
|
||||
|
||||
(deffoo nnselect-retrieve-headers (articles &optional _group _server fetch-old)
|
||||
(setq gnus-newsgroup-selection (or gnus-newsgroup-selection nnselect-artlist))
|
||||
(let ((gnus-inhibit-demon t)
|
||||
(gartids (ids-by-group articles))
|
||||
headers)
|
||||
(with-current-buffer nntp-server-buffer
|
||||
(pcase-dolist (`(,artgroup . ,artids) gartids)
|
||||
(let ((artlist (sort (mapcar 'cdr artids) '<))
|
||||
(gnus-override-method (gnus-find-method-for-group artgroup))
|
||||
(fetch-old
|
||||
(or
|
||||
(car-safe
|
||||
(gnus-group-find-parameter artgroup 'gnus-fetch-old-headers t))
|
||||
fetch-old))
|
||||
parsefunc)
|
||||
(erase-buffer)
|
||||
(pcase (setq gnus-headers-retrieved-by
|
||||
(or
|
||||
(and
|
||||
nnselect-retrieve-headers-override-function
|
||||
(funcall nnselect-retrieve-headers-override-function
|
||||
artlist artgroup))
|
||||
(gnus-retrieve-headers artlist artgroup fetch-old)))
|
||||
('nov
|
||||
(setq parsefunc 'nnheader-parse-nov))
|
||||
('headers
|
||||
(setq parsefunc 'nnheader-parse-head))
|
||||
(_ (error "Unknown header type %s while requesting articles \
|
||||
of group %s" gnus-headers-retrieved-by artgroup)))
|
||||
(goto-char (point-min))
|
||||
(while (not (eobp))
|
||||
(let* ((novitem (funcall parsefunc))
|
||||
(artno (and novitem
|
||||
(mail-header-number novitem)))
|
||||
(art (car (rassq artno artids))))
|
||||
(when art
|
||||
(mail-header-set-number novitem art)
|
||||
(push novitem headers))
|
||||
(forward-line 1)))))
|
||||
(setq headers
|
||||
(sort headers
|
||||
(lambda (x y)
|
||||
(< (mail-header-number x) (mail-header-number y)))))
|
||||
(erase-buffer)
|
||||
(mapc 'nnheader-insert-nov headers)
|
||||
'nov)))
|
||||
|
||||
(declare-function gnus-search-run-query "gnus-search" (specs))
|
||||
(deffoo nnselect-request-article (article &optional _group server to-buffer)
|
||||
(let* ((gnus-override-method nil)
|
||||
servers group-art artlist)
|
||||
(if (numberp article)
|
||||
(with-current-buffer gnus-summary-buffer
|
||||
(unless (zerop (nnselect-artlist-length
|
||||
gnus-newsgroup-selection))
|
||||
(setq group-art (cons (nnselect-article-group article)
|
||||
(nnselect-article-number article)))))
|
||||
;; message-id: either coming from a referral or a pseudo-article
|
||||
;; 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)))
|
||||
(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)))
|
||||
(gnus-articles-in-thread thread)))))
|
||||
(setq servers (list (list server))))
|
||||
(setq artlist
|
||||
(gnus-search-run-query
|
||||
(list
|
||||
(cons 'search-query-spec
|
||||
(list (cons 'query `((id . ,article)))))
|
||||
(cons 'search-group-spec servers))))
|
||||
(unless (zerop (nnselect-artlist-length artlist))
|
||||
(setq
|
||||
group-art
|
||||
(cons
|
||||
(nnselect-artitem-group (nnselect-artlist-article artlist 1))
|
||||
(nnselect-artitem-number (nnselect-artlist-article artlist 1))))))
|
||||
(when (numberp (cdr group-art))
|
||||
(message "Requesting article %d from group %s"
|
||||
(cdr group-art) (car group-art))
|
||||
(if to-buffer
|
||||
(with-current-buffer to-buffer
|
||||
(let ((gnus-article-decode-hook nil))
|
||||
(gnus-request-article-this-buffer
|
||||
(cdr group-art) (car group-art))))
|
||||
(gnus-request-article (cdr group-art) (car group-art)))
|
||||
group-art)))
|
||||
|
||||
(deffoo nnselect-request-move-article
|
||||
(article _group _server accept-form &optional last _internal-move-group)
|
||||
;; is this necessary?
|
||||
;; (nnselect-possibly-change-group group server)
|
||||
(let* ((artgroup (nnselect-article-group article))
|
||||
(artnumber (nnselect-article-number article))
|
||||
(to-newsgroup (nth 1 accept-form))
|
||||
(to-method (gnus-find-method-for-group to-newsgroup))
|
||||
(from-method (gnus-find-method-for-group artgroup))
|
||||
(move-is-internal (gnus-server-equal from-method to-method)))
|
||||
(unless (gnus-check-backend-function
|
||||
'request-move-article artgroup)
|
||||
(error "The group %s does not support article moving" artgroup))
|
||||
(gnus-request-move-article
|
||||
artnumber
|
||||
artgroup
|
||||
(nth 1 from-method)
|
||||
accept-form
|
||||
last
|
||||
(and move-is-internal
|
||||
to-newsgroup ; Not respooling
|
||||
(gnus-group-real-name to-newsgroup)))))
|
||||
|
||||
|
||||
(deffoo nnselect-request-expire-articles
|
||||
(articles _group &optional _server force)
|
||||
;; is this necessary?
|
||||
;; (nnselect-possibly-change-group group server)
|
||||
(if force
|
||||
(let (not-expired)
|
||||
(pcase-dolist (`(,artgroup . ,artids) (ids-by-group articles))
|
||||
(let ((artlist (sort (mapcar 'cdr artids) '<)))
|
||||
(unless (gnus-check-backend-function 'request-expire-articles
|
||||
artgroup)
|
||||
(error "Group %s does not support article expiration" artgroup))
|
||||
(unless (gnus-check-server (gnus-find-method-for-group artgroup))
|
||||
(error "Couldn't open server for group %s" artgroup))
|
||||
(push (mapcar #'(lambda (art)
|
||||
(car (rassq art artids)))
|
||||
(gnus-request-expire-articles
|
||||
artlist artgroup force))
|
||||
not-expired)))
|
||||
(sort (delq nil not-expired) '<))
|
||||
articles))
|
||||
|
||||
(deffoo nnselect-warp-to-article ()
|
||||
;; is this necessary?
|
||||
;; (nnselect-possibly-change-group gnus-newsgroup-name)
|
||||
(let* ((cur (if (> (gnus-summary-article-number) 0)
|
||||
(gnus-summary-article-number)
|
||||
(error "Can't warp to a pseudo-article")))
|
||||
(artgroup (nnselect-article-group cur))
|
||||
(artnumber (nnselect-article-number cur))
|
||||
(_quit-config (gnus-ephemeral-group-p gnus-newsgroup-name)))
|
||||
|
||||
;; what should we do here? we could leave all the buffers around
|
||||
;; and assume that we have to exit from them one by one. or we can
|
||||
;; try to clean up directly
|
||||
|
||||
;;first exit from the nnselect summary buffer.
|
||||
; (gnus-summary-exit)
|
||||
;; and if the nnselect summary buffer in turn came from another
|
||||
;; summary buffer we have to clean that summary up too.
|
||||
; (when (not (eq (cdr quit-config) 'group))
|
||||
; (gnus-summary-exit))
|
||||
(gnus-summary-read-group-1 artgroup t t nil
|
||||
nil (list artnumber))))
|
||||
|
||||
|
||||
;; we pass this through to the real group in case it wants to adjust
|
||||
;; the mark. We also use this to mark an article expirable iff it is
|
||||
;; expirable in the real group.
|
||||
(deffoo nnselect-request-update-mark (_group article mark)
|
||||
(let* ((artgroup (nnselect-article-group article))
|
||||
(artnumber (nnselect-article-number article))
|
||||
(gmark (gnus-request-update-mark artgroup artnumber mark)))
|
||||
(when (and artnumber
|
||||
(memq mark gnus-auto-expirable-marks)
|
||||
(= mark gmark)
|
||||
(gnus-group-auto-expirable-p artgroup))
|
||||
(setq gmark gnus-expirable-mark))
|
||||
gmark))
|
||||
|
||||
(deffoo nnselect-request-set-mark (_group actions &optional _server)
|
||||
;; is this necessary?
|
||||
;; (nnselect-possibly-change-group group server)
|
||||
(mapc
|
||||
(lambda (request) (gnus-request-set-mark (car request) (cdr request)))
|
||||
(nnselect-categorize
|
||||
(cl-mapcan
|
||||
(lambda (act)
|
||||
(cl-destructuring-bind (range action marks) act
|
||||
(mapcar
|
||||
(lambda (artgroup)
|
||||
(list (car artgroup)
|
||||
(gnus-compress-sequence (sort (cdr artgroup) '<))
|
||||
action marks))
|
||||
(numbers-by-group
|
||||
(gnus-uncompress-range range)))))
|
||||
actions)
|
||||
'car 'cdr)))
|
||||
|
||||
(deffoo nnselect-request-update-info (group info &optional server)
|
||||
(let ((group (nnselect-possibly-change-group group server))
|
||||
(gnus-newsgroup-selection (or gnus-newsgroup-selection
|
||||
nnselect-artlist)))
|
||||
(gnus-info-set-marks info nil)
|
||||
(gnus-info-set-read info nil)
|
||||
(pcase-dolist (`(,artgroup . ,nartids)
|
||||
(ids-by-group
|
||||
(number-sequence 1 (nnselect-artlist-length
|
||||
gnus-newsgroup-selection))))
|
||||
(let* ((gnus-newsgroup-active nil)
|
||||
(artids (cl-sort nartids '< :key 'car))
|
||||
(group-info (gnus-get-info artgroup))
|
||||
(marks (gnus-info-marks group-info))
|
||||
(read (gnus-uncompress-sequence (gnus-info-read group-info))))
|
||||
(gnus-atomic-progn
|
||||
(gnus-info-set-read
|
||||
info
|
||||
(gnus-add-to-range
|
||||
(gnus-info-read info)
|
||||
(delq nil
|
||||
(mapcar
|
||||
#'(lambda (art)
|
||||
(when (member (cdr art) read) (car art)))
|
||||
artids))))
|
||||
(pcase-dolist (`(,type . ,range) marks)
|
||||
(setq range (gnus-uncompress-sequence range))
|
||||
(gnus-add-marked-articles
|
||||
group type
|
||||
(delq nil
|
||||
(mapcar
|
||||
#'(lambda (art)
|
||||
(when (member (cdr art) range)
|
||||
(car art))) artids)))))))
|
||||
(gnus-set-active group (cons 1 (nnselect-artlist-length
|
||||
gnus-newsgroup-selection)))))
|
||||
|
||||
(declare-function gnus-search-run-query "gnus-search" (specs))
|
||||
(deffoo nnselect-request-thread (header &optional group server)
|
||||
(let ((group (nnselect-possibly-change-group group server)) ;; necessary?
|
||||
;; find the best group for the originating article. if its a
|
||||
;; pseudo-article look for real articles in the same thread
|
||||
;; and see where they come from.
|
||||
(artgroup (nnselect-article-group
|
||||
(if (> (mail-header-number header) 0)
|
||||
(mail-header-number header)
|
||||
(with-current-buffer gnus-summary-buffer
|
||||
(if (> (gnus-summary-article-number) 0)
|
||||
(gnus-summary-article-number)
|
||||
(let ((thread
|
||||
(gnus-id-to-thread (mail-header-id header))))
|
||||
(when thread
|
||||
(cl-some #'(lambda (x)
|
||||
(when (and x (> x 0)) x))
|
||||
(gnus-articles-in-thread thread))))))))))
|
||||
;; Check if search-based thread referral is permitted, and
|
||||
;; possible.
|
||||
(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))))))
|
||||
(ids (cons (mail-header-id header)
|
||||
(split-string
|
||||
(or (mail-header-references header)
|
||||
""))))
|
||||
(query-spec
|
||||
(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
|
||||
(gnus-search-run-query
|
||||
(list (cons 'search-query-spec query-spec)
|
||||
(cons 'search-group-spec group-spec))))
|
||||
old-arts seq
|
||||
headers)
|
||||
(mapc
|
||||
#'(lambda (article)
|
||||
(if
|
||||
(setq seq
|
||||
(cl-position article
|
||||
gnus-newsgroup-selection :test 'equal))
|
||||
(push (1+ seq) old-arts)
|
||||
(setq gnus-newsgroup-selection
|
||||
(vconcat gnus-newsgroup-selection (vector article)))
|
||||
(cl-incf last)))
|
||||
new-nnselect-artlist)
|
||||
(setq headers
|
||||
(gnus-fetch-headers
|
||||
(append (sort old-arts '<)
|
||||
(number-sequence first last)) nil t))
|
||||
(gnus-group-set-parameter
|
||||
group
|
||||
'nnselect-artlist
|
||||
gnus-newsgroup-selection)
|
||||
(when (>= last first)
|
||||
(let (new-marks)
|
||||
(pcase-dolist (`(,artgroup . ,artids)
|
||||
(ids-by-group (number-sequence first last)))
|
||||
(pcase-dolist (`(,type . ,marked)
|
||||
(gnus-info-marks (gnus-get-info artgroup)))
|
||||
(setq marked (gnus-uncompress-sequence marked))
|
||||
(when (setq new-marks
|
||||
(delq nil
|
||||
(mapcar
|
||||
#'(lambda (art)
|
||||
(when (member (cdr art) marked)
|
||||
(car art)))
|
||||
artids)))
|
||||
(nconc
|
||||
(symbol-value (intern (format "gnus-newsgroup-%s"
|
||||
(car (rassq type gnus-article-mark-lists)))))
|
||||
new-marks)))))
|
||||
(setq gnus-newsgroup-active
|
||||
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection)))
|
||||
(gnus-set-active
|
||||
group
|
||||
(cons 1 (nnselect-artlist-length gnus-newsgroup-selection))))
|
||||
headers)
|
||||
;; If we can't or won't use search, just warp to the original
|
||||
;; article group and punt back to gnus-summary-refer-thread.
|
||||
(and (gnus-warp-to-article) (gnus-summary-refer-thread)))))
|
||||
|
||||
|
||||
|
||||
(deffoo nnselect-close-group (group &optional server)
|
||||
(let ((group (nnselect-possibly-change-group group server)))
|
||||
(unless gnus-group-is-exiting-without-update-p
|
||||
(nnselect-push-info group))
|
||||
(setq nnselect-artlist nil)
|
||||
(when (gnus-ephemeral-group-p group)
|
||||
(gnus-kill-ephemeral-group group)
|
||||
(setq gnus-ephemeral-servers
|
||||
(assq-delete-all 'nnselect gnus-ephemeral-servers)))))
|
||||
|
||||
|
||||
(deffoo nnselect-request-create-group (group &optional _server args)
|
||||
(message "Creating nnselect group %s" group)
|
||||
(let* ((group (gnus-group-prefixed-name group '(nnselect "nnselect")))
|
||||
(specs (assq 'nnselect-specs args))
|
||||
(function-spec
|
||||
(or (alist-get 'nnselect-function specs)
|
||||
(intern (completing-read "Function: " obarray #'functionp))))
|
||||
(args-spec
|
||||
(or (alist-get 'nnselect-args specs)
|
||||
(read-from-minibuffer "Args: " nil nil t nil "nil")))
|
||||
(nnselect-specs (list (cons 'nnselect-function function-spec)
|
||||
(cons 'nnselect-args args-spec))))
|
||||
(gnus-group-set-parameter group 'nnselect-specs nnselect-specs)
|
||||
(gnus-group-set-parameter
|
||||
group 'nnselect-artlist
|
||||
(or (alist-get 'nnselect-artlist args)
|
||||
(nnselect-run nnselect-specs)))
|
||||
(nnselect-request-update-info group (gnus-get-info group)))
|
||||
t)
|
||||
|
||||
|
||||
(deffoo nnselect-request-type (_group &optional article)
|
||||
(if (and (numberp article) (> article 0))
|
||||
(gnus-request-type
|
||||
(nnselect-article-group article) (nnselect-article-number article))
|
||||
'unknown))
|
||||
|
||||
(deffoo nnselect-request-post (&optional _server)
|
||||
(if (not gnus-message-group-art)
|
||||
(nnheader-report 'nnselect "Can't post to an nnselect group")
|
||||
(gnus-request-post
|
||||
(gnus-find-method-for-group
|
||||
(nnselect-article-group (cdr gnus-message-group-art))))))
|
||||
|
||||
(deffoo nnselect-request-rename-group (_group _new-name &optional _server)
|
||||
t)
|
||||
|
||||
(deffoo nnselect-request-scan (_group _method)
|
||||
t)
|
||||
|
||||
(deffoo nnselect-request-list (&optional _server)
|
||||
t)
|
||||
|
||||
;; Add any undefined required backend functions
|
||||
|
||||
(nnoo-define-skeleton nnselect)
|
||||
|
||||
;;; Util Code:
|
||||
|
||||
(defun gnus-nnselect-group-p (group)
|
||||
"Say whether GROUP is nnselect or not."
|
||||
(or (and (gnus-group-prefixed-p group)
|
||||
(eq 'nnselect (car (gnus-find-method-for-group group))))
|
||||
(eq 'nnselect (car gnus-command-method))))
|
||||
|
||||
|
||||
(defun nnselect-run (specs)
|
||||
"Apply FUNCTION to ARGS and return an article list."
|
||||
(let ((func (alist-get 'nnselect-function specs))
|
||||
(args (alist-get 'nnselect-args specs)))
|
||||
(funcall func args)))
|
||||
|
||||
|
||||
(defun nnselect-possibly-change-group (group &optional _server)
|
||||
"If GROUP method for SERVER is `nnselect' install the
|
||||
`nnselect-artlist'. Return the fully prefixed group name."
|
||||
;; (or (not server) (nnselect-server-opened server)
|
||||
;; (nnselect-open-server server))
|
||||
(let ((group (gnus-group-prefixed-name
|
||||
(gnus-group-short-name group) '(nnselect "nnselect"))))
|
||||
(when (gnus-nnselect-group-p group)
|
||||
(setq nnselect-artlist (gnus-group-get-parameter
|
||||
group
|
||||
'nnselect-artlist t)))
|
||||
group))
|
||||
|
||||
|
||||
(declare-function gnus-registry-get-id-key "gnus-registry"
|
||||
(id key))
|
||||
(defun nnselect-search-thread (header)
|
||||
"Make an nnselect group containing the thread with 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-read-ephemeral-group
|
||||
(concat "nnselect-" (message-unique-id))
|
||||
(list 'nnselect "nnselect")
|
||||
nil
|
||||
(cons (current-buffer) gnus-current-window-configuration)
|
||||
; nil
|
||||
nil nil
|
||||
(list
|
||||
(cons 'nnselect-specs
|
||||
(list
|
||||
(cons 'nnselect-function 'gnus-search-run-query)
|
||||
(cons 'nnselect-args
|
||||
(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)))))
|
||||
|
||||
|
||||
|
||||
(defun nnselect-push-info (group)
|
||||
"Copy read and article mark info from the nnselect group to the
|
||||
originating groups."
|
||||
(let ((select-unreads (numbers-by-group gnus-newsgroup-unreads))
|
||||
(select-reads (numbers-by-group
|
||||
(gnus-uncompress-range
|
||||
(gnus-info-read (gnus-get-info group)))))
|
||||
(select-unseen (numbers-by-group gnus-newsgroup-unseen))
|
||||
(gnus-newsgroup-active nil)
|
||||
mark-list type-list)
|
||||
(pcase-dolist (`(,mark . ,type) gnus-article-mark-lists)
|
||||
(when (setq type-list
|
||||
(symbol-value (intern (format "gnus-newsgroup-%s" mark))))
|
||||
(push (cons type
|
||||
(numbers-by-group
|
||||
(gnus-uncompress-range type-list))) mark-list)))
|
||||
(pcase-dolist (`(,artgroup . ,artlist)
|
||||
(numbers-by-group gnus-newsgroup-articles))
|
||||
(let* ((group-info (gnus-get-info artgroup))
|
||||
(old-unread (gnus-list-of-unread-articles artgroup))
|
||||
newmarked)
|
||||
(when group-info
|
||||
(pcase-dolist (`(,_mark . ,type) gnus-article-mark-lists)
|
||||
(let ((select-type
|
||||
(sort
|
||||
(cdr (assoc artgroup (alist-get type mark-list)))
|
||||
'<)) list)
|
||||
(setq list
|
||||
(gnus-uncompress-range
|
||||
(gnus-add-to-range
|
||||
(gnus-remove-from-range
|
||||
(alist-get type (gnus-info-marks group-info))
|
||||
artlist)
|
||||
select-type)))
|
||||
|
||||
(when list
|
||||
;; Get rid of the entries of the articles that have the
|
||||
;; default score.
|
||||
(when (and (eq type 'score)
|
||||
gnus-save-score
|
||||
list)
|
||||
(let* ((arts list)
|
||||
(prev (cons nil list))
|
||||
(all prev))
|
||||
(while arts
|
||||
(if (or (not (consp (car arts)))
|
||||
(= (cdar arts) gnus-summary-default-score))
|
||||
(setcdr prev (cdr arts))
|
||||
(setq prev arts))
|
||||
(setq arts (cdr arts)))
|
||||
(setq list (cdr all)))))
|
||||
|
||||
(when (or (eq (gnus-article-mark-to-type type) 'list)
|
||||
(eq (gnus-article-mark-to-type type) 'range))
|
||||
(setq list
|
||||
(gnus-compress-sequence (sort list '<) t)))
|
||||
|
||||
;; When exiting the group, everything that's previously been
|
||||
;; unseen is now seen.
|
||||
(when (eq type 'seen)
|
||||
(setq list (gnus-range-add
|
||||
list (cdr (assoc artgroup select-unseen)))))
|
||||
|
||||
(when (or list (eq type 'unexist))
|
||||
(push (cons type list) newmarked))))
|
||||
|
||||
(gnus-atomic-progn
|
||||
;; Enter these new marks into the info of the group.
|
||||
(if (nthcdr 3 group-info)
|
||||
(setcar (nthcdr 3 group-info) newmarked)
|
||||
;; Add the marks lists to the end of the info.
|
||||
(when newmarked
|
||||
(setcdr (nthcdr 2 group-info) (list newmarked))))
|
||||
|
||||
;; Cut off the end of the info if there's nothing else there.
|
||||
(let ((i 5))
|
||||
(while (and (> i 2)
|
||||
(not (nth i group-info)))
|
||||
(when (nthcdr (cl-decf i) group-info)
|
||||
(setcdr (nthcdr i group-info) nil))))
|
||||
|
||||
;; update read and unread
|
||||
(gnus-update-read-articles
|
||||
artgroup
|
||||
(gnus-uncompress-range
|
||||
(gnus-add-to-range
|
||||
(gnus-remove-from-range
|
||||
old-unread
|
||||
(cdr (assoc artgroup select-reads)))
|
||||
(sort (cdr (assoc artgroup select-unreads)) '<))))
|
||||
(gnus-get-unread-articles-in-group
|
||||
group-info (gnus-active artgroup) t)
|
||||
(gnus-group-update-group artgroup t)))))))
|
||||
|
||||
(declare-function gnus-registry-get-id-key "gnus-registry" (id key))
|
||||
|
||||
(defun gnus-summary-make-search-group (extra-parms)
|
||||
"Search a group from the summary buffer."
|
||||
(interactive "P")
|
||||
(gnus-warp-to-article)
|
||||
(let ((spec
|
||||
(list
|
||||
(cons 'search-group-spec
|
||||
(list (list
|
||||
(gnus-group-server gnus-newsgroup-name)
|
||||
gnus-newsgroup-name))))))
|
||||
(gnus-group-make-search-group extra-parms spec)))
|
||||
|
||||
;; The end.
|
||||
(provide 'nnselect)
|
||||
|
||||
;;; nnselect.el ends here
|
||||
|
|
@ -69,17 +69,15 @@
|
|||
"^\\*\\*\\* Starting TLS handshake\n\\)*"
|
||||
"\\)")
|
||||
"Regexp matching end of TLS client informational messages.
|
||||
Client data stream begins after the last character matched by
|
||||
this. The default matches `openssl s_client' (version 0.9.8c)
|
||||
and `gnutls-cli' (version 2.0.1) output."
|
||||
Client data stream begins after the last character this matches.
|
||||
The default matches the output of \"gnutls-cli\" (version 2.0.1)."
|
||||
:version "22.2"
|
||||
:type 'regexp
|
||||
:group 'tls)
|
||||
|
||||
(defcustom tls-program
|
||||
'("gnutls-cli --x509cafile %t -p %p %h"
|
||||
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"
|
||||
"openssl s_client -connect %h:%p -no_ssl2 -ign_eof")
|
||||
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3")
|
||||
"List of strings containing commands to start TLS stream to a host.
|
||||
Each entry in the list is tried until a connection is successful.
|
||||
%h is replaced with the server hostname, %p with the port to
|
||||
|
|
@ -94,24 +92,21 @@ successful negotiation."
|
|||
'(choice
|
||||
(const :tag "Default list of commands"
|
||||
("gnutls-cli --x509cafile %t -p %p %h"
|
||||
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"
|
||||
"openssl s_client -CAfile %t -connect %h:%p -no_ssl2 -ign_eof"))
|
||||
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"))
|
||||
(list :tag "Choose commands"
|
||||
:value
|
||||
("gnutls-cli --x509cafile %t -p %p %h"
|
||||
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3"
|
||||
"openssl s_client -connect %h:%p -no_ssl2 -ign_eof")
|
||||
"gnutls-cli --x509cafile %t -p %p %h --protocols ssl3")
|
||||
(set :inline t
|
||||
;; FIXME: add brief `:tag "..."' descriptions.
|
||||
;; (repeat :inline t :tag "Other" (string))
|
||||
;; No trust check:
|
||||
(const "gnutls-cli --insecure -p %p %h")
|
||||
(const "gnutls-cli --insecure -p %p %h --protocols ssl3")
|
||||
(const "openssl s_client -connect %h:%p -no_ssl2 -ign_eof"))
|
||||
(const "gnutls-cli --insecure -p %p %h --protocols ssl3"))
|
||||
(repeat :inline t :tag "Other" (string)))
|
||||
(list :tag "List of commands"
|
||||
(repeat :tag "Command" (string))))
|
||||
:version "22.1"
|
||||
:version "26.1" ; remove s_client
|
||||
:group 'tls)
|
||||
|
||||
(defcustom tls-process-connection-type nil
|
||||
|
|
@ -122,8 +117,8 @@ successful negotiation."
|
|||
|
||||
(defcustom tls-success "- Handshake was completed\\|SSL handshake has read "
|
||||
"Regular expression indicating completed TLS handshakes.
|
||||
The default is what GnuTLS's \"gnutls-cli\" or OpenSSL's
|
||||
\"openssl s_client\" outputs."
|
||||
The default is what GnuTLS's \"gnutls-cli\" outputs."
|
||||
;; or OpenSSL's \"openssl s_client\"
|
||||
:version "22.1"
|
||||
:type 'regexp
|
||||
:group 'tls)
|
||||
|
|
@ -138,8 +133,7 @@ consider trustworthy, e.g.:
|
|||
|
||||
\(setq tls-program
|
||||
\\='(\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h\"
|
||||
\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h --protocols ssl3\"
|
||||
\"openssl s_client -connect %h:%p -CAfile /etc/ssl/certs/ca-certificates.crt -no_ssl2 -ign_eof\"))"
|
||||
\"gnutls-cli --x509cafile /etc/ssl/certs/ca-certificates.crt -p %p %h --protocols ssl3\"))"
|
||||
:type '(choice (const :tag "Always" t)
|
||||
(const :tag "Never" nil)
|
||||
(const :tag "Ask" ask))
|
||||
|
|
@ -149,9 +143,9 @@ consider trustworthy, e.g.:
|
|||
(defcustom tls-untrusted
|
||||
"- Peer's certificate is NOT trusted\\|Verify return code: \\([^0] \\|.[^ ]\\)"
|
||||
"Regular expression indicating failure of TLS certificate verification.
|
||||
The default is what GnuTLS's \"gnutls-cli\" or OpenSSL's
|
||||
\"openssl s_client\" return in the event of unsuccessful
|
||||
verification."
|
||||
The default is what GnuTLS's \"gnutls-cli\" returns in the event of
|
||||
unsuccessful verification."
|
||||
;; or OpenSSL's \"openssl s_client\"
|
||||
:type 'regexp
|
||||
:version "23.1" ;; No Gnus
|
||||
:group 'tls)
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ - (void)dealloc
|
|||
planes[1][i] = gg;
|
||||
planes[2][i] = bb;
|
||||
}
|
||||
xbm_fg = ((rr << 16) & 0xff) + ((gg << 8) & 0xff) + (bb & 0xff);
|
||||
xbm_fg = ((rr << 16) & 0xff0000) + ((gg << 8) & 0xff00) + (bb & 0xff);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
|
|
|||
BIN
test/data/image/blank-100x200.png
Normal file
BIN
test/data/image/blank-100x200.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 423 B |
99
test/lisp/gnus/search-tests.el
Normal file
99
test/lisp/gnus/search-tests.el
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
;;; gnus-search-tests.el --- Tests for Gnus' search routines -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2017 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: Eric Abrahamsen <eric@ericabrahamsen.net>
|
||||
;; Keywords:
|
||||
|
||||
;; 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Tests for the search parsing, search engines, and their
|
||||
;; transformations.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'ert)
|
||||
(require 'gnus-search)
|
||||
|
||||
(ert-deftest gnus-s-parse ()
|
||||
"Test basic structural parsing."
|
||||
(let ((pairs
|
||||
'(("string" . ("string"))
|
||||
("from:john" . ((from . "john")))
|
||||
("here and there" . ("here" and "there"))
|
||||
("here or there" . ((or "here" "there")))
|
||||
("here (there or elsewhere)" . ("here" ((or "there" "elsewhere"))))
|
||||
("here not there" . ("here" (not "there")))
|
||||
("from:boss or not vacation" . ((or (from . "boss") (not "vacation")))))))
|
||||
(dolist (p pairs)
|
||||
(should (equal (gnus-search-parse-query (car p)) (cdr p))))))
|
||||
|
||||
(ert-deftest gnus-s-expand-keyword ()
|
||||
"Test expansion of keywords"
|
||||
(let ((gnus-search-expandable-keys
|
||||
(default-value 'gnus-search-expandable-keys))
|
||||
(pairs
|
||||
'(("su" . "subject")
|
||||
("f" . "from")
|
||||
("co-f" . "contact-from"))))
|
||||
(dolist (p pairs)
|
||||
(should (equal (gnus-search-query-expand-key (car p))
|
||||
(cdr p))))
|
||||
(should-error (gnus-search-query-expand-key "s")
|
||||
:type 'gnus-search-parse-error)
|
||||
(should-error (gnus-search-query-expand-key "c-f")
|
||||
:type 'gnus-search-parse-error)))
|
||||
|
||||
(ert-deftest gnus-s-parse-date ()
|
||||
"Test parsing of date expressions."
|
||||
(let ((rel-date (encode-time 0 0 0 15 4 2017))
|
||||
(pairs
|
||||
'(("January" . (nil 1 nil))
|
||||
("2017" . (nil nil 2017))
|
||||
("15" . (15 nil nil))
|
||||
("January 15" . (15 1 nil))
|
||||
("tuesday" . (11 4 2017))
|
||||
("1d" . (14 4 2017))
|
||||
("1w" . (8 4 2017)))))
|
||||
(dolist (p pairs)
|
||||
(should (equal (gnus-search-query-parse-date (car p) rel-date)
|
||||
(cdr p))))))
|
||||
|
||||
(ert-deftest gnus-s-delimited-string ()
|
||||
"Test proper functioning of `gnus-search-query-return-string'."
|
||||
(with-temp-buffer
|
||||
(insert "one\ntwo words\nthree \"words with quotes\"\n\"quotes at start\"\n/alternate \"quotes\"/\n(more bits)")
|
||||
(goto-char (point-min))
|
||||
(should (string= (gnus-search-query-return-string)
|
||||
"one"))
|
||||
(forward-line)
|
||||
(should (string= (gnus-search-query-return-string)
|
||||
"two"))
|
||||
(forward-line)
|
||||
(should (string= (gnus-search-query-return-string)
|
||||
"three"))
|
||||
(forward-line)
|
||||
(should (string= (gnus-search-query-return-string "\"")
|
||||
"\"quotes at start\""))
|
||||
(forward-line)
|
||||
(should (string= (gnus-search-query-return-string "/")
|
||||
"/alternate \"quotes\"/"))
|
||||
(forward-line)
|
||||
(should (string= (gnus-search-query-return-string ")" t)
|
||||
"more bits"))))
|
||||
|
||||
(provide 'gnus-search-tests)
|
||||
;;; search-tests.el ends here
|
||||
|
|
@ -22,15 +22,21 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(defmacro im-should (form)
|
||||
`(unless ,form
|
||||
(error "%s didn't succeed" ',form)))
|
||||
(defmacro im-should (image width height &rest props)
|
||||
`(let ((im (im-image ,image ,@props)))
|
||||
(unless (im-compare im ,width ,height)
|
||||
(error "%s didn't succeed; size is %s"
|
||||
',props (image-size im t)))))
|
||||
|
||||
(defun im-image (&rest props)
|
||||
(defun im-image (type &rest props)
|
||||
(let ((image-scaling-factor 1))
|
||||
(apply
|
||||
#'create-image
|
||||
(expand-file-name "test/data/image/blank-200x100.png" source-directory)
|
||||
(expand-file-name
|
||||
(if (eq type :w)
|
||||
"test/data/image/blank-200x100.png"
|
||||
"test/data/image/blank-100x200.png")
|
||||
source-directory)
|
||||
'imagemagick nil props)))
|
||||
|
||||
(defun im-compare (image width height)
|
||||
|
|
@ -41,24 +47,46 @@
|
|||
(defun image-size-tests ()
|
||||
(unless (imagemagick-types)
|
||||
(error "This only makes sense if ImageMagick is installed"))
|
||||
;; Test the image that's wider than it is tall.
|
||||
;; Default sizes.
|
||||
(im-should (im-compare (im-image) 200 100))
|
||||
(im-should :w 200 100)
|
||||
;; Changing one dimension changes the other.
|
||||
(im-should (im-compare (im-image :width 100) 100 50))
|
||||
(im-should (im-compare (im-image :height 50) 100 50))
|
||||
(im-should :w 100 50 :width 100)
|
||||
(im-should :w 100 50 :height 50)
|
||||
;; The same with :max-width etc.
|
||||
(im-should (im-compare (im-image :max-width 100) 100 50))
|
||||
(im-should (im-compare (im-image :max-height 50) 100 50))
|
||||
(im-should :w 100 50 :max-width 100)
|
||||
(im-should :w 100 50 :max-height 50)
|
||||
;; :width wins over :max-width etc
|
||||
(im-should (im-compare (im-image :width 300 :max-width 100) 300 150))
|
||||
(im-should (im-compare (im-image :height 200 :max-height 100) 400 200))
|
||||
(im-should :w 300 150 :width 300 :max-width 100)
|
||||
(im-should :w 400 200 :height 200 :max-height 100)
|
||||
;; Specifying both width and height is fine.
|
||||
(im-should (im-compare (im-image :width 300 :height 50) 300 50))
|
||||
(im-should :w 300 50 :width 300 :height 50)
|
||||
;; A too-large :max-width (etc) has no effect.
|
||||
(im-should (im-compare (im-image :max-width 300) 200 100))
|
||||
(im-should (im-compare (im-image :max-height 300) 200 100))
|
||||
(im-should :w 200 100 :max-width 300)
|
||||
(im-should :w 200 100 :max-height 300)
|
||||
;; Both max-width/height.
|
||||
(im-should (im-compare (im-image :max-width 100 :max-height 75) 100 50))
|
||||
(im-should (im-compare (im-image :max-width 100 :max-height 25) 50 25)))
|
||||
(im-should :w 100 50 :max-width 100 :max-height 75)
|
||||
(im-should :w 50 25 :max-width 100 :max-height 25)
|
||||
|
||||
;; Test the image that's taller than it is wide.
|
||||
(im-should :h 100 200)
|
||||
;; Changing one dimension changes the other.
|
||||
(im-should :h 50 100 :width 50)
|
||||
(im-should :h 50 100 :height 100)
|
||||
;; The same with :max-width etc.
|
||||
(im-should :h 50 100 :max-width 50)
|
||||
(im-should :h 50 100 :max-height 100)
|
||||
;; :width wins over :max-width etc
|
||||
(im-should :h 300 600 :width 300 :max-width 100)
|
||||
(im-should :h 150 300 :height 300 :max-height 100)
|
||||
;; Specifying both width and height is fine.
|
||||
(im-should :h 300 50 :width 300 :height 50)
|
||||
;; A too-large :max-width (etc) has no effect.
|
||||
(im-should :h 100 200 :max-width 300)
|
||||
(im-should :h 100 200 :max-height 300)
|
||||
;; Both max-width/height.
|
||||
(im-should :h 50 100 :max-width 75 :max-height 100)
|
||||
(im-should :h 25 50 :max-width 25 :max-height 100)
|
||||
)
|
||||
|
||||
;;; image-size-tests.el ends here
|
||||
|
|
|
|||
Loading…
Reference in a new issue