Re: [PATCH] emacs: wash: make word-wrap bound message width
[notmuch-archives.git] / f7 / 3903cf1fc4669d4f8404892869274791931975
1 Return-Path: <jani@nikula.org>\r
2 X-Original-To: notmuch@notmuchmail.org\r
3 Delivered-To: notmuch@notmuchmail.org\r
4 Received: from localhost (localhost [127.0.0.1])\r
5         by olra.theworths.org (Postfix) with ESMTP id D9727431FD0\r
6         for <notmuch@notmuchmail.org>; Sat,  1 Nov 2014 01:55:18 -0700 (PDT)\r
7 X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
8 X-Spam-Flag: NO\r
9 X-Spam-Score: -0.7\r
10 X-Spam-Level: \r
11 X-Spam-Status: No, score=-0.7 tagged_above=-999 required=5\r
12         tests=[RCVD_IN_DNSWL_LOW=-0.7] autolearn=disabled\r
13 Received: from olra.theworths.org ([127.0.0.1])\r
14         by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
15         with ESMTP id CMz+UlWTVCYw for <notmuch@notmuchmail.org>;\r
16         Sat,  1 Nov 2014 01:55:14 -0700 (PDT)\r
17 Received: from mail-wg0-f47.google.com (mail-wg0-f47.google.com\r
18  [74.125.82.47])        (using TLSv1 with cipher RC4-SHA (128/128 bits))        (No client\r
19  certificate requested) by olra.theworths.org (Postfix) with ESMTPS id\r
20  E5994431FAF    for <notmuch@notmuchmail.org>; Sat,  1 Nov 2014 01:55:13 -0700\r
21  (PDT)\r
22 Received: by mail-wg0-f47.google.com with SMTP id a1so9303595wgh.6\r
23         for <notmuch@notmuchmail.org>; Sat, 01 Nov 2014 01:55:12 -0700 (PDT)\r
24 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r
25         d=1e100.net; s=20130820;\r
26         h=x-gm-message-state:from:to:subject:in-reply-to:references\r
27         :user-agent:date:message-id:mime-version:content-type;\r
28         bh=otA/EnOStfjmAXX2XpaHXp3ilREuNPvn2w4VHM82nZ0=;\r
29         b=h1EC9tdRcMHteyP2WDQ0yHAt2UeDe1FFbZzEPpdCROqy2PYK3SSzLGUT0B9YD7T3Mq\r
30         AMDf3P007zEofBowyYaJbyblY+Yrhmt+epPS77RLUtW2rPrHM/FgwxVFEZUAv2znahQC\r
31         BLpQzHOdSF1JbOVQrYbnZE4LZ4BVxgXe0xqlePiGv2bh3iElBpOWZWUlsmIEO+WprPUQ\r
32         K8GZmW8FU3TpecwjTcrkczo4as7tQMij4xT1Jb0VjgJGdR5gVxd93jCFaXt0O/ZCaL37\r
33         p+K+imPVxyOA7WFSgQi/jTjdyygjOfcd+Ey38PefVfHNBXM9RpAM/IiqzMbhWIBANcd/\r
34         jVSw==\r
35 X-Gm-Message-State:\r
36  ALoCoQlIBf59mxWN4xNZmMwJh6CWt3qzK6QRYQwx/1Oqkg8y9CsJ4OkUALFUkwvHTuVbtKF1hA7p\r
37 X-Received: by 10.194.82.74 with SMTP id g10mr1095434wjy.116.1414832112433;\r
38         Sat, 01 Nov 2014 01:55:12 -0700 (PDT)\r
39 Received: from localhost (dsl-hkibrasgw2-58c36d-48.dhcp.inet.fi.\r
40         [88.195.109.48])\r
41         by mx.google.com with ESMTPSA id wl1sm14710640wjb.4.2014.11.01.01.55.11\r
42         for <multiple recipients>\r
43         (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\r
44         Sat, 01 Nov 2014 01:55:11 -0700 (PDT)\r
45 From: Jani Nikula <jani@nikula.org>\r
46 To: Michal Sojka <sojkam1@fel.cvut.cz>, notmuch@notmuchmail.org\r
47 Subject: Re: [PATCH v6 7/7] cli: search: Add --filter-by option to\r
48         configure       address filtering\r
49 In-Reply-To: <1414792441-29555-8-git-send-email-sojkam1@fel.cvut.cz>\r
50 References: <1414792441-29555-1-git-send-email-sojkam1@fel.cvut.cz>\r
51         <1414792441-29555-8-git-send-email-sojkam1@fel.cvut.cz>\r
52 User-Agent: Notmuch/0.18.2+156~g3cc8ed5 (http://notmuchmail.org) Emacs/24.3.1\r
53         (x86_64-pc-linux-gnu)\r
54 Date: Sat, 01 Nov 2014 10:55:09 +0200\r
55 Message-ID: <87mw8be1w2.fsf@nikula.org>\r
56 MIME-Version: 1.0\r
57 Content-Type: text/plain\r
58 X-BeenThere: notmuch@notmuchmail.org\r
59 X-Mailman-Version: 2.1.13\r
60 Precedence: list\r
61 List-Id: "Use and development of the notmuch mail system."\r
62         <notmuch.notmuchmail.org>\r
63 List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
64         <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
65 List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
66 List-Post: <mailto:notmuch@notmuchmail.org>\r
67 List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
68 List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
69         <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
70 X-List-Received-Date: Sat, 01 Nov 2014 08:55:19 -0000\r
71 \r
72 On Fri, 31 Oct 2014, Michal Sojka <sojkam1@fel.cvut.cz> wrote:\r
73 > This option allows to configure the criterion for duplicate address\r
74 > filtering. Without this option, all unique combinations of name and\r
75 > address parts are printed. This option allows to filter the output\r
76 > more, for example to only contain unique address parts.\r
77 \r
78 This patch finally makes me think we should have a separate 'notmuch\r
79 address' command for all of this. We are starting to have two orthogonal\r
80 sets of 'notmuch search' options, one set for search and another for\r
81 addresses. I regret not following the series and then making the\r
82 observation so late.\r
83 \r
84 BR,\r
85 Jani.\r
86 \r
87 \r
88 > ---\r
89 >  completion/notmuch-completion.bash |  6 +++-\r
90 >  completion/notmuch-completion.zsh  |  3 +-\r
91 >  doc/man1/notmuch-search.rst        | 39 +++++++++++++++++++-\r
92 >  notmuch-search.c                   | 53 +++++++++++++++++++++++++--\r
93 >  test/T095-search-filter-by.sh      | 73 ++++++++++++++++++++++++++++++++++++++\r
94 >  5 files changed, 169 insertions(+), 5 deletions(-)\r
95 >  create mode 100755 test/T095-search-filter-by.sh\r
96 >\r
97 > diff --git a/completion/notmuch-completion.bash b/completion/notmuch-completion.bash\r
98 > index 39cd829..b625b02 100644\r
99 > --- a/completion/notmuch-completion.bash\r
100 > +++ b/completion/notmuch-completion.bash\r
101 > @@ -305,12 +305,16 @@ _notmuch_search()\r
102 >           COMPREPLY=( $( compgen -W "true false flag all" -- "${cur}" ) )\r
103 >           return\r
104 >           ;;\r
105 > +     --filter-by)\r
106 > +         COMPREPLY=( $( compgen -W "nameaddr name addr addrfold nameaddrfold" -- "${cur}" ) )\r
107 > +         return\r
108 > +         ;;\r
109 >      esac\r
110 >  \r
111 >      ! $split &&\r
112 >      case "${cur}" in\r
113 >       -*)\r
114 > -         local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate="\r
115 > +         local options="--format= --output= --sort= --offset= --limit= --exclude= --duplicate= --filter-by="\r
116 >           compopt -o nospace\r
117 >           COMPREPLY=( $(compgen -W "$options" -- ${cur}) )\r
118 >           ;;\r
119 > diff --git a/completion/notmuch-completion.zsh b/completion/notmuch-completion.zsh\r
120 > index d7e5a5e..c1ccc32 100644\r
121 > --- a/completion/notmuch-completion.zsh\r
122 > +++ b/completion/notmuch-completion.zsh\r
123 > @@ -53,7 +53,8 @@ _notmuch_search()\r
124 >      '--max-threads=[display only the first x threads from the search results]:number of threads to show: ' \\r
125 >      '--first=[omit the first x threads from the search results]:number of threads to omit: ' \\r
126 >      '--sort=[sort results]:sorting:((newest-first\:"reverse chronological order" oldest-first\:"chronological order"))' \\r
127 > -    '--output=[select what to output]:output:((summary threads messages files tags sender recipients count))'\r
128 > +    '--output=[select what to output]:output:((summary threads messages files tags sender recipients count))' \\r
129 > +    '--filter-by=[filter out duplicate addresses]:filter-by:((nameaddr\:"both name and address part" name\:"name part" addr\:"address part" addrfold\:"case-insensitive address part" nameaddrfold\:"name and case-insensitive address part"))'\r
130 >  }\r
131 >  \r
132 >  _notmuch()\r
133 > diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst\r
134 > index ec89200..3a5556b 100644\r
135 > --- a/doc/man1/notmuch-search.rst\r
136 > +++ b/doc/man1/notmuch-search.rst\r
137 > @@ -85,7 +85,8 @@ Supported options for **search** include\r
138 >              (--format=text0), as a JSON array (--format=json), or as\r
139 >              an S-Expression list (--format=sexp).\r
140 >  \r
141 > -            Duplicate addresses are filtered out.\r
142 > +            Duplicate addresses are filtered out. Filtering can be\r
143 > +            configured with the --filter-by option.\r
144 >  \r
145 >           Note: Searching for **sender** should be much faster than\r
146 >           searching for **recipients**, because sender addresses are\r
147 > @@ -158,6 +159,42 @@ Supported options for **search** include\r
148 >          prefix. The prefix matches messages based on filenames. This\r
149 >          option filters filenames of the matching messages.\r
150 >  \r
151 > +    ``--filter-by=``\ (**nameaddr**\ \|\ **name** \|\ **addr**\ \|\ **addrfold**\ \|\ **nameaddrfold**\)\r
152 > +\r
153 > +     Can be used with ``--output=sender`` or\r
154 > +     ``--output=recipients`` to filter out duplicate addresses. The\r
155 > +     filtering algorithm receives a sequence of email addresses and\r
156 > +     outputs the same sequence without the addresses that are\r
157 > +     considered a duplicate of a previously output address. What is\r
158 > +     considered a duplicate depends on how the two addresses are\r
159 > +     compared and this can be controlled with the following\r
160 > +     keywords:\r
161 > +\r
162 > +     **nameaddr** means that both name and address parts are\r
163 > +     compared in case-sensitive manner. Therefore, all same looking\r
164 > +     addresses strings are considered duplicate. This is the\r
165 > +     default.\r
166 > +\r
167 > +     **name** means that only the name part is compared (in\r
168 > +     case-sensitive manner). For example, the addresses "John Doe\r
169 > +     <me@example.com>" and "John Doe <john@doe.name>" will be\r
170 > +     considered duplicate.\r
171 > +\r
172 > +     **addr** means that only the address part is compared (in\r
173 > +     case-sensitive manner). For example, the addresses "John Doe\r
174 > +     <john@example.com>" and "Dr. John Doe <john@example.com>" will\r
175 > +     be considered duplicate.\r
176 > +\r
177 > +     **addrfold** is like **addr**, but comparison is done in\r
178 > +     canse-insensitive manner. For example, the addresses "John Doe\r
179 > +     <john@example.com>" and "Dr. John Doe <JOHN@EXAMPLE.COM>" will\r
180 > +     be considered duplicate.\r
181 > +\r
182 > +     **nameaddrfold** is like **nameaddr**, but address comparison\r
183 > +     is done in canse-insensitive manner. For example, the\r
184 > +     addresses "John Doe <john@example.com>" and "John Doe\r
185 > +     <JOHN@EXAMPLE.COM>" will be considered duplicate.\r
186 > +\r
187 >  EXIT STATUS\r
188 >  ===========\r
189 >  \r
190 > diff --git a/notmuch-search.c b/notmuch-search.c\r
191 > index 4b39dfc..a350f06 100644\r
192 > --- a/notmuch-search.c\r
193 > +++ b/notmuch-search.c\r
194 > @@ -35,6 +35,14 @@ typedef enum {\r
195 >  \r
196 >  #define OUTPUT_ADDRESS_FLAGS (OUTPUT_SENDER | OUTPUT_RECIPIENTS | OUTPUT_COUNT)\r
197 >  \r
198 > +typedef enum {\r
199 > +    FILTER_BY_NAMEADDR = 0,\r
200 > +    FILTER_BY_NAME,\r
201 > +    FILTER_BY_ADDR,\r
202 > +    FILTER_BY_ADDRFOLD,\r
203 > +    FILTER_BY_NAMEADDRFOLD,\r
204 > +} filter_by_t;\r
205 > +\r
206 >  typedef struct {\r
207 >      sprinter_t *format;\r
208 >      notmuch_query_t *query;\r
209 > @@ -43,6 +51,7 @@ typedef struct {\r
210 >      int offset;\r
211 >      int limit;\r
212 >      int dupe;\r
213 > +    filter_by_t filter_by;\r
214 >  } search_options_t;\r
215 >  \r
216 >  typedef struct {\r
217 > @@ -231,15 +240,42 @@ do_search_threads (search_options_t *opt)\r
218 >      return 0;\r
219 >  }\r
220 >  \r
221 > -/* Returns TRUE iff name and addr is duplicate. */\r
222 > +/* Returns TRUE iff name and/or addr is considered duplicate. */\r
223 >  static notmuch_bool_t\r
224 >  is_duplicate (const search_options_t *opt, GHashTable *addrs, const char *name, const char *addr)\r
225 >  {\r
226 >      notmuch_bool_t duplicate;\r
227 >      char *key;\r
228 > +    gchar *addrfold = NULL;\r
229 >      mailbox_t *mailbox;\r
230 >  \r
231 > -    key = talloc_asprintf (opt->format, "%s <%s>", name, addr);\r
232 > +    if (opt->filter_by == FILTER_BY_ADDRFOLD ||\r
233 > +     opt->filter_by == FILTER_BY_NAMEADDRFOLD)\r
234 > +     addrfold = g_utf8_casefold (addr, -1);\r
235 > +\r
236 > +    switch (opt->filter_by) {\r
237 > +    case FILTER_BY_NAMEADDR:\r
238 > +     key = talloc_asprintf (opt->format, "%s <%s>", name, addr);\r
239 > +     break;\r
240 > +    case FILTER_BY_NAMEADDRFOLD:\r
241 > +     key = talloc_asprintf (opt->format, "%s <%s>", name, addrfold);\r
242 > +     break;\r
243 > +    case FILTER_BY_NAME:\r
244 > +     key = talloc_strdup (opt->format, name); /* !name results in !key */\r
245 > +     break;\r
246 > +    case FILTER_BY_ADDR:\r
247 > +     key = talloc_strdup (opt->format, addr);\r
248 > +     break;\r
249 > +    case FILTER_BY_ADDRFOLD:\r
250 > +     key = talloc_strdup (opt->format, addrfold);\r
251 > +     break;\r
252 > +    default:\r
253 > +     INTERNAL_ERROR("invalid --filter-by flags");\r
254 > +    }\r
255 > +\r
256 > +    if (addrfold)\r
257 > +     g_free (addrfold);\r
258 > +\r
259 >      if (! key)\r
260 >       return FALSE;\r
261 >  \r
262 > @@ -523,6 +559,7 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])\r
263 >       .offset = 0,\r
264 >       .limit = -1, /* unlimited */\r
265 >       .dupe = -1,\r
266 > +     .filter_by = FILTER_BY_NAMEADDR,\r
267 >      };\r
268 >      char *query_str;\r
269 >      int opt_index, ret;\r
270 > @@ -567,6 +604,13 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])\r
271 >       { NOTMUCH_OPT_INT, &opt.offset, "offset", 'O', 0 },\r
272 >       { NOTMUCH_OPT_INT, &opt.limit, "limit", 'L', 0  },\r
273 >       { NOTMUCH_OPT_INT, &opt.dupe, "duplicate", 'D', 0  },\r
274 > +     { NOTMUCH_OPT_KEYWORD, &opt.filter_by, "filter-by", 'b',\r
275 > +       (notmuch_keyword_t []){ { "nameaddr", FILTER_BY_NAMEADDR },\r
276 > +                               { "name", FILTER_BY_NAME },\r
277 > +                               { "addr", FILTER_BY_ADDR },\r
278 > +                               { "addrfold", FILTER_BY_ADDRFOLD },\r
279 > +                               { "nameaddrfold", FILTER_BY_NAMEADDRFOLD },\r
280 > +                               { 0, 0 } } },\r
281 >       { 0, 0, 0, 0, 0 }\r
282 >      };\r
283 >  \r
284 > @@ -577,6 +621,11 @@ notmuch_search_command (notmuch_config_t *config, int argc, char *argv[])\r
285 >      if (! opt.output)\r
286 >       opt.output = OUTPUT_SUMMARY;\r
287 >  \r
288 > +    if (opt.filter_by && !(opt.output & OUTPUT_ADDRESS_FLAGS)) {\r
289 > +     fprintf (stderr, "Error: --filter-by can only be used with address output.\n");\r
290 > +     return EXIT_FAILURE;\r
291 > +    }\r
292 > +\r
293 >      switch (format_sel) {\r
294 >      case NOTMUCH_FORMAT_TEXT:\r
295 >       opt.format = sprinter_text_create (config, stdout);\r
296 > diff --git a/test/T095-search-filter-by.sh b/test/T095-search-filter-by.sh\r
297 > new file mode 100755\r
298 > index 0000000..15c9f77\r
299 > --- /dev/null\r
300 > +++ b/test/T095-search-filter-by.sh\r
301 > @@ -0,0 +1,73 @@\r
302 > +#!/usr/bin/env bash\r
303 > +test_description='duplicite address filtering in "notmuch search --output=recipients"'\r
304 > +. ./test-lib.sh\r
305 > +\r
306 > +add_message '[to]="John Doe <foo@example.com>, John Doe <bar@example.com>"'\r
307 > +add_message '[to]="\"Doe, John\" <foo@example.com>"' '[cc]="John Doe <Bar@Example.COM>"'\r
308 > +add_message '[to]="\"Doe, John\" <foo@example.com>"' '[bcc]="John Doe <Bar@Example.COM>"'\r
309 > +\r
310 > +test_begin_subtest "--output=recipients"\r
311 > +notmuch search --output=recipients "*" >OUTPUT\r
312 > +cat <<EOF >EXPECTED\r
313 > +John Doe <foo@example.com>\r
314 > +John Doe <bar@example.com>\r
315 > +"Doe, John" <foo@example.com>\r
316 > +John Doe <Bar@Example.COM>\r
317 > +EOF\r
318 > +test_expect_equal_file OUTPUT EXPECTED\r
319 > +\r
320 > +test_begin_subtest "--output=recipients --filter-by=nameaddr"\r
321 > +notmuch search --output=recipients --filter-by=nameaddr "*" >OUTPUT\r
322 > +# The same as above\r
323 > +cat <<EOF >EXPECTED\r
324 > +John Doe <foo@example.com>\r
325 > +John Doe <bar@example.com>\r
326 > +"Doe, John" <foo@example.com>\r
327 > +John Doe <Bar@Example.COM>\r
328 > +EOF\r
329 > +test_expect_equal_file OUTPUT EXPECTED\r
330 > +\r
331 > +test_begin_subtest "--output=recipients --filter-by=name"\r
332 > +notmuch search --output=recipients --filter-by=name "*" >OUTPUT\r
333 > +cat <<EOF >EXPECTED\r
334 > +John Doe <foo@example.com>\r
335 > +"Doe, John" <foo@example.com>\r
336 > +EOF\r
337 > +test_expect_equal_file OUTPUT EXPECTED\r
338 > +\r
339 > +test_begin_subtest "--output=recipients --filter-by=addr"\r
340 > +notmuch search --output=recipients --filter-by=addr "*" >OUTPUT\r
341 > +cat <<EOF >EXPECTED\r
342 > +John Doe <foo@example.com>\r
343 > +John Doe <bar@example.com>\r
344 > +John Doe <Bar@Example.COM>\r
345 > +EOF\r
346 > +test_expect_equal_file OUTPUT EXPECTED\r
347 > +\r
348 > +test_begin_subtest "--output=recipients --filter-by=addrfold"\r
349 > +notmuch search --output=recipients --filter-by=addrfold "*" >OUTPUT\r
350 > +cat <<EOF >EXPECTED\r
351 > +John Doe <foo@example.com>\r
352 > +John Doe <bar@example.com>\r
353 > +EOF\r
354 > +test_expect_equal_file OUTPUT EXPECTED\r
355 > +\r
356 > +test_begin_subtest "--output=recipients --filter-by=nameaddrfold"\r
357 > +notmuch search --output=recipients --filter-by=nameaddrfold "*" >OUTPUT\r
358 > +cat <<EOF >EXPECTED\r
359 > +John Doe <foo@example.com>\r
360 > +John Doe <bar@example.com>\r
361 > +"Doe, John" <foo@example.com>\r
362 > +EOF\r
363 > +test_expect_equal_file OUTPUT EXPECTED\r
364 > +\r
365 > +test_begin_subtest "--output=recipients --filter-by=nameaddrfold --output=count"\r
366 > +notmuch search --output=recipients --filter-by=nameaddrfold --output=count "*" | sort -n >OUTPUT\r
367 > +cat <<EOF >EXPECTED\r
368 > +1    John Doe <foo@example.com>\r
369 > +2    "Doe, John" <foo@example.com>\r
370 > +3    John Doe <bar@example.com>\r
371 > +EOF\r
372 > +test_expect_equal_file OUTPUT EXPECTED\r
373 > +\r
374 > +test_done\r
375 > -- \r
376 > 2.1.1\r
377 >\r
378 > _______________________________________________\r
379 > notmuch mailing list\r
380 > notmuch@notmuchmail.org\r
381 > http://notmuchmail.org/mailman/listinfo/notmuch\r