mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-11-23 03:18:08 +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
|
||||||
tags
|
tags
|
||||||
*cscope*
|
*cscope*
|
||||||
|
|
58
Makefile
58
Makefile
|
@ -1,6 +1,5 @@
|
||||||
# Default FLAGS, (can be overridden by user such as "make CFLAGS=-O2")
|
WARN_CXXFLAGS=-Wall -Wextra -Wwrite-strings -Wswitch-enum
|
||||||
WARN_FLAGS=-Wall -Wextra -Wmissing-declarations -Wwrite-strings -Wswitch-enum
|
WARN_CFLAGS=$(WARN_CXXFLAGS) -Wmissing-declarations
|
||||||
CFLAGS=-O2
|
|
||||||
|
|
||||||
# Additional programs that are used during the compilation process.
|
# Additional programs that are used during the compilation process.
|
||||||
EMACS ?= emacs
|
EMACS ?= emacs
|
||||||
|
@ -8,66 +7,69 @@ EMACS ?= emacs
|
||||||
# arguments to gzip.
|
# arguments to gzip.
|
||||||
gzip = gzip
|
gzip = gzip
|
||||||
|
|
||||||
# Additional flags that we will append to whatever the user set.
|
bash_completion_dir = /etc/bash_completion.d
|
||||||
# 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
|
|
||||||
|
|
||||||
all_deps = Makefile Makefile.local Makefile.config \
|
all_deps = Makefile Makefile.local Makefile.config \
|
||||||
lib/Makefile lib/Makefile.local
|
lib/Makefile lib/Makefile.local
|
||||||
|
|
||||||
|
extra_cflags :=
|
||||||
|
extra_cxxflags :=
|
||||||
|
|
||||||
# Now smash together user's values with our extra values
|
# Now smash together user's values with our extra values
|
||||||
override CFLAGS += $(WARN_FLAGS) $(extra_cflags)
|
FINAL_CFLAGS = $(CFLAGS) $(WARN_CFLAGS) $(CONFIGURE_CFLAGS) $(extra_cflags)
|
||||||
override CXXFLAGS += $(WARN_FLAGS) $(extra_cflags) $(extra_cxxflags)
|
FINAL_CXXFLAGS = $(CXXFLAGS) $(WARN_CXXFLAGS) $(CONFIGURE_CXXFLAGS) $(extra_cflags) $(extra_cxxflags)
|
||||||
|
FINAL_LDFLAGS = $(LDFLAGS) $(CONFIGURE_LDFLAGS)
|
||||||
|
|
||||||
override LDFLAGS += \
|
all: notmuch notmuch.1.gz
|
||||||
$(shell pkg-config --libs glib-2.0 gmime-2.4 talloc) \
|
|
||||||
$(shell xapian-config --libs)
|
|
||||||
|
|
||||||
# Include our local Makefile.local first so that its first target is default
|
# Before including any other Makefile fragments, get settings from the
|
||||||
include Makefile.local
|
# output of configure
|
||||||
include lib/Makefile.local
|
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 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
|
# The user has not set any verbosity, default to quiet mode and inform the
|
||||||
# user how to enable verbose compiles.
|
# user how to enable verbose compiles.
|
||||||
ifeq ($(V),)
|
ifeq ($(V),)
|
||||||
quiet_DOC := "Use \"$(MAKE) V=1\" to see the verbose compile lines.\n"
|
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
|
endif
|
||||||
# The user has explicitly enabled quiet compilation.
|
# The user has explicitly enabled quiet compilation.
|
||||||
ifeq ($(V),0)
|
ifeq ($(V),0)
|
||||||
quiet = @echo " $1 $@"; $($1)
|
quiet = @printf " $1 $@\n"; $($1)
|
||||||
endif
|
endif
|
||||||
# Otherwise, print the full command line.
|
# Otherwise, print the full command line.
|
||||||
quiet ?= $($1)
|
quiet ?= $($1)
|
||||||
|
|
||||||
%.o: %.cc $(all_deps)
|
%.o: %.cc $(all_deps)
|
||||||
$(call quiet,CXX) -c $(CXXFLAGS) $< -o $@
|
$(call quiet,CXX,$(CXXFLAGS)) -c $(FINAL_CXXFLAGS) $< -o $@
|
||||||
|
|
||||||
%.o: %.c $(all_deps)
|
%.o: %.c $(all_deps)
|
||||||
$(call quiet,CC) -c $(CFLAGS) $< -o $@
|
$(call quiet,CC,$(CFLAGS)) -c $(FINAL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
%.elc: %.el
|
%.elc: %.el
|
||||||
$(call quiet,EMACS) -batch -f batch-byte-compile $<
|
$(call quiet,EMACS) -batch -f batch-byte-compile $<
|
||||||
|
|
||||||
.deps/%.d: %.c $(all_deps)
|
.deps/%.d: %.c $(all_deps)
|
||||||
@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
|
@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' < $@.$$$$ > $@; \
|
sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@.$$$$ > $@; \
|
||||||
rm -f $@.$$$$
|
rm -f $@.$$$$
|
||||||
|
|
||||||
.deps/%.d: %.cc $(all_deps)
|
.deps/%.d: %.cc $(all_deps)
|
||||||
@set -e; rm -f $@; mkdir -p $$(dirname $@) ; \
|
@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' < $@.$$$$ > $@; \
|
sed 's,'$$(basename $*)'\.o[ :]*,$*.o $@ : ,g' < $@.$$$$ > $@; \
|
||||||
rm -f $@.$$$$
|
rm -f $@.$$$$
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
all: notmuch notmuch.1.gz
|
|
||||||
|
|
||||||
emacs: notmuch.elc
|
emacs: notmuch.elc
|
||||||
|
|
||||||
notmuch_client_srcs = \
|
notmuch_client_srcs = \
|
||||||
|
$(notmuch_compat_srcs) \
|
||||||
debugger.c \
|
debugger.c \
|
||||||
gmime-filter-reply.c \
|
gmime-filter-reply.c \
|
||||||
notmuch.c \
|
notmuch.c \
|
||||||
|
@ -23,21 +22,18 @@ notmuch_client_srcs = \
|
||||||
|
|
||||||
notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
|
notmuch_client_modules = $(notmuch_client_srcs:.c=.o)
|
||||||
notmuch: $(notmuch_client_modules) lib/notmuch.a
|
notmuch: $(notmuch_client_modules) lib/notmuch.a
|
||||||
$(call quiet,CXX) $^ $(LDFLAGS) -o $@
|
$(call quiet,CXX,$(LDFLAGS)) $^ $(FINAL_LDFLAGS) -o $@
|
||||||
|
|
||||||
notmuch.1.gz: notmuch.1
|
notmuch.1.gz: notmuch.1
|
||||||
$(call quiet,gzip) --stdout $^ > $@
|
$(call quiet,gzip) --stdout $^ > $@
|
||||||
|
|
||||||
install: all notmuch.1.gz
|
install: all notmuch.1.gz
|
||||||
for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 \
|
for d in $(DESTDIR)$(prefix)/bin/ $(DESTDIR)$(prefix)/share/man/man1 ; \
|
||||||
$(DESTDIR)$(bash_completion_dir) ; \
|
|
||||||
do \
|
do \
|
||||||
install -d $$d ; \
|
install -d $$d ; \
|
||||||
done ;
|
done ;
|
||||||
install notmuch $(DESTDIR)$(prefix)/bin/
|
install notmuch $(DESTDIR)$(prefix)/bin/
|
||||||
install -m0644 notmuch.1.gz $(DESTDIR)$(prefix)/share/man/man1/
|
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
|
install-emacs: install emacs
|
||||||
for d in $(DESTDIR)/$(emacs_lispdir) ; \
|
for d in $(DESTDIR)/$(emacs_lispdir) ; \
|
||||||
|
@ -47,5 +43,10 @@ install-emacs: install emacs
|
||||||
install -m0644 notmuch.el $(DESTDIR)$(emacs_lispdir)
|
install -m0644 notmuch.el $(DESTDIR)$(emacs_lispdir)
|
||||||
install -m0644 notmuch.elc $(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)
|
SRCS := $(SRCS) $(notmuch_client_srcs)
|
||||||
CLEAN := $(CLEAN) notmuch $(notmuch_client_modules) notmuch.elc notmuch.1.gz
|
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)
|
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
|
Add a global keybinding table for notmuch, and then view-specific
|
||||||
tables that add to it.
|
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 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
|
When a thread has been entirely read, start out by closing all
|
||||||
messages except those that matched the search terms.
|
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.
|
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
|
Completion
|
||||||
----------
|
----------
|
||||||
Fix bash completion to complete multiple search options (both --first
|
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
|
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
|
Teach "notmuch search" to return many different kinds of results. Some
|
||||||
ideas:
|
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
|
Xapian bugs fixed that are making this operation slow, we really need
|
||||||
to let the user know that things are still moving.
|
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
|
Add a "-f <filename>" option to select an alternate configuration
|
||||||
file.
|
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
|
new directory will result in notmuch creating new timestamp documents
|
||||||
and leaving stale ones behind.)
|
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
|
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
|
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
|
noting how far back in the past mail has been indexed, and whether it
|
||||||
|
@ -104,10 +100,12 @@ indexing.
|
||||||
|
|
||||||
notmuch library
|
notmuch library
|
||||||
---------------
|
---------------
|
||||||
|
Index content from citations, please.
|
||||||
|
|
||||||
Provide a sane syntax for date ranges. First, we don't want to require
|
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
|
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
|
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
|
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
|
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
|
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
|
(tag-name, search-specification). The database is responsible for
|
||||||
ensuring that the virtual tag is always consistent.
|
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
|
General
|
||||||
-------
|
-------
|
||||||
Audit everything for dealing with out-of-memory (and drop xutil.c).
|
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
|
#! /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
|
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
|
for option; do
|
||||||
if [ "${option%=*}" = '--prefix' ] ; then
|
if [ "${option}" = '--help' ] ; then
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
elif [ "${option%%=*}" = '--prefix' ] ; then
|
||||||
PREFIX="${option#*=}"
|
PREFIX="${option#*=}"
|
||||||
|
else
|
||||||
|
echo "Unrecognized option: ${option}."
|
||||||
|
echo "See:"
|
||||||
|
echo " $0 --help"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
done
|
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
|
and smooth so that you can soon be reading and processing your email
|
||||||
more efficiently than ever.
|
more efficiently than ever.
|
||||||
|
|
||||||
If anything goes wrong in this process, please do as much as you can
|
If anything goes wrong in the configure process, you can override any
|
||||||
to figure out what could be different on your machine compared to
|
decisions it makes by manually editing the Makefile.config file that
|
||||||
those of the notmuch developers. Then, please email those details to
|
it creates. Also please do as much as you can to figure out what could
|
||||||
the Notmuch list (notmuch@notmuchmail.org) so that we can hopefully make
|
be different on your machine compared to those of the notmuch
|
||||||
future versions of notmuch easier for you to use.
|
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
|
We'll now investigate your system to verify that all required
|
||||||
components that notmuch relies on are available.
|
dependencies are available:
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
@ -36,48 +96,57 @@ else
|
||||||
have_pkg_config=0
|
have_pkg_config=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
printf "Checking for Xapian development files... "
|
||||||
if xapian-config --version > /dev/null 2>&1; then
|
if xapian-config --version > /dev/null 2>&1; then
|
||||||
echo "Checking for Xapian development files... Yes."
|
printf "Yes.\n"
|
||||||
have_xapian=1
|
have_xapian=1
|
||||||
|
xapian_cxxflags=$(xapian-config --cxxflags)
|
||||||
|
xapian_ldflags=$(xapian-config --libs)
|
||||||
else
|
else
|
||||||
echo "Checking for Xapian development files... No."
|
printf "No.\n"
|
||||||
have_xapian=0
|
have_xapian=0
|
||||||
errors=$((errors + 1))
|
errors=$((errors + 1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
printf "Checking for GMime 2.4 development files... "
|
||||||
if pkg-config --modversion gmime-2.4 > /dev/null 2>&1; then
|
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
|
have_gmime=1
|
||||||
|
gmime_cflags=$(pkg-config --cflags gmime-2.4)
|
||||||
|
gmime_ldflags=$(pkg-config --libs gmime-2.4)
|
||||||
else
|
else
|
||||||
echo "Checking for GMime 2.4 development files... No."
|
printf "No.\n"
|
||||||
have_gmime=0
|
have_gmime=0
|
||||||
errors=$((errors + 1))
|
errors=$((errors + 1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
printf "Checking for talloc development files... "
|
||||||
if pkg-config --modversion talloc > /dev/null 2>&1; then
|
if pkg-config --modversion talloc > /dev/null 2>&1; then
|
||||||
echo "Checking for talloc development files... Yes."
|
printf "Yes.\n"
|
||||||
have_talloc=1
|
have_talloc=1
|
||||||
|
talloc_cflags=$(pkg-config --cflags talloc)
|
||||||
|
talloc_ldflags=$(pkg-config --libs talloc)
|
||||||
else
|
else
|
||||||
echo "Checking for talloc development files... No."
|
printf "No.\n"
|
||||||
have_talloc=0
|
have_talloc=0
|
||||||
|
talloc_cflags=
|
||||||
errors=$((errors + 1))
|
errors=$((errors + 1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if printf 'int main(){return 0;}' | gcc -x c -lz -o /dev/null - > /dev/null 2>&1; then
|
printf "Checking for valgrind development files... "
|
||||||
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
|
|
||||||
|
|
||||||
if pkg-config --modversion valgrind > /dev/null 2>&1; then
|
if pkg-config --modversion valgrind > /dev/null 2>&1; then
|
||||||
echo "Checking for valgrind development files... Yes."
|
printf "Yes.\n"
|
||||||
have_valgrind=-DHAVE_VALGRIND
|
have_valgrind=1
|
||||||
|
valgrind_cflags=$(pkg-config --cflags valgrind)
|
||||||
else
|
else
|
||||||
echo "Checking for valgrind development files... No."
|
printf "No (but that's fine).\n"
|
||||||
have_valgrind=
|
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
|
fi
|
||||||
|
|
||||||
if [ $errors -gt 0 ]; then
|
if [ $errors -gt 0 ]; then
|
||||||
|
@ -100,34 +169,39 @@ EOF
|
||||||
echo " The talloc library (including development files such as headers)"
|
echo " The talloc library (including development files such as headers)"
|
||||||
echo " http://talloc.samba.org/"
|
echo " http://talloc.samba.org/"
|
||||||
fi
|
fi
|
||||||
if [ $have_zlib -eq 0 ]; then
|
|
||||||
echo " The zlib library (including development files such as headers)"
|
|
||||||
fi
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
On a modern, package-based operating system such as Debian, you can
|
With any luck, you're using a modern, package-based operating system
|
||||||
install all of the dependencies with the following simple command
|
that has all of these packages available in the distribution. In that
|
||||||
line:
|
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
|
sudo apt-get install libxapian-dev libgmime-2.4-dev libtalloc-dev
|
||||||
package names may be different, (such as "devel" in place of "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
|
EOF
|
||||||
if [ $have_pkg_config -eq 0 ]; then
|
if [ $have_pkg_config -eq 0 ]; then
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Note: the pkg-config program is not available. Both this configure
|
Note: the pkg-config program is not available. This configure script
|
||||||
script and the Makefile of notmuch use pkg-config to find the
|
uses pkg-config to find the compilation flags required to link against
|
||||||
compilation flags required to link against the various libraries
|
the various libraries needed by notmuch. It's possible you simply need
|
||||||
needed by notmuch. It's possible you simply need to install pkg-config
|
to install pkg-config with a command such as:
|
||||||
with a command such as:
|
|
||||||
|
|
||||||
sudo apt-get install pkg-config
|
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
|
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
|
to modify the configure script to manually set the cflags and ldflags
|
||||||
NOTMUCH_LDFLAGS to the correct values without calling pkg-config.
|
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
|
EOF
|
||||||
fi
|
fi
|
||||||
|
@ -140,6 +214,17 @@ EOF
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
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
|
cat <<EOF
|
||||||
|
|
||||||
All required packages were found. You may now run the following
|
All required packages were found. You may now run the following
|
||||||
|
@ -152,7 +237,59 @@ EOF
|
||||||
|
|
||||||
# construct the Makefile.config
|
# construct the Makefile.config
|
||||||
cat > Makefile.config <<EOF
|
cat > Makefile.config <<EOF
|
||||||
prefix = $PREFIX
|
# This Makefile.config was automatically generated by the ./configure
|
||||||
bash_completion_dir = /etc/bash_completion.d
|
# script of notmuch. If the configure script identified anything
|
||||||
CFLAGS += ${have_valgrind}
|
# 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
|
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);
|
InternetAddressMailbox *mailbox = INTERNET_ADDRESS_MAILBOX (address);
|
||||||
const char *name, *addr;
|
const char *name, *addr;
|
||||||
int own_name = 0;
|
void *local = talloc_new (NULL);
|
||||||
|
|
||||||
name = internet_address_get_name (address);
|
name = internet_address_get_name (address);
|
||||||
addr = internet_address_mailbox_get_addr (mailbox);
|
addr = internet_address_mailbox_get_addr (mailbox);
|
||||||
|
@ -42,16 +42,16 @@ _index_address_mailbox (notmuch_message_t *message,
|
||||||
const char *at;
|
const char *at;
|
||||||
|
|
||||||
at = strchr (addr, '@');
|
at = strchr (addr, '@');
|
||||||
if (at) {
|
if (at)
|
||||||
name = strndup (addr, at - addr);
|
name = talloc_strndup (local, addr, at - addr);
|
||||||
own_name = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name)
|
if (name)
|
||||||
_notmuch_message_gen_terms (message, prefix_name, name);
|
_notmuch_message_gen_terms (message, prefix_name, name);
|
||||||
if (addr)
|
if (addr)
|
||||||
_notmuch_message_gen_terms (message, prefix_name, addr);
|
_notmuch_message_gen_terms (message, prefix_name, addr);
|
||||||
|
|
||||||
|
talloc_free (local);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -26,6 +26,8 @@
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
#include "notmuch.h"
|
#include "notmuch.h"
|
||||||
|
|
||||||
NOTMUCH_BEGIN_DECLS
|
NOTMUCH_BEGIN_DECLS
|
||||||
|
@ -330,18 +332,6 @@ void
|
||||||
_notmuch_message_add_reply (notmuch_message_t *message,
|
_notmuch_message_add_reply (notmuch_message_t *message,
|
||||||
notmuch_message_node_t *reply);
|
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 */
|
/* sha1.c */
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
* Author: Carl Worth <cworth@cworth.org>
|
* Author: Carl Worth <cworth@cworth.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE /* For strndup */
|
|
||||||
#include "notmuch-private.h"
|
#include "notmuch-private.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -84,11 +83,16 @@ xstrndup (const char *s, size_t n)
|
||||||
{
|
{
|
||||||
char *ret;
|
char *ret;
|
||||||
|
|
||||||
ret = strndup (s, n);
|
if (strlen (s) <= n)
|
||||||
|
n = strlen (s);
|
||||||
|
|
||||||
|
ret = malloc (n + 1);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
fprintf (stderr, "Out of memory.\n");
|
fprintf (stderr, "Out of memory.\n");
|
||||||
exit (1);
|
exit (1);
|
||||||
}
|
}
|
||||||
|
memcpy (ret, s, n);
|
||||||
|
ret[n] = '\0';
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
#ifndef NOTMUCH_CLIENT_H
|
#ifndef NOTMUCH_CLIENT_H
|
||||||
#define NOTMUCH_CLIENT_H
|
#define NOTMUCH_CLIENT_H
|
||||||
|
|
||||||
|
|
||||||
#ifndef _GNU_SOURCE
|
#ifndef _GNU_SOURCE
|
||||||
#define _GNU_SOURCE /* for getline */
|
#define _GNU_SOURCE /* for getline */
|
||||||
#endif
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
#include <gmime/gmime.h>
|
#include <gmime/gmime.h>
|
||||||
|
|
||||||
#include "notmuch.h"
|
#include "notmuch.h"
|
||||||
|
|
|
@ -317,9 +317,11 @@ notmuch_config_save (notmuch_config_t *config)
|
||||||
fprintf (stderr, "Error saving configuration to %s: %s\n",
|
fprintf (stderr, "Error saving configuration to %s: %s\n",
|
||||||
config->filename, error->message);
|
config->filename, error->message);
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
|
g_free (data);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free (data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,10 @@ static volatile sig_atomic_t interrupted;
|
||||||
static void
|
static void
|
||||||
handle_sigint (unused (int sig))
|
handle_sigint (unused (int sig))
|
||||||
{
|
{
|
||||||
|
ssize_t ignored;
|
||||||
static char msg[] = "Stopping... \n";
|
static char msg[] = "Stopping... \n";
|
||||||
write(2, msg, sizeof(msg)-1);
|
|
||||||
|
ignored = write(2, msg, sizeof(msg)-1);
|
||||||
interrupted = 1;
|
interrupted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,17 @@ reply_part_content (GMimeObject *part)
|
||||||
{
|
{
|
||||||
GMimeStream *stream_stdout = NULL, *stream_filter = NULL;
|
GMimeStream *stream_stdout = NULL, *stream_filter = NULL;
|
||||||
GMimeDataWrapper *wrapper;
|
GMimeDataWrapper *wrapper;
|
||||||
|
const char *charset;
|
||||||
|
|
||||||
|
charset = g_mime_object_get_content_type_parameter (part, "charset");
|
||||||
stream_stdout = g_mime_stream_file_new (stdout);
|
stream_stdout = g_mime_stream_file_new (stdout);
|
||||||
if (stream_stdout) {
|
if (stream_stdout) {
|
||||||
g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
|
g_mime_stream_file_set_owner (GMIME_STREAM_FILE (stream_stdout), FALSE);
|
||||||
stream_filter = g_mime_stream_filter_new(stream_stdout);
|
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_stream_filter_add(GMIME_STREAM_FILTER(stream_filter),
|
||||||
g_mime_filter_reply_new(TRUE));
|
g_mime_filter_reply_new(TRUE));
|
||||||
|
|
|
@ -100,12 +100,15 @@ notmuch_setup_command (unused (void *ctx),
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int is_new;
|
int is_new;
|
||||||
|
|
||||||
#define prompt(format, ...) \
|
#define prompt(format, ...) \
|
||||||
do { \
|
do { \
|
||||||
printf (format, ##__VA_ARGS__); \
|
printf (format, ##__VA_ARGS__); \
|
||||||
fflush (stdout); \
|
fflush (stdout); \
|
||||||
getline (&response, &response_size, stdin); \
|
if (getline (&response, &response_size, stdin) < 0) { \
|
||||||
chomp_newline (response); \
|
printf ("Exiting.\n"); \
|
||||||
|
exit (1); \
|
||||||
|
} \
|
||||||
|
chomp_newline (response); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
config = notmuch_config_open (ctx, NULL, &is_new);
|
config = notmuch_config_open (ctx, NULL, &is_new);
|
||||||
|
|
|
@ -184,9 +184,12 @@ show_message (void *ctx, notmuch_message_t *message, int indent)
|
||||||
|
|
||||||
|
|
||||||
static void
|
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_message_t *message;
|
||||||
|
notmuch_bool_t match;
|
||||||
|
int next_indent;
|
||||||
|
|
||||||
for (;
|
for (;
|
||||||
notmuch_messages_has_more (messages);
|
notmuch_messages_has_more (messages);
|
||||||
|
@ -194,9 +197,17 @@ show_messages (void *ctx, notmuch_messages_t *messages, int indent)
|
||||||
{
|
{
|
||||||
message = notmuch_messages_get (messages);
|
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);
|
notmuch_message_destroy (message);
|
||||||
}
|
}
|
||||||
|
@ -212,6 +223,24 @@ notmuch_show_command (void *ctx, unused (int argc), unused (char *argv[]))
|
||||||
notmuch_thread_t *thread;
|
notmuch_thread_t *thread;
|
||||||
notmuch_messages_t *messages;
|
notmuch_messages_t *messages;
|
||||||
char *query_string;
|
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);
|
config = notmuch_config_open (ctx, NULL, NULL);
|
||||||
if (config == 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",
|
INTERNAL_ERROR ("Thread %s has no toplevel messages.\n",
|
||||||
notmuch_thread_get_thread_id (thread));
|
notmuch_thread_get_thread_id (thread));
|
||||||
|
|
||||||
show_messages (ctx, messages, 0);
|
show_messages (ctx, messages, 0, entire_thread);
|
||||||
|
|
||||||
notmuch_thread_destroy (thread);
|
notmuch_thread_destroy (thread);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,10 @@ static volatile sig_atomic_t interrupted;
|
||||||
static void
|
static void
|
||||||
handle_sigint (unused (int sig))
|
handle_sigint (unused (int sig))
|
||||||
{
|
{
|
||||||
|
ssize_t ignored;
|
||||||
|
|
||||||
static char msg[] = "Stopping... \n";
|
static char msg[] = "Stopping... \n";
|
||||||
write(2, msg, sizeof(msg)-1);
|
ignored = write(2, msg, sizeof(msg)-1);
|
||||||
interrupted = 1;
|
interrupted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
18
notmuch.1
18
notmuch.1
|
@ -169,6 +169,8 @@ when sorting by
|
||||||
.B newest\-first
|
.B newest\-first
|
||||||
the threads will be sorted by the newest message in each thread.
|
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,
|
By default, results will be displayed in reverse chronological order,
|
||||||
(that is, the newest results will be displayed first).
|
(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>.
|
section below for details of the supported syntax for <search-terms>.
|
||||||
.RE
|
.RE
|
||||||
.TP
|
.TP
|
||||||
.BR show " <search-term>..."
|
.BR show " [options...] <search-term>..."
|
||||||
|
|
||||||
Shows all messages matching the search terms.
|
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
|
depth tags are printed so that proper indentation can be performed by
|
||||||
a post-processor (such as the emacs interface to notmuch).
|
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
|
The output format is plain-text, with all text-content MIME parts
|
||||||
decoded. Various components in the output,
|
decoded. Various components in the output,
|
||||||
.RB ( message ", " header ", " body ", " attachment ", and MIME " part ),
|
.RB ( message ", " header ", " body ", " attachment ", and MIME " part ),
|
||||||
|
@ -207,6 +222,7 @@ See the
|
||||||
.B "SEARCH SYNTAX"
|
.B "SEARCH SYNTAX"
|
||||||
section below for details of the supported syntax for <search-terms>.
|
section below for details of the supported syntax for <search-terms>.
|
||||||
.RE
|
.RE
|
||||||
|
.RE
|
||||||
|
|
||||||
The
|
The
|
||||||
.B reply
|
.B reply
|
||||||
|
|
|
@ -177,6 +177,15 @@ command_t commands[] = {
|
||||||
"\t\t(all replies to a particular message appear immediately\n"
|
"\t\t(all replies to a particular message appear immediately\n"
|
||||||
"\t\tafter that message in date order).\n"
|
"\t\tafter that message in date order).\n"
|
||||||
"\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\tThe output format is plain-text, with all text-content\n"
|
||||||
"\t\tMIME parts decoded. Various components in the output,\n"
|
"\t\tMIME parts decoded. Various components in the output,\n"
|
||||||
"\t\t('message', 'header', 'body', 'attachment', and MIME 'part')\n"
|
"\t\t('message', 'header', 'body', 'attachment', and MIME 'part')\n"
|
||||||
|
|
604
notmuch.el
604
notmuch.el
|
@ -53,37 +53,31 @@
|
||||||
|
|
||||||
(defvar notmuch-show-mode-map
|
(defvar notmuch-show-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
; I don't actually want all of these toggle commands occupying
|
(define-key map "?" 'notmuch-help)
|
||||||
; 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 "q" 'kill-this-buffer)
|
(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 "s" 'notmuch-search)
|
||||||
(define-key map "v" 'notmuch-show-view-all-mime-parts)
|
(define-key map "m" 'message-mail)
|
||||||
(define-key map "V" 'notmuch-show-view-raw-message)
|
(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 "w" 'notmuch-show-save-attachments)
|
||||||
(define-key map "x" 'kill-this-buffer)
|
(define-key map "V" 'notmuch-show-view-raw-message)
|
||||||
(define-key map "+" 'notmuch-show-add-tag)
|
(define-key map "v" 'notmuch-show-view-all-mime-parts)
|
||||||
(define-key map "-" 'notmuch-show-remove-tag)
|
(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 (kbd "DEL") 'notmuch-show-rewind)
|
||||||
(define-key map " " 'notmuch-show-advance-marking-read-and-archiving)
|
(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)
|
map)
|
||||||
"Keymap for \"notmuch show\" buffers.")
|
"Keymap for \"notmuch show\" buffers.")
|
||||||
(fset 'notmuch-show-mode-map notmuch-show-mode-map)
|
(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-marker-regexp "\f\\(message\\|header\\|body\\|attachment\\|part\\)[{}].*$")
|
||||||
|
|
||||||
(defvar notmuch-show-id-regexp "\\(id:[^ ]*\\)")
|
(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-filename-regexp "filename:\\(.*\\)$")
|
||||||
(defvar notmuch-show-tags-regexp "(\\([^)]*\\))$")
|
(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.
|
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)
|
(interactive)
|
||||||
(set 'this-command 'previous-line)
|
(set 'this-command 'previous-line)
|
||||||
(call-interactively 'previous-line)
|
(call-interactively 'previous-line)
|
||||||
|
@ -252,7 +246,7 @@ Unlike builtin `next-line' this version accepts no arguments."
|
||||||
(notmuch-search-show-thread)))))
|
(notmuch-search-show-thread)))))
|
||||||
|
|
||||||
(defun notmuch-show-mark-read-then-archive-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\"
|
Archive each message currently shown by removing the \"unread\"
|
||||||
and \"inbox\" tag from each. Then kill this buffer and show the
|
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))
|
(notmuch-show-archive-thread-maybe-mark-read t))
|
||||||
|
|
||||||
(defun notmuch-show-archive-thread ()
|
(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\"
|
Archive each message currently shown by removing the \"inbox\"
|
||||||
tag from each. Then kill this buffer and show the next thread
|
tag from each. Then kill this buffer and show the next thread
|
||||||
|
@ -280,6 +274,18 @@ buffer."
|
||||||
(interactive)
|
(interactive)
|
||||||
(notmuch-show-archive-thread-maybe-mark-read nil))
|
(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 ()
|
(defun notmuch-show-view-raw-message ()
|
||||||
"View the raw email of the current message."
|
"View the raw email of the current message."
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -296,7 +302,7 @@ buffer."
|
||||||
(kill-buffer buf)))))
|
(kill-buffer buf)))))
|
||||||
|
|
||||||
(defun notmuch-show-view-all-mime-parts ()
|
(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)
|
(interactive)
|
||||||
(with-current-notmuch-show-message
|
(with-current-notmuch-show-message
|
||||||
(mm-display-parts (mm-dissect-buffer))))
|
(mm-display-parts (mm-dissect-buffer))))
|
||||||
|
@ -334,7 +340,7 @@ buffer."
|
||||||
mm-handle))
|
mm-handle))
|
||||||
|
|
||||||
(defun notmuch-show-save-attachments ()
|
(defun notmuch-show-save-attachments ()
|
||||||
"Save the attachments to a message"
|
"Save all attachments from the current message."
|
||||||
(interactive)
|
(interactive)
|
||||||
(with-current-notmuch-show-message
|
(with-current-notmuch-show-message
|
||||||
(let ((mm-handle (mm-dissect-buffer)))
|
(let ((mm-handle (mm-dissect-buffer)))
|
||||||
|
@ -360,7 +366,7 @@ buffer."
|
||||||
(notmuch-reply message-id)))
|
(notmuch-reply message-id)))
|
||||||
|
|
||||||
(defun notmuch-show-forward-current ()
|
(defun notmuch-show-forward-current ()
|
||||||
"Forward a the current message."
|
"Forward the current message."
|
||||||
(interactive)
|
(interactive)
|
||||||
(with-current-notmuch-show-message
|
(with-current-notmuch-show-message
|
||||||
(message-forward)))
|
(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).
|
when a command ends with point on an invisible character).
|
||||||
|
|
||||||
Emits an error if point is not within a valid message, (that is
|
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)."
|
by searching backward)."
|
||||||
(beginning-of-line)
|
(beginning-of-line)
|
||||||
(if (not (looking-at notmuch-show-message-begin-regexp))
|
(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)))))
|
(not (re-search-forward notmuch-show-message-begin-regexp nil t)))))
|
||||||
|
|
||||||
(defun notmuch-show-message-unread-p ()
|
(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)))
|
(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 ()
|
(defun notmuch-show-next-message ()
|
||||||
"Advance to the beginning of the next message in the buffer.
|
"Advance to the beginning of the next message in the buffer.
|
||||||
|
|
||||||
Moves to the last visible character of the current message if
|
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)
|
(interactive)
|
||||||
(notmuch-show-move-to-current-message-summary-line)
|
(notmuch-show-move-to-current-message-summary-line)
|
||||||
(if (re-search-forward notmuch-show-message-begin-regexp nil t)
|
(if (re-search-forward notmuch-show-message-begin-regexp nil t)
|
||||||
(notmuch-show-move-to-current-message-summary-line)
|
(progn
|
||||||
|
(notmuch-show-move-to-current-message-summary-line)
|
||||||
|
(recenter 0)
|
||||||
|
t)
|
||||||
(goto-char (- (point-max) 1))
|
(goto-char (- (point-max) 1))
|
||||||
(while (point-invisible-p)
|
(while (point-invisible-p)
|
||||||
(backward-char)))
|
(backward-char))
|
||||||
(recenter 0))
|
(recenter 0)
|
||||||
|
nil))
|
||||||
|
|
||||||
(defun notmuch-show-find-next-message ()
|
(defun notmuch-show-find-next-message ()
|
||||||
"Returns the position of the next message in the buffer.
|
"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)))
|
(notmuch-show-next-message)))
|
||||||
|
|
||||||
(defun notmuch-show-next-open-message ()
|
(defun notmuch-show-next-open-message ()
|
||||||
"Advance to the next message which is not hidden.
|
"Advance to the next open message (that is, body is not invisible)."
|
||||||
|
(while (and (notmuch-show-next-message)
|
||||||
If read messages are currently hidden, advance to the next unread
|
(not (notmuch-show-message-open-p)))))
|
||||||
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)))
|
|
||||||
|
|
||||||
(defun notmuch-show-previous-message ()
|
(defun notmuch-show-previous-message ()
|
||||||
"Backup to the beginning of the previous message in the buffer.
|
"Backup to the beginning of the previous message in the buffer.
|
||||||
|
@ -486,13 +500,13 @@ it."
|
||||||
(point))))
|
(point))))
|
||||||
|
|
||||||
(defun notmuch-show-mark-read-then-next-open-message ()
|
(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)
|
(interactive)
|
||||||
(notmuch-show-remove-tag "unread")
|
(notmuch-show-remove-tag "unread")
|
||||||
(notmuch-show-next-open-message))
|
(notmuch-show-next-open-message))
|
||||||
|
|
||||||
(defun notmuch-show-rewind ()
|
(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
|
Specifically, if the beginning of the previous email is fewer
|
||||||
than `window-height' lines from the current point, move to it
|
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))))
|
(notmuch-show-previous-message))))
|
||||||
|
|
||||||
(defun notmuch-show-advance-marking-read-and-archiving ()
|
(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
|
This command is intended to be one of the simplest ways to
|
||||||
process a thread of email. It does the following:
|
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)))))
|
(goto-char (button-start (previous-button (point)))))
|
||||||
|
|
||||||
(defun notmuch-toggle-invisible-action (cite-button)
|
(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)
|
(if (invisible-p invis-spec)
|
||||||
(remove-from-invisibility-spec invis-spec)
|
(remove-from-invisibility-spec invis-spec)
|
||||||
(add-to-invisibility-spec invis-spec)
|
(add-to-invisibility-spec invis-spec)
|
||||||
|
@ -560,14 +574,19 @@ which this thread was originally shown."
|
||||||
(force-window-update)
|
(force-window-update)
|
||||||
(redisplay t))
|
(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"
|
(define-button-type 'notmuch-button-citation-toggle-type 'help-echo "mouse-1, RET: Show citation"
|
||||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||||
(define-button-type 'notmuch-button-signature-toggle-type 'help-echo "mouse-1, RET: Show signature"
|
(define-button-type 'notmuch-button-signature-toggle-type 'help-echo "mouse-1, RET: Show signature"
|
||||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||||
(define-button-type 'notmuch-button-headers-toggle-type 'help-echo "mouse-1, RET: Show headers"
|
(define-button-type 'notmuch-button-headers-toggle-type 'help-echo "mouse-1, RET: Show headers"
|
||||||
:supertype 'notmuch-button-invisibility-toggle-type)
|
: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)
|
:supertype 'notmuch-button-invisibility-toggle-type)
|
||||||
|
|
||||||
(defun notmuch-show-markup-citations-region (beg end depth)
|
(defun notmuch-show-markup-citations-region (beg end depth)
|
||||||
|
@ -665,7 +684,20 @@ which this thread was originally shown."
|
||||||
(notmuch-show-markup-part
|
(notmuch-show-markup-part
|
||||||
beg end depth mime-message))))))
|
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)
|
(re-search-forward notmuch-show-body-begin-regexp)
|
||||||
(forward-line)
|
(forward-line)
|
||||||
(let ((beg (point-marker)))
|
(let ((beg (point-marker)))
|
||||||
|
@ -676,86 +708,95 @@ which this thread was originally shown."
|
||||||
(overlay-put (make-overlay beg end)
|
(overlay-put (make-overlay beg end)
|
||||||
'invisible invis-spec)
|
'invisible invis-spec)
|
||||||
(button-put btn 'invisibility-spec 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)))
|
(add-to-invisibility-spec invis-spec)))
|
||||||
(set-marker beg nil)
|
(set-marker beg nil)
|
||||||
(set-marker end nil)
|
(set-marker end nil)
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(defun notmuch-fontify-headers ()
|
(defun notmuch-fontify-headers ()
|
||||||
(progn
|
(while (looking-at "[[:space:]]")
|
||||||
(if (looking-at "[Tt]o:")
|
(forward-char))
|
||||||
(progn
|
(if (looking-at "[Tt]o:")
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
(progn
|
||||||
'face 'message-header-name)
|
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
'face 'message-header-name)
|
||||||
'face 'message-header-to))
|
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
||||||
|
'face 'message-header-to))
|
||||||
(if (looking-at "[B]?[Cc][Cc]:")
|
(if (looking-at "[B]?[Cc][Cc]:")
|
||||||
(progn
|
(progn
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
||||||
'face 'message-header-name)
|
'face 'message-header-name)
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
||||||
'face 'message-header-cc))
|
'face 'message-header-cc))
|
||||||
(if (looking-at "[Ss]ubject:")
|
(if (looking-at "[Ss]ubject:")
|
||||||
(progn
|
(progn
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
||||||
'face 'message-header-name)
|
'face 'message-header-name)
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
||||||
'face 'message-header-subject))
|
'face 'message-header-subject))
|
||||||
(if (looking-at "[Ff]rom:")
|
(if (looking-at "[Ff]rom:")
|
||||||
(progn
|
(progn
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
(overlay-put (make-overlay (point) (re-search-forward ":"))
|
||||||
'face 'message-header-name)
|
'face 'message-header-name)
|
||||||
(overlay-put (make-overlay (point) (re-search-forward ".*$"))
|
(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)
|
(re-search-forward notmuch-show-header-begin-regexp)
|
||||||
(forward-line)
|
(forward-line)
|
||||||
(let ((beg (point-marker))
|
(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))
|
(btn nil))
|
||||||
(end-of-line)
|
(re-search-forward notmuch-show-header-end-regexp)
|
||||||
; Inverse video for subject
|
(beginning-of-line)
|
||||||
(overlay-put (make-overlay beg (point)) 'face '(:inverse-video t))
|
(let ((end (point-marker)))
|
||||||
(setq btn (make-button beg (point) :type 'notmuch-button-body-toggle-type))
|
(indent-rigidly beg end depth)
|
||||||
(forward-line 1)
|
(goto-char beg)
|
||||||
(end-of-line)
|
(setq btn (make-button message-begin summary-end :type 'notmuch-button-body-toggle-type))
|
||||||
(let ((beg-hidden (point-marker)))
|
(forward-line)
|
||||||
(re-search-forward notmuch-show-header-end-regexp)
|
(add-to-invisibility-spec invis-spec)
|
||||||
(beginning-of-line)
|
(overlay-put (make-overlay subject-end end)
|
||||||
(let ((end (point-marker)))
|
'invisible invis-spec)
|
||||||
(goto-char beg)
|
(make-button (line-beginning-position) subject-end
|
||||||
(forward-line)
|
'invisibility-spec invis-spec
|
||||||
(while (looking-at "[A-Za-z][-A-Za-z0-9]*:")
|
:type 'notmuch-button-headers-toggle-type)
|
||||||
(beginning-of-line)
|
(while (looking-at "[[:space:]]*[A-Za-z][-A-Za-z0-9]*:")
|
||||||
(notmuch-fontify-headers)
|
(beginning-of-line)
|
||||||
(forward-line)
|
(notmuch-fontify-headers)
|
||||||
)
|
(forward-line)
|
||||||
(indent-rigidly beg end depth)
|
)
|
||||||
(let ((invis-spec (make-symbol "notmuch-show-header")))
|
(goto-char end)
|
||||||
(add-to-invisibility-spec (cons invis-spec t))
|
(insert "\n")
|
||||||
(overlay-put (make-overlay beg-hidden end)
|
(set-marker beg nil)
|
||||||
'invisible invis-spec)
|
(set-marker summary-end nil)
|
||||||
(goto-char beg)
|
(set-marker subject-end nil)
|
||||||
(forward-line)
|
(set-marker end nil)
|
||||||
(make-button (line-beginning-position) (line-end-position)
|
)
|
||||||
'invisibility-spec (cons invis-spec t)
|
btn))
|
||||||
:type 'notmuch-button-headers-toggle-type))
|
|
||||||
(goto-char end)
|
|
||||||
(insert "\n")
|
|
||||||
(set-marker beg nil)
|
|
||||||
(set-marker beg-hidden nil)
|
|
||||||
(set-marker end nil)
|
|
||||||
))
|
|
||||||
btn))
|
|
||||||
|
|
||||||
(defun notmuch-show-markup-message ()
|
(defun notmuch-show-markup-message ()
|
||||||
(if (re-search-forward notmuch-show-message-begin-regexp nil t)
|
(if (re-search-forward notmuch-show-message-begin-regexp nil t)
|
||||||
(progn
|
(let ((message-begin (match-beginning 0)))
|
||||||
(re-search-forward notmuch-show-depth-regexp)
|
(re-search-forward notmuch-show-depth-match-regexp)
|
||||||
(let ((depth (string-to-number (buffer-substring (match-beginning 1) (match-end 1))))
|
(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))
|
(btn nil))
|
||||||
(setq btn (notmuch-show-markup-header depth))
|
(setq btn (notmuch-show-markup-header message-begin depth))
|
||||||
(notmuch-show-markup-body depth btn)))
|
(notmuch-show-markup-body depth match btn)))
|
||||||
(goto-char (point-max))))
|
(goto-char (point-max))))
|
||||||
|
|
||||||
(defun notmuch-show-hide-markers ()
|
(defun notmuch-show-hide-markers ()
|
||||||
|
@ -775,6 +816,72 @@ which this thread was originally shown."
|
||||||
(notmuch-show-markup-message)))
|
(notmuch-show-markup-message)))
|
||||||
(notmuch-show-hide-markers))
|
(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
|
;;;###autoload
|
||||||
(defun notmuch-show-mode ()
|
(defun notmuch-show-mode ()
|
||||||
"Major mode for viewing a thread with notmuch.
|
"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.
|
for displaying a single thread of email from your email archives.
|
||||||
|
|
||||||
By default, various components of email messages, (citations,
|
By default, various components of email messages, (citations,
|
||||||
signatures, already-read messages), are invisible to help you
|
signatures, already-read messages), are hidden. You can make
|
||||||
focus on the most important things, (new text from unread
|
these parts visible by clicking with the mouse button or by
|
||||||
messages). See the various commands below for toggling the
|
pressing RET after positioning the cursor on a hidden part, (for
|
||||||
visibility of hidden components.
|
which \\[notmuch-show-next-button] and \\[notmuch-show-previous-button] are helpful).
|
||||||
|
|
||||||
The `notmuch-show-next-message' and
|
Reading the thread sequentially is well-supported by pressing
|
||||||
`notmuch-show-previous-message' commands, (bound to 'n' and 'p by
|
\\[notmuch-show-advance-marking-read-and-archiving]. This will scroll the current message (if necessary),
|
||||||
default), allow you to navigate to the next and previous
|
advance to the next message, or advance to the next thread (if
|
||||||
messages. Each time you navigate away from a message with
|
already on the last message of a thread). As each message is
|
||||||
`notmuch-show-next-message' the current message will have its
|
scrolled away its \"unread\" tag will be removed, and as each
|
||||||
\"unread\" tag removed.
|
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
|
Other commands are available to read or manipulate the thread more
|
||||||
'-'. You can also archive all messages in the current
|
selectively, (such as '\\[notmuch-show-next-message]' and '\\[notmuch-show-previous-message]' to advance to messages without
|
||||||
view, (remove the \"inbox\" tag from each), with
|
removing any tags, and '\\[notmuch-show-archive-thread]' to archive an entire thread without
|
||||||
`notmuch-show-archive-thread' (bound to 'a' by default).
|
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}"
|
\\{notmuch-show-mode-map}"
|
||||||
(interactive)
|
(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
|
which this notmuch-show command was executed, (so that the next
|
||||||
thread from that buffer can be show when done with this one)."
|
thread from that buffer can be show when done with this one)."
|
||||||
(interactive "sNotmuch show: ")
|
(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)
|
(switch-to-buffer buffer)
|
||||||
(notmuch-show-mode)
|
(notmuch-show-mode)
|
||||||
(set (make-local-variable 'notmuch-show-parent-buffer) parent-buffer)
|
(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)
|
(erase-buffer)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(save-excursion
|
(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)
|
(notmuch-show-markup-messages)
|
||||||
)
|
)
|
||||||
(run-hooks 'notmuch-show-hook)
|
(run-hooks 'notmuch-show-hook)
|
||||||
; Move straight to the first unread message
|
; Move straight to the first open message
|
||||||
(if (not (notmuch-show-message-unread-p))
|
(if (not (notmuch-show-message-open-p))
|
||||||
(progn
|
(notmuch-show-next-open-message))
|
||||||
(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)
|
|
||||||
))))
|
|
||||||
)))
|
)))
|
||||||
|
|
||||||
(defvar notmuch-search-authors-width 40
|
(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
|
(defvar notmuch-search-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map "a" 'notmuch-search-archive-thread)
|
(define-key map "?" 'notmuch-help)
|
||||||
(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 "q" 'kill-this-buffer)
|
(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 "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 (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)
|
map)
|
||||||
"Keymap for \"notmuch search\" buffers.")
|
"Keymap for \"notmuch search\" buffers.")
|
||||||
(fset 'notmuch-search-mode-map notmuch-search-mode-map)
|
(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
|
(defvar notmuch-search-oldest-first t
|
||||||
"Show the oldest mail first in the search-mode")
|
"Show the oldest mail first in the search-mode")
|
||||||
|
|
||||||
|
(defvar notmuch-search-disjunctive-regexp "\\<[oO][rR]\\>")
|
||||||
|
|
||||||
(defun notmuch-search-scroll-up ()
|
(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)
|
(interactive)
|
||||||
(condition-case nil
|
(condition-case nil
|
||||||
(scroll-up nil)
|
(scroll-up nil)
|
||||||
((end-of-buffer) (notmuch-search-goto-last-thread))))
|
((end-of-buffer) (notmuch-search-last-thread))))
|
||||||
|
|
||||||
(defun notmuch-search-scroll-down ()
|
(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)
|
(interactive)
|
||||||
; I don't know why scroll-down doesn't signal beginning-of-buffer
|
; 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.
|
; 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
|
; directly to that position. (We have to count lines since the
|
||||||
; window-start position is not the same as point-min due to the
|
; window-start position is not the same as point-min due to the
|
||||||
; invisible thread-ID characters on the first line.
|
; invisible thread-ID characters on the first line.
|
||||||
(if (equal (count-lines (point-min) (window-start)) 1)
|
(if (equal (count-lines (point-min) (window-start)) 0)
|
||||||
(goto-char (window-start))
|
(goto-char (point-min))
|
||||||
(scroll-down nil)))
|
(scroll-down nil)))
|
||||||
|
|
||||||
(defun notmuch-search-goto-last-thread ()
|
(defun notmuch-search-next-thread ()
|
||||||
"Move point to the last thread in the buffer."
|
"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)
|
(interactive)
|
||||||
(goto-char (point-max))
|
(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
|
(defface notmuch-tag-face
|
||||||
'((((class color)
|
'((((class color)
|
||||||
|
@ -966,22 +1084,27 @@ thread from that buffer can be show when done with this one)."
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun notmuch-search-mode ()
|
(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
|
This buffer contains the results of a \"notmuch search\" of your
|
||||||
email archives. Each line in the buffer represents a single
|
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 '-'
|
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 'a' key
|
keys can be used to add or remove tags from a thread. The '\\[notmuch-search-archive-thread]' key
|
||||||
is a convenience key for archiving a thread (removing the
|
is a convenience for archiving a thread (removing the \"inbox\"
|
||||||
\"inbox\" tag).
|
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
|
Other useful commands are '\\[notmuch-search-filter]' for filtering the current search
|
||||||
the current search based on an additional query string,
|
based on an additional query string, '\\[notmuch-search-filter-by-tag]' for filtering to include
|
||||||
`notmuch-search-filter-by-tag' for filtering to include only
|
only messages with a given tag, and '\\[notmuch-search]' to execute a new, global
|
||||||
messages with a given tag, and `notmuch-search' to execute a new,
|
search.
|
||||||
global search.
|
|
||||||
|
Complete list of currently available key bindings:
|
||||||
|
|
||||||
\\{notmuch-search-mode-map}"
|
\\{notmuch-search-mode-map}"
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -998,12 +1121,11 @@ global search.
|
||||||
(if (not notmuch-tag-face-alist)
|
(if (not notmuch-tag-face-alist)
|
||||||
(add-to-list 'notmuch-search-font-lock-keywords (list
|
(add-to-list 'notmuch-search-font-lock-keywords (list
|
||||||
"(\\([^)]*\\))$" '(1 'notmuch-tag-face)))
|
"(\\([^)]*\\))$" '(1 'notmuch-tag-face)))
|
||||||
(progn
|
(let ((notmuch-search-tags (mapcar 'car notmuch-tag-face-alist)))
|
||||||
(setq notmuch-search-tags (mapcar 'car notmuch-tag-face-alist))
|
(loop for notmuch-search-tag in notmuch-search-tags
|
||||||
(loop for notmuch-search-tag in notmuch-search-tags
|
do (add-to-list 'notmuch-search-font-lock-keywords (list
|
||||||
do (add-to-list 'notmuch-search-font-lock-keywords (list
|
(concat "([^)]*\\(" notmuch-search-tag "\\)[^)]*)$")
|
||||||
(concat "([^)]*\\(" notmuch-search-tag "\\)[^)]*)$")
|
`(1 ,(cdr (assoc notmuch-search-tag notmuch-tag-face-alist))))))))
|
||||||
`(1 ,(cdr (assoc notmuch-search-tag notmuch-tag-face-alist))))))))
|
|
||||||
(set (make-local-variable 'font-lock-defaults)
|
(set (make-local-variable 'font-lock-defaults)
|
||||||
'(notmuch-search-font-lock-keywords t)))
|
'(notmuch-search-font-lock-keywords t)))
|
||||||
|
|
||||||
|
@ -1012,6 +1134,7 @@ global search.
|
||||||
(get-text-property (point) 'notmuch-search-thread-id))
|
(get-text-property (point) 'notmuch-search-thread-id))
|
||||||
|
|
||||||
(defun notmuch-search-show-thread ()
|
(defun notmuch-search-show-thread ()
|
||||||
|
"Display the currently selected thread."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((thread-id (notmuch-search-find-thread-id)))
|
(let ((thread-id (notmuch-search-find-thread-id)))
|
||||||
(if (> (length thread-id) 0)
|
(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))))))
|
(split-string (buffer-substring beg end))))))
|
||||||
|
|
||||||
(defun notmuch-search-add-tag (tag)
|
(defun notmuch-search-add-tag (tag)
|
||||||
"Add a tag to messages in the current thread matching the
|
"Add a tag to the currently selected thread.
|
||||||
active query."
|
|
||||||
|
The tag is added to messages in the currently selected thread
|
||||||
|
which match the current search terms."
|
||||||
(interactive
|
(interactive
|
||||||
(list (notmuch-select-tag-with-completion "Tag to add: ")))
|
(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-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<))))
|
(notmuch-search-set-tags (delete-dups (sort (cons tag (notmuch-search-get-tags)) 'string<))))
|
||||||
|
|
||||||
(defun notmuch-search-remove-tag (tag)
|
(defun notmuch-search-remove-tag (tag)
|
||||||
"Remove a tag from messages in the current thread matching the
|
"Remove a tag from the currently selected thread.
|
||||||
active query."
|
|
||||||
|
The tag is removed from messages in the currently selected thread
|
||||||
|
which match the current search terms."
|
||||||
(interactive
|
(interactive
|
||||||
(list (notmuch-select-tag-with-completion "Tag to remove: " (notmuch-search-find-thread-id))))
|
(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-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))))
|
(notmuch-search-set-tags (delete tag (notmuch-search-get-tags))))
|
||||||
|
|
||||||
(defun notmuch-search-archive-thread ()
|
(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)
|
(interactive)
|
||||||
(notmuch-search-remove-tag "inbox")
|
(notmuch-search-remove-tag "inbox")
|
||||||
(forward-line))
|
(forward-line))
|
||||||
|
@ -1136,12 +1263,12 @@ This function advances point to the next line when finished."
|
||||||
(delete-process proc))))
|
(delete-process proc))))
|
||||||
|
|
||||||
(defun notmuch-search-operate-all (action)
|
(defun notmuch-search-operate-all (action)
|
||||||
"Operate on all messages matching the current query. Any
|
"Add/remove tags from all matching messages.
|
||||||
number of whitespace separated actions can be given. Each action
|
|
||||||
must have one of the two forms
|
|
||||||
|
|
||||||
+tagname Add the tag `tagname'
|
Tis command adds or removes tags from all messages matching the
|
||||||
-tagname Remove the tag `tagname'
|
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
|
Each character of the tag name may consist of alphanumeric
|
||||||
characters as well as `_.+-'.
|
characters as well as `_.+-'.
|
||||||
|
@ -1227,7 +1354,8 @@ search."
|
||||||
Runs a new search matching only messages that match both the
|
Runs a new search matching only messages that match both the
|
||||||
current search results AND the additional query string provided."
|
current search results AND the additional query string provided."
|
||||||
(interactive "sFilter search: ")
|
(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)
|
(defun notmuch-search-filter-by-tag (tag)
|
||||||
"Filter the current search results based on a single 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
|
(defvar notmuch-folder-mode-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map "n" 'next-line)
|
(define-key map "?" 'notmuch-help)
|
||||||
(define-key map "p" 'previous-line)
|
|
||||||
(define-key map "x" 'kill-this-buffer)
|
(define-key map "x" 'kill-this-buffer)
|
||||||
(define-key map "q" 'kill-this-buffer)
|
(define-key map "q" 'kill-this-buffer)
|
||||||
(define-key map "s" 'notmuch-search)
|
(define-key map ">" 'notmuch-folder-last)
|
||||||
(define-key map (kbd "RET") 'notmuch-folder-show-search)
|
(define-key map "<" 'notmuch-folder-first)
|
||||||
(define-key map "<" 'beginning-of-buffer)
|
|
||||||
(define-key map "=" 'notmuch-folder)
|
(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 [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)
|
map)
|
||||||
"Keymap for \"notmuch folder\" buffers.")
|
"Keymap for \"notmuch folder\" buffers.")
|
||||||
|
|
||||||
|
@ -1272,12 +1401,26 @@ current search results AND that are tagged with the given tag."
|
||||||
(defun notmuch-folder-mode ()
|
(defun notmuch-folder-mode ()
|
||||||
"Major mode for showing notmuch 'folders'.
|
"Major mode for showing notmuch 'folders'.
|
||||||
|
|
||||||
This buffer contains a list of messages counts returned by a
|
This buffer contains a list of message counts returned by a
|
||||||
customizable set of searches of your email archives. Each line
|
customizable set of searches of your email archives. Each line in
|
||||||
in the buffer shows the search terms and the resulting message count.
|
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
|
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}"
|
\\{notmuch-folder-mode-map}"
|
||||||
(interactive)
|
(interactive)
|
||||||
|
@ -1289,6 +1432,29 @@ results for the search terms in that line.
|
||||||
mode-name "notmuch-folder")
|
mode-name "notmuch-folder")
|
||||||
(setq buffer-read-only t))
|
(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)
|
(defun notmuch-folder-add (folders)
|
||||||
(if folders
|
(if folders
|
||||||
(let ((name (car (car folders)))
|
(let ((name (car (car folders)))
|
||||||
|
|
|
@ -275,6 +275,7 @@ function! s:NM_search_show_thread(everything)
|
||||||
call add(words, ')')
|
call add(words, ')')
|
||||||
endif
|
endif
|
||||||
call <SID>NM_cmd_show(words)
|
call <SID>NM_cmd_show(words)
|
||||||
|
let b:nm_show_everything = a:everything
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:NM_search_prompt()
|
function! s:NM_search_prompt()
|
||||||
|
@ -408,7 +409,7 @@ endfunction
|
||||||
|
|
||||||
function! s:NM_cmd_show(words)
|
function! s:NM_cmd_show(words)
|
||||||
let prev_bufnr = bufnr('%')
|
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 lines = split(data, "\n")
|
||||||
|
|
||||||
let info = s:NM_cmd_show_parse(lines)
|
let info = s:NM_cmd_show_parse(lines)
|
||||||
|
@ -430,6 +431,7 @@ function! s:NM_cmd_show(words)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:NM_show_previous(can_change_thread, find_matching)
|
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 info = b:nm_raw_info
|
||||||
let lnum = line('.')
|
let lnum = line('.')
|
||||||
for msg in reverse(copy(info['msgs']))
|
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()
|
call <SID>NM_kill_this_buffer()
|
||||||
if line('.') > 1
|
if line('.') > 1
|
||||||
norm k
|
norm k
|
||||||
call <SID>NM_search_show_thread()
|
call <SID>NM_search_show_thread(everything)
|
||||||
norm G
|
norm G
|
||||||
call <SID>NM_show_previous(0, a:find_matching)
|
call <SID>NM_show_previous(0, a:find_matching)
|
||||||
else
|
else
|
||||||
|
@ -479,10 +481,11 @@ function! s:NM_show_next(can_change_thread, find_matching)
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
function! s:NM_show_next_thread()
|
function! s:NM_show_next_thread()
|
||||||
|
let everything = exists('b:nm_show_everything') ? b:nm_show_everything : 0
|
||||||
call <SID>NM_kill_this_buffer()
|
call <SID>NM_kill_this_buffer()
|
||||||
if line('.') != line('$')
|
if line('.') != line('$')
|
||||||
norm j
|
norm j
|
||||||
call <SID>NM_search_show_thread()
|
call <SID>NM_search_show_thread(everything)
|
||||||
else
|
else
|
||||||
echo 'No more messages.'
|
echo 'No more messages.'
|
||||||
endif
|
endif
|
||||||
|
|
Loading…
Reference in a new issue