mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-26 04:45:20 +01:00
merge changes from upstream
This commit is contained in:
commit
e72a6176e3
26 changed files with 958 additions and 357 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
Makefile.config
|
||||
TAGS
|
||||
tags
|
||||
*cscope*
|
||||
|
|
58
Makefile
58
Makefile
|
@ -1,6 +1,5 @@
|
|||
# Default FLAGS, (can be overridden by user such as "make CFLAGS=-O2")
|
||||
WARN_FLAGS=-Wall -Wextra -Wmissing-declarations -Wwrite-strings -Wswitch-enum
|
||||
CFLAGS=-O2
|
||||
WARN_CXXFLAGS=-Wall -Wextra -Wwrite-strings -Wswitch-enum
|
||||
WARN_CFLAGS=$(WARN_CXXFLAGS) -Wmissing-declarations
|
||||
|
||||
# Additional programs that are used during the compilation process.
|
||||
EMACS ?= emacs
|
||||
|
@ -8,66 +7,69 @@ EMACS ?= emacs
|
|||
# arguments to gzip.
|
||||
gzip = gzip
|
||||
|
||||
# Additional flags that we will append to whatever the user set.
|
||||
# These aren't intended for the user to manipulate.
|
||||
extra_cflags := $(shell pkg-config --cflags glib-2.0 gmime-2.4 talloc)
|
||||
extra_cxxflags := $(shell xapian-config --cxxflags)
|
||||
|
||||
emacs_lispdir := $(shell pkg-config emacs --variable sitepkglispdir)
|
||||
# Hard-code if this system doesn't have an emacs.pc file
|
||||
ifeq ($(emacs_lispdir),)
|
||||
emacs_lispdir = $(prefix)/share/emacs/site-lisp
|
||||
endif
|
||||
bash_completion_dir = /etc/bash_completion.d
|
||||
|
||||
all_deps = Makefile Makefile.local Makefile.config \
|
||||
lib/Makefile lib/Makefile.local
|
||||
|
||||
extra_cflags :=
|
||||
extra_cxxflags :=
|
||||
|
||||
# Now smash together user's values with our extra values
|
||||
override CFLAGS += $(WARN_FLAGS) $(extra_cflags)
|
||||
override CXXFLAGS += $(WARN_FLAGS) $(extra_cflags) $(extra_cxxflags)
|
||||
FINAL_CFLAGS = $(CFLAGS) $(WARN_CFLAGS) $(CONFIGURE_CFLAGS) $(extra_cflags)
|
||||
FINAL_CXXFLAGS = $(CXXFLAGS) $(WARN_CXXFLAGS) $(CONFIGURE_CXXFLAGS) $(extra_cflags) $(extra_cxxflags)
|
||||
FINAL_LDFLAGS = $(LDFLAGS) $(CONFIGURE_LDFLAGS)
|
||||
|
||||
override LDFLAGS += \
|
||||
$(shell pkg-config --libs glib-2.0 gmime-2.4 talloc) \
|
||||
$(shell xapian-config --libs)
|
||||
all: notmuch notmuch.1.gz
|
||||
|
||||
# Include our local Makefile.local first so that its first target is default
|
||||
include Makefile.local
|
||||
include lib/Makefile.local
|
||||
# Before including any other Makefile fragments, get settings from the
|
||||
# output of configure
|
||||
Makefile.config: configure
|
||||
@echo ""
|
||||
@echo "Note: Calling ./configure with no command-line arguments. This is often fine,"
|
||||
@echo " but if you want to specify any arguments (such as an alternate prefix"
|
||||
@echo " into which to install), call ./configure explicitly and then make again."
|
||||
@echo " See \"./configure --help\" for more details."
|
||||
@echo ""
|
||||
./configure
|
||||
|
||||
# And get user settings from the output of configure
|
||||
include Makefile.config
|
||||
|
||||
include lib/Makefile.local
|
||||
include compat/Makefile.local
|
||||
include Makefile.local
|
||||
|
||||
# The user has not set any verbosity, default to quiet mode and inform the
|
||||
# user how to enable verbose compiles.
|
||||
ifeq ($(V),)
|
||||
quiet_DOC := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
|
||||
quiet = @echo $(quiet_DOC)$(eval quiet_DOC:=)" $1 $@"; $($1)
|
||||
quiet = @printf $(quiet_DOC)$(eval quiet_DOC:=)" $1 $2 $@\n"; $($1)
|
||||
endif
|
||||
# The user has explicitly enabled quiet compilation.
|
||||
ifeq ($(V),0)
|
||||
quiet = @echo " $1 $@"; $($1)
|
||||
quiet = @printf " $1 $@\n"; $($1)
|
||||
endif
|
||||
# Otherwise, print the full command line.
|
||||
quiet ?= $($1)
|
||||
|
||||
%.o: %.cc $(all_deps)
|
||||
$(call quiet,CXX) -c $(CXXFLAGS) $< -o $@
|
||||
$(call quiet,CXX,$(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@
|
||||
|
||||
%.o: %.c $(all_deps)
|
||||
$(call quiet,CC) -c $(CFLAGS) $< -o $@
|
||||
$(call quiet,CC,$(CFLAGS)) -c $(FINAL_CFLAGS) $< -o $@
|
||||
|
||||
%.elc: %.el
|
||||
$(call quiet,EMACS) -batch -f batch-byte-compile $<
|
||||
|
||||
.deps/%.d: %.c $(all_deps)
|
||||
@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
|
||||
$(CC) -M $(CPPFLAGS) $(CFLAGS) $< > $@.$$$$; \
|
||||
$(CC) -M $(CPPFLAGS) $(FINAL_CFLAGS) $< > $@.$$$$ 2>/dev/null ; \
|
||||
sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
rm -f $@.$$$$
|
||||
|
||||
.deps/%.d: %.cc $(all_deps)
|
||||
@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
|
||||
$(CXX) -M $(CPPFLAGS) $(CXXFLAGS) $< > $@.$$$$; \
|
||||
$(CXX) -M $(CPPFLAGS) $(FINAL_CXXFLAGS) $< > $@.$$$$ 2>/dev/null ; \
|
||||
sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@.$$$$ > $@; \
|
||||
rm -f $@.$$$$
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
all: notmuch notmuch.1.gz
|
||||
|
||||
emacs: notmuch.elc
|
||||
|
||||
notmuch_client_srcs = \
|
||||
$(notmuch_compat_srcs) \
|
||||
debugger.c \
|
||||
gmime-filter-reply.c \
|
||||
notmuch.c \
|
||||
|
@ -23,21 +22,18 @@ notmuch_client_srcs = \
|
|||
|
||||
notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
|
||||
notmuch: $(notmuch_client_modules) lib/notmuch.a
|
||||
$(call quiet,CXX) $^ $(LDFLAGS) -o $@
|
||||
$(call quiet,CXX,$(LDFLAGS)) $^ $(FINAL_LDFLAGS) -o $@
|
||||
|
||||
notmuch.1.gz: notmuch.1
|
||||
$(call quiet,gzip) --stdout $^ > $@
|
||||
|
||||
install: all notmuch.1.gz
|
||||
for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 \
|
||||
$(DESTDIR)$(bash_completion_dir) ; \
|
||||
for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 ; \
|
||||
do \
|
||||
install -d $$d ; \
|
||||
done ;
|
||||
install notmuch $(DESTDIR)$(prefix)/bin/
|
||||
install -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
|
||||
install -m0644 contrib/notmuch-completion.bash \
|
||||
$(DESTDIR)$(bash_completion_dir)/notmuch
|
||||
|
||||
install-emacs: install emacs
|
||||
for d in $(DESTDIR)/$(emacs_lispdir) ; \
|
||||
|
@ -47,5 +43,10 @@ install-emacs: install emacs
|
|||
install -m0644 notmuch.el $(DESTDIR)$(emacs_lispdir)
|
||||
install -m0644 notmuch.elc $(DESTDIR)$(emacs_lispdir)
|
||||
|
||||
install-bash:
|
||||
install -d $(DESTDIR)$(bash_completion_dir)
|
||||
install -m0644 contrib/notmuch-completion.bash \
|
||||
$(DESTDIR)$(bash_completion_dir)/notmuch
|
||||
|
||||
SRCS := $(SRCS) $(notmuch_client_srcs)
|
||||
CLEAN := $(CLEAN) notmuch $(notmuch_client_modules) notmuch.elc notmuch.1.gz
|
||||
|
|
31
TODO
31
TODO
|
@ -8,9 +8,6 @@ Fix the things that are causing the most pain to new users
|
|||
|
||||
Emacs interface (notmuch.el)
|
||||
----------------------------
|
||||
Make the keybindings help ('?') display the summary of each command's
|
||||
documentation, not the function name.
|
||||
|
||||
Add a global keybinding table for notmuch, and then view-specific
|
||||
tables that add to it.
|
||||
|
||||
|
@ -18,8 +15,6 @@ Add a command to archive all threads in a search view.
|
|||
|
||||
Add a '|' binding from the search view.
|
||||
|
||||
Add a binding to run a search from notmuch-show-mode.
|
||||
|
||||
When a thread has been entirely read, start out by closing all
|
||||
messages except those that matched the search terms.
|
||||
|
||||
|
@ -41,10 +36,6 @@ Portability
|
|||
-----------
|
||||
Fix configure script to test each compiler warning we want to use.
|
||||
|
||||
Implement strndup locally (or call talloc_strndup instead).
|
||||
|
||||
Implement getline locally, (look at gnulib).
|
||||
|
||||
Completion
|
||||
----------
|
||||
Fix bash completion to complete multiple search options (both --first
|
||||
|
@ -53,6 +44,11 @@ and *then* --max-threads), and also complete value for --sort=
|
|||
|
||||
notmuch command-line tool
|
||||
-------------------------
|
||||
Fix "notmuch show" so that the UI doesn't fail to show a thread that
|
||||
is visible in a search buffer, but happens to no longer match the
|
||||
current search. (Perhaps add a --matching=<secondary-search-terms>
|
||||
option (or similar) to "notmuch show".)
|
||||
|
||||
Teach "notmuch search" to return many different kinds of results. Some
|
||||
ideas:
|
||||
|
||||
|
@ -72,6 +68,10 @@ Give "notmuch restore" some progress indicator. Until we get the
|
|||
Xapian bugs fixed that are making this operation slow, we really need
|
||||
to let the user know that things are still moving.
|
||||
|
||||
Fix "notmuch restore" to operate in a single pass much like "notmuch
|
||||
dump" does, rather than doing N searches into the database, each
|
||||
matching 1/N messages.
|
||||
|
||||
Add a "-f <filename>" option to select an alternate configuration
|
||||
file.
|
||||
|
||||
|
@ -80,10 +80,6 @@ relative to the database path. (Otherwise, moving the database to a
|
|||
new directory will result in notmuch creating new timestamp documents
|
||||
and leaving stale ones behind.)
|
||||
|
||||
Ensure that "notmuch new" is sane if its first, giant indexing session
|
||||
gets interrupted, (that is, ensure that any results indexed so far are
|
||||
flushed).
|
||||
|
||||
Fix notmuch.c to use a DIR prefix for directory timestamps, (the idea
|
||||
being that it can then add other non-directory timestamps such as for
|
||||
noting how far back in the past mail has been indexed, and whether it
|
||||
|
@ -104,10 +100,12 @@ indexing.
|
|||
|
||||
notmuch library
|
||||
---------------
|
||||
Index content from citations, please.
|
||||
|
||||
Provide a sane syntax for date ranges. First, we don't want to require
|
||||
both endpoints to be specified. For example it would be nice to be
|
||||
able to say things like "since:2009-01-1" or "until:2009-01-1" and
|
||||
have the other enpoint be implicit. Second we'de like to support
|
||||
have the other endpoint be implicit. Second we'd like to support
|
||||
relative specifications of time such as "since:'2 months ago'". To do
|
||||
any of this we're probably going to need to break down an write our
|
||||
own parser for the query string rather than using Xapian's QueryParser
|
||||
|
@ -132,11 +130,6 @@ Add support for configuring "virtual tags" which are a tuple of
|
|||
(tag-name, search-specification). The database is responsible for
|
||||
ensuring that the virtual tag is always consistent.
|
||||
|
||||
Think about optimizing chunked searches (max-threads > 0) to avoid
|
||||
repeating work. That would be saving state from the previous chunk and
|
||||
reusing it if the next search is the next chunk with the same search
|
||||
string.
|
||||
|
||||
General
|
||||
-------
|
||||
Audit everything for dealing with out-of-memory (and drop xutil.c).
|
||||
|
|
5
compat/Makefile
Normal file
5
compat/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
all:
|
||||
$(MAKE) -C .. all
|
||||
|
||||
clean:
|
||||
$(MAKE) -C .. clean
|
8
compat/Makefile.local
Normal file
8
compat/Makefile.local
Normal file
|
@ -0,0 +1,8 @@
|
|||
dir=compat
|
||||
extra_cflags += -I$(dir)
|
||||
|
||||
notmuch_compat_srcs =
|
||||
|
||||
ifneq ($(HAVE_GETLINE),1)
|
||||
notmuch_compat_srcs += $(dir)/getline.c $(dir)/getdelim.c
|
||||
endif
|
41
compat/compat.h
Normal file
41
compat/compat.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/* notmuch - Not much of an email library, (just index and search)
|
||||
*
|
||||
* Copyright © 2009 Carl Worth
|
||||
*
|
||||
* 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/ .
|
||||
*
|
||||
* Author: Carl Worth <cworth@cworth.org>
|
||||
*/
|
||||
|
||||
/* This header file defines functions that will only be conditionally
|
||||
* compiled for compatibility on systems that don't provide their own
|
||||
* implementations of the functions.
|
||||
*/
|
||||
|
||||
#ifndef NOTMUCH_COMPAT_H
|
||||
#define NOTMUCH_COMPAT_H
|
||||
|
||||
#if !HAVE_GETLINE
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
ssize_t
|
||||
getline (char **lineptr, size_t *n, FILE *stream);
|
||||
|
||||
ssize_t
|
||||
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp);
|
||||
|
||||
#endif /* !HAVE_GETLINE */
|
||||
|
||||
#endif /* NOTMUCH_COMPAT_H */
|
133
compat/getdelim.c
Normal file
133
compat/getdelim.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/* getdelim.c --- Implementation of replacement getdelim function.
|
||||
Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2005, 2006, 2007,
|
||||
2008, 2009 Free Software Foundation, Inc.
|
||||
|
||||
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, 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA. */
|
||||
|
||||
/* Ported from glibc by Simon Josefsson. */
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef SSIZE_MAX
|
||||
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
|
||||
#endif
|
||||
|
||||
#if USE_UNLOCKED_IO
|
||||
# include "unlocked-io.h"
|
||||
# define getc_maybe_unlocked(fp) getc(fp)
|
||||
#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
|
||||
# undef flockfile
|
||||
# undef funlockfile
|
||||
# define flockfile(x) ((void) 0)
|
||||
# define funlockfile(x) ((void) 0)
|
||||
# define getc_maybe_unlocked(fp) getc(fp)
|
||||
#else
|
||||
# define getc_maybe_unlocked(fp) getc_unlocked(fp)
|
||||
#endif
|
||||
|
||||
/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
|
||||
NUL-terminate it). *LINEPTR is a pointer returned from malloc (or
|
||||
NULL), pointing to *N characters of space. It is realloc'ed as
|
||||
necessary. Returns the number of characters read (not including
|
||||
the null terminator), or -1 on error or EOF. */
|
||||
|
||||
ssize_t
|
||||
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
|
||||
{
|
||||
ssize_t result = -1;
|
||||
size_t cur_len = 0;
|
||||
|
||||
if (lineptr == NULL || n == NULL || fp == NULL)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
flockfile (fp);
|
||||
|
||||
if (*lineptr == NULL || *n == 0)
|
||||
{
|
||||
char *new_lineptr;
|
||||
*n = 120;
|
||||
new_lineptr = (char *) realloc (*lineptr, *n);
|
||||
if (new_lineptr == NULL)
|
||||
{
|
||||
result = -1;
|
||||
goto unlock_return;
|
||||
}
|
||||
*lineptr = new_lineptr;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = getc_maybe_unlocked (fp);
|
||||
if (i == EOF)
|
||||
{
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make enough space for len+1 (for final NUL) bytes. */
|
||||
if (cur_len + 1 >= *n)
|
||||
{
|
||||
size_t needed_max =
|
||||
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
|
||||
size_t needed = 2 * *n + 1; /* Be generous. */
|
||||
char *new_lineptr;
|
||||
|
||||
if (needed_max < needed)
|
||||
needed = needed_max;
|
||||
if (cur_len + 1 >= needed)
|
||||
{
|
||||
result = -1;
|
||||
errno = EOVERFLOW;
|
||||
goto unlock_return;
|
||||
}
|
||||
|
||||
new_lineptr = (char *) realloc (*lineptr, needed);
|
||||
if (new_lineptr == NULL)
|
||||
{
|
||||
result = -1;
|
||||
goto unlock_return;
|
||||
}
|
||||
|
||||
*lineptr = new_lineptr;
|
||||
*n = needed;
|
||||
}
|
||||
|
||||
(*lineptr)[cur_len] = i;
|
||||
cur_len++;
|
||||
|
||||
if (i == delimiter)
|
||||
break;
|
||||
}
|
||||
(*lineptr)[cur_len] = '\0';
|
||||
result = cur_len ? (ssize_t) cur_len : result;
|
||||
|
||||
unlock_return:
|
||||
funlockfile (fp); /* doesn't set errno */
|
||||
|
||||
return result;
|
||||
}
|
29
compat/getline.c
Normal file
29
compat/getline.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* getline.c --- Implementation of replacement getline function.
|
||||
Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
|
||||
|
||||
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, 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, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301, USA. */
|
||||
|
||||
/* Written by Simon Josefsson. */
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
ssize_t
|
||||
getline (char **lineptr, size_t *n, FILE *stream)
|
||||
{
|
||||
return getdelim (lineptr, n, '\n', stream);
|
||||
}
|
5
config/README
Normal file
5
config/README
Normal file
|
@ -0,0 +1,5 @@
|
|||
notmuch/config
|
||||
|
||||
This directory consists of small programs used by the notmuch
|
||||
configure script to test for the availability of certain system
|
||||
features, (library functions, etc.).
|
13
config/have_getline.c
Normal file
13
config/have_getline.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
ssize_t count = 0;
|
||||
size_t n = 0;
|
||||
char **lineptr = NULL;
|
||||
FILE *stream = NULL;
|
||||
|
||||
count = getline(lineptr, &n, stream);
|
||||
}
|
233
configure
vendored
233
configure
vendored
|
@ -1,12 +1,70 @@
|
|||
#! /bin/sh
|
||||
|
||||
# defaults
|
||||
# Set several defaults (optionally specified by the user in
|
||||
# environemnt variables)
|
||||
CC=${CC:-gcc}
|
||||
CXX=${CXX:-g++}
|
||||
CFLAGS=${CFLAGS:--O2}
|
||||
CXXFLAGS=${CXXFLAGS:-\$(CFLAGS)}
|
||||
|
||||
# Set the defaults for values the user can specify with command-line
|
||||
# options.
|
||||
PREFIX=/usr/local
|
||||
|
||||
# option parsing
|
||||
usage ()
|
||||
{
|
||||
cat <<EOF
|
||||
Usage: ./configure [options]...
|
||||
|
||||
This script configures notmuch to build on your system.
|
||||
|
||||
It verifies that dependencies are available, determines flags needed
|
||||
to compile and link against various required libraries, and identifies
|
||||
whether various system functions can be used or if locally-provided
|
||||
replacements will be built instead.
|
||||
|
||||
Finally, it allows you to control various aspects of the build and
|
||||
installation process.
|
||||
|
||||
First, some common variables can specified via environment variables:
|
||||
|
||||
CC The C compiler to use
|
||||
CFLAGS Flags to pass to the C compiler
|
||||
CXX The C++ compiler to use
|
||||
CXXFLAGS Flags to pass to the C compiler
|
||||
LDFLAGS Flags to pass when linking
|
||||
|
||||
Each of these values can further be controlled by specifying them
|
||||
later on the "make" command line.
|
||||
|
||||
Additionally, various options can be specified on the configure
|
||||
command line.
|
||||
|
||||
--prefix=PREFIX Install files in PREFIX [$PREFIX]
|
||||
|
||||
By default, "make install" will install the resulting program to
|
||||
$PREFIX/bin, documentation to $PREFIX/share, etc. You can
|
||||
specify an installation prefix other than $PREFIX using
|
||||
--prefix, for instance:
|
||||
|
||||
./configure --prefix=\$HOME
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse command-line options
|
||||
for option; do
|
||||
if [ "${option%=*}" = '--prefix' ] ; then
|
||||
if [ "${option}" = '--help' ] ; then
|
||||
usage
|
||||
exit 0
|
||||
elif [ "${option%%=*}" = '--prefix' ] ; then
|
||||
PREFIX="${option#*=}"
|
||||
else
|
||||
echo "Unrecognized option: ${option}."
|
||||
echo "See:"
|
||||
echo " $0 --help"
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
|
@ -17,14 +75,16 @@ We hope that the process of building and installing notmuch is quick
|
|||
and smooth so that you can soon be reading and processing your email
|
||||
more efficiently than ever.
|
||||
|
||||
If anything goes wrong in this process, please do as much as you can
|
||||
to figure out what could be different on your machine compared to
|
||||
those of the notmuch developers. Then, please email those details to
|
||||
the Notmuch list (notmuch@notmuchmail.org) so that we can hopefully make
|
||||
future versions of notmuch easier for you to use.
|
||||
If anything goes wrong in the configure process, you can override any
|
||||
decisions it makes by manually editing the Makefile.config file that
|
||||
it creates. Also please do as much as you can to figure out what could
|
||||
be different on your machine compared to those of the notmuch
|
||||
developers. Then, please email those details to the Notmuch list
|
||||
(notmuch@notmuchmail.org) so that we can hopefully make future
|
||||
versions of notmuch easier for you to use.
|
||||
|
||||
We'll now investigate your system to find verify that various software
|
||||
components that notmuch relies on are available.
|
||||
We'll now investigate your system to verify that all required
|
||||
dependencies are available:
|
||||
|
||||
EOF
|
||||
|
||||
|
@ -36,48 +96,57 @@ else
|
|||
have_pkg_config=0
|
||||
fi
|
||||
|
||||
printf "Checking for Xapian development files... "
|
||||
if xapian-config --version > /dev/null 2>&1; then
|
||||
echo "Checking for Xapian development files... Yes."
|
||||
printf "Yes.\n"
|
||||
have_xapian=1
|
||||
xapian_cxxflags=$(xapian-config --cxxflags)
|
||||
xapian_ldflags=$(xapian-config --libs)
|
||||
else
|
||||
echo "Checking for Xapian development files... No."
|
||||
printf "No.\n"
|
||||
have_xapian=0
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
printf "Checking for GMime 2.4 development files... "
|
||||
if pkg-config --modversion gmime-2.4 > /dev/null 2>&1; then
|
||||
echo "Checking for GMime 2.4 development files... Yes."
|
||||
printf "Yes.\n"
|
||||
have_gmime=1
|
||||
gmime_cflags=$(pkg-config --cflags gmime-2.4)
|
||||
gmime_ldflags=$(pkg-config --libs gmime-2.4)
|
||||
else
|
||||
echo "Checking for GMime 2.4 development files... No."
|
||||
printf "No.\n"
|
||||
have_gmime=0
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
printf "Checking for talloc development files... "
|
||||
if pkg-config --modversion talloc > /dev/null 2>&1; then
|
||||
echo "Checking for talloc development files... Yes."
|
||||
printf "Yes.\n"
|
||||
have_talloc=1
|
||||
talloc_cflags=$(pkg-config --cflags talloc)
|
||||
talloc_ldflags=$(pkg-config --libs talloc)
|
||||
else
|
||||
echo "Checking for talloc development files... No."
|
||||
printf "No.\n"
|
||||
have_talloc=0
|
||||
talloc_cflags=
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
if printf 'int main(){return 0;}' | gcc -x c -lz -o /dev/null - > /dev/null 2>&1; then
|
||||
echo "Checking for zlib development files... Yes."
|
||||
have_zlib=1
|
||||
else
|
||||
echo "Checking for zlib development files... No."
|
||||
have_zlib=0
|
||||
errors=$((errors + 1))
|
||||
fi
|
||||
|
||||
printf "Checking for valgrind development files... "
|
||||
if pkg-config --modversion valgrind > /dev/null 2>&1; then
|
||||
echo "Checking for valgrind development files... Yes."
|
||||
have_valgrind=-DHAVE_VALGRIND
|
||||
printf "Yes.\n"
|
||||
have_valgrind=1
|
||||
valgrind_cflags=$(pkg-config --cflags valgrind)
|
||||
else
|
||||
echo "Checking for valgrind development files... No."
|
||||
have_valgrind=
|
||||
printf "No (but that's fine).\n"
|
||||
have_valgrind=0
|
||||
fi
|
||||
|
||||
if pkg-config --modversion emacs > /dev/null 2>&1; then
|
||||
emacs_lispdir=$(pkg-config emacs --variable sitepkglispdir)
|
||||
else
|
||||
emacs_lispdir='$(prefix)/share/emacs/site-lisp'
|
||||
fi
|
||||
|
||||
if [ $errors -gt 0 ]; then
|
||||
|
@ -100,34 +169,39 @@ EOF
|
|||
echo " The talloc library (including development files such as headers)"
|
||||
echo " http://talloc.samba.org/"
|
||||
fi
|
||||
if [ $have_zlib -eq 0 ]; then
|
||||
echo " The zlib library (including development files such as headers)"
|
||||
fi
|
||||
cat <<EOF
|
||||
|
||||
On a modern, package-based operating system such as Debian, you can
|
||||
install all of the dependencies with the following simple command
|
||||
line:
|
||||
With any luck, you're using a modern, package-based operating system
|
||||
that has all of these packages available in the distribution. In that
|
||||
case a simple command will install everything you need. For example:
|
||||
|
||||
sudo apt-get install libxapian-dev libgmime-2.4-dev libtalloc-dev libz-dev
|
||||
On Debian and similar systems:
|
||||
|
||||
On other systems, a similar command can be used, but the details of the
|
||||
package names may be different, (such as "devel" in place of "dev").
|
||||
sudo apt-get install libxapian-dev libgmime-2.4-dev libtalloc-dev
|
||||
|
||||
Or on Fedora and similar systems:
|
||||
|
||||
sudo yum install xapian-core-devel gmime-devel libtalloc-devel
|
||||
|
||||
On other systems, similar commands can be used, but the details of the
|
||||
package names may be different.
|
||||
|
||||
EOF
|
||||
if [ $have_pkg_config -eq 0 ]; then
|
||||
cat <<EOF
|
||||
Note: the pkg-config program is not available. Both this configure
|
||||
script and the Makefile of notmuch use pkg-config to find the
|
||||
compilation flags required to link against the various libraries
|
||||
needed by notmuch. It's possible you simply need to install pkg-config
|
||||
with a command such as:
|
||||
Note: the pkg-config program is not available. This configure script
|
||||
uses pkg-config to find the compilation flags required to link against
|
||||
the various libraries needed by notmuch. It's possible you simply need
|
||||
to install pkg-config with a command such as:
|
||||
|
||||
sudo apt-get install pkg-config
|
||||
Or:
|
||||
sudo yum install pkgconfig
|
||||
|
||||
But if pkg-config is not available for your system, then you will need
|
||||
to manually edit the notmuch Makefile to set NOTMUCH_CFLAGS and
|
||||
NOTMUCH_LDFLAGS to the correct values without calling pkg-config.
|
||||
to modify the configure script to manually set the cflags and ldflags
|
||||
variables to the correct values to link against each library in each
|
||||
case that pkg-config could not be used to determine those values.
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
@ -140,6 +214,17 @@ EOF
|
|||
exit 1
|
||||
fi
|
||||
|
||||
printf "Checking for getline... "
|
||||
if ${CC} -o config/have_getline config/have_getline.c > /dev/null 2>&1
|
||||
then
|
||||
printf "Yes.\n"
|
||||
have_getline=1
|
||||
else
|
||||
printf "No (will use our own instead).\n"
|
||||
have_getline=0
|
||||
fi
|
||||
rm -f config/have_getline
|
||||
|
||||
cat <<EOF
|
||||
|
||||
All required packages were found. You may now run the following
|
||||
|
@ -152,7 +237,59 @@ EOF
|
|||
|
||||
# construct the Makefile.config
|
||||
cat > Makefile.config <<EOF
|
||||
prefix = $PREFIX
|
||||
bash_completion_dir = /etc/bash_completion.d
|
||||
CFLAGS += ${have_valgrind}
|
||||
# This Makefile.config was automatically generated by the ./configure
|
||||
# script of notmuch. If the configure script identified anything
|
||||
# incorrectly, then you can edit this file to try to correct things,
|
||||
# but be warned that if configure is run again it will destroy your
|
||||
# changes, (and this could happen by simply calling "make" if the
|
||||
# configure script is updated).
|
||||
|
||||
# The C compiler to use
|
||||
CC = ${CC}
|
||||
|
||||
# The C++ compiler to use
|
||||
CXX = ${CXX}
|
||||
|
||||
# Default FLAGS for C compiler (can be overridden by user such as "make CFLAGS=-g")
|
||||
CFLAGS = ${CFLAGS}
|
||||
|
||||
# Default FLAGS for C++ compiler (can be overridden by user such as "make CXXFLAGS=-g")
|
||||
CXXFLAGS = ${CXXFLAGS}
|
||||
|
||||
# The prefix to which notmuch should be installed
|
||||
prefix = ${PREFIX}
|
||||
|
||||
# The directory to which emacs lisp files should be installed
|
||||
emacs_lispdir=${emacs_lispdir}
|
||||
|
||||
# Whether the getline function is available (if not, then notmuch will
|
||||
# build its own version)
|
||||
HAVE_GETLINE = ${have_getline}
|
||||
|
||||
# Flags needed to compile and link against Xapian
|
||||
XAPIAN_CXXFLAGS = ${xapian_cxxflags}
|
||||
XAPIAN_LDFLAGS = ${xapian_ldflags}
|
||||
|
||||
# Flags needed to compile and link against GMime-2.4
|
||||
GMIME_CFLAGS = ${gmime_cflags}
|
||||
GMIME_LDFLAGS = ${gmime_ldflags}
|
||||
|
||||
# Flags needed to compile and link against talloc
|
||||
TALLOC_CFLAGS = ${talloc_cflags}
|
||||
TALLOC_LDFLAGS = ${talloc_ldflags}
|
||||
|
||||
# Whether valgrind header files are available
|
||||
HAVE_VALGRIND = ${have_valgrind}
|
||||
|
||||
# And if so, flags needed at compile time for valgrind macros
|
||||
VALGRIND_CFLAGS = ${valgrind_cflags}
|
||||
|
||||
# Combined flags for compiling and linking against all of the above
|
||||
CONFIGURE_CFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS) \\
|
||||
\$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND) \\
|
||||
\$(VALGRIND_CFLAGS)
|
||||
CONFIGURE_CXXFLAGS = -DHAVE_GETLINE=\$(HAVE_GETLINE) \$(GMIME_CFLAGS) \\
|
||||
\$(TALLOC_CFLAGS) -DHAVE_VALGRIND=\$(HAVE_VALGRIND) \\
|
||||
\$(VALGRIND_CFLAGS) \$(XAPIAN_CXXFLAGS)
|
||||
CONFIGURE_LDFLAGS = \$(GMIME_LDFLAGS) \$(TALLOC_LDFLAGS) \$(XAPIAN_LDFLAGS)
|
||||
EOF
|
||||
|
|
10
lib/index.cc
10
lib/index.cc
|
@ -31,7 +31,7 @@ _index_address_mailbox (notmuch_message_t *message,
|
|||
{
|
||||
InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX (address);
|
||||
const char *name, *addr;
|
||||
int own_name = 0;
|
||||
void *local = talloc_new (NULL);
|
||||
|
||||
name = internet_address_get_name (address);
|
||||
addr = internet_address_mailbox_get_addr (mailbox);
|
||||
|
@ -42,16 +42,16 @@ _index_address_mailbox (notmuch_message_t *message,
|
|||
const char *at;
|
||||
|
||||
at = strchr (addr, '@');
|
||||
if (at) {
|
||||
name = strndup (addr, at - addr);
|
||||
own_name = 1;
|
||||
}
|
||||
if (at)
|
||||
name = talloc_strndup (local, addr, at - addr);
|
||||
}
|
||||
|
||||
if (name)
|
||||
_notmuch_message_gen_terms (message, prefix_name, name);
|
||||
if (addr)
|
||||
_notmuch_message_gen_terms (message, prefix_name, addr);
|
||||
|
||||
talloc_free (local);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include "notmuch.h"
|
||||
|
||||
NOTMUCH_BEGIN_DECLS
|
||||
|
@ -330,18 +332,6 @@ void
|
|||
_notmuch_message_add_reply (notmuch_message_t *message,
|
||||
notmuch_message_node_t *reply);
|
||||
|
||||
/* date.c */
|
||||
|
||||
/* Parse an RFC 8222 date string to a time_t value.
|
||||
*
|
||||
* The tz_offset argument can be used to also obtain the time-zone
|
||||
* offset, (but can be NULL if the call is not interested in that).
|
||||
*
|
||||
* Returns 0 on error.
|
||||
*/
|
||||
time_t
|
||||
notmuch_parse_date (const char *str, int *tz_offset);
|
||||
|
||||
/* sha1.c */
|
||||
|
||||
char *
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
* Author: Carl Worth <cworth@cworth.org>
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* For strndup */
|
||||
#include "notmuch-private.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -84,11 +83,16 @@ xstrndup (const char *s, size_t n)
|
|||
{
|
||||
char *ret;
|
||||
|
||||
ret = strndup (s, n);
|
||||
if (strlen (s) <= n)
|
||||
n = strlen (s);
|
||||
|
||||
ret = malloc (n + 1);
|
||||
if (ret == NULL) {
|
||||
fprintf (stderr, "Out of memory.\n");
|
||||
exit (1);
|
||||
}
|
||||
memcpy (ret, s, n);
|
||||
ret[n] = '\0';
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
#ifndef NOTMUCH_CLIENT_H
|
||||
#define NOTMUCH_CLIENT_H
|
||||
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE /* for getline */
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#include <gmime/gmime.h>
|
||||
|
||||
#include "notmuch.h"
|
||||
|
|
|
@ -317,9 +317,11 @@ notmuch_config_save (notmuch_config_t *config)
|
|||
fprintf (stderr, "Error saving configuration to %s: %s\n",
|
||||
config->filename, error->message);
|
||||
g_error_free (error);
|
||||
g_free (data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
g_free (data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,8 +35,10 @@ static volatile sig_atomic_t interrupted;
|
|||
static void
|
||||
handle_sigint (unused (int sig))
|
||||
{
|
||||
ssize_t ignored;
|
||||
static char msg[] = "Stopping... \n";
|
||||
write(2, msg, sizeof(msg)-1);
|
||||
|
||||
ignored = write(2, msg, sizeof(msg)-1);
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,11 +39,17 @@ reply_part_content (GMimeObject *part)
|
|||
{
|
||||
GMimeStream *stream_stdout = NULL, *stream_filter = NULL;
|
||||
GMimeDataWrapper *wrapper;
|
||||
const char *charset;
|
||||
|
||||
charset = g_mime_object_get_content_type_parameter (part, "charset");
|
||||
stream_stdout = g_mime_stream_file_new (stdout);
|
||||
if (stream_stdout) {
|
||||
g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
|
||||
stream_filter = g_mime_stream_filter_new(stream_stdout);
|
||||
if (charset) {
|
||||
g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
|
||||
g_mime_filter_charset_new(charset, "UTF-8"));
|
||||
}
|
||||
}
|
||||
g_mime_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
|
||||
g_mime_filter_reply_new(TRUE));
|
||||
|
|
|
@ -104,7 +104,10 @@ notmuch_setup_command (unused (void *ctx),
|
|||
do { \
|
||||
printf (format, ##__VA_ARGS__); \
|
||||
fflush (stdout); \
|
||||
getline (&response, &response_size, stdin); \
|
||||
if (getline (&response, &response_size, stdin) < 0) { \
|
||||
printf ("Exiting.\n"); \
|
||||
exit (1); \
|
||||
} \
|
||||
chomp_newline (response); \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -184,9 +184,12 @@ show_message (void *ctx, notmuch_message_t *message, int indent)
|
|||
|
||||
|
||||
static void
|
||||
show_messages (void *ctx, notmuch_messages_t *messages, int indent)
|
||||
show_messages (void *ctx, notmuch_messages_t *messages, int indent,
|
||||
notmuch_bool_t entire_thread)
|
||||
{
|
||||
notmuch_message_t *message;
|
||||
notmuch_bool_t match;
|
||||
int next_indent;
|
||||
|
||||
for (;
|
||||
notmuch_messages_has_more (messages);
|
||||
|
@ -194,9 +197,17 @@ show_messages (void *ctx, notmuch_messages_t *messages, int indent)
|
|||
{
|
||||
message = notmuch_messages_get (messages);
|
||||
|
||||
show_message (ctx, message, indent);
|
||||
match = notmuch_message_get_flag (message, NOTMUCH_MESSAGE_FLAG_MATCH);
|
||||
|
||||
show_messages (ctx, notmuch_message_get_replies (message), indent + 1);
|
||||
next_indent = indent;
|
||||
|
||||
if (match || entire_thread) {
|
||||
show_message (ctx, message, indent);
|
||||
next_indent = indent + 1;
|
||||
}
|
||||
|
||||
show_messages (ctx, notmuch_message_get_replies (message),
|
||||
next_indent, entire_thread);
|
||||
|
||||
notmuch_message_destroy (message);
|
||||
}
|
||||
|
@ -212,6 +223,24 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
|
|||
notmuch_thread_t *thread;
|
||||
notmuch_messages_t *messages;
|
||||
char *query_string;
|
||||
int entire_thread = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc && argv[i][0] == '-'; i++) {
|
||||
if (strcmp (argv[i], "--") == 0) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (strcmp(argv[i], "--entire-thread") == 0) {
|
||||
entire_thread = 1;
|
||||
} else {
|
||||
fprintf (stderr, "Unrecognized option: %s\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= i;
|
||||
argv += i;
|
||||
|
||||
config = notmuch_config_open (ctx, NULL, NULL);
|
||||
if (config == NULL)
|
||||
|
@ -251,7 +280,7 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
|
|||
INTERNAL_ERROR ("Thread %s has no toplevel messages.\n",
|
||||
notmuch_thread_get_thread_id (thread));
|
||||
|
||||
show_messages (ctx, messages, 0);
|
||||
show_messages (ctx, messages, 0, entire_thread);
|
||||
|
||||
notmuch_thread_destroy (thread);
|
||||
}
|
||||
|
|
|
@ -25,8 +25,10 @@ static volatile sig_atomic_t interrupted;
|
|||
static void
|
||||
handle_sigint (unused (int sig))
|
||||
{
|
||||
ssize_t ignored;
|
||||
|
||||
static char msg[] = "Stopping... \n";
|
||||
write(2, msg, sizeof(msg)-1);
|
||||
ignored = write(2, msg, sizeof(msg)-1);
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
|
|
18
notmuch.1
18
notmuch.1
|
@ -169,6 +169,8 @@ when sorting by
|
|||
.B newest\-first
|
||||
the threads will be sorted by the newest message in each thread.
|
||||
|
||||
.RE
|
||||
.RS 4
|
||||
By default, results will be displayed in reverse chronological order,
|
||||
(that is, the newest results will be displayed first).
|
||||
|
||||
|
@ -177,7 +179,7 @@ See the
|
|||
section below for details of the supported syntax for <search-terms>.
|
||||
.RE
|
||||
.TP
|
||||
.BR show " <search-term>..."
|
||||
.BR show " [options...] <search-term>..."
|
||||
|
||||
Shows all messages matching the search terms.
|
||||
|
||||
|
@ -187,6 +189,19 @@ message in date order). The output is not indented by default, but
|
|||
depth tags are printed so that proper indentation can be performed by
|
||||
a post-processor (such as the emacs interface to notmuch).
|
||||
|
||||
Supported options for
|
||||
.B show
|
||||
include
|
||||
.RS 4
|
||||
.TP 4
|
||||
.B \-\-entire\-thread
|
||||
|
||||
By default only those messages that match the search terms will be
|
||||
displayed. With this option, all messages in the same thread as any
|
||||
matched message will be displayed.
|
||||
.RE
|
||||
|
||||
.RS 4
|
||||
The output format is plain-text, with all text-content MIME parts
|
||||
decoded. Various components in the output,
|
||||
.RB ( message ", " header ", " body ", " attachment ", and MIME " part ),
|
||||
|
@ -207,6 +222,7 @@ See the
|
|||
.B "SEARCH SYNTAX"
|
||||
section below for details of the supported syntax for <search-terms>.
|
||||
.RE
|
||||
.RE
|
||||
|
||||
The
|
||||
.B reply
|
||||
|
|
|
@ -177,6 +177,15 @@ command_t commands[] = {
|
|||
"\t\t(all replies to a particular message appear immediately\n"
|
||||
"\t\tafter that message in date order).\n"
|
||||
"\n"
|
||||
"\t\tSupported options for show include:\n"
|
||||
"\n"
|
||||
"\t\t--entire-thread\n"
|
||||
"\n"
|
||||
"\t\t\tBy default only those messages that match the\n"
|
||||
"\t\t\tsearch terms will be displayed. With this option,\n"
|
||||
"\t\t\tall messages in the same thread as any matched\n"
|
||||
"\t\t\tmessage will be displayed.\n"
|
||||
"\n"
|
||||
"\t\tThe output format is plain-text, with all text-content\n"
|
||||
"\t\tMIME parts decoded. Various components in the output,\n"
|
||||
"\t\t('message', 'header', 'body', 'attachment', and MIME 'part')\n"
|
||||
|
|
526
notmuch.el
526
notmuch.el
|
@ -53,37 +53,31 @@
|
|||
|
||||
(defvar notmuch-show-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
; I don't actually want all of these toggle commands occupying
|
||||
; keybindings. They steal valuable key-binding space, are hard
|
||||
; to remember, and act globally rather than locally.
|
||||
;
|
||||
; Will be much preferable to switch to direct manipulation for
|
||||
; toggling visibility of these components. Probably using
|
||||
; overlays-at to query and manipulate the current overlay.
|
||||
(define-key map "a" 'notmuch-show-archive-thread)
|
||||
(define-key map "A" 'notmuch-show-mark-read-then-archive-thread)
|
||||
(define-key map "f" 'notmuch-show-forward-current)
|
||||
(define-key map "m" 'message-mail)
|
||||
(define-key map "n" 'notmuch-show-next-message)
|
||||
(define-key map "N" 'notmuch-show-mark-read-then-next-open-message)
|
||||
(define-key map "p" 'notmuch-show-previous-message)
|
||||
(define-key map (kbd "C-n") 'notmuch-show-next-line)
|
||||
(define-key map (kbd "C-p") 'notmuch-show-previous-line)
|
||||
(define-key map "?" 'notmuch-help)
|
||||
(define-key map "q" 'kill-this-buffer)
|
||||
(define-key map "r" 'notmuch-show-reply)
|
||||
(define-key map (kbd "C-p") 'notmuch-show-previous-line)
|
||||
(define-key map (kbd "C-n") 'notmuch-show-next-line)
|
||||
(define-key map (kbd "M-TAB") 'notmuch-show-previous-button)
|
||||
(define-key map (kbd "TAB") 'notmuch-show-next-button)
|
||||
(define-key map "s" 'notmuch-search)
|
||||
(define-key map "v" 'notmuch-show-view-all-mime-parts)
|
||||
(define-key map "V" 'notmuch-show-view-raw-message)
|
||||
(define-key map "m" 'message-mail)
|
||||
(define-key map "f" 'notmuch-show-forward-current)
|
||||
(define-key map "r" 'notmuch-show-reply)
|
||||
(define-key map "|" 'notmuch-show-pipe-message)
|
||||
(define-key map "w" 'notmuch-show-save-attachments)
|
||||
(define-key map "x" 'kill-this-buffer)
|
||||
(define-key map "+" 'notmuch-show-add-tag)
|
||||
(define-key map "V" 'notmuch-show-view-raw-message)
|
||||
(define-key map "v" 'notmuch-show-view-all-mime-parts)
|
||||
(define-key map "-" 'notmuch-show-remove-tag)
|
||||
(define-key map "+" 'notmuch-show-add-tag)
|
||||
(define-key map "X" 'notmuch-show-mark-read-then-archive-then-exit)
|
||||
(define-key map "x" 'notmuch-show-archive-thread-then-exit)
|
||||
(define-key map "A" 'notmuch-show-mark-read-then-archive-thread)
|
||||
(define-key map "a" 'notmuch-show-archive-thread)
|
||||
(define-key map "p" 'notmuch-show-previous-message)
|
||||
(define-key map "N" 'notmuch-show-mark-read-then-next-open-message)
|
||||
(define-key map "n" 'notmuch-show-next-message)
|
||||
(define-key map (kbd "DEL") 'notmuch-show-rewind)
|
||||
(define-key map " " 'notmuch-show-advance-marking-read-and-archiving)
|
||||
(define-key map "|" 'notmuch-show-pipe-message)
|
||||
(define-key map "?" 'describe-mode)
|
||||
(define-key map (kbd "TAB") 'notmuch-show-next-button)
|
||||
(define-key map (kbd "M-TAB") 'notmuch-show-previous-button)
|
||||
map)
|
||||
"Keymap for \"notmuch show\" buffers.")
|
||||
(fset 'notmuch-show-mode-map notmuch-show-mode-map)
|
||||
|
@ -117,7 +111,7 @@ pattern can still test against the entire line).")
|
|||
(defvar notmuch-show-marker-regexp "\f\\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$")
|
||||
|
||||
(defvar notmuch-show-id-regexp "\\(id:[^ ]*\\)")
|
||||
(defvar notmuch-show-depth-regexp " depth:\\([0-9]*\\) ")
|
||||
(defvar notmuch-show-depth-match-regexp " depth:\\([0-9]*\\).*match:\\([01]\\) ")
|
||||
(defvar notmuch-show-filename-regexp "filename:\\(.*\\)$")
|
||||
(defvar notmuch-show-tags-regexp "(\\([^)]*\\))$")
|
||||
|
||||
|
@ -165,7 +159,7 @@ Unlike builtin `next-line' this version accepts no arguments."
|
|||
|
||||
By advancing forward until reaching a visible character.
|
||||
|
||||
Unlike builtin `next-line' this version accepts no arguments."
|
||||
Unlike builtin `previous-line' this version accepts no arguments."
|
||||
(interactive)
|
||||
(set 'this-command 'previous-line)
|
||||
(call-interactively 'previous-line)
|
||||
|
@ -252,7 +246,7 @@ Unlike builtin `next-line' this version accepts no arguments."
|
|||
(notmuch-search-show-thread)))))
|
||||
|
||||
(defun notmuch-show-mark-read-then-archive-thread ()
|
||||
"Remove \"unread\" tag from each message, then archive and show next thread.
|
||||
"Remove unread tags from thread, then archive and show next thread.
|
||||
|
||||
Archive each message currently shown by removing the \"unread\"
|
||||
and \"inbox\" tag from each. Then kill this buffer and show the
|
||||
|
@ -267,7 +261,7 @@ buffer."
|
|||
(notmuch-show-archive-thread-maybe-mark-read t))
|
||||
|
||||
(defun notmuch-show-archive-thread ()
|
||||
"Archive each message in thread, and show next thread from search.
|
||||
"Archive each message in thread, then show next thread from search.
|
||||
|
||||
Archive each message currently shown by removing the \"inbox\"
|
||||
tag from each. Then kill this buffer and show the next thread
|
||||
|
@ -280,6 +274,18 @@ buffer."
|
|||
(interactive)
|
||||
(notmuch-show-archive-thread-maybe-mark-read nil))
|
||||
|
||||
(defun notmuch-show-archive-thread-then-exit ()
|
||||
"Archive each message in thread, then exit back to search results."
|
||||
(interactive)
|
||||
(notmuch-show-archive-thread)
|
||||
(kill-this-buffer))
|
||||
|
||||
(defun notmuch-show-mark-read-then-archive-then-exit ()
|
||||
"Remove unread tags from thread, then archive and exit to search results."
|
||||
(interactive)
|
||||
(notmuch-show-mark-read-then-archive-thread)
|
||||
(kill-this-buffer))
|
||||
|
||||
(defun notmuch-show-view-raw-message ()
|
||||
"View the raw email of the current message."
|
||||
(interactive)
|
||||
|
@ -296,7 +302,7 @@ buffer."
|
|||
(kill-buffer buf)))))
|
||||
|
||||
(defun notmuch-show-view-all-mime-parts ()
|
||||
"Use external viewers (according to mailcap) to view all MIME-encoded parts."
|
||||
"Use external viewers to view all attachments from the current message."
|
||||
(interactive)
|
||||
(with-current-notmuch-show-message
|
||||
(mm-display-parts (mm-dissect-buffer))))
|
||||
|
@ -334,7 +340,7 @@ buffer."
|
|||
mm-handle))
|
||||
|
||||
(defun notmuch-show-save-attachments ()
|
||||
"Save the attachments to a message"
|
||||
"Save all attachments from the current message."
|
||||
(interactive)
|
||||
(with-current-notmuch-show-message
|
||||
(let ((mm-handle (mm-dissect-buffer)))
|
||||
|
@ -360,7 +366,7 @@ buffer."
|
|||
(notmuch-reply message-id)))
|
||||
|
||||
(defun notmuch-show-forward-current ()
|
||||
"Forward a the current message."
|
||||
"Forward the current message."
|
||||
(interactive)
|
||||
(with-current-notmuch-show-message
|
||||
(message-forward)))
|
||||
|
@ -385,7 +391,7 @@ point either forward or backward to the next visible character
|
|||
when a command ends with point on an invisible character).
|
||||
|
||||
Emits an error if point is not within a valid message, (that is
|
||||
not pattern of `notmuch-show-message-begin-regexp' could be found
|
||||
no pattern of `notmuch-show-message-begin-regexp' could be found
|
||||
by searching backward)."
|
||||
(beginning-of-line)
|
||||
(if (not (looking-at notmuch-show-message-begin-regexp))
|
||||
|
@ -402,22 +408,35 @@ by searching backward)."
|
|||
(not (re-search-forward notmuch-show-message-begin-regexp nil t)))))
|
||||
|
||||
(defun notmuch-show-message-unread-p ()
|
||||
"Preficate testing whether current message is unread."
|
||||
"Predicate testing whether current message is unread."
|
||||
(member "unread" (notmuch-show-get-tags)))
|
||||
|
||||
(defun notmuch-show-message-open-p ()
|
||||
"Predicate testing whether current message is open (body is visible)."
|
||||
(let ((btn (previous-button (point) t)))
|
||||
(while (not (button-has-type-p btn 'notmuch-button-body-toggle-type))
|
||||
(setq btn (previous-button (button-start btn))))
|
||||
(not (invisible-p (button-get btn 'invisibility-spec)))))
|
||||
|
||||
(defun notmuch-show-next-message ()
|
||||
"Advance to the beginning of the next message in the buffer.
|
||||
|
||||
Moves to the last visible character of the current message if
|
||||
already on the last message in the buffer."
|
||||
already on the last message in the buffer.
|
||||
|
||||
Returns nil if already on the last message in the buffer."
|
||||
(interactive)
|
||||
(notmuch-show-move-to-current-message-summary-line)
|
||||
(if (re-search-forward notmuch-show-message-begin-regexp nil t)
|
||||
(progn
|
||||
(notmuch-show-move-to-current-message-summary-line)
|
||||
(recenter 0)
|
||||
t)
|
||||
(goto-char (- (point-max) 1))
|
||||
(while (point-invisible-p)
|
||||
(backward-char)))
|
||||
(recenter 0))
|
||||
(backward-char))
|
||||
(recenter 0)
|
||||
nil))
|
||||
|
||||
(defun notmuch-show-find-next-message ()
|
||||
"Returns the position of the next message in the buffer.
|
||||
|
@ -445,14 +464,9 @@ there are no more unread messages past the current point."
|
|||
(notmuch-show-next-message)))
|
||||
|
||||
(defun notmuch-show-next-open-message ()
|
||||
"Advance to the next message which is not hidden.
|
||||
|
||||
If read messages are currently hidden, advance to the next unread
|
||||
message. Otherwise, advance to the next message."
|
||||
(if (or (memq 'notmuch-show-body-read buffer-invisibility-spec)
|
||||
(assq 'notmuch-show-body-read buffer-invisibility-spec))
|
||||
(notmuch-show-next-unread-message)
|
||||
(notmuch-show-next-message)))
|
||||
"Advance to the next open message (that is, body is not invisible)."
|
||||
(while (and (notmuch-show-next-message)
|
||||
(not (notmuch-show-message-open-p)))))
|
||||
|
||||
(defun notmuch-show-previous-message ()
|
||||
"Backup to the beginning of the previous message in the buffer.
|
||||
|
@ -486,13 +500,13 @@ it."
|
|||
(point))))
|
||||
|
||||
(defun notmuch-show-mark-read-then-next-open-message ()
|
||||
"Remove unread tag from current message, then advance to next unread message."
|
||||
"Remove unread tag from this message, then advance to next open message."
|
||||
(interactive)
|
||||
(notmuch-show-remove-tag "unread")
|
||||
(notmuch-show-next-open-message))
|
||||
|
||||
(defun notmuch-show-rewind ()
|
||||
"Do reverse scrolling compared to `notmuch-show-advance-marking-read-and-archiving'
|
||||
"Backup through the thread, (reverse scrolling compared to \\[notmuch-show-advance-marking-read-and-archiving]).
|
||||
|
||||
Specifically, if the beginning of the previous email is fewer
|
||||
than `window-height' lines from the current point, move to it
|
||||
|
@ -514,7 +528,7 @@ any effects from previous calls to
|
|||
(notmuch-show-previous-message))))
|
||||
|
||||
(defun notmuch-show-advance-marking-read-and-archiving ()
|
||||
"Advance through buffer, marking read and archiving.
|
||||
"Advance through thread, marking read and archiving.
|
||||
|
||||
This command is intended to be one of the simplest ways to
|
||||
process a thread of email. It does the following:
|
||||
|
@ -552,7 +566,7 @@ which this thread was originally shown."
|
|||
(goto-char (button-start (previous-button (point)))))
|
||||
|
||||
(defun notmuch-toggle-invisible-action (cite-button)
|
||||
(let ((invis-spec (button-get button 'invisibility-spec)))
|
||||
(let ((invis-spec (button-get cite-button 'invisibility-spec)))
|
||||
(if (invisible-p invis-spec)
|
||||
(remove-from-invisibility-spec invis-spec)
|
||||
(add-to-invisibility-spec invis-spec)
|
||||
|
@ -560,14 +574,19 @@ which this thread was originally shown."
|
|||
(force-window-update)
|
||||
(redisplay t))
|
||||
|
||||
(define-button-type 'notmuch-button-invisibility-toggle-type 'action 'notmuch-toggle-invisible-action 'follow-link t)
|
||||
(define-button-type 'notmuch-button-invisibility-toggle-type
|
||||
'action 'notmuch-toggle-invisible-action
|
||||
'follow-link t
|
||||
'face "default")
|
||||
(define-button-type 'notmuch-button-citation-toggle-type 'help-echo "mouse-1, RET: Show citation"
|
||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||
(define-button-type 'notmuch-button-signature-toggle-type 'help-echo "mouse-1, RET: Show signature"
|
||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||
(define-button-type 'notmuch-button-headers-toggle-type 'help-echo "mouse-1, RET: Show headers"
|
||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||
(define-button-type 'notmuch-button-body-toggle-type 'help-echo "mouse-1, RET: Show message"
|
||||
(define-button-type 'notmuch-button-body-toggle-type
|
||||
'help-echo "mouse-1, RET: Show message"
|
||||
'face 'notmuch-message-summary-face
|
||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||
|
||||
(defun notmuch-show-markup-citations-region (beg end depth)
|
||||
|
@ -665,7 +684,20 @@ which this thread was originally shown."
|
|||
(notmuch-show-markup-part
|
||||
beg end depth mime-message))))))
|
||||
|
||||
(defun notmuch-show-markup-body (depth btn)
|
||||
(defun notmuch-show-markup-body (depth match btn)
|
||||
"Markup a message body, (indenting, buttonizing citations,
|
||||
etc.), and conditionally hiding the body itself if the message
|
||||
has been read and does not match the current search.
|
||||
|
||||
DEPTH specifies the depth at which this message appears in the
|
||||
tree of the current thread, (the top-level messages have depth 0
|
||||
and each reply increases depth by 1). MATCH indicates whether
|
||||
this message is regarded as matching the current search. BTN is
|
||||
the button which is used to toggle the visibility of this
|
||||
message.
|
||||
|
||||
When this function is called, point must be within the message, but
|
||||
before the delimiter marking the beginning of the body."
|
||||
(re-search-forward notmuch-show-body-begin-regexp)
|
||||
(forward-line)
|
||||
(let ((beg (point-marker)))
|
||||
|
@ -676,13 +708,15 @@ which this thread was originally shown."
|
|||
(overlay-put (make-overlay beg end)
|
||||
'invisible invis-spec)
|
||||
(button-put btn 'invisibility-spec invis-spec)
|
||||
(if (not (notmuch-show-message-unread-p))
|
||||
(if (not (or (notmuch-show-message-unread-p) match))
|
||||
(add-to-invisibility-spec invis-spec)))
|
||||
(set-marker beg nil)
|
||||
(set-marker end nil)
|
||||
)))
|
||||
|
||||
(defun notmuch-fontify-headers ()
|
||||
(progn
|
||||
(while (looking-at "[[:space:]]")
|
||||
(forward-char))
|
||||
(if (looking-at "[Tt]o:")
|
||||
(progn
|
||||
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
||||
|
@ -706,56 +740,63 @@ which this thread was originally shown."
|
|||
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
||||
'face 'message-header-name)
|
||||
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
||||
'face 'message-header-other))))))))
|
||||
'face 'message-header-other)))))))
|
||||
|
||||
(defun notmuch-show-markup-header (depth)
|
||||
(defun notmuch-show-markup-header (message-begin depth)
|
||||
"Buttonize and decorate faces in a message header.
|
||||
|
||||
MESSAGE-BEGIN is the position of the absolute first character in
|
||||
the message (including all delimiters that will end up being
|
||||
invisible etc.). This is to allow a button to reliably extend to
|
||||
the beginning of the message even if point is positioned at an
|
||||
invisible character (such as the beginning of the buffer).
|
||||
|
||||
DEPTH specifies the depth at which this message appears in the
|
||||
tree of the current thread, (the top-level messages have depth 0
|
||||
and each reply increases depth by 1)."
|
||||
(re-search-forward notmuch-show-header-begin-regexp)
|
||||
(forward-line)
|
||||
(let ((beg (point-marker))
|
||||
(summary-end (copy-marker (line-beginning-position 2)))
|
||||
(subject-end (copy-marker (line-end-position 2)))
|
||||
(invis-spec (make-symbol "notmuch-show-header"))
|
||||
(btn nil))
|
||||
(end-of-line)
|
||||
; Inverse video for subject
|
||||
(overlay-put (make-overlay beg (point)) 'face '(:inverse-video t))
|
||||
(setq btn (make-button beg (point) :type 'notmuch-button-body-toggle-type))
|
||||
(forward-line 1)
|
||||
(end-of-line)
|
||||
(let ((beg-hidden (point-marker)))
|
||||
(re-search-forward notmuch-show-header-end-regexp)
|
||||
(beginning-of-line)
|
||||
(let ((end (point-marker)))
|
||||
(indent-rigidly beg end depth)
|
||||
(goto-char beg)
|
||||
(setq btn (make-button message-begin summary-end :type 'notmuch-button-body-toggle-type))
|
||||
(forward-line)
|
||||
(while (looking-at "[A-Za-z][-A-Za-z0-9]*:")
|
||||
(add-to-invisibility-spec invis-spec)
|
||||
(overlay-put (make-overlay subject-end end)
|
||||
'invisible invis-spec)
|
||||
(make-button (line-beginning-position) subject-end
|
||||
'invisibility-spec invis-spec
|
||||
:type 'notmuch-button-headers-toggle-type)
|
||||
(while (looking-at "[[:space:]]*[A-Za-z][-A-Za-z0-9]*:")
|
||||
(beginning-of-line)
|
||||
(notmuch-fontify-headers)
|
||||
(forward-line)
|
||||
)
|
||||
(indent-rigidly beg end depth)
|
||||
(let ((invis-spec (make-symbol "notmuch-show-header")))
|
||||
(add-to-invisibility-spec (cons invis-spec t))
|
||||
(overlay-put (make-overlay beg-hidden end)
|
||||
'invisible invis-spec)
|
||||
(goto-char beg)
|
||||
(forward-line)
|
||||
(make-button (line-beginning-position) (line-end-position)
|
||||
'invisibility-spec (cons invis-spec t)
|
||||
:type 'notmuch-button-headers-toggle-type))
|
||||
(goto-char end)
|
||||
(insert "\n")
|
||||
(set-marker beg nil)
|
||||
(set-marker beg-hidden nil)
|
||||
(set-marker summary-end nil)
|
||||
(set-marker subject-end nil)
|
||||
(set-marker end nil)
|
||||
))
|
||||
)
|
||||
btn))
|
||||
|
||||
(defun notmuch-show-markup-message ()
|
||||
(if (re-search-forward notmuch-show-message-begin-regexp nil t)
|
||||
(progn
|
||||
(re-search-forward notmuch-show-depth-regexp)
|
||||
(let ((message-begin (match-beginning 0)))
|
||||
(re-search-forward notmuch-show-depth-match-regexp)
|
||||
(let ((depth (string-to-number (buffer-substring (match-beginning 1) (match-end 1))))
|
||||
(match (string= "1" (buffer-substring (match-beginning 2) (match-end 2))))
|
||||
(btn nil))
|
||||
(setq btn (notmuch-show-markup-header depth))
|
||||
(notmuch-show-markup-body depth btn)))
|
||||
(setq btn (notmuch-show-markup-header message-begin depth))
|
||||
(notmuch-show-markup-body depth match btn)))
|
||||
(goto-char (point-max))))
|
||||
|
||||
(defun notmuch-show-hide-markers ()
|
||||
|
@ -775,6 +816,72 @@ which this thread was originally shown."
|
|||
(notmuch-show-markup-message)))
|
||||
(notmuch-show-hide-markers))
|
||||
|
||||
(defun notmuch-documentation-first-line (symbol)
|
||||
"Return the first line of the documentation string for SYMBOL."
|
||||
(let ((doc (documentation symbol)))
|
||||
(if doc
|
||||
(with-temp-buffer
|
||||
(insert (documentation symbol t))
|
||||
(goto-char (point-min))
|
||||
(let ((beg (point)))
|
||||
(end-of-line)
|
||||
(buffer-substring beg (point))))
|
||||
"")))
|
||||
|
||||
(defun notmuch-prefix-key-description (key)
|
||||
"Given a prefix key code, return a human-readable string representation.
|
||||
|
||||
This is basically just `format-kbd-macro' but we also convert ESC to M-."
|
||||
(let ((desc (format-kbd-macro (vector key))))
|
||||
(if (string= desc "ESC")
|
||||
"M-"
|
||||
(concat desc " "))))
|
||||
|
||||
; I would think that emacs would have code handy for walking a keymap
|
||||
; and generating strings for each key, and I would prefer to just call
|
||||
; that. But I couldn't find any (could be all implemented in C I
|
||||
; suppose), so I wrote my own here.
|
||||
(defun notmuch-substitute-one-command-key-with-prefix (prefix binding)
|
||||
"For a key binding, return a string showing a human-readable
|
||||
representation of the prefixed key as well as the first line of
|
||||
documentation from the bound function.
|
||||
|
||||
For a mouse binding, return nil."
|
||||
(let ((key (car binding))
|
||||
(action (cdr binding)))
|
||||
(if (mouse-event-p key)
|
||||
nil
|
||||
(if (keymapp action)
|
||||
(let ((substitute (apply-partially 'notmuch-substitute-one-command-key-with-prefix (notmuch-prefix-key-description key))))
|
||||
(mapconcat substitute (cdr action) "\n"))
|
||||
(concat prefix (format-kbd-macro (vector key))
|
||||
"\t"
|
||||
(notmuch-documentation-first-line action))))))
|
||||
|
||||
(defalias 'notmuch-substitute-one-command-key
|
||||
(apply-partially 'notmuch-substitute-one-command-key-with-prefix nil))
|
||||
|
||||
(defun notmuch-substitute-command-keys (doc)
|
||||
"Like `substitute-command-keys' but with documentation, not function names."
|
||||
(let ((beg 0))
|
||||
(while (string-match "\\\\{\\([^}[:space:]]*\\)}" doc beg)
|
||||
(let ((map (substring doc (match-beginning 1) (match-end 1))))
|
||||
(setq doc (replace-match (mapconcat 'notmuch-substitute-one-command-key
|
||||
(cdr (symbol-value (intern map))) "\n") 1 1 doc)))
|
||||
(setq beg (match-end 0)))
|
||||
doc))
|
||||
|
||||
(defun notmuch-help ()
|
||||
"Display help for the current notmuch mode."
|
||||
(interactive)
|
||||
(let* ((mode major-mode)
|
||||
(doc (substitute-command-keys (notmuch-substitute-command-keys (documentation mode t)))))
|
||||
(with-current-buffer (generate-new-buffer "*notmuch-help*")
|
||||
(insert doc)
|
||||
(goto-char (point-min))
|
||||
(set-buffer-modified-p nil)
|
||||
(view-buffer (current-buffer) 'kill-buffer-if-not-modified))))
|
||||
|
||||
;;;###autoload
|
||||
(defun notmuch-show-mode ()
|
||||
"Major mode for viewing a thread with notmuch.
|
||||
|
@ -783,22 +890,28 @@ This buffer contains the results of the \"notmuch show\" command
|
|||
for displaying a single thread of email from your email archives.
|
||||
|
||||
By default, various components of email messages, (citations,
|
||||
signatures, already-read messages), are invisible to help you
|
||||
focus on the most important things, (new text from unread
|
||||
messages). See the various commands below for toggling the
|
||||
visibility of hidden components.
|
||||
signatures, already-read messages), are hidden. You can make
|
||||
these parts visible by clicking with the mouse button or by
|
||||
pressing RET after positioning the cursor on a hidden part, (for
|
||||
which \\[notmuch-show-next-button] and \\[notmuch-show-previous-button] are helpful).
|
||||
|
||||
The `notmuch-show-next-message' and
|
||||
`notmuch-show-previous-message' commands, (bound to 'n' and 'p by
|
||||
default), allow you to navigate to the next and previous
|
||||
messages. Each time you navigate away from a message with
|
||||
`notmuch-show-next-message' the current message will have its
|
||||
\"unread\" tag removed.
|
||||
Reading the thread sequentially is well-supported by pressing
|
||||
\\[notmuch-show-advance-marking-read-and-archiving]. This will scroll the current message (if necessary),
|
||||
advance to the next message, or advance to the next thread (if
|
||||
already on the last message of a thread). As each message is
|
||||
scrolled away its \"unread\" tag will be removed, and as each
|
||||
thread is scrolled away the \"inbox\" tag will be removed from
|
||||
each message in the thread.
|
||||
|
||||
You can add or remove tags from the current message with '+' and
|
||||
'-'. You can also archive all messages in the current
|
||||
view, (remove the \"inbox\" tag from each), with
|
||||
`notmuch-show-archive-thread' (bound to 'a' by default).
|
||||
Other commands are available to read or manipulate the thread more
|
||||
selectively, (such as '\\[notmuch-show-next-message]' and '\\[notmuch-show-previous-message]' to advance to messages without
|
||||
removing any tags, and '\\[notmuch-show-archive-thread]' to archive an entire thread without
|
||||
scrolling through with \\[notmuch-show-advance-marking-read-and-archiving]).
|
||||
|
||||
You can add or remove arbitary tags from the current message with
|
||||
'\\[notmuch-show-add-tag]' or '\\[notmuch-show-remove-tag]'.
|
||||
|
||||
All currently available key bindings:
|
||||
|
||||
\\{notmuch-show-mode-map}"
|
||||
(interactive)
|
||||
|
@ -843,7 +956,8 @@ The optional PARENT-BUFFER is the notmuch-search buffer from
|
|||
which this notmuch-show command was executed, (so that the next
|
||||
thread from that buffer can be show when done with this one)."
|
||||
(interactive "sNotmuch show: ")
|
||||
(let ((buffer (get-buffer-create (concat "*notmuch-show-" thread-id "*"))))
|
||||
(let ((query notmuch-search-query-string)
|
||||
(buffer (get-buffer-create (concat "*notmuch-show-" thread-id "*"))))
|
||||
(switch-to-buffer buffer)
|
||||
(notmuch-show-mode)
|
||||
(set (make-local-variable 'notmuch-show-parent-buffer) parent-buffer)
|
||||
|
@ -855,30 +969,13 @@ thread from that buffer can be show when done with this one)."
|
|||
(erase-buffer)
|
||||
(goto-char (point-min))
|
||||
(save-excursion
|
||||
(call-process notmuch-command nil t nil "show" thread-id)
|
||||
(call-process notmuch-command nil t nil "show" "--entire-thread" thread-id "and (" query ")")
|
||||
(notmuch-show-markup-messages)
|
||||
)
|
||||
(run-hooks 'notmuch-show-hook)
|
||||
; Move straight to the first unread message
|
||||
(if (not (notmuch-show-message-unread-p))
|
||||
(progn
|
||||
(notmuch-show-next-unread-message)
|
||||
; But if there are no unread messages, go back to the
|
||||
; beginning of the buffer, and open up the bodies of all
|
||||
; read message.
|
||||
(if (not (notmuch-show-message-unread-p))
|
||||
(progn
|
||||
(goto-char (point-min))
|
||||
(let ((btn (forward-button 1)))
|
||||
(while btn
|
||||
(if (button-has-type-p btn 'notmuch-button-body-toggle-type)
|
||||
(push-button))
|
||||
(condition-case err
|
||||
(setq btn (forward-button 1))
|
||||
(error (setq btn nil)))
|
||||
))
|
||||
(beginning-of-buffer)
|
||||
))))
|
||||
; Move straight to the first open message
|
||||
(if (not (notmuch-show-message-open-p))
|
||||
(notmuch-show-next-open-message))
|
||||
)))
|
||||
|
||||
(defvar notmuch-search-authors-width 40
|
||||
|
@ -886,30 +983,29 @@ thread from that buffer can be show when done with this one)."
|
|||
|
||||
(defvar notmuch-search-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "a" 'notmuch-search-archive-thread)
|
||||
(define-key map "b" 'notmuch-search-scroll-down)
|
||||
(define-key map "f" 'notmuch-search-filter)
|
||||
(define-key map "m" 'message-mail)
|
||||
(define-key map "n" 'next-line)
|
||||
(define-key map "o" 'notmuch-search-toggle-order)
|
||||
(define-key map "p" 'previous-line)
|
||||
(define-key map "?" 'notmuch-help)
|
||||
(define-key map "q" 'kill-this-buffer)
|
||||
(define-key map "r" 'notmuch-search-reply-to-thread)
|
||||
(define-key map "s" 'notmuch-search)
|
||||
(define-key map "t" 'notmuch-search-filter-by-tag)
|
||||
(define-key map "x" 'kill-this-buffer)
|
||||
(define-key map (kbd "RET") 'notmuch-search-show-thread)
|
||||
(define-key map [mouse-1] 'notmuch-search-show-thread)
|
||||
(define-key map "+" 'notmuch-search-add-tag)
|
||||
(define-key map "-" 'notmuch-search-remove-tag)
|
||||
(define-key map "*" 'notmuch-search-operate-all)
|
||||
(define-key map "<" 'beginning-of-buffer)
|
||||
(define-key map ">" 'notmuch-search-goto-last-thread)
|
||||
(define-key map "=" 'notmuch-search-refresh-view)
|
||||
(define-key map "\M->" 'notmuch-search-goto-last-thread)
|
||||
(define-key map " " 'notmuch-search-scroll-up)
|
||||
(define-key map (kbd "<DEL>") 'notmuch-search-scroll-down)
|
||||
(define-key map "?" 'describe-mode)
|
||||
(define-key map "b" 'notmuch-search-scroll-down)
|
||||
(define-key map " " 'notmuch-search-scroll-up)
|
||||
(define-key map "<" 'notmuch-search-first-thread)
|
||||
(define-key map ">" 'notmuch-search-last-thread)
|
||||
(define-key map "p" 'notmuch-search-previous-thread)
|
||||
(define-key map "n" 'notmuch-search-next-thread)
|
||||
(define-key map "r" 'notmuch-search-reply-to-thread)
|
||||
(define-key map "m" 'message-mail)
|
||||
(define-key map "s" 'notmuch-search)
|
||||
(define-key map "o" 'notmuch-search-toggle-order)
|
||||
(define-key map "=" 'notmuch-search-refresh-view)
|
||||
(define-key map "t" 'notmuch-search-filter-by-tag)
|
||||
(define-key map "f" 'notmuch-search-filter)
|
||||
(define-key map [mouse-1] 'notmuch-search-show-thread)
|
||||
(define-key map "*" 'notmuch-search-operate-all)
|
||||
(define-key map "a" 'notmuch-search-archive-thread)
|
||||
(define-key map "-" 'notmuch-search-remove-tag)
|
||||
(define-key map "+" 'notmuch-search-add-tag)
|
||||
(define-key map (kbd "RET") 'notmuch-search-show-thread)
|
||||
map)
|
||||
"Keymap for \"notmuch search\" buffers.")
|
||||
(fset 'notmuch-search-mode-map notmuch-search-mode-map)
|
||||
|
@ -918,16 +1014,17 @@ thread from that buffer can be show when done with this one)."
|
|||
(defvar notmuch-search-oldest-first t
|
||||
"Show the oldest mail first in the search-mode")
|
||||
|
||||
(defvar notmuch-search-disjunctive-regexp "\\<[oO][rR]\\>")
|
||||
|
||||
(defun notmuch-search-scroll-up ()
|
||||
"Scroll up, moving point to last message in thread if at end."
|
||||
"Move forward through search results by one window's worth."
|
||||
(interactive)
|
||||
(condition-case nil
|
||||
(scroll-up nil)
|
||||
((end-of-buffer) (notmuch-search-goto-last-thread))))
|
||||
((end-of-buffer) (notmuch-search-last-thread))))
|
||||
|
||||
(defun notmuch-search-scroll-down ()
|
||||
"Scroll down, moving point to first message in thread if at beginning."
|
||||
"Move backward through the search results by one window's worth."
|
||||
(interactive)
|
||||
; I don't know why scroll-down doesn't signal beginning-of-buffer
|
||||
; the way that scroll-up signals end-of-buffer, but c'est la vie.
|
||||
|
@ -937,15 +1034,36 @@ thread from that buffer can be show when done with this one)."
|
|||
; directly to that position. (We have to count lines since the
|
||||
; window-start position is not the same as point-min due to the
|
||||
; invisible thread-ID characters on the first line.
|
||||
(if (equal (count-lines (point-min) (window-start)) 1)
|
||||
(goto-char (window-start))
|
||||
(if (equal (count-lines (point-min) (window-start)) 0)
|
||||
(goto-char (point-min))
|
||||
(scroll-down nil)))
|
||||
|
||||
(defun notmuch-search-goto-last-thread ()
|
||||
"Move point to the last thread in the buffer."
|
||||
(defun notmuch-search-next-thread ()
|
||||
"Select the next thread in the search results."
|
||||
(interactive)
|
||||
(forward-line 1))
|
||||
|
||||
(defun notmuch-search-previous-thread ()
|
||||
"Select the previous thread in the search results."
|
||||
(interactive)
|
||||
(forward-line -1))
|
||||
|
||||
(defun notmuch-search-last-thread ()
|
||||
"Select the last thread in the search results."
|
||||
(interactive)
|
||||
(goto-char (point-max))
|
||||
(forward-line -1))
|
||||
(forward-line -2))
|
||||
|
||||
(defun notmuch-search-first-thread ()
|
||||
"Select the first thread in the search results."
|
||||
(interactive)
|
||||
(goto-char (point-min)))
|
||||
|
||||
(defface notmuch-message-summary-face
|
||||
'((((class color) (background light)) (:background "#f0f0f0"))
|
||||
(((class color) (background dark)) (:background "#303030")))
|
||||
"Face for the single-line message summary in notmuch-show-mode."
|
||||
:group 'notmuch)
|
||||
|
||||
(defface notmuch-tag-face
|
||||
'((((class color)
|
||||
|
@ -966,22 +1084,27 @@ thread from that buffer can be show when done with this one)."
|
|||
|
||||
;;;###autoload
|
||||
(defun notmuch-search-mode ()
|
||||
"Major mode for searching mail with notmuch.
|
||||
"Major mode displaying results of a notmuch search.
|
||||
|
||||
This buffer contains the results of a \"notmuch search\" of your
|
||||
email archives. Each line in the buffer represents a single
|
||||
thread giving a relative date for the thread and a subject.
|
||||
thread giving a summary of the thread (a relative date, the
|
||||
number of matched messages and total messages in the thread,
|
||||
participants in the thread, a representative subject line, and
|
||||
any tags).
|
||||
|
||||
Pressing RET on any line displays that thread. The '+' and '-'
|
||||
keys can be used to add or remove tags from a thread. The 'a' key
|
||||
is a convenience key for archiving a thread (removing the
|
||||
\"inbox\" tag).
|
||||
Pressing \\[notmuch-search-show-thread] on any line displays that thread. The '\\[notmuch-search-add-tag]' and '\\[notmuch-search-remove-tag]'
|
||||
keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
|
||||
is a convenience for archiving a thread (removing the \"inbox\"
|
||||
tag). The '\\[notmuch-search-operate-all]' key can be used to add or remove a tag from all
|
||||
threads in the current buffer.
|
||||
|
||||
Other useful commands are `notmuch-search-filter' for filtering
|
||||
the current search based on an additional query string,
|
||||
`notmuch-search-filter-by-tag' for filtering to include only
|
||||
messages with a given tag, and `notmuch-search' to execute a new,
|
||||
global search.
|
||||
Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
|
||||
based on an additional query string, '\\[notmuch-search-filter-by-tag]' for filtering to include
|
||||
only messages with a given tag, and '\\[notmuch-search]' to execute a new, global
|
||||
search.
|
||||
|
||||
Complete list of currently available key bindings:
|
||||
|
||||
\\{notmuch-search-mode-map}"
|
||||
(interactive)
|
||||
|
@ -998,8 +1121,7 @@ global search.
|
|||
(if (not notmuch-tag-face-alist)
|
||||
(add-to-list 'notmuch-search-font-lock-keywords (list
|
||||
"(\\([^)]*\\))$" '(1 'notmuch-tag-face)))
|
||||
(progn
|
||||
(setq notmuch-search-tags (mapcar 'car notmuch-tag-face-alist))
|
||||
(let ((notmuch-search-tags (mapcar 'car notmuch-tag-face-alist)))
|
||||
(loop for notmuch-search-tag in notmuch-search-tags
|
||||
do (add-to-list 'notmuch-search-font-lock-keywords (list
|
||||
(concat "([^)]*\\(" notmuch-search-tag "\\)[^)]*)$")
|
||||
|
@ -1012,6 +1134,7 @@ global search.
|
|||
(get-text-property (point) 'notmuch-search-thread-id))
|
||||
|
||||
(defun notmuch-search-show-thread ()
|
||||
"Display the currently selected thread."
|
||||
(interactive)
|
||||
(let ((thread-id (notmuch-search-find-thread-id)))
|
||||
(if (> (length thread-id) 0)
|
||||
|
@ -1064,25 +1187,29 @@ and will also appear in a buffer named \"*Notmuch errors*\"."
|
|||
(split-string (buffer-substring beg end))))))
|
||||
|
||||
(defun notmuch-search-add-tag (tag)
|
||||
"Add a tag to messages in the current thread matching the
|
||||
active query."
|
||||
"Add a tag to the currently selected thread.
|
||||
|
||||
The tag is added to messages in the currently selected thread
|
||||
which match the current search terms."
|
||||
(interactive
|
||||
(list (notmuch-select-tag-with-completion "Tag to add: ")))
|
||||
(notmuch-call-notmuch-process "tag" (concat "+" tag) (notmuch-search-find-thread-id) " and " notmuch-search-query-string)
|
||||
(notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<))))
|
||||
|
||||
(defun notmuch-search-remove-tag (tag)
|
||||
"Remove a tag from messages in the current thread matching the
|
||||
active query."
|
||||
"Remove a tag from the currently selected thread.
|
||||
|
||||
The tag is removed from messages in the currently selected thread
|
||||
which match the current search terms."
|
||||
(interactive
|
||||
(list (notmuch-select-tag-with-completion "Tag to remove: " (notmuch-search-find-thread-id))))
|
||||
(notmuch-call-notmuch-process "tag" (concat "-" tag) (notmuch-search-find-thread-id) " and " notmuch-search-query-string)
|
||||
(notmuch-search-set-tags (delete tag (notmuch-search-get-tags))))
|
||||
|
||||
(defun notmuch-search-archive-thread ()
|
||||
"Archive the current thread (remove its \"inbox\" tag).
|
||||
"Archive the currently selected thread (remove its \"inbox\" tag).
|
||||
|
||||
This function advances point to the next line when finished."
|
||||
This function advances the next thread when finished."
|
||||
(interactive)
|
||||
(notmuch-search-remove-tag "inbox")
|
||||
(forward-line))
|
||||
|
@ -1136,12 +1263,12 @@ This function advances point to the next line when finished."
|
|||
(delete-process proc))))
|
||||
|
||||
(defun notmuch-search-operate-all (action)
|
||||
"Operate on all messages matching the current query. Any
|
||||
number of whitespace separated actions can be given. Each action
|
||||
must have one of the two forms
|
||||
"Add/remove tags from all matching messages.
|
||||
|
||||
+tagname Add the tag `tagname'
|
||||
-tagname Remove the tag `tagname'
|
||||
Tis command adds or removes tags from all messages matching the
|
||||
current search terms. When called interactively, this command
|
||||
will prompt for tags to be added or removed. Tags prefixed with
|
||||
'+' will be added and tags prefixed with '-' will be removed.
|
||||
|
||||
Each character of the tag name may consist of alphanumeric
|
||||
characters as well as `_.+-'.
|
||||
|
@ -1227,7 +1354,8 @@ search."
|
|||
Runs a new search matching only messages that match both the
|
||||
current search results AND the additional query string provided."
|
||||
(interactive "sFilter search: ")
|
||||
(notmuch-search (concat notmuch-search-query-string " and " query) notmuch-search-oldest-first))
|
||||
(let ((grouped-query (if (string-match-p notmuch-search-disjunctive-regexp query) (concat "( " query " )") query)))
|
||||
(notmuch-search (concat notmuch-search-query-string " and " grouped-query) notmuch-search-oldest-first)))
|
||||
|
||||
(defun notmuch-search-filter-by-tag (tag)
|
||||
"Filter the current search results based on a single tag.
|
||||
|
@ -1249,16 +1377,17 @@ current search results AND that are tagged with the given tag."
|
|||
|
||||
(defvar notmuch-folder-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map "n" 'next-line)
|
||||
(define-key map "p" 'previous-line)
|
||||
(define-key map "?" 'notmuch-help)
|
||||
(define-key map "x" 'kill-this-buffer)
|
||||
(define-key map "q" 'kill-this-buffer)
|
||||
(define-key map "s" 'notmuch-search)
|
||||
(define-key map (kbd "RET") 'notmuch-folder-show-search)
|
||||
(define-key map "<" 'beginning-of-buffer)
|
||||
(define-key map ">" 'notmuch-folder-last)
|
||||
(define-key map "<" 'notmuch-folder-first)
|
||||
(define-key map "=" 'notmuch-folder)
|
||||
(define-key map "?" 'describe-mode)
|
||||
(define-key map "s" 'notmuch-search)
|
||||
(define-key map [mouse-1] 'notmuch-folder-show-search)
|
||||
(define-key map (kbd "RET") 'notmuch-folder-show-search)
|
||||
(define-key map "p" 'notmuch-folder-previous)
|
||||
(define-key map "n" 'notmuch-folder-next)
|
||||
map)
|
||||
"Keymap for \"notmuch folder\" buffers.")
|
||||
|
||||
|
@ -1272,12 +1401,26 @@ current search results AND that are tagged with the given tag."
|
|||
(defun notmuch-folder-mode ()
|
||||
"Major mode for showing notmuch 'folders'.
|
||||
|
||||
This buffer contains a list of messages counts returned by a
|
||||
customizable set of searches of your email archives. Each line
|
||||
in the buffer shows the search terms and the resulting message count.
|
||||
This buffer contains a list of message counts returned by a
|
||||
customizable set of searches of your email archives. Each line in
|
||||
the buffer shows the name of a saved search and the resulting
|
||||
message count.
|
||||
|
||||
Pressing RET on any line opens a search window containing the
|
||||
results for the search terms in that line.
|
||||
results for the saved search on that line.
|
||||
|
||||
Here is an example of how the search list could be
|
||||
customized, (the following text would be placed in your ~/.emacs
|
||||
file):
|
||||
|
||||
(setq notmuch-folders '((\"inbox\" . \"tag:inbox\")
|
||||
(\"unread\" . \"tag:inbox AND tag:unread\")
|
||||
(\"notmuch\" . \"tag:inbox AND to:notmuchmail.org\")))
|
||||
|
||||
Of course, you can have any number of folders, each configured
|
||||
with any supported search terms (see \"notmuch help search-terms\").
|
||||
|
||||
Currently available key bindings:
|
||||
|
||||
\\{notmuch-folder-mode-map}"
|
||||
(interactive)
|
||||
|
@ -1289,6 +1432,29 @@ results for the search terms in that line.
|
|||
mode-name "notmuch-folder")
|
||||
(setq buffer-read-only t))
|
||||
|
||||
(defun notmuch-folder-next ()
|
||||
"Select the next folder in the list."
|
||||
(interactive)
|
||||
(forward-line 1)
|
||||
(if (eobp)
|
||||
(forward-line -1)))
|
||||
|
||||
(defun notmuch-folder-previous ()
|
||||
"Select the previous folder in the list."
|
||||
(interactive)
|
||||
(forward-line -1))
|
||||
|
||||
(defun notmuch-folder-first ()
|
||||
"Select the first folder in the list."
|
||||
(interactive)
|
||||
(goto-char (point-min)))
|
||||
|
||||
(defun notmuch-folder-last ()
|
||||
"Select the last folder in the list."
|
||||
(interactive)
|
||||
(goto-char (point-max))
|
||||
(forward-line -1))
|
||||
|
||||
(defun notmuch-folder-add (folders)
|
||||
(if folders
|
||||
(let ((name (car (car folders)))
|
||||
|
|
|
@ -275,6 +275,7 @@ function! s:NM_search_show_thread(everything)
|
|||
call add(words, ')')
|
||||
endif
|
||||
call <SID>NM_cmd_show(words)
|
||||
let b:nm_show_everything = a:everything
|
||||
endfunction
|
||||
|
||||
function! s:NM_search_prompt()
|
||||
|
@ -408,7 +409,7 @@ endfunction
|
|||
|
||||
function! s:NM_cmd_show(words)
|
||||
let prev_bufnr = bufnr('%')
|
||||
let data = s:NM_run(['show'] + a:words)
|
||||
let data = s:NM_run(['show', '--entire-thread'] + a:words)
|
||||
let lines = split(data, "\n")
|
||||
|
||||
let info = s:NM_cmd_show_parse(lines)
|
||||
|
@ -430,6 +431,7 @@ function! s:NM_cmd_show(words)
|
|||
endfunction
|
||||
|
||||
function! s:NM_show_previous(can_change_thread, find_matching)
|
||||
let everything = exists('b:nm_show_everything') ? b:nm_show_everything : 0
|
||||
let info = b:nm_raw_info
|
||||
let lnum = line('.')
|
||||
for msg in reverse(copy(info['msgs']))
|
||||
|
@ -450,7 +452,7 @@ function! s:NM_show_previous(can_change_thread, find_matching)
|
|||
call <SID>NM_kill_this_buffer()
|
||||
if line('.') > 1
|
||||
norm k
|
||||
call <SID>NM_search_show_thread()
|
||||
call <SID>NM_search_show_thread(everything)
|
||||
norm G
|
||||
call <SID>NM_show_previous(0, a:find_matching)
|
||||
else
|
||||
|
@ -479,10 +481,11 @@ function! s:NM_show_next(can_change_thread, find_matching)
|
|||
endfunction
|
||||
|
||||
function! s:NM_show_next_thread()
|
||||
let everything = exists('b:nm_show_everything') ? b:nm_show_everything : 0
|
||||
call <SID>NM_kill_this_buffer()
|
||||
if line('.') != line('$')
|
||||
norm j
|
||||
call <SID>NM_search_show_thread()
|
||||
call <SID>NM_search_show_thread(everything)
|
||||
else
|
||||
echo 'No more messages.'
|
||||
endif
|
||||
|
|
Loading…
Reference in a new issue