aboutsummaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorDavid Bremner <bremner@debian.org>2023-12-01 07:51:09 -0400
committerDavid Bremner <bremner@debian.org>2023-12-01 07:51:09 -0400
commit126347b6942dd4b0291beb67b119431ebd750a2a (patch)
tree532c5163cb0972c8b9e6c8b4577b86afb9c6a6a2 /doc
Import notmuch_0.38.2.orig.tar.xz
[dgit import orig notmuch_0.38.2.orig.tar.xz]
Diffstat (limited to 'doc')
-rw-r--r--doc/.gitignore3
-rw-r--r--doc/INSTALL11
-rw-r--r--doc/Makefile5
-rw-r--r--doc/Makefile.local163
-rw-r--r--doc/command-line.rst36
-rw-r--r--doc/conf.py226
-rw-r--r--doc/doxygen.cfg298
-rw-r--r--doc/elisp.py445
-rw-r--r--doc/index.rst20
-rw-r--r--doc/man1/notmuch-address.rst141
-rw-r--r--doc/man1/notmuch-compact.rst56
-rw-r--r--doc/man1/notmuch-config.rst385
-rw-r--r--doc/man1/notmuch-count.rst81
-rw-r--r--doc/man1/notmuch-dump.rst123
-rw-r--r--doc/man1/notmuch-emacs-mua.rst102
-rw-r--r--doc/man1/notmuch-git.rst340
-rw-r--r--doc/man1/notmuch-insert.rst133
-rw-r--r--doc/man1/notmuch-new.rst113
-rw-r--r--doc/man1/notmuch-reindex.rst105
-rw-r--r--doc/man1/notmuch-reply.rst143
-rw-r--r--doc/man1/notmuch-restore.rst107
-rw-r--r--doc/man1/notmuch-search.rst191
-rw-r--r--doc/man1/notmuch-show.rst271
-rw-r--r--doc/man1/notmuch-tag.rst121
-rw-r--r--doc/man1/notmuch.rst237
-rw-r--r--doc/man5/notmuch-hooks.rst64
-rw-r--r--doc/man7/notmuch-properties.rst148
-rw-r--r--doc/man7/notmuch-search-terms.rst481
-rw-r--r--doc/man7/notmuch-sexp-queries.rst366
-rw-r--r--doc/notmuch-emacs.rst785
-rw-r--r--doc/python-bindings.rst5
-rw-r--r--doc/queries.rst9
32 files changed, 5714 insertions, 0 deletions
diff --git a/doc/.gitignore b/doc/.gitignore
new file mode 100644
index 00000000..bbb749fa
--- /dev/null
+++ b/doc/.gitignore
@@ -0,0 +1,3 @@
+*.pyc
+/_build
+/config.dox
diff --git a/doc/INSTALL b/doc/INSTALL
new file mode 100644
index 00000000..05854760
--- /dev/null
+++ b/doc/INSTALL
@@ -0,0 +1,11 @@
+This file contains some more detailed information about building and
+installing the documentation.
+
+- You need sphinx at least version 1.0.
+
+- You can build build and install man pages with 'make install-man'
+
+- You can build man, info, html, and pdf versions of the docs
+ (currently only the man pages) with
+
+ 'make install-{man|info|html|pdf}'
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 00000000..fa25832e
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,5 @@
+all:
+ $(MAKE) -C .. all
+
+.DEFAULT:
+ $(MAKE) -C .. $@
diff --git a/doc/Makefile.local b/doc/Makefile.local
new file mode 100644
index 00000000..aafa77a0
--- /dev/null
+++ b/doc/Makefile.local
@@ -0,0 +1,163 @@
+# -*- makefile-gmake -*-
+
+dir := doc
+
+# You can set these variables from the command line.
+SPHINXOPTS := -q
+SPHINXBUILD = env LD_LIBRARY_PATH=${NOTMUCH_BUILDDIR}/lib sphinx-build
+DOCBUILDDIR := $(dir)/_build
+
+# Internal variables.
+ALLSPHINXOPTS := $(SPHINXOPTS) $(srcdir)/$(dir)
+APIMAN := $(DOCBUILDDIR)/man/man3/notmuch.3
+DOXYFILE := $(srcdir)/$(dir)/doxygen.cfg
+
+MAN1_RST := $(wildcard $(srcdir)/doc/man1/*.rst)
+MAN5_RST := $(wildcard $(srcdir)/doc/man5/*.rst)
+MAN7_RST := $(wildcard $(srcdir)/doc/man7/*.rst)
+MAN_RST_FILES := $(MAN1_RST) $(MAN5_RST) $(MAN7_RST)
+ALL_RST_FILES := $(MAN_RST_FILES) $(srcdir)/doc/notmuch-emacs.rst
+
+COPY_ROFF1 := $(patsubst %,$(DOCBUILDDIR)/man/man1/%.1,nmbug notmuch-setup)
+MAN1_ROFF := $(patsubst $(srcdir)/doc/%,$(DOCBUILDDIR)/man/%,$(MAN1_RST:.rst=.1))
+MAN1_ROFF := $(MAN1_ROFF) $(COPY_ROFF1)
+MAN5_ROFF := $(patsubst $(srcdir)/doc/%,$(DOCBUILDDIR)/man/%,$(MAN5_RST:.rst=.5))
+MAN7_ROFF := $(patsubst $(srcdir)/doc/%,$(DOCBUILDDIR)/man/%,$(MAN7_RST:.rst=.7))
+MAN_ROFF_FILES := $(MAN1_ROFF) $(MAN5_ROFF) $(MAN7_ROFF)
+
+MAN_GZIP_FILES := $(addsuffix .gz,${MAN_ROFF_FILES})
+
+MAN1_TEXI := $(patsubst $(srcdir)/doc/man1/%.rst,$(DOCBUILDDIR)/texinfo/%.texi,$(MAN1_RST))
+MAN5_TEXI := $(patsubst $(srcdir)/doc/man5/%.rst,$(DOCBUILDDIR)/texinfo/%.texi,$(MAN5_RST))
+MAN7_TEXI := $(patsubst $(srcdir)/doc/man7/%.rst,$(DOCBUILDDIR)/texinfo/%.texi,$(MAN7_RST))
+INFO_TEXI_FILES := $(MAN1_TEXI) $(MAN5_TEXI) $(MAN7_TEXI)
+ifeq ($(WITH_EMACS),1)
+ INFO_TEXI_FILES += $(DOCBUILDDIR)/texinfo/notmuch-emacs.texi
+endif
+
+COPY_INFO1 := $(patsubst $(DOCBUILDDIR)/man/man1/%.1,$(DOCBUILDDIR)/texinfo/%.info,$(COPY_ROFF1))
+INFO_INFO_FILES := $(INFO_TEXI_FILES:.texi=.info) $(COPY_INFO1)
+
+.PHONY: sphinx-html sphinx-texinfo sphinx-info
+
+.PHONY: install-man build-man apidocs install-apidocs
+
+%.gz: %
+ rm -f $@ && gzip --no-name --stdout $^ > $@
+
+ifeq ($(WITH_EMACS),1)
+$(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.texi.stamp : docstring.stamp
+endif
+
+ifeq ($(HAVE_PYTHON3_CFFI),1)
+DOC_PREREQS=bindings/python-cffi.stamp
+else
+DOC_PREREQS=
+endif
+
+sphinx-html: $(DOCBUILDDIR)/.html.stamp
+
+$(DOCBUILDDIR)/.html.stamp: $(ALL_RST_FILES) $(DOC_PREREQS)
+ $(SPHINXBUILD) -b html -d $(DOCBUILDDIR)/html_doctrees $(ALLSPHINXOPTS) $(DOCBUILDDIR)/html
+ touch $@
+
+sphinx-texinfo: $(DOCBUILDDIR)/.texi.stamp
+
+$(DOCBUILDDIR)/.texi.stamp: $(ALL_RST_FILES) $(DOC_PREREQS)
+ $(SPHINXBUILD) -b texinfo -d $(DOCBUILDDIR)/texinfo_doctrees $(ALLSPHINXOPTS) $(DOCBUILDDIR)/texinfo
+ touch $@
+
+sphinx-info: $(DOCBUILDDIR)/.info.stamp
+
+$(DOCBUILDDIR)/.info.stamp: $(DOCBUILDDIR)/.texi.stamp $(DOC_PREREQS)
+ $(MAKE) -C $(DOCBUILDDIR)/texinfo info
+ touch $@
+
+# Use the man page converter that is available. We should never depend
+# on MAN_ROFF_FILES if a converter is not available.
+${MAN_ROFF_FILES}: $(DOCBUILDDIR)/.roff.stamp
+
+# By using $(DOCBUILDDIR)/.roff.stamp instead of ${MAN_ROFF_FILES}, we
+# convey to make that a single invocation of this recipe builds all
+# of the roff files. This prevents parallel make from starting an
+# instance of this recipe for each roff file.
+$(DOCBUILDDIR)/.roff.stamp: ${MAN_RST_FILES}
+ifeq ($(HAVE_SPHINX),1)
+ $(SPHINXBUILD) -b man -d $(DOCBUILDDIR)/man_doctrees $(ALLSPHINXOPTS) $(DOCBUILDDIR)/man
+ for section in 1 5 7; do \
+ mkdir -p $(DOCBUILDDIR)/man/man$${section}; \
+ mv $(DOCBUILDDIR)/man/*.$${section} $(DOCBUILDDIR)/man/man$${section}; \
+ done
+else
+ @echo "Fatal: build dependency fail."
+ @false
+endif
+ touch $@
+
+install-man: install-apidocs
+
+ifeq ($(HAVE_DOXYGEN),1)
+MAN_GZIP_FILES += ${APIMAN}.gz
+apidocs: $(APIMAN)
+install-apidocs: ${APIMAN}.gz
+ mkdir -p "$(DESTDIR)$(mandir)/man3"
+ install -m0644 $(filter %.3.gz,$(MAN_GZIP_FILES)) $(DESTDIR)/$(mandir)/man3
+
+$(APIMAN): $(dir)/config.dox $(srcdir)/$(dir)/doxygen.cfg $(srcdir)/lib/notmuch.h
+ mkdir -p $(DOCBUILDDIR)/man/man3
+ doxygen $(DOXYFILE)
+ rm -f $(DOCBUILDDIR)/man/man3/_*.3
+ perl -pi -e 's/^[.]RI "\\fI/.RI "\\fP/' $(APIMAN)
+else
+apidocs:
+install-apidocs:
+endif
+
+# Do not try to build or install man pages if a man page converter is
+# not available.
+ifeq ($(HAVE_SPHINX),0)
+build-man:
+install-man:
+ @echo "No sphinx, will not install man pages."
+else
+
+# it should be safe to depend on the stamp file, because it is created
+# after all roff files are moved into place.
+${MAN_GZIP_FILES}: ${DOCBUILDDIR}/.roff.stamp
+
+build-man: ${MAN_GZIP_FILES}
+install-man: ${MAN_GZIP_FILES}
+ mkdir -m0755 -p "$(DESTDIR)$(mandir)/man1"
+ mkdir -m0755 -p "$(DESTDIR)$(mandir)/man5"
+ mkdir -m0755 -p "$(DESTDIR)$(mandir)/man7"
+ install -m0644 $(filter %.1.gz,$(MAN_GZIP_FILES)) $(DESTDIR)/$(mandir)/man1
+ install -m0644 $(filter %.5.gz,$(MAN_GZIP_FILES)) $(DESTDIR)/$(mandir)/man5
+ install -m0644 $(filter %.7.gz,$(MAN_GZIP_FILES)) $(DESTDIR)/$(mandir)/man7
+endif
+
+ifneq ($(HAVE_SPHINX)$(HAVE_MAKEINFO),11)
+build-info:
+ @echo "Missing sphinx or makeinfo, not building info pages"
+else
+build-info: $(DOCBUILDDIR)/.info.stamp
+endif
+
+ifneq ($(HAVE_SPHINX)$(HAVE_MAKEINFO)$(HAVE_INSTALL_INFO),111)
+install-info:
+ @echo "Missing prerequisites, not installing info pages"
+else
+install-info: build-info
+ mkdir -m0755 -p "$(DESTDIR)$(infodir)"
+ install -m0644 $(INFO_INFO_FILES) $(DESTDIR)$(infodir)
+ for file in $(INFO_INFO_FILES); do install-info $$file $(DESTDIR)$(infodir)/dir; done
+endif
+
+$(dir)/config.dox: version.stamp
+ echo "PROJECT_NAME = \"Notmuch $(VERSION)\"" > $@
+ echo "INPUT=${srcdir}/lib/notmuch.h" >> $@
+
+CLEAN := $(CLEAN) $(DOCBUILDDIR) $(DOCBUILDDIR)/.roff.stamp $(DOCBUILDDIR)/.texi.stamp
+CLEAN := $(CLEAN) $(DOCBUILDDIR)/.html.stamp $(DOCBUILDDIR)/.info.stamp
+CLEAN := $(CLEAN) $(MAN_GZIP_FILES) $(MAN_ROFF_FILES) $(dir)/conf.pyc $(dir)/config.dox
+
+CLEAN := $(CLEAN) $(dir)/__pycache__
diff --git a/doc/command-line.rst b/doc/command-line.rst
new file mode 100644
index 00000000..543a5f9e
--- /dev/null
+++ b/doc/command-line.rst
@@ -0,0 +1,36 @@
+Notmuch Command Line Interface
+==============================
+
+Main commands
+-------------
+
+.. toctree::
+ :titlesonly:
+
+ man1/notmuch
+ man1/notmuch-address
+ man1/notmuch-compact
+ man1/notmuch-config
+ man1/notmuch-count
+ man1/notmuch-dump
+ man1/notmuch-emacs-mua
+ man1/notmuch-git
+ man1/notmuch-insert
+ man1/notmuch-new
+ man1/notmuch-reindex
+ man1/notmuch-reply
+ man1/notmuch-restore
+ man1/notmuch-search
+ man1/notmuch-show
+ man1/notmuch-tag
+ man5/notmuch-hooks
+
+Aliases
+-------
+
+.. toctree::
+ :titlesonly:
+
+ nmbug <man1/notmuch-git>
+ notmuch-setup <man1/notmuch>
+
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 00000000..7ac13a5d
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,226 @@
+
+# -*- coding: utf-8 -*-
+
+import sys
+import os
+from pathlib import Path
+sys.path.append(str(Path(__file__).parent))
+
+extensions = [ 'sphinx.ext.autodoc', 'elisp' ]
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'notmuch'
+copyright = u'2009-2023, Carl Worth and many others'
+
+location = os.path.dirname(__file__)
+
+for pathdir in ['.', '..']:
+ version_file = os.path.join(location,pathdir,'version.txt')
+ if os.path.exists(version_file):
+ with open(version_file,'r') as infile:
+ version=infile.read().replace('\n','')
+
+# for autodoc
+sys.path.insert(0, os.path.join(location, '..', 'bindings', 'python-cffi', 'build', 'stage'))
+
+# read generated config
+for pathdir in ['.', '..']:
+ conf_file = os.path.join(location,pathdir,'sphinx.config')
+ if os.path.exists(conf_file):
+ with open(conf_file,'r') as infile:
+ exec(''.join(infile.readlines()))
+
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+if tags.has('WITH_EMACS'):
+ # Hacky reimplementation of include to workaround limitations of
+ # sphinx-doc
+ lines = ['.. include:: /../emacs/rstdoc.rsti\n\n'] # in the source tree
+ for file in ('notmuch.rsti', 'notmuch-lib.rsti', 'notmuch-hello.rsti', 'notmuch-show.rsti', 'notmuch-tag.rsti', 'notmuch-tree.rsti'):
+ lines.extend(open(rsti_dir+'/'+file))
+ rst_epilog = ''.join(lines)
+ del lines
+else:
+ # If we don't have emacs (or the user configured --without-emacs),
+ # don't build the notmuch-emacs docs, as they need emacs to generate
+ # the docstring include files
+ exclude_patterns.append('notmuch-emacs.rst')
+
+if not tags.has('WITH_PYTHON'):
+ exclude_patterns.append('python-bindings.rst')
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# prevent generation of python module index
+html_domain_indices=[]
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = []
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'notmuchdoc'
+
+# Disable SmartyPants, as it mangles command lines.
+# Despite the name, this actually affects manual pages as well.
+html_use_smartypants = False
+
+# See:
+# - https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-manpages_url
+# - https://manpages.debian.org/
+manpages_url = 'https://manpages.debian.org/{page}.{section}.html'
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+
+notmuch_authors = u'Carl Worth and many others'
+
+man_make_section_directory = False
+
+man_pages = [
+ ('man1/notmuch', 'notmuch',
+ u'thread-based email index, search, and tagging',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-address', 'notmuch-address',
+ u'output addresses from matching messages',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-compact', 'notmuch-compact',
+ u'compact the notmuch database',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-config', 'notmuch-config',
+ u'access notmuch configuration file',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-count', 'notmuch-count',
+ u'count messages matching the given search terms',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-dump', 'notmuch-dump',
+ u'creates a plain-text dump of the tags of each message',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-emacs-mua', 'notmuch-emacs-mua',
+ u'send mail with notmuch and emacs',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-git', 'notmuch-git',
+ u'manage notmuch tags with git',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-git', 'nmbug',
+ u'manage notmuch bugs with git',
+ [notmuch_authors], 1),
+
+ ('man5/notmuch-hooks', 'notmuch-hooks',
+ u'hooks for notmuch',
+ [notmuch_authors], 5),
+
+ ('man1/notmuch-insert', 'notmuch-insert',
+ u'add a message to the maildir and notmuch database',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-new', 'notmuch-new',
+ u'incorporate new mail into the notmuch database',
+ [notmuch_authors], 1),
+
+ ('man7/notmuch-properties', 'notmuch-properties',
+ u'notmuch message property conventions and documentation',
+ [notmuch_authors], 7),
+
+ ('man1/notmuch-reindex', 'notmuch-reindex',
+ u're-index matching messages',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-reply', 'notmuch-reply',
+ u'constructs a reply template for a set of messages',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-restore', 'notmuch-restore',
+ u'restores the tags from the given file (see notmuch dump)',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-search', 'notmuch-search',
+ u'search for messages matching the given search terms',
+ [notmuch_authors], 1),
+
+ ('man7/notmuch-search-terms', 'notmuch-search-terms',
+ u'syntax for notmuch queries',
+ [notmuch_authors], 7),
+
+ ('man1/notmuch', 'notmuch-setup',
+ u'getting started with notmuch',
+ [notmuch_authors], 1),
+
+ ('man7/notmuch-sexp-queries', 'notmuch-sexp-queries',
+ u's-expression syntax for notmuch queries',
+ [notmuch_authors], 7),
+
+ ('man1/notmuch-show', 'notmuch-show',
+ u'show messages matching the given search terms',
+ [notmuch_authors], 1),
+
+ ('man1/notmuch-tag', 'notmuch-tag',
+ u'add/remove tags for all messages matching the search terms',
+ [notmuch_authors], 1),
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+texinfo_no_detailmenu = True
+
+texinfo_documents = [
+ ('notmuch-emacs', 'notmuch-emacs', u'notmuch-emacs documentation',
+ notmuch_authors, 'notmuch-emacs',
+ 'emacs based front-end for notmuch', 'Miscellaneous'),
+]
+
+# generate texinfo list from man page list
+texinfo_documents += [
+ (
+ x[0], # source start file
+ x[1], # target name
+ x[1] + u' documentation', # title
+ x[3][0], # author
+ x[1], # dir menu entry
+ x[2], # description
+ 'Miscellaneous' # category
+ ) for x in man_pages]
+
+def setup(app):
+ import docutils.nodes
+ # define nmconfig role and directive for config items.
+ app.add_object_type('nmconfig','nmconfig',
+ indextemplate='pair: configuration item; %s',
+ ref_nodeclass=docutils.nodes.generated,
+ objname='config item' )
diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg
new file mode 100644
index 00000000..4a022de1
--- /dev/null
+++ b/doc/doxygen.cfg
@@ -0,0 +1,298 @@
+# Doxyfile 1.8.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+@INCLUDE = "doc/config.dox"
+PROJECT_NUMBER =
+PROJECT_BRIEF =
+PROJECT_LOGO =
+OUTPUT_DIRECTORY = doc/_build
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF =
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING =
+MARKDOWN_SUPPORT = YES
+AUTOLINK_SUPPORT = YES
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+INLINE_GROUPED_CLASSES = NO
+INLINE_SIMPLE_STRUCTS = NO
+TYPEDEF_HIDES_STRUCT = YES
+LOOKUP_CACHE_SIZE = 0
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_PACKAGE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = NO
+FORCE_LOCAL_INCLUDES = NO
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = NO
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+STRICT_PROTO_MATCHING = NO
+GENERATE_TODOLIST = NO
+GENERATE_TESTLIST = NO
+GENERATE_BUGLIST = NO
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = NO
+SHOW_FILES = NO
+SHOW_NAMESPACES = NO
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+CITE_BIB_FILES =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS =
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+FILTER_SOURCE_PATTERNS =
+USE_MDFILE_AS_MAINPAGE =
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = NO
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_EXTRA_STYLESHEET =
+HTML_EXTRA_FILES =
+HTML_COLORSTYLE_HUE = 220
+HTML_COLORSTYLE_SAT = 100
+HTML_COLORSTYLE_GAMMA = 80
+HTML_TIMESTAMP = YES
+HTML_DYNAMIC_SECTIONS = NO
+HTML_INDEX_NUM_ENTRIES = 100
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME = Publisher
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE = org.doxygen.Project
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+GENERATE_ECLIPSEHELP = NO
+ECLIPSE_DOC_ID = org.doxygen.Project
+DISABLE_INDEX = NO
+GENERATE_TREEVIEW = NO
+ENUM_VALUES_PER_LINE = 4
+TREEVIEW_WIDTH = 250
+EXT_LINKS_IN_WINDOW = NO
+FORMULA_FONTSIZE = 10
+FORMULA_TRANSPARENT = YES
+USE_MATHJAX = NO
+MATHJAX_FORMAT = HTML-CSS
+MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest
+MATHJAX_EXTENSIONS =
+MATHJAX_CODEFILE =
+SEARCHENGINE = YES
+SERVER_BASED_SEARCH = NO
+EXTERNAL_SEARCH = NO
+SEARCHENGINE_URL =
+SEARCHDATA_FILE = searchdata.xml
+EXTERNAL_SEARCH_ID =
+EXTRA_SEARCH_MAPPINGS =
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4
+EXTRA_PACKAGES =
+LATEX_HEADER =
+LATEX_FOOTER =
+LATEX_EXTRA_FILES =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+LATEX_SOURCE_CODE = NO
+LATEX_BIB_STYLE = plain
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = YES
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+GENERATE_DOCBOOK = NO
+DOCBOOK_OUTPUT = docbook
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = NO
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = __DOXYGEN__
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = NO
+EXTERNAL_PAGES = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+DOT_NUM_THREADS = 0
+DOT_FONTNAME = Helvetica
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+UML_LIMIT_NUM_FIELDS = 10
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = NO
+INCLUDED_BY_GRAPH = NO
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = NO
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+INTERACTIVE_SVG = NO
+DOT_PATH =
+DOTFILE_DIRS =
+MSCFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = YES
+GENERATE_LEGEND = NO
+DOT_CLEANUP = YES
diff --git a/doc/elisp.py b/doc/elisp.py
new file mode 100644
index 00000000..1b0392e6
--- /dev/null
+++ b/doc/elisp.py
@@ -0,0 +1,445 @@
+# Copyright (C) 2016 Sebastian Wiesner and Flycheck contributors
+
+# This file is not part of GNU Emacs.
+
+# 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/>.
+
+
+from collections import namedtuple
+from sphinx import addnodes
+from sphinx.util import ws_re
+from sphinx.roles import XRefRole
+from sphinx.domains import Domain, ObjType
+from sphinx.util.nodes import make_refnode
+from sphinx.directives import ObjectDescription
+
+
+def make_target(cell, name):
+ """Create a target name from ``cell`` and ``name``.
+
+ ``cell`` is the name of a symbol cell, and ``name`` is a symbol name, both
+ as strings.
+
+ The target names are used as cross-reference targets for Sphinx.
+
+ """
+ return '{cell}-{name}'.format(cell=cell, name=name)
+
+
+def to_mode_name(symbol_name):
+ """Convert ``symbol_name`` to a mode name.
+
+ Split at ``-`` and titlecase each part.
+
+ """
+ return ' '.join(p.title() for p in symbol_name.split('-'))
+
+
+class Cell(namedtuple('Cell', 'objtype docname')):
+ """A cell in a symbol.
+
+ A cell holds the object type and the document name of the description for
+ the cell.
+
+ Cell objects are used within symbol entries in the domain data.
+
+ """
+
+ pass
+
+
+class KeySequence(namedtuple('KeySequence', 'keys')):
+ """A key sequence."""
+
+ PREFIX_KEYS = {'C-u'}
+ PREFIX_KEYS.update('M-{}'.format(n) for n in range(10))
+
+ @classmethod
+ def fromstring(cls, s):
+ return cls(s.split())
+
+ @property
+ def command_name(self):
+ """The command name in this key sequence.
+
+ Return ``None`` for key sequences that are no command invocations with
+ ``M-x``.
+
+ """
+ try:
+ return self.keys[self.keys.index('M-x') + 1]
+ except ValueError:
+ return None
+
+ @property
+ def has_prefix(self):
+ """Whether this key sequence has a prefix."""
+ return self.keys[0] in self.PREFIX_KEYS
+
+ def __str__(self):
+ return ' '.join(self.keys)
+
+
+class EmacsLispSymbol(ObjectDescription):
+ """An abstract base class for directives documenting symbols.
+
+ Provide target and index generation and registration of documented symbols
+ within the domain data.
+
+ Deriving classes must have a ``cell`` attribute which refers to the cell
+ the documentation goes in, and a ``label`` attribute which provides a
+ human-readable name for what is documented, used in the index entry.
+
+ """
+
+ cell_for_objtype = {
+ 'defcustom': 'variable',
+ 'defconst': 'variable',
+ 'defvar': 'variable',
+ 'defface': 'face'
+ }
+
+ category_for_objtype = {
+ 'defcustom': 'Emacs variable (customizable)',
+ 'defconst': 'Emacs constant',
+ 'defvar': 'Emacs variable',
+ 'defface': 'Emacs face'
+ }
+
+ @property
+ def cell(self):
+ """The cell in which to store symbol metadata."""
+ return self.cell_for_objtype[self.objtype]
+
+ @property
+ def label(self):
+ """The label for the documented object type."""
+ return self.objtype
+
+ @property
+ def category(self):
+ """Index category"""
+ return self.category_for_objtype[self.objtype]
+
+ def handle_signature(self, signature, signode):
+ """Create nodes in ``signode`` for the ``signature``.
+
+ ``signode`` is a docutils node to which to add the nodes, and
+ ``signature`` is the symbol name.
+
+ Add the object type label before the symbol name and return
+ ``signature``.
+
+ """
+ label = self.label + ' '
+ signode += addnodes.desc_annotation(label, label)
+ signode += addnodes.desc_name(signature, signature)
+ return signature
+
+ def _add_index(self, name, target):
+ index_text = '{name}; {label}'.format(
+ name=name, label=self.category)
+ self.indexnode['entries'].append(
+ ('pair', index_text, target, '', None))
+
+ def _add_target(self, name, sig, signode):
+ target = make_target(self.cell, name)
+ if target not in self.state.document.ids:
+ signode['names'].append(name)
+ signode['ids'].append(target)
+ signode['first'] = (not self.names)
+ self.state.document.note_explicit_target(signode)
+
+ obarray = self.env.domaindata['el']['obarray']
+ symbol = obarray.setdefault(name, {})
+ if self.cell in symbol:
+ self.state_machine.reporter.warning(
+ 'duplicate description of %s %s, ' % (self.objtype, name)
+ + 'other instance in '
+ + self.env.doc2path(symbol[self.cell].docname),
+ line=self.lineno)
+ symbol[self.cell] = Cell(self.objtype, self.env.docname)
+
+ return target
+
+ def add_target_and_index(self, name, sig, signode):
+ target = self._add_target(name, sig, signode)
+ self._add_index(name, target)
+
+
+class EmacsLispMinorMode(EmacsLispSymbol):
+ cell = 'function'
+ label = 'Minor Mode'
+
+ def handle_signature(self, signature, signode):
+ """Create nodes in ``signode`` for the ``signature``.
+
+ ``signode`` is a docutils node to which to add the nodes, and
+ ``signature`` is the symbol name.
+
+ Add the object type label before the symbol name and return
+ ``signature``.
+
+ """
+ label = self.label + ' '
+ signode += addnodes.desc_annotation(label, label)
+ signode += addnodes.desc_name(signature, to_mode_name(signature))
+ return signature
+
+ def _add_index(self, name, target):
+ return super()._add_index(to_mode_name(name), target)
+
+
+class EmacsLispFunction(EmacsLispSymbol):
+ """A directive to document Emacs Lisp functions."""
+
+ cell_for_objtype = {
+ 'defun': 'function',
+ 'defmacro': 'function'
+ }
+
+ def handle_signature(self, signature, signode):
+ function_name, *args = ws_re.split(signature)
+ label = self.label + ' '
+ signode += addnodes.desc_annotation(label, label)
+ signode += addnodes.desc_name(function_name, function_name)
+ for arg in args:
+ is_keyword = arg.startswith('&')
+ node = (addnodes.desc_annotation
+ if is_keyword
+ else addnodes.desc_addname)
+ signode += node(' ' + arg, ' ' + arg)
+
+ return function_name
+
+
+class EmacsLispKey(ObjectDescription):
+ """A directive to document interactive commands via their bindings."""
+
+ label = 'Emacs command'
+
+ def handle_signature(self, signature, signode):
+ """Create nodes to ``signode`` for ``signature``.
+
+ ``signode`` is a docutils node to which to add the nodes, and
+ ``signature`` is the symbol name.
+ """
+ key_sequence = KeySequence.fromstring(signature)
+ signode += addnodes.desc_name(signature, str(key_sequence))
+ return str(key_sequence)
+
+ def _add_command_target_and_index(self, name, sig, signode):
+ target_name = make_target('function', name)
+ if target_name not in self.state.document.ids:
+ signode['names'].append(name)
+ signode['ids'].append(target_name)
+ self.state.document.note_explicit_target(signode)
+
+ obarray = self.env.domaindata['el']['obarray']
+ symbol = obarray.setdefault(name, {})
+ if 'function' in symbol:
+ self.state_machine.reporter.warning(
+ 'duplicate description of %s %s, ' % (self.objtype, name)
+ + 'other instance in '
+ + self.env.doc2path(symbol['function'].docname),
+ line=self.lineno)
+ symbol['function'] = Cell(self.objtype, self.env.docname)
+
+ index_text = '{name}; {label}'.format(name=name, label=self.label)
+ self.indexnode['entries'].append(
+ ('pair', index_text, target_name, '', None))
+
+ def _add_binding_target_and_index(self, binding, sig, signode):
+ reftarget = make_target('key', binding)
+
+ if reftarget not in self.state.document.ids:
+ signode['names'].append(reftarget)
+ signode['ids'].append(reftarget)
+ signode['first'] = (not self.names)
+ self.state.document.note_explicit_target(signode)
+
+ keymap = self.env.domaindata['el']['keymap']
+ if binding in keymap:
+ self.state_machine.reporter.warning(
+ 'duplicate description of binding %s, ' % binding
+ + 'other instance in '
+ + self.env.doc2path(keymap[binding]),
+ line=self.lineno)
+ keymap[binding] = self.env.docname
+
+ index_text = '{name}; Emacs key binding'.format(name=binding)
+ self.indexnode['entries'].append(
+ ('pair', index_text, reftarget, '', None))
+
+ def add_target_and_index(self, name, sig, signode):
+ # If unprefixed M-x command index as function and not as key binding
+ sequence = KeySequence.fromstring(name)
+ if sequence.command_name and not sequence.has_prefix:
+ self._add_command_target_and_index(sequence.command_name,
+ sig, signode)
+ else:
+ self._add_binding_target_and_index(name, sig, signode)
+
+
+class XRefModeRole(XRefRole):
+ """A role to cross-reference a minor mode.
+
+ Like a normal cross-reference role but appends ``-mode`` to the reference
+ target and title-cases the symbol name like Emacs does when referring to
+ modes.
+
+ """
+
+ fix_parens = False
+ lowercase = False
+
+ def process_link(self, env, refnode, has_explicit_title, title, target):
+ refnode['reftype'] = 'minor-mode'
+ target = target + '-mode'
+ return (title if has_explicit_title else to_mode_name(target), target)
+
+
+class EmacsLispDomain(Domain):
+ """A domain to document Emacs Lisp code."""
+
+ name = 'el'
+ label = ''
+
+ object_types = {
+ # TODO: Set search prio for object types
+ # Types for user-facing options and commands
+ 'minor-mode': ObjType('minor-mode', 'function', 'mode',
+ cell='function'),
+ 'define-key': ObjType('key binding', cell='interactive'),
+ 'defcustom': ObjType('defcustom', 'defcustom', cell='variable'),
+ 'defface': ObjType('defface', 'defface', cell='face'),
+ # Object types for code
+ 'defun': ObjType('defun', 'defun', cell='function'),
+ 'defmacro': ObjType('defmacro', 'defmacro', cell='function'),
+ 'defvar': ObjType('defvar', 'defvar', cell='variable'),
+ 'defconst': ObjType('defconst', 'defconst', cell='variable')
+ }
+ directives = {
+ 'minor-mode': EmacsLispMinorMode,
+ 'define-key': EmacsLispKey,
+ 'defcustom': EmacsLispSymbol,
+ 'defvar': EmacsLispSymbol,
+ 'defconst': EmacsLispSymbol,
+ 'defface': EmacsLispSymbol,
+ 'defun': EmacsLispFunction,
+ 'defmacro': EmacsLispFunction
+ }
+ roles = {
+ 'mode': XRefModeRole(),
+ 'defvar': XRefRole(),
+ 'defconst': XRefRole(),
+ 'defcustom': XRefRole(),
+ 'defface': XRefRole(),
+ 'defun': XRefRole(),
+ 'defmacro': XRefRole()
+ }
+
+ data_version = 1
+ initial_data = {
+ # Our domain data attempts to somewhat mirror the semantics of Emacs
+ # Lisp, so we have an obarray which holds symbols which in turn have
+ # function, variable, face, etc. cells, and a keymap which holds the
+ # documentation for key bindings.
+ 'obarray': {},
+ 'keymap': {}
+ }
+
+ def clear_doc(self, docname):
+ """Clear all cells documented ``docname``."""
+ for symbol in self.data['obarray'].values():
+ for cell in list(symbol.keys()):
+ if docname == symbol[cell].docname:
+ del symbol[cell]
+ for binding in list(self.data['keymap']):
+ if self.data['keymap'][binding] == docname:
+ del self.data['keymap'][binding]
+
+ def resolve_xref(self, env, fromdocname, builder,
+ objtype, target, node, contnode):
+ """Resolve a cross reference to ``target``."""
+ if objtype == 'key':
+ todocname = self.data['keymap'].get(target)
+ if not todocname:
+ return None
+ reftarget = make_target('key', target)
+ else:
+ cell = self.object_types[objtype].attrs['cell']
+ symbol = self.data['obarray'].get(target, {})
+ if cell not in symbol:
+ return None
+ reftarget = make_target(cell, target)
+ todocname = symbol[cell].docname
+
+ return make_refnode(builder, fromdocname, todocname,
+ reftarget, contnode, target)
+
+ def resolve_any_xref(self, env, fromdocname, builder,
+ target, node, contnode):
+ """Return all possible cross references for ``target``."""
+ nodes = ((objtype, self.resolve_xref(env, fromdocname, builder,
+ objtype, target, node, contnode))
+ for objtype in ['key', 'defun', 'defvar', 'defface'])
+ return [('el:{}'.format(objtype), node) for (objtype, node) in nodes
+ if node is not None]
+
+ def merge_warn_duplicate(self, objname, our_docname, their_docname):
+ self.env.warn(
+ their_docname,
+ "Duplicate declaration: '{}' also defined in '{}'.\n".format(
+ objname, their_docname))
+
+ def merge_keymapdata(self, docnames, our_keymap, their_keymap):
+ for key, docname in their_keymap.items():
+ if docname in docnames:
+ if key in our_keymap:
+ our_docname = our_keymap[key]
+ self.merge_warn_duplicate(key, our_docname, docname)
+ else:
+ our_keymap[key] = docname
+
+ def merge_obarraydata(self, docnames, our_obarray, their_obarray):
+ for objname, their_cells in their_obarray.items():
+ our_cells = our_obarray.setdefault(objname, dict())
+ for cellname, their_cell in their_cells.items():
+ if their_cell.docname in docnames:
+ our_cell = our_cells.get(cellname)
+ if our_cell:
+ self.merge_warn_duplicate(objname, our_cell.docname,
+ their_cell.docname)
+ else:
+ our_cells[cellname] = their_cell
+
+ def merge_domaindata(self, docnames, otherdata):
+ self.merge_keymapdata(docnames, self.data['keymap'],
+ otherdata['keymap'])
+ self.merge_obarraydata(docnames, self.data['obarray'],
+ otherdata['obarray'])
+
+ def get_objects(self):
+ """Get all documented symbols for use in the search index."""
+ for name, symbol in self.data['obarray'].items():
+ for cellname, cell in symbol.items():
+ yield (name, name, cell.objtype, cell.docname,
+ make_target(cellname, name),
+ self.object_types[cell.objtype].attrs['searchprio'])
+
+
+def setup(app):
+ app.add_domain(EmacsLispDomain)
+ return {'version': '0.1', 'parallel_read_safe': True}
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 00000000..fec3e6c2
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,20 @@
+
+Welcome to notmuch's documentation!
+===================================
+
+Content
+-------
+
+.. toctree::
+ :titlesonly:
+
+ command-line
+ queries
+ notmuch-emacs
+ python-bindings
+
+Index and search
+-----------------
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/doc/man1/notmuch-address.rst b/doc/man1/notmuch-address.rst
new file mode 100644
index 00000000..c70dde35
--- /dev/null
+++ b/doc/man1/notmuch-address.rst
@@ -0,0 +1,141 @@
+.. _notmuch-address(1):
+
+===============
+notmuch-address
+===============
+
+SYNOPSIS
+========
+
+**notmuch** **address** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Search for messages matching the given search terms, and display the
+addresses from them. Duplicate addresses are filtered out.
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<search-terms>.
+
+Supported options for **address** include
+
+.. program:: address
+
+.. option:: --format=(json|sexp|text|text0)
+
+ Presents the results in either JSON, S-Expressions, newline
+ character separated plain-text (default), or null character
+ separated plain-text (compatible with :manpage:`xargs(1)` -0
+ option where available).
+
+.. option:: --format-version=N
+
+ Use the specified structured output format version. This is
+ intended for programs that invoke :any:`notmuch(1)` internally. If
+ omitted, the latest supported version will be used.
+
+.. option:: --output=(sender|recipients|count|address)
+
+ Controls which information appears in the output. This option can
+ be given multiple times to combine different outputs. When
+ neither ``--output=sender`` nor ``--output=recipients`` is
+ given, ``--output=sender`` is implied.
+
+ sender
+ Output all addresses from the *From* header.
+
+ Note: Searching for **sender** should be much faster than
+ searching for **recipients**, because sender addresses are
+ cached directly in the database whereas other addresses need
+ to be fetched from message files.
+
+ recipients
+ Output all addresses from the *To*, *Cc* and *Bcc* headers.
+
+ count
+ Print the count of how many times was the address encountered
+ during search.
+
+ Note: With this option, addresses are printed only after the
+ whole search is finished. This may take long time.
+
+ address
+ Output only the email addresses instead of the full mailboxes
+ with names and email addresses. This option has no effect on
+ the JSON or S-Expression output formats.
+
+.. option:: --deduplicate=(no|mailbox|address)
+
+ Control the deduplication of results.
+
+ no
+ Output all occurrences of addresses in the matching
+ messages. This is not applicable with ``--output=count``.
+
+ mailbox
+ Deduplicate addresses based on the full, case sensitive name
+ and email address, or mailbox. This is effectively the same as
+ piping the ``--deduplicate=no`` output to **sort | uniq**, except
+ for the order of results. This is the default.
+
+ address
+ Deduplicate addresses based on the case insensitive address
+ part of the mailbox. Of all the variants (with different name
+ or case), print the one occurring most frequently among the
+ matching messages. If ``--output=count`` is specified, include all
+ variants in the count.
+
+.. option:: --sort=(newest-first|oldest-first)
+
+ This option can be used to present results in either chronological
+ order (**oldest-first**) or reverse chronological order
+ (**newest-first**).
+
+ By default, results will be displayed in reverse chronological
+ order, (that is, the newest results will be displayed first).
+
+ However, if either ``--output=count`` or ``--deduplicate=address`` is
+ specified, this option is ignored and the order of the results is
+ unspecified.
+
+.. option:: --exclude=(true|false)
+
+ A message is called "excluded" if it matches at least one tag in
+ search.exclude\_tags that does not appear explicitly in the search
+ terms. This option specifies whether to omit excluded messages in
+ the search process.
+
+ The default value, **true**, prevents excluded messages from
+ matching the search terms.
+
+ **false** allows excluded messages to match search terms and
+ appear in displayed results.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-compact.rst b/doc/man1/notmuch-compact.rst
new file mode 100644
index 00000000..cb1c858b
--- /dev/null
+++ b/doc/man1/notmuch-compact.rst
@@ -0,0 +1,56 @@
+.. _notmuch-compact(1):
+
+===============
+notmuch-compact
+===============
+
+SYNOPSIS
+========
+
+**notmuch** **compact** [--quiet] [--backup=<*directory*>]
+
+DESCRIPTION
+===========
+
+The **compact** command can be used to compact the notmuch database.
+This can both reduce the space required by the database and improve
+lookup performance.
+
+The compacted database is built in a temporary directory and is later
+moved into the place of the origin database. The original uncompacted
+database is discarded, unless the ``--backup=``\ <directory> option is
+used.
+
+Note that the database write lock will be held during the compaction
+process (which may be quite long) to protect data integrity.
+
+Supported options for **compact** include
+
+.. program:: compact
+
+.. option:: --backup=<directory>
+
+ Save the current database to the given directory before replacing
+ it with the compacted database. The backup directory must not
+ exist and it must reside on the same mounted filesystem as the
+ current database.
+
+.. option:: --quiet
+
+ Do not report database compaction progress to stdout.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-config.rst b/doc/man1/notmuch-config.rst
new file mode 100644
index 00000000..bd34afa4
--- /dev/null
+++ b/doc/man1/notmuch-config.rst
@@ -0,0 +1,385 @@
+.. _notmuch-config(1):
+
+==============
+notmuch-config
+==============
+
+SYNOPSIS
+========
+
+**notmuch** **config** **get** <*section*>.<*item*>
+
+**notmuch** **config** **set** [--database] <*section*>.<*item*> [*value* ...]
+
+**notmuch** **config** **list**
+
+DESCRIPTION
+===========
+
+The **config** command can be used to get or set settings in the notmuch
+configuration file and corresponding database.
+
+.. program:: config
+
+.. option:: get
+
+ The value of the specified configuration item is printed to
+ stdout. If the item has multiple values (it is a list), each value
+ is separated by a newline character.
+
+.. option:: set
+
+ The specified configuration item is set to the given value. To
+ specify a multiple-value item (a list), provide each value as a
+ separate command-line argument.
+
+ If no values are provided, the specified configuration item will
+ be removed from the configuration file.
+
+ With the `--database` option, updates configuration metadata
+ stored in the database, rather than the default (text)
+ configuration file.
+
+.. option:: list
+
+ Every configuration item is printed to stdout, each on a separate
+ line of the form::
+
+ section.item=value
+
+ No additional whitespace surrounds the dot or equals sign
+ characters. In a multiple-value item (a list), the values are
+ separated by semicolon characters.
+
+The available configuration items are described below. Non-absolute
+paths are presumed relative to `$HOME` for items in section
+**database**.
+
+.. nmconfig:: built_with.<name>
+
+ Compile time feature <name>. Current possibilities include
+ "retry_lock" (configure option, included by default).
+ (since notmuch 0.30, "compact" and "field_processor" are
+ always included.)
+
+.. nmconfig:: database.autocommit
+
+ How often to commit transactions to disk. `0` means wait until
+ command completes, otherwise an integer `n` specifies to commit to
+ disk after every `n` completed transactions.
+
+ History: this configuration value was introduced in notmuch 0.33.
+
+.. nmconfig:: database.backup_dir
+
+ Directory to store tag dumps when upgrading database.
+
+ History: this configuration value was introduced in notmuch 0.32.
+
+ Default: A sibling directory of the Xapian database called
+ `backups`.
+
+.. nmconfig:: database.hook_dir
+
+ Directory containing hooks run by notmuch commands. See
+ :any:`notmuch-hooks(5)`.
+
+ History: this configuration value was introduced in notmuch 0.32.
+
+ Default: See HOOKS, below.
+
+.. nmconfig:: database.mail_root
+
+ The top-level directory where your mail currently exists and to
+ where mail will be delivered in the future. Files should be
+ individual email messages.
+
+ History: this configuration value was introduced in notmuch 0.32.
+
+ Default: For compatibility with older configurations, the value of
+ database.path is used if :nmconfig:`database.mail_root` is unset.
+
+.. nmconfig:: database.path
+
+ Notmuch will store its database here, (in
+ sub-directory named ``.notmuch`` if :nmconfig:`database.mail_root`
+ is unset).
+
+ Default: see :ref:`database`
+
+.. nmconfig:: git.path
+
+ Default location for git repository for :any:`notmuch-git`.
+
+.. nmconfig:: git.safe_fraction
+
+ Some :any:`notmuch-git` operations check that the fraction of
+ messages changed (in the database or in git, as appropriate) is not
+ too large. This item controls what fraction of total messages is
+ considered "not too large".
+
+.. nmconfig:: git.tag_prefix
+
+ Default tag prefix (filter) for :any:`notmuch-git`.
+
+.. nmconfig:: index.as_text
+
+ List of regular expressions (without delimiters) for MIME types to
+ be indexed as text. Currently this applies only to attachments. By
+ default the regex matches anywhere in the content type; if the
+ user wants an anchored match, they should include anchors in their
+ regexes.
+
+ History: This configuration value was introduced in notmuch 0.38.
+
+.. nmconfig:: index.decrypt
+
+ Policy for decrypting encrypted messages during indexing. Must be
+ one of: ``false``, ``auto``, ``nostash``, or ``true``.
+
+ When indexing an encrypted e-mail message, if this variable is set
+ to ``true``, notmuch will try to decrypt the message and index the
+ cleartext, stashing a copy of any discovered session keys for the
+ message. If ``auto``, it will try to index the cleartext if a
+ stashed session key is already known for the message (e.g. from a
+ previous copy), but will not try to access your secret keys. Use
+ ``false`` to avoid decrypting even when a stashed session key is
+ already present.
+
+ ``nostash`` is the same as ``true`` except that it will not stash
+ newly-discovered session keys in the database.
+
+ From the command line (i.e. during :any:`notmuch-new(1)`,
+ :any:`notmuch-insert(1)`, or :any:`notmuch-reindex(1)`), the user can
+ override the database's stored decryption policy with the
+ ``--decrypt=`` option.
+
+ Here is a table that summarizes the functionality of each of these
+ policies:
+
+ +------------------------+-------+------+---------+------+
+ | | false | auto | nostash | true |
+ +========================+=======+======+=========+======+
+ | Index cleartext using | | X | X | X |
+ | stashed session keys | | | | |
+ +------------------------+-------+------+---------+------+
+ | Index cleartext | | | X | X |
+ | using secret keys | | | | |
+ +------------------------+-------+------+---------+------+
+ | Stash session keys | | | | X |
+ +------------------------+-------+------+---------+------+
+ | Delete stashed session | X | | | |
+ | keys on reindex | | | | |
+ +------------------------+-------+------+---------+------+
+
+ Stashed session keys are kept in the database as properties
+ associated with the message. See ``session-key`` in
+ :any:`notmuch-properties(7)` for more details about how they can be
+ useful.
+
+ Be aware that the notmuch index is likely sufficient (and a
+ stashed session key is certainly sufficient) to reconstruct the
+ cleartext of the message itself, so please ensure that the notmuch
+ message index is adequately protected. DO NOT USE
+ ``index.decrypt=true`` or ``index.decrypt=nostash`` without
+ considering the security of your index.
+
+ Default: ``auto``.
+
+.. _index.header:
+
+.. nmconfig:: index.header.<prefix>
+
+ Define the query prefix <prefix>, based on a mail header. For
+ example ``index.header.List=List-Id`` will add a probabilistic
+ prefix ``List:`` that searches the ``List-Id`` field. User
+ defined prefixes must not start with 'a'...'z'; in particular
+ adding a prefix with same name as a predefined prefix is not
+ supported. See :any:`notmuch-search-terms(7)` for a list of existing
+ prefixes, and an explanation of probabilistic prefixes.
+
+.. nmconfig:: maildir.synchronize_flags
+
+ If true, then the following maildir flags (in message filenames)
+ will be synchronized with the corresponding notmuch tags:
+
+ +--------+-----------------------------------------------+
+ | Flag | Tag |
+ +========+===============================================+
+ | D | draft |
+ +--------+-----------------------------------------------+
+ | F | flagged |
+ +--------+-----------------------------------------------+
+ | P | passed |
+ +--------+-----------------------------------------------+
+ | R | replied |
+ +--------+-----------------------------------------------+
+ | S | unread (added when 'S' flag is not present) |
+ +--------+-----------------------------------------------+
+
+ The :any:`notmuch-new(1)` command will notice flag changes in
+ filenames and update tags, while the :any:`notmuch-tag(1)` and
+ :any:`notmuch-restore(1)` commands will notice tag changes and
+ update flags in filenames.
+
+ If there have been any changes in the maildir (new messages added,
+ old ones removed or renamed, maildir flags changed, etc.), it is
+ advisable to run :any:`notmuch-new(1)` before
+ :any:`notmuch-tag(1)` or :any:`notmuch-restore(1)` commands to
+ ensure the tag changes are properly synchronized to the maildir
+ flags, as the commands expect the database and maildir to be in
+ sync.
+
+ Default: ``true``.
+
+.. nmconfig:: new.ignore
+
+ A list to specify files and directories that will not be searched
+ for messages by :any:`notmuch-new(1)`. Each entry in the list is either:
+
+ A file or a directory name, without path, that will be ignored,
+ regardless of the location in the mail store directory hierarchy.
+
+ Or:
+
+ A regular expression delimited with // that will be matched
+ against the path of the file or directory relative to the database
+ path. Matching files and directories will be ignored. The
+ beginning and end of string must be explicitly anchored. For
+ example, /.*/foo$/ would match "bar/foo" and "bar/baz/foo", but
+ not "foo" or "bar/foobar".
+
+ Default: empty list.
+
+.. nmconfig:: new.tags
+
+ A list of tags that will be added to all messages incorporated by
+ **notmuch new**.
+
+ Default: ``unread;inbox``.
+
+.. nmconfig:: query.<name>
+
+ Expansion for named query called <name>. See
+ :any:`notmuch-search-terms(7)` for more information about named
+ queries.
+
+.. nmconfig:: search.exclude_tags
+
+ A list of tags that will be excluded from search results by
+ default. Using an excluded tag in a query will override that
+ exclusion.
+
+ Default: empty list. Note that :any:`notmuch-setup(1)` puts
+ ``deleted;spam`` here when creating new configuration file.
+
+.. nmconfig:: show.extra_headers
+
+ By default :any:`notmuch-show(1)` includes the following headers
+ in structured output if they are present in the message:
+ `Subject`, `From`, `To`, `Cc`, `Bcc`, `Reply-To`, `Date`. This
+ option allows the specification of a list of further
+ headers to output.
+
+ History: This configuration value was introduced in notmuch 0.35.
+
+ Default: empty list.
+
+.. nmconfig:: squery.<name>
+
+ Expansion for named query called <name>, using s-expression syntax. See
+ :any:`notmuch-sexp-queries(7)` for more information about s-expression
+ queries.
+
+.. nmconfig:: user.name
+
+ Your full name.
+
+ Default: ``$NAME`` variable if set, otherwise read from
+ ``/etc/passwd``.
+
+.. nmconfig:: user.other_email
+
+ A list of other email addresses at which you receive email
+ (see also, :nmconfig:`user.primary_email`)
+
+ Default: not set.
+
+.. nmconfig:: user.primary_email
+
+ Your primary email address.
+
+ Default: ``$EMAIL`` variable if set, otherwise constructed from
+ the username and hostname of the current machine.
+
+FILES
+=====
+
+.. _config_search:
+
+CONFIGURATION
+-------------
+
+Notmuch configuration file search order:
+
+1. File specified by :option:`notmuch --config` global option; see
+ :any:`notmuch(1)`.
+
+2. File specified by :envvar:`NOTMUCH_CONFIG` environment variable.
+
+3. ``$XDG_CONFIG_HOME/notmuch/<profile>/config`` where ``<profile>``
+ is defined by :envvar:`NOTMUCH_PROFILE` environment variable if
+ set, ``$XDG_CONFIG_HOME/notmuch/default/config`` otherwise.
+
+4. ``$HOME/.notmuch-config.<profile>`` where ``<profile>`` is defined
+ by :envvar:`NOTMUCH_PROFILE` environment variable if set,
+ ``$HOME/.notmuch-config`` otherwise.
+
+.. _database:
+
+DATABASE LOCATION
+-----------------
+
+Notmuch database search order:
+
+1. Directory specified by :envvar:`NOTMUCH_DATABASE` environment variable.
+
+2. Directory specified by config key ``database.path``.
+
+3. ``$XDG_DATA_HOME/notmuch/<profile>`` where ``<profile>``
+ is defined by :envvar:`NOTMUCH_PROFILE` environment variable if
+ set, ``$XDG_DATA_HOME/notmuch/default`` otherwise.
+
+4. Directory specified by :envvar:`MAILDIR` environment variable.
+
+5. ``$HOME/mail``
+
+HOOKS
+-----
+
+Notmuch hook directory search order:
+
+1. Directory specified by ``database.hook_dir`` configuration option.
+
+2. ``$XDG_CONFIG_HOME/notmuch/<profile>/hooks`` where ``<profile>``
+ is defined by :envvar:`NOTMUCH_PROFILE` environment variable if
+ set, ``$XDG_CONFIG_HOME/notmuch/default/hooks`` otherwise.
+
+3. ``<database.path>/.notmuch/hooks``
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-properties(7)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-count.rst b/doc/man1/notmuch-count.rst
new file mode 100644
index 00000000..4c9c9a1c
--- /dev/null
+++ b/doc/man1/notmuch-count.rst
@@ -0,0 +1,81 @@
+.. _notmuch-count(1):
+
+=============
+notmuch-count
+=============
+
+SYNOPSIS
+========
+
+**notmuch** **count** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Count messages matching the search terms.
+
+The number of matching messages (or threads) is output to stdout.
+
+With no search terms, a count of all messages (or threads) in the
+database will be displayed.
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<search-terms>.
+
+Supported options for **count** include
+
+.. program:: count
+
+.. option:: --output=(messages|threads|files)
+
+ messages
+ Output the number of matching messages. This is the default.
+
+ threads
+ Output the number of matching threads.
+
+ files
+ Output the number of files associated with matching
+ messages. This may be bigger than the number of matching
+ messages due to duplicates (i.e. multiple files having the
+ same message-id).
+
+.. option:: --exclude=(true|false)
+
+ Specify whether to omit messages matching search.exclude\_tags from
+ the count (the default) or not.
+
+.. option:: --batch
+
+ Read queries from a file (stdin by default), one per line, and
+ output the number of matching messages (or threads) to stdout, one
+ per line. On an empty input line the count of all messages (or
+ threads) in the database will be output. This option is not
+ compatible with specifying search terms on the command line.
+
+.. option:: --lastmod
+
+ Append lastmod (counter for number of database updates) and UUID
+ to the output. lastmod values are only comparable between
+ databases with the same UUID.
+
+.. option:: --input=<filename>
+
+ Read input from given file, instead of from stdin. Implies
+ ``--batch``.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-dump.rst b/doc/man1/notmuch-dump.rst
new file mode 100644
index 00000000..a7ca39d0
--- /dev/null
+++ b/doc/man1/notmuch-dump.rst
@@ -0,0 +1,123 @@
+.. _notmuch-dump(1):
+
+============
+notmuch-dump
+============
+
+SYNOPSIS
+========
+
+**notmuch** **dump** [--gzip] [--format=(batch-tag|sup)] [--output=<*file*>] [--] [<*search-term*> ...]
+
+DESCRIPTION
+===========
+
+Dump tags for messages matching the given search terms.
+
+Output is to the given filename, if any, or to stdout.
+
+These tags are the only data in the notmuch database that can't be
+recreated from the messages themselves. The output of notmuch dump is
+therefore the only critical thing to backup (and much more friendly to
+incremental backup than the native database files.)
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax
+for <search-terms>. With no search terms, a dump of all messages in
+the database will be generated. A ``--`` argument instructs notmuch that
+the remaining arguments are search terms.
+
+Supported options for **dump** include
+
+.. program:: dump
+
+.. option:: --gzip
+
+ Compress the output in a format compatible with :manpage:`gzip(1)`.
+
+.. option:: --format=(sup|batch-tag)
+
+ Notmuch restore supports two plain text dump formats, both with
+ one message-id per line, followed by a list of tags.
+
+ batch-tag
+ The default **batch-tag** dump format is intended to more
+ robust against malformed message-ids and tags containing
+ whitespace or non-\ :manpage:`ascii(7)` characters. Each line
+ has the form::
+
+ +<*encoded-tag*\ > +<*encoded-tag*\ > ... -- id:<*quoted-message-id*\ >
+
+ Tags are hex-encoded by replacing every byte not matching the
+ regex **[A-Za-z0-9@=.,\_+-]** with **%nn** where nn is the two
+ digit hex encoding. The message ID is a valid Xapian query,
+ quoted using Xapian boolean term quoting rules: if the ID
+ contains whitespace or a close paren or starts with a double
+ quote, it must be enclosed in double quotes and double quotes
+ inside the ID must be doubled. The astute reader will notice
+ this is a special case of the batch input format for
+ :any:`notmuch-tag(1)`; note that the single message-id query is
+ mandatory for :any:`notmuch-restore(1)`.
+
+ sup
+ The **sup** dump file format is specifically chosen to be
+ compatible with the format of files produced by
+ :manpage:`sup-dump(1)`. So if you've previously been using sup
+ for mail, then the :any:`notmuch-restore(1)` command provides
+ you a way to import all of your tags (or labels as sup calls
+ them). Each line has the following form::
+
+ <*message-id*\ > **(** <*tag*\ > ... **)**
+
+ with zero or more tags are separated by spaces. Note that
+ (malformed) message-ids may contain arbitrary non-null
+ characters. Note also that tags with spaces will not be
+ correctly restored with this format.
+
+.. option:: --include=(config|properties|tags)
+
+ Control what kind of metadata is included in the output.
+
+ config
+ Output configuration data stored in the database. Each line
+ starts with "#@ ", followed by a space separated key-value
+ pair. Both key and value are hex encoded if needed.
+
+ properties
+ Output per-message (key,value) metadata. Each line starts
+ with "#= ", followed by a message id, and a space separated
+ list of key=value pairs. Ids, keys and values are hex encoded
+ if needed. See :any:`notmuch-properties(7)` for more details.
+
+ tags
+ Output per-message boolean metadata, namely tags. See *format* above
+ for description of the output.
+
+ The default is to include all available types of data. The option
+ can be specified multiple times to select some subset. As of
+ version 3 of the dump format, there is a header line of the
+ following form::
+
+ #notmuch-dump <*format*>:<*version*> <*included*>
+
+ where <*included*> is a comma separated list of the above options.
+
+.. option:: --output=<filename>
+
+ Write output to given file instead of stdout.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-properties(7)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-emacs-mua.rst b/doc/man1/notmuch-emacs-mua.rst
new file mode 100644
index 00000000..d8af08bd
--- /dev/null
+++ b/doc/man1/notmuch-emacs-mua.rst
@@ -0,0 +1,102 @@
+.. _notmuch-emacs-mua(1):
+
+=================
+notmuch-emacs-mua
+=================
+
+SYNOPSIS
+========
+
+**notmuch** **emacs-mua** [options ...] [<to-address> ... | <mailto-url>]
+
+DESCRIPTION
+===========
+
+Start composing an email in the Notmuch Emacs UI with the specified
+subject, recipients, and message body, or mailto: URL.
+
+Supported options for **emacs-mua** include
+
+.. program:: emacs-mua
+
+.. option:: -h, --help
+
+ Display help.
+
+.. option:: -s, --subject=<subject>
+
+ Specify the subject of the message.
+
+.. option:: --to=<to-address>
+
+ Specify a recipient (To).
+
+.. option:: -c, --cc=<cc-address>
+
+ Specify a carbon-copy (Cc) recipient.
+
+.. option:: -b, --bcc=<bcc-address>
+
+ Specify a blind-carbon-copy (Bcc) recipient.
+
+.. option:: -i, --body=<file>
+
+ Specify a file to include into the body of the message.
+
+.. option:: --hello
+
+ Go to the Notmuch hello screen instead of the message composition
+ window if no message composition parameters are given.
+
+.. option:: --no-window-system
+
+ Even if a window system is available, use the current terminal.
+
+.. option:: --client
+
+ Use :manpage:`emacsclient(1)`, rather than
+ :manpage:`emacs(1)`. For :manpage:`emacsclient(1)` to work, you
+ need an already running Emacs with a server, or use
+ ``--auto-daemon``.
+
+.. option:: --auto-daemon
+
+ Automatically start Emacs in daemon mode, if the Emacs server is
+ not running. Applicable with ``--client``. Implies
+ ``--create-frame``.
+
+.. option:: --create-frame
+
+ Create a new frame instead of trying to use the current Emacs
+ frame. Applicable with ``--client``. This will be required when
+ Emacs is running (or automatically started with ``--auto-daemon``)
+ in daemon mode.
+
+.. option:: --print
+
+ Output the resulting elisp to stdout instead of evaluating it.
+
+The supported positional parameters and short options are a compatible
+subset of the :manpage:`mutt(1)` MUA command-line options. The options
+and positional parameters modifying the message can't be combined with
+the mailto: URL.
+
+Options may be specified multiple times.
+
+ENVIRONMENT VARIABLES
+=====================
+
+.. envvar:: EMACS
+
+ Name of emacs command to invoke. Defaults to "emacs".
+
+.. envvar:: EMACSCLIENT
+
+ Name of emacsclient command to invoke. Defaults to "emacsclient".
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:manpage:`emacsclient(1)`,
+:manpage:`mutt(1)`
diff --git a/doc/man1/notmuch-git.rst b/doc/man1/notmuch-git.rst
new file mode 100644
index 00000000..33a46f84
--- /dev/null
+++ b/doc/man1/notmuch-git.rst
@@ -0,0 +1,340 @@
+.. _notmuch-git(1):
+
+===========
+notmuch-git
+===========
+
+SYNOPSIS
+========
+
+**notmuch** **git** [-h] [-N] [-C *repo*] [-p *prefix*] [-v] [-l *log level*] *subcommand*
+
+**nmbug** [-h] [-C *repo*] [-p *prefix*] [-v] [-l *log level*] *subcommand*
+
+DESCRIPTION
+===========
+
+Manage notmuch tags with Git.
+
+OPTIONS
+-------
+
+Supported options for `notmuch git` include
+
+.. program:: notmuch-git
+
+.. option:: -h, --help
+
+ show help message and exit
+
+.. option:: -N, --nmbug
+
+ Set defaults for :option:`--tag-prefix` and :option:`--git-dir` suitable for the
+ :any:`notmuch` bug tracker
+
+.. option:: -C <repo>, --git-dir <repo>
+
+ Operate on git repository *repo*. See :ref:`repo_location` for
+ defaults.
+
+.. option:: -p <prefix>, --tag-prefix <prefix>
+
+ Operate only on tags with prefix *prefix*. See :ref:`prefix_val` for
+ defaults.
+
+.. option:: -v, --version
+
+ show notmuch-git's version number and exit
+
+.. option:: -l <level>, --log-level <level>
+
+ Log verbosity, one of: `critical`, `error`, `warning`, `info`,
+ `debug`. Defaults to `warning`.
+
+SUBCOMMANDS
+-----------
+
+For help on a particular subcommand, run: 'notmuch-git ... <command> --help'.
+
+.. program:: notmuch-git
+
+.. option:: archive [tree-ish] [arg ...]
+
+Dump a tar archive of a committed tag set using 'git archive'. See
+:any:`format` for details of the archive contents.
+
+ .. describe:: tree-ish
+
+ The tree or commit to produce an archive for. Defaults to 'HEAD'.
+
+ .. describe:: arg
+
+ If present, any optional arguments are passed through to
+ :manpage:`git-archive(1)`. Arguments to `git-archive` are reordered
+ so that *tree-ish* comes last.
+
+.. option:: checkout [-f|--force]
+
+Update the notmuch database from Git.
+
+This is mainly useful to discard your changes in notmuch relative
+to Git.
+
+ .. describe:: [-f|--force]
+
+ Override checks that prevent modifying tags for large fractions of
+ messages in the database. See also :nmconfig:`git.safe_fraction`.
+
+.. option:: clone <repository>
+
+Create a local `notmuch git` repository from a remote source.
+
+This wraps 'git clone', adding some options to avoid creating a
+working tree while preserving remote-tracking branches and
+upstreams.
+
+ .. describe:: repository
+
+ The (possibly remote) repository to clone from. See the URLS
+ section of :manpage:`git-clone(1)` for more information on
+ specifying repositories.
+
+.. option:: commit [-f|--force] [message]
+
+Commit prefix-matching tags from the notmuch database to Git.
+
+ .. describe:: message
+
+ Optional text for the commit message.
+
+ .. describe:: -f|--force
+
+ Override checks that prevent modifying tags for large fractions of
+ messages in the database. See also :nmconfig:`git.safe_fraction`.
+
+.. option:: fetch [remote]
+
+Fetch changes from the remote repository.
+
+ .. describe:: remote
+
+ Override the default configured in `branch.<name>.remote` to fetch
+ from a particular remote repository (e.g. `origin`).
+
+.. option:: help
+
+Show brief help for an `notmuch git` command.
+
+.. option:: init [--format-version=N]
+
+Create an empty `notmuch git` repository.
+
+This wraps 'git init' with a few extra steps to support subsequent
+status and commit commands.
+
+ .. describe:: --format-version=N
+
+ Create a repo in format version N. By default :any:`notmuch-git`
+ uses the highest supported version, which is the best choice for
+ most use-cases.
+
+.. option:: log [arg ...]
+
+A wrapper for 'git log'.
+
+ .. describe:: arg
+
+ Additional arguments are passed through to 'git log'.
+
+After running `notmuch git fetch`, you can inspect the changes with
+
+::
+
+ $ notmuch git log HEAD..@{upstream}
+
+.. option:: merge [reference]
+
+Merge changes from 'reference' into HEAD and load the result into notmuch.
+
+ .. describe:: reference
+
+ Reference, usually other branch heads, to merge into our
+ branch. Defaults to `@{upstream}`.
+
+.. option:: pull [repository] [refspec ...]
+
+Pull (merge) remote repository changes to notmuch.
+
+**pull** is equivalent to **fetch** followed by **merge**. We use the
+Git-configured repository for your current branch
+(`branch.<name>.repository`, likely `origin`, and `branch.<name>.merge`,
+likely `master` or `main`).
+
+ .. describe:: repository
+
+ The "remote" repository that is the source of the pull. This parameter
+ can be either a URL (see the section GIT URLS in :manpage:`git-pull(1)`) or the
+ name of a remote (see the section REMOTES in :manpage:`git-pull(1)`).
+
+ .. describe:: refspec
+
+ Refspec (usually a branch name) to fetch and merge. See the
+ *refspec* entry in the OPTIONS section of :manpage:`git-pull(1`) for
+ other possibilities.
+
+.. option:: push [repository] [refspec]
+
+Push the local `notmuch git` Git state to a remote repository.
+
+ .. describe:: repository
+
+ The "remote" repository that is the destination of the push. This
+ parameter can be either a URL (see the section GIT URLS in
+ :manpage:`git-push(1)`) or the name of a remote (see the section
+ REMOTES in :manpage:`git-push(1)`).
+
+ .. describe:: refspec
+
+ Refspec (usually a branch name) to push. See the *refspec* entry in the OPTIONS section of
+ :manpage:`git-push(1)` for other possibilities.
+
+.. option:: status
+
+Show pending updates in notmuch or git repo.
+
+Prints lines of the form
+
+| ng Message-Id tag
+
+where n is a single character representing notmuch database status
+
+ .. describe:: A
+
+ Tag is present in notmuch database, but not committed to nmbug
+ (equivalently, tag has been deleted in nmbug repo, e.g. by a
+ pull, but not restored to notmuch database).
+
+ .. describe:: D
+
+ Tag is present in nmbug repo, but not restored to notmuch
+ database (equivalently, tag has been deleted in notmuch).
+
+ .. describe:: U
+
+ Message is unknown (missing from local notmuch database).
+
+The second character *g* (if present) represents a difference between
+local and upstream branches. Typically `notmuch git fetch` needs to be
+run to update this.
+
+ .. describe:: a
+
+ Tag is present in upstream, but not in the local Git branch.
+
+ .. describe:: d
+
+ Tag is present in local Git branch, but not upstream.
+
+.. _format:
+
+REPOSITORY CONTENTS
+===================
+
+The tags are stored in the git repo (and exported) as a set of empty
+files. These empty files are contained within a directory named after
+the message-id.
+
+In what follows `encode()` represents a POSIX filesystem safe
+encoding. The encoding preserves alphanumerics, and the characters
+`+-_@=.,:`. All other octets are replaced with `%` followed by a two
+digit hex number.
+
+Currently :any:`notmuch-git` can read any format version, but can only
+create (via :any:`init`) :ref:`version 1 <format_version_1>` repositories.
+
+.. _format_version_0:
+
+Version 0
+---------
+
+This is the legacy format created by the `nmbug` tool prior to release
+0.37. For a message with Message-Id *id*, for each tag *tag*, there
+is an empty file with path
+
+ tags/ `encode` (*id*) / `encode` (*tag*)
+
+.. _format_version_1:
+
+Version 1
+---------
+
+In format version 1 and later, the format version is contained in a
+top level file called FORMAT.
+
+For a message with Message-Id *id*, for each tag *tag*, there
+is an empty file with path
+
+ tags/ `hash1` (*id*) / `hash2` (*id*) `encode` (*id*) / `encode` (*tag*)
+
+The hash functions each represent one byte of the `blake2b` hex
+digest.
+
+Compared to :ref:`version 0 <format_version_0>`, this reduces the
+number of subdirectories within each directory.
+
+.. _repo_location:
+
+REPOSITORY LOCATION
+===================
+
+:any:`notmuch-git` uses the first of the following with a non-empty
+value to locate the git repository.
+
+- Option :option:`--git-dir`.
+
+- Environment variable :envvar:`NOTMUCH_GIT_DIR`.
+
+- Configuration item :nmconfig:`git.path`
+
+- If invoked as `nmbug` or with the :option:`--nmbug` option,
+ :code:`$HOME/.nmbug`; otherwise
+ :code:`$XDG_DATA_HOME/notmuch/$NOTMUCH_PROFILE/git`.
+
+.. _prefix_val:
+
+PREFIX VALUE
+============
+
+:any:`notmuch-git` uses the first of the following with a non-null
+value to define the tag prefix.
+
+- Option :option:`--tag-prefix`.
+
+- Environment variable :envvar:`NOTMUCH_GIT_PREFIX`.
+
+- Configuration item :nmconfig:`git.tag_prefix`.
+
+- If invoked as `nmbug` or with the :option:`--nmbug` option,
+ :code:`notmuch::`, otherwise the empty string.
+
+ENVIRONMENT
+===========
+
+Variable :envvar:`NOTMUCH_PROFILE` influences :ref:`repo_location`.
+If it is unset, 'default' is assumed.
+
+.. envvar:: NOTMUCH_GIT_DIR
+
+ Default location of git repository. Overridden by :option:`--git-dir`.
+
+.. envvar:: NOTMUCH_GIT_PREFIX
+
+ Default tag prefix (filter). Overridden by :option:`--tag-prefix`.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-insert.rst b/doc/man1/notmuch-insert.rst
new file mode 100644
index 00000000..e05bd0b5
--- /dev/null
+++ b/doc/man1/notmuch-insert.rst
@@ -0,0 +1,133 @@
+.. _notmuch-insert(1):
+
+==============
+notmuch-insert
+==============
+
+SYNOPSIS
+========
+
+**notmuch** **insert** [option ...] [+<*tag*>|-<*tag*> ...]
+
+DESCRIPTION
+===========
+
+**notmuch insert** reads a message from standard input and delivers it
+into the maildir directory given by configuration option
+:nmconfig:`database.mail_root`, then incorporates the message into the notmuch
+database. It is an alternative to using a separate tool to deliver the
+message then running :any:`notmuch-new(1)` afterwards.
+
+The new message will be tagged with the tags specified by the
+:nmconfig:`new.tags` configuration option, then by operations specified on the
+command-line: tags prefixed by '+' are added while those prefixed by '-'
+are removed.
+
+If the new message is a duplicate of an existing message in the database
+(it has same Message-ID), it will be added to the maildir folder and
+notmuch database, but the tags will not be changed.
+
+The **insert** command supports hooks. See :any:`notmuch-hooks(5)` for
+more details on hooks.
+
+Option arguments must appear before any tag operation arguments.
+Supported options for **insert** include
+
+.. program:: insert
+
+.. option:: --folder=<folder>
+
+ Deliver the message to the specified folder, relative to the
+ top-level directory given by the value of :nmconfig:`database.mail_root`. The
+ default is the empty string, which means delivering to the
+ top-level directory.
+
+.. option:: --create-folder
+
+ Try to create the folder named by the ``--folder`` option, if it
+ does not exist. Otherwise the folder must already exist for mail
+ delivery to succeed.
+
+.. option:: --keep
+
+ Keep the message file if indexing fails, and keep the message
+ indexed if applying tags or maildir flag synchronization
+ fails. Ignore these errors and return exit status 0 to indicate
+ successful mail delivery.
+
+.. option:: --no-hooks
+
+ Prevent hooks from being run.
+
+.. option:: --world-readable
+
+ When writing mail to the mailbox, allow it to be read by users
+ other than the current user. Note that this does not override
+ umask. By default, delivered mail is only readable by the current
+ user.
+
+.. option:: --decrypt=(true|nostash|auto|false)
+
+ If ``true`` and the message is encrypted, try to decrypt the
+ message while indexing, stashing any session keys discovered. If
+ ``auto``, and notmuch already knows about a session key for the
+ message, it will try decrypting using that session key but will
+ not try to access the user's secret keys. If decryption is
+ successful, index the cleartext itself. Either way, the message
+ is always stored to disk in its original form (ciphertext).
+
+ ``nostash`` is the same as ``true`` except that it will not stash
+ newly-discovered session keys in the database.
+
+ Be aware that the index is likely sufficient (and a stashed
+ session key is certainly sufficient) to reconstruct the cleartext
+ of the message itself, so please ensure that the notmuch message
+ index is adequately protected. DO NOT USE ``--decrypt=true`` or
+ ``--decrypt=nostash`` without considering the security of your
+ index.
+
+ See also :nmconfig:`index.decrypt` in :any:`notmuch-config(1)`.
+
+CONFIGURATION
+=============
+
+Indexing is influenced by the configuration options
+:nmconfig:`index.decrypt` and :nmconfig:`index.header.\<prefix\>`. Tagging
+is controlled by options :nmconfig:`new.tags` and
+:nmconfig:`maildir.synchronize_flags`. See
+:any:`notmuch-config(1)` for details.
+
+EXIT STATUS
+===========
+
+This command returns exit status 0 on successful mail delivery,
+non-zero otherwise. The default is to indicate failed mail delivery on
+any errors, including message file delivery to the filesystem, message
+indexing to Notmuch database, changing tags, and synchronizing tags to
+maildir flags. The ``--keep`` option may be used to settle for
+successful message file delivery.
+
+This command supports the following special exit status code for
+errors most likely to be temporary in nature, e.g. failure to get a
+database write lock.
+
+``75 (EX_TEMPFAIL)``
+ A temporary failure occurred; the user is invited to retry.
+
+The exit status of the **post-insert** hook does not affect the exit
+status of the **insert** command.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-new.rst b/doc/man1/notmuch-new.rst
new file mode 100644
index 00000000..f0ed8eb8
--- /dev/null
+++ b/doc/man1/notmuch-new.rst
@@ -0,0 +1,113 @@
+.. _notmuch-new(1):
+
+===========
+notmuch-new
+===========
+
+SYNOPSIS
+========
+
+**notmuch** **new** [options]
+
+DESCRIPTION
+===========
+
+Find and import any new messages to the database.
+
+The **new** command scans all sub-directories of the database,
+performing full-text indexing on new messages that are found. Each new
+message will automatically be tagged with both the **inbox** and
+**unread** tags.
+
+You should run **notmuch new** once after first running
+:any:`notmuch-setup(1)` to create the initial database. The first run
+may take a long time if you have a significant amount of mail (several
+hundred thousand messages or more). Subsequently, you should run
+**notmuch new** whenever new mail is delivered and you wish to
+incorporate it into the database. These subsequent runs will be much
+quicker than the initial run.
+
+Invoking ``notmuch`` with no command argument will run **new** if
+:any:`notmuch-setup(1)` has previously been completed, but **notmuch
+new** has not previously been run.
+
+**notmuch new** updates tags according to maildir flag changes if the
+**maildir.synchronize\_flags** configuration option is enabled. See
+:any:`notmuch-config(1)` for details.
+
+The **new** command supports hooks. See :any:`notmuch-hooks(5)` for more
+details on hooks.
+
+Supported options for **new** include
+
+.. program:: new
+
+.. option:: --no-hooks
+
+ Prevents hooks from being run.
+
+.. option:: --quiet
+
+ Do not print progress or results.
+
+.. option:: --verbose
+
+ Print file names being processed. Ignored when combined with
+ ``--quiet``.
+
+.. option:: --decrypt=(true|nostash|auto|false)
+
+ If ``true``, when encountering an encrypted message, try to
+ decrypt it while indexing, and stash any discovered session keys.
+ If ``auto``, try to use any session key already known to belong to
+ this message, but do not attempt to use the user's secret keys.
+ If decryption is successful, index the cleartext of the message.
+
+ Be aware that the index is likely sufficient (and the session key
+ is certainly sufficient) to reconstruct the cleartext of the
+ message itself, so please ensure that the notmuch message index is
+ adequately protected. DO NOT USE ``--decrypt=true`` or
+ ``--decrypt=nostash`` without considering the security of your
+ index.
+
+ See also ``index.decrypt`` in :any:`notmuch-config(1)`.
+
+.. option:: --full-scan
+
+ By default notmuch-new uses directory modification times (mtimes)
+ to optimize the scanning of directories for new mail. This option turns
+ that optimization off.
+
+CONFIGURATION
+=============
+
+Indexing is influenced by the configuration options
+:nmconfig:`index.decrypt`, :nmconfig:`index.header.\<prefix\>`
+and :nmconfig:`new.ignore`. Tagging
+is controlled by :nmconfig:`new.tags` and
+:nmconfig:`maildir.synchronize_flags`. See
+:any:`notmuch-config(1)` for details.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status code
+
+``75 (EX_TEMPFAIL)``
+ A temporary failure occurred; the user is invited to retry.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-reindex.rst b/doc/man1/notmuch-reindex.rst
new file mode 100644
index 00000000..85dad249
--- /dev/null
+++ b/doc/man1/notmuch-reindex.rst
@@ -0,0 +1,105 @@
+.. _notmuch-reindex(1):
+
+===============
+notmuch-reindex
+===============
+
+SYNOPSIS
+========
+
+**notmuch** **reindex** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Re-index all messages matching the search terms.
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<*search-term*\ >.
+
+The **reindex** command searches for all messages matching the
+supplied search terms, and re-creates the full-text index on these
+messages using the supplied options.
+
+Supported options for **reindex** include
+
+.. program:: reindex
+
+.. option:: --decrypt=(true|nostash|auto|false)
+
+ If ``true``, when encountering an encrypted message, try to
+ decrypt it while reindexing, stashing any session keys discovered.
+ If ``auto``, and notmuch already knows about a session key for the
+ message, it will try decrypting using that session key but will
+ not try to access the user's secret keys. If decryption is
+ successful, index the cleartext itself.
+
+ ``nostash`` is the same as ``true`` except that it will not stash
+ newly-discovered session keys in the database.
+
+ If ``false``, notmuch reindex will also delete any stashed session
+ keys for all messages matching the search terms.
+
+ Be aware that the index is likely sufficient (and a stashed
+ session key is certainly sufficient) to reconstruct the cleartext
+ of the message itself, so please ensure that the notmuch message
+ index is adequately protected. DO NOT USE ``--decrypt=true`` or
+ ``--decrypt=nostash`` without considering the security of your
+ index.
+
+ See also ``index.decrypt`` in :any:`notmuch-config(1)`.
+
+EXAMPLES
+========
+
+A user just received an encrypted message without indexing its
+cleartext. After reading it (via ``notmuch show --decrypt=true``),
+they decide that they want to index its cleartext so that they can
+easily find it later and read it without having to have access to
+their secret keys:
+
+::
+
+ notmuch reindex --decrypt=true id:1234567@example.com
+
+A user wants to change their policy going forward to start indexing
+cleartext. But they also want indexed access to the cleartext of all
+previously-received encrypted messages. Some messages might have
+already been indexed in the clear (as in the example above). They can
+ask notmuch to just reindex the not-yet-indexed messages:
+
+::
+
+ notmuch config set index.decrypt true
+ notmuch reindex tag:encrypted and not property:index.decryption=success
+
+Later, the user changes their mind, and wants to stop indexing
+cleartext (perhaps their threat model has changed, or their trust in
+their index store has been shaken). They also want to clear all of
+their old cleartext from the index. Note that they compact the
+database afterward as a workaround for
+https://trac.xapian.org/ticket/742:
+
+::
+
+ notmuch config set index.decrypt false
+ notmuch reindex property:index.decryption=success
+ notmuch compact
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-compact(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-reply.rst b/doc/man1/notmuch-reply.rst
new file mode 100644
index 00000000..4f39a959
--- /dev/null
+++ b/doc/man1/notmuch-reply.rst
@@ -0,0 +1,143 @@
+.. _notmuch-reply(1):
+
+=============
+notmuch-reply
+=============
+
+SYNOPSIS
+========
+
+**notmuch** **reply** [option ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Constructs a reply template for a set of messages.
+
+To make replying to email easier, **notmuch reply** takes an existing
+set of messages and constructs a suitable mail template. Its To:
+address is set according to the original email in this way: if the
+Reply-to: header is present and different from any To:/Cc: address it
+is used, otherwise From: header is used. Unless
+``--reply-to=sender`` is specified, values from the To: and Cc: headers
+are copied, but not including any of the current user's email addresses
+(as configured in primary\_mail or other\_email in the .notmuch-config
+file) in the recipient list.
+
+It also builds a suitable new subject, including Re: at the front (if
+not already present), and adding the message IDs of the messages being
+replied to to the References list and setting the In-Reply-To: field
+correctly.
+
+Finally, the original contents of the emails are quoted by prefixing
+each line with '> ' and included in the body.
+
+The resulting message template is output to stdout.
+
+Supported options for **reply** include
+
+.. program:: reply
+
+.. option:: --duplicate=N
+
+ Reply to duplicate number N. The numbering starts from 1, and
+ matches the order used by :option:`show --duplicate` and
+ :option:`search --output=files <search --output>`.
+
+.. option:: --format=(default|json|sexp|headers-only)
+
+ default
+ Includes subject and quoted message body as an RFC 2822
+ message.
+
+ json
+ Produces JSON output containing headers for a reply message
+ and the contents of the original message. This output can be
+ used by a client to create a reply message intelligently.
+
+ sexp
+ Produces S-Expression output containing headers for a reply
+ message and the contents of the original message. This output
+ can be used by a client to create a reply message
+ intelligently.
+
+ headers-only
+ Only produces In-Reply-To, References, To, Cc, and Bcc
+ headers.
+
+.. option:: --format-version=N
+
+ Use the specified structured output format version. This is
+ intended for programs that invoke :any:`notmuch(1)` internally. If
+ omitted, the latest supported version will be used.
+
+.. option:: --reply-to=(all|sender)
+
+ all (default)
+ Replies to all addresses.
+
+ sender
+ Replies only to the sender. If replying to user's own message
+ (Reply-to: or From: header is one of the user's configured
+ email addresses), try To:, Cc:, and Bcc: headers in this
+ order, and copy values from the first that contains something
+ other than only the user's addresses.
+
+.. option:: --decrypt=(false|auto|true)
+
+ If ``true``, decrypt any MIME encrypted parts found in the
+ selected content (i.e., "multipart/encrypted" parts). Status
+ of the decryption will be reported (currently only supported
+ with ``--format=json`` and ``--format=sexp``), and on successful
+ decryption the multipart/encrypted part will be replaced by
+ the decrypted content.
+
+ If ``auto``, and a session key is already known for the
+ message, then it will be decrypted, but notmuch will not try
+ to access the user's secret keys.
+
+ Use ``false`` to avoid even automatic decryption.
+
+ Non-automatic decryption expects a functioning
+ :manpage:`gpg-agent(1)` to provide any needed credentials. Without
+ one, the decryption will likely fail.
+
+ Default: ``auto``
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<search-terms>.
+
+Note: It is most common to use **notmuch reply** with a search string
+matching a single message, (such as id:<message-id>), but it can be
+useful to reply to several messages at once. For example, when a series
+of patches are sent in a single thread, replying to the entire thread
+allows for the reply to comment on issues found in multiple patches. The
+default format supports replying to multiple messages at once, but the
+JSON and S-Expression formats do not.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-restore.rst b/doc/man1/notmuch-restore.rst
new file mode 100644
index 00000000..ac6b4245
--- /dev/null
+++ b/doc/man1/notmuch-restore.rst
@@ -0,0 +1,107 @@
+.. _notmuch-restore(1):
+
+===============
+notmuch-restore
+===============
+
+SYNOPSIS
+========
+
+**notmuch** **restore** [--accumulate] [--format=(auto|batch-tag|sup)] [--input=<*filename*>]
+
+DESCRIPTION
+===========
+
+Restores the tags from the given file (see :any:`notmuch-dump(1)`).
+
+The input is read from the given filename, if any, or from stdin.
+
+Supported options for **restore** include
+
+.. program:: restore
+
+.. option:: --accumulate
+
+ The union of the existing and new tags is applied, instead of
+ replacing each message's tags as they are read in from the dump
+ file.
+
+.. option:: --format=(sup|batch-tag|auto)
+
+ Notmuch restore supports two plain text dump formats, with each
+ line specifying a message-id and a set of tags. For details of the
+ actual formats, see :any:`notmuch-dump(1)`.
+
+ sup
+ The **sup** dump file format is specifically chosen to be
+ compatible with the format of files produced by sup-dump. So
+ if you've previously been using sup for mail, then the
+ **notmuch restore** command provides you a way to import all
+ of your tags (or labels as sup calls them).
+
+ batch-tag
+ The **batch-tag** dump format is intended to more robust
+ against malformed message-ids and tags containing whitespace
+ or non-\ **ascii(7)** characters. See :any:`notmuch-dump(1)` for
+ details on this format.
+
+ **notmuch restore** updates the maildir flags according to tag
+ changes if the **maildir.synchronize\_flags** configuration
+ option is enabled. See :any:`notmuch-config(1)` for details.
+
+ auto
+ This option (the default) tries to guess the format from the
+ input. For correctly formed input in either supported format,
+ this heuristic, based the fact that batch-tag format contains
+ no parentheses, should be accurate.
+
+.. option:: --include=(config|properties|tags)
+
+ Control what kind of metadata is restored.
+
+ config
+ Restore configuration data to the database. Each configuration
+ line starts with "#@ ", followed by a space separated
+ key-value pair. Both key and value are hex encoded if needed.
+
+ properties
+ Restore per-message (key,value) metadata. Each line starts
+ with "#= ", followed by a message id, and a space separated
+ list of key=value pairs. Ids, keys and values are hex encoded
+ if needed. See :any:`notmuch-properties(7)` for more details.
+
+ tags
+ Restore per-message metadata, namely tags. See *format* above
+ for more details.
+
+ The default is to restore all available types of data. The option
+ can be specified multiple times to select some subset.
+
+.. option:: --input=<filename>
+
+ Read input from given file instead of stdin.
+
+GZIPPED INPUT
+=============
+
+\ **notmuch restore** will detect if the input is compressed in
+:manpage:`gzip(1)` format and automatically decompress it while
+reading. This detection does not depend on file naming and in
+particular works for standard input.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-properties(7)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-search.rst b/doc/man1/notmuch-search.rst
new file mode 100644
index 00000000..b87737ea
--- /dev/null
+++ b/doc/man1/notmuch-search.rst
@@ -0,0 +1,191 @@
+.. _notmuch-search(1):
+
+==============
+notmuch-search
+==============
+
+SYNOPSIS
+========
+
+**notmuch** **search** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Search for messages matching the given search terms, and display as
+results the threads containing the matched messages.
+
+The output consists of one line per thread, giving a thread ID, the date
+of the newest (or oldest, depending on the sort option) matched message
+in the thread, the number of matched messages and total messages in the
+thread, the names of all participants in the thread, and the subject of
+the newest (or oldest) message.
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<search-terms>.
+
+Supported options for **search** include
+
+.. program:: search
+
+.. option:: --format=(json|sexp|text|text0)
+
+ Presents the results in either JSON, S-Expressions, newline
+ character separated plain-text (default), or null character
+ separated plain-text (compatible with :manpage:`xargs(1)` -0
+ option where available).
+
+.. option:: --format-version=N
+
+ Use the specified structured output format version. This is
+ intended for programs that invoke :any:`notmuch(1)` internally. If
+ omitted, the latest supported version will be used.
+
+.. option:: --output=(summary|threads|messages|files|tags)
+
+ summary (default)
+ Output a summary of each thread with any message matching the
+ search terms. The summary includes the thread ID, date, the
+ number of messages in the thread (both the number matched and
+ the total number), the authors of the thread and the
+ subject. In the case where a thread contains multiple files
+ for some messages, the total number of files is printed in
+ parentheses (see below for an example).
+
+ threads
+ Output the thread IDs of all threads with any message matching
+ the search terms, either one per line (``--format=text``),
+ separated by null characters (``--format=text0``), as a JSON array
+ (``--format=json``), or an S-Expression list (``--format=sexp``).
+
+ messages
+ Output the message IDs of all messages matching the search
+ terms, either one per line (``--format=text``), separated by null
+ characters (``--format=text0``), as a JSON array (``--format=json``),
+ or as an S-Expression list (``--format=sexp``).
+
+ files
+ Output the filenames of all messages matching the search
+ terms, either one per line (``--format=text``), separated by null
+ characters (``--format=text0``), as a JSON array (``--format=json``),
+ or as an S-Expression list (``--format=sexp``).
+
+ Note that each message may have multiple filenames associated
+ with it. All of them are included in the output (unless
+ limited with the ``--duplicate=N`` option). This may be
+ particularly confusing for **folder:** or **path:** searches
+ in a specified directory, as the messages may have duplicates
+ in other directories that are included in the output, although
+ these files alone would not match the search.
+
+ tags
+ Output all tags that appear on any message matching the search
+ terms, either one per line (``--format=text``), separated by null
+ characters (``--format=text0``), as a JSON array (``--format=json``),
+ or as an S-Expression list (``--format=sexp``).
+
+.. option:: --sort=(newest-first|oldest-first)
+
+ This option can be used to present results in either chronological
+ order (**oldest-first**) or reverse chronological order
+ (**newest-first**).
+
+ Note: The thread order will be distinct between these two options
+ (beyond being simply reversed). When sorting by **oldest-first**
+ the threads will be sorted by the oldest message in each thread,
+ but when sorting by **newest-first** the threads will be sorted by
+ the newest message in each thread.
+
+ By default, results will be displayed in reverse chronological
+ order, (that is, the newest results will be displayed first).
+
+.. option:: --offset=[-]N
+
+ Skip displaying the first N results. With the leading '-', start
+ at the Nth result from the end.
+
+.. option:: --limit=N
+
+ Limit the number of displayed results to N.
+
+.. option:: --exclude=(true|false|all|flag)
+
+ A message is called "excluded" if it matches at least one tag in
+ search.exclude\_tags that does not appear explicitly in the search
+ terms. This option specifies whether to omit excluded messages in
+ the search process.
+
+ true (default)
+ Prevent excluded messages from matching the search terms.
+
+ all
+ Additionally prevent excluded messages from appearing in
+ displayed results, in effect behaving as though the excluded
+ messages do not exist.
+
+ false
+ Allow excluded messages to match search terms and appear in
+ displayed results. Excluded messages are still marked in the
+ relevant outputs.
+
+ flag
+ Only has an effect when ``--output=summary``. The output is
+ almost identical to **false**, but the "match count" is the
+ number of matching non-excluded messages in the thread, rather
+ than the number of matching messages.
+
+.. option:: --duplicate=N
+
+ For ``--output=files``, output the Nth filename associated with
+ each message matching the query (N is 1-based). If N is greater
+ than the number of files associated with the message, don't print
+ anything.
+
+ For ``--output=messages``, only output message IDs of messages
+ matching the search terms that have at least N filenames
+ associated with them.
+
+ Note that this option is orthogonal with the **folder:** search
+ prefix. The prefix matches messages based on filenames. This
+ option filters filenames of the matching messages.
+
+EXAMPLE
+=======
+
+The following shows an example of the summary output format, with one
+message having multiple filenames.
+
+::
+
+ % notmuch search date:today.. and tag:bad-news
+ thread:0000000000063c10 Today [1/1] Some Persun; To the bone (bad-news inbox unread)
+ thread:0000000000063c25 Today [1/1(2)] Ann Other; Bears (bad-news inbox unread)
+ thread:0000000000063c00 Today [1/1] A Thurd; Bites, stings, sad feelings (bad-news unread)
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-address(1)`
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-show.rst b/doc/man1/notmuch-show.rst
new file mode 100644
index 00000000..c13d94de
--- /dev/null
+++ b/doc/man1/notmuch-show.rst
@@ -0,0 +1,271 @@
+.. _notmuch-show(1):
+
+============
+notmuch-show
+============
+
+SYNOPSIS
+========
+
+**notmuch** **show** [*option* ...] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Shows all messages matching the search terms.
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<search-terms>.
+
+The messages will be grouped and sorted based on the threading (all
+replies to a particular message will appear immediately after that
+message in date order). The output is not indented by default, but depth
+tags are printed so that proper indentation can be performed by a
+post-processor (such as the emacs interface to notmuch).
+
+Supported options for **show** include
+
+.. program:: show
+
+.. option:: --duplicate=N
+
+ Output duplicate number N. The numbering starts from 1, and matches
+ the order used by :option:`search --duplicate` and
+ :option:`search --output=files <search --output>`
+
+.. option:: --entire-thread=(true|false)
+
+ If true, **notmuch show** outputs all messages in the thread of
+ any message matching the search terms; if false, it outputs only
+ the matching messages. For ``--format=json`` and ``--format=sexp``
+ this defaults to true. For other formats, this defaults to false.
+
+.. option:: --format=(text|json|sexp|mbox|raw)
+
+ text (default for messages)
+ The default plain-text format has all text-content MIME parts
+ decoded. Various components in the output, (**message**,
+ **header**, **body**, **attachment**, and MIME **part**), will
+ be delimited by easily-parsed markers. Each marker consists of
+ a Control-L character (ASCII decimal 12), the name of the
+ marker, and then either an opening or closing brace, ('{' or
+ '}'), to either open or close the component. For a multipart
+ MIME message, these parts will be nested.
+
+ json
+ The output is formatted with Javascript Object Notation
+ (JSON). This format is more robust than the text format for
+ automated processing. The nested structure of multipart MIME
+ messages is reflected in nested JSON output. By default JSON
+ output includes all messages in a matching thread; that is, by
+ default, ``--format=json`` sets ``--entire-thread``. The
+ caller can disable this behaviour by setting
+ ``--entire-thread=false``. The JSON output is always encoded
+ as UTF-8 and any message content included in the output will
+ be charset-converted to UTF-8.
+
+ sexp
+ The output is formatted as the Lisp s-expression (sexp)
+ equivalent of the JSON format above. Objects are formatted as
+ property lists whose keys are keywords (symbols preceded by a
+ colon). True is formatted as ``t`` and both false and null are
+ formatted as ``nil``. As for JSON, the s-expression output is
+ always encoded as UTF-8.
+
+ mbox
+ All matching messages are output in the traditional, Unix mbox
+ format with each message being prefixed by a line beginning
+ with "From " and a blank line separating each message. Lines
+ in the message content beginning with "From " (preceded by
+ zero or more '>' characters) have an additional '>' character
+ added. This reversible escaping is termed "mboxrd" format and
+ described in detail here:
+
+ http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html
+
+ raw (default if ``--part`` is given)
+ Write the raw bytes of the given MIME part of a message to
+ standard out. For this format, it is an error to specify a
+ query that matches more than one message.
+
+ If the specified part is a leaf part, this outputs the body of
+ the part after performing content transfer decoding (but no
+ charset conversion). This is suitable for saving attachments,
+ for example.
+
+ For a multipart or message part, the output includes the part
+ headers as well as the body (including all child parts). No
+ decoding is performed because multipart and message parts
+ cannot have non-trivial content transfer encoding. Consumers
+ of this may need to implement MIME decoding and similar
+ functions.
+
+.. option:: --format-version=N
+
+ Use the specified structured output format version. This is
+ intended for programs that invoke :any:`notmuch(1)` internally. If
+ omitted, the latest supported version will be used.
+
+.. option:: --part=N
+
+ Output the single decoded MIME part N of a single message. The
+ search terms must match only a single message. Message parts are
+ numbered in a depth-first walk of the message MIME structure, and
+ are identified in the 'json', 'sexp' or 'text' output formats.
+
+ Note that even a message with no MIME structure or a single body
+ part still has two MIME parts: part 0 is the whole message
+ (headers and body) and part 1 is just the body.
+
+.. option:: --sort=(newest-first|oldest-first)
+
+ This option can be used to present results in either chronological
+ order (**oldest-first**) or reverse chronological order
+ (**newest-first**).
+
+ Only threads as a whole are reordered. Ordering of messages within
+ each thread will not be affected by this flag, since that order is
+ always determined by the thread's replies.
+
+ By default, results will be displayed in reverse chronological
+ order, (that is, the newest results will be displayed first).
+
+.. option:: --offset=[-]N
+
+ Skip displaying the first N results. With the leading '-', start
+ at the Nth result from the end.
+
+.. option:: --limit=N
+
+ Limit the number of displayed results to N.
+
+.. option:: --verify
+
+ Compute and report the validity of any MIME cryptographic
+ signatures found in the selected content (e.g., "multipart/signed"
+ parts). Status of the signature will be reported (currently only
+ supported with ``--format=json`` and ``--format=sexp``), and the
+ multipart/signed part will be replaced by the signed data.
+
+.. option:: --decrypt=(false|auto|true|stash)
+
+ If ``true``, decrypt any MIME encrypted parts found in the
+ selected content (e.g., "multipart/encrypted" parts). Status of
+ the decryption will be reported (currently only supported
+ with ``--format=json`` and ``--format=sexp``) and on successful
+ decryption the multipart/encrypted part will be replaced by
+ the decrypted content.
+
+ ``stash`` behaves like ``true``, but upon successful decryption it
+ will also stash the message's session key in the database, and
+ index the cleartext of the message, enabling automatic decryption
+ in the future.
+
+ If ``auto``, and a session key is already known for the
+ message, then it will be decrypted, but notmuch will not try
+ to access the user's keys.
+
+ Use ``false`` to avoid even automatic decryption.
+
+ Non-automatic decryption (``stash`` or ``true``, in the absence of
+ a stashed session key) expects a functioning :manpage:`gpg-agent(1)` to
+ provide any needed credentials. Without one, the decryption will
+ fail.
+
+ Note: setting either ``true`` or ``stash`` here implies
+ ``--verify``.
+
+ Here is a table that summarizes each of these policies:
+
+ +------------------------+-------+------+------+-------+
+ | | false | auto | true | stash |
+ +========================+=======+======+======+=======+
+ | Show cleartext if | | X | X | X |
+ | session key is | | | | |
+ | already known | | | | |
+ +------------------------+-------+------+------+-------+
+ | Use secret keys to | | | X | X |
+ | show cleartext | | | | |
+ +------------------------+-------+------+------+-------+
+ | Stash any newly | | | | X |
+ | recovered session keys,| | | | |
+ | reindexing message if | | | | |
+ | found | | | | |
+ +------------------------+-------+------+------+-------+
+
+ Note: ``--decrypt=stash`` requires write access to the database.
+ Otherwise, ``notmuch show`` operates entirely in read-only mode.
+
+ Default: ``auto``
+
+.. option:: --exclude=(true|false)
+
+ Specify whether to omit threads only matching search.exclude\_tags
+ from the search results (the default) or not. In either case the
+ excluded message will be marked with the exclude flag (except when
+ output=mbox when there is nowhere to put the flag).
+
+ If ``--entire-thread`` is specified then complete threads are returned
+ regardless (with the excluded flag being set when appropriate) but
+ threads that only match in an excluded message are not returned
+ when ``--exclude=true.``
+
+ The default is ``--exclude=true.``
+
+.. option:: --body=(true|false)
+
+ If true (the default) **notmuch show** includes the bodies of the
+ messages in the output; if false, bodies are omitted.
+ ``--body=false`` is only implemented for the text, json and sexp
+ formats and it is incompatible with ``--part > 0.``
+
+ This is useful if the caller only needs the headers as body-less
+ output is much faster and substantially smaller.
+
+.. option:: --include-html
+
+ Include "text/html" parts as part of the output (currently
+ only supported with ``--format=text``, ``--format=json`` and
+ ``--format=sexp``). By default, unless ``--part=N`` is used to
+ select a specific part or ``--include-html`` is used to include all
+ "text/html" parts, no part with content type "text/html" is included
+ in the output.
+
+A common use of **notmuch show** is to display a single thread of
+email messages. For this, use a search term of "thread:<thread-id>" as
+can be seen in the first column of output from the
+:any:`notmuch-search(1)` command.
+
+CONFIGURATION
+=============
+
+Structured output (json / sexp) is influenced by the configuration
+option :nmconfig:`show.extra_headers`. See
+:any:`notmuch-config(1)` for details.
+
+EXIT STATUS
+===========
+
+This command supports the following special exit status codes
+
+``20``
+ The requested format version is too old.
+
+``21``
+ The requested format version is too new.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man1/notmuch-tag.rst b/doc/man1/notmuch-tag.rst
new file mode 100644
index 00000000..ae311a23
--- /dev/null
+++ b/doc/man1/notmuch-tag.rst
@@ -0,0 +1,121 @@
+.. _notmuch-tag(1):
+
+===========
+notmuch-tag
+===========
+
+SYNOPSIS
+========
+
+**notmuch** **tag** [options ...] +<*tag*>|-<*tag*> [--] <*search-term*> ...
+
+**notmuch** **tag** **--batch** [--input=<*filename*>]
+
+DESCRIPTION
+===========
+
+Add/remove tags for all messages matching the search terms.
+
+See :any:`notmuch-search-terms(7)` for details of the supported syntax for
+<*search-term*\ >.
+
+Tags prefixed by '+' are added while those prefixed by '-' are removed.
+For each message, tag changes are applied in the order they appear on
+the command line.
+
+The beginning of the search terms is recognized by the first argument
+that begins with neither '+' nor '-'. Support for an initial search term
+beginning with '+' or '-' is provided by allowing the user to specify a
+"--" argument to separate the tags from the search terms.
+
+**notmuch tag** updates the maildir flags according to tag changes if
+the **maildir.synchronize\_flags** configuration option is enabled. See
+:any:`notmuch-config(1)` for details.
+
+Supported options for **tag** include
+
+.. program:: tag
+
+.. option:: --remove-all
+
+ Remove all tags from each message matching the search terms before
+ applying the tag changes appearing on the command line. This
+ means setting the tags of each message to the tags to be added. If
+ there are no tags to be added, the messages will have no tags.
+
+.. option:: --batch
+
+ Read batch tagging operations from a file (stdin by default).
+ This is more efficient than repeated **notmuch tag**
+ invocations. See `TAG FILE FORMAT <#tag_file_format>`__ below for
+ the input format. This option is not compatible with specifying
+ tagging on the command line.
+
+.. option:: --input=<filename>
+
+ Read input from given file, instead of from stdin. Implies
+ ``--batch``.
+
+TAG FILE FORMAT
+===============
+
+The input must consist of lines of the format:
+
++<*tag*\ >\|-<*tag*\ > [...] [--] <*query*\ >
+
+Each line is interpreted similarly to **notmuch tag** command line
+arguments. The delimiter is one or more spaces ' '. Any characters in
+<*tag*\ > **may** be hex-encoded with %NN where NN is the hexadecimal
+value of the character. To hex-encode a character with a multi-byte
+UTF-8 encoding, hex-encode each byte. Any spaces in <tag> **must** be
+hex-encoded as %20. Any characters that are not part of <*tag*\ > **must
+not** be hex-encoded.
+
+In the future tag:"tag with spaces" style quoting may be supported for
+<*tag*\ > as well; for this reason all double quote characters in
+<*tag*\ > **should** be hex-encoded.
+
+The <*query*\ > should be quoted using Xapian boolean term quoting
+rules: if a term contains whitespace or a close paren or starts with a
+double quote, it must be enclosed in double quotes (not including any
+prefix) and double quotes inside the term must be doubled (see below for
+examples).
+
+Leading and trailing space ' ' is ignored. Empty lines and lines
+beginning with '#' are ignored.
+
+EXAMPLE
+-------
+
+The following shows a valid input to batch tagging. Note that only the
+isolated '\*' acts as a wildcard. Also note the two different quotings
+of the tag **space in tags**
+
+::
+
+ +winner *
+ +foo::bar%25 -- (One and Two) or (One and tag:winner)
+ +found::it -- tag:foo::bar%
+ # ignore this line and the next
+
+ +space%20in%20tags -- Two
+ # add tag '(tags)', among other stunts.
+ +crazy{ +(tags) +&are +#possible\ -- tag:"space in tags"
+ +match*crazy -- tag:crazy{
+ +some_tag -- id:"this is ""nauty)"""
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
diff --git a/doc/man1/notmuch.rst b/doc/man1/notmuch.rst
new file mode 100644
index 00000000..c488f12a
--- /dev/null
+++ b/doc/man1/notmuch.rst
@@ -0,0 +1,237 @@
+.. _notmuch(1):
+.. _notmuch-setup(1):
+
+=======
+notmuch
+=======
+
+SYNOPSIS
+========
+
+**notmuch** [option ...] **command** [arg ...]
+
+DESCRIPTION
+===========
+
+Notmuch is a command-line based program for indexing, searching,
+reading, and tagging large collections of email messages.
+
+This page describes how to get started using notmuch from the command
+line, and gives a brief overview of the commands available. For more
+information on e.g. **notmuch show** consult the
+:any:`notmuch-show(1)` man page, also accessible via **notmuch help
+show**
+
+The quickest way to get started with Notmuch is to simply invoke the
+``notmuch`` command with no arguments, which will interactively guide
+you through the process of indexing your mail.
+
+NOTE
+====
+
+While the command-line program ``notmuch`` provides powerful
+functionality, it does not provide the most convenient interface for
+that functionality. More sophisticated interfaces are expected to be
+built on top of either the command-line interface, or more likely, on
+top of the notmuch library interface. See https://notmuchmail.org for
+more about alternate interfaces to notmuch. The emacs-based interface to
+notmuch (available under **emacs/** in the Notmuch source distribution)
+is probably the most widely used at this time.
+
+OPTIONS
+=======
+
+Supported global options for ``notmuch`` include
+
+.. program:: notmuch
+
+.. option:: --help [command-name]
+
+ Print a synopsis of available commands and exit. With an optional
+ command name, show the man page for that subcommand.
+
+.. option:: --version
+
+ Print the installed version of notmuch, and exit.
+
+.. option:: --config=FILE
+
+ Specify the configuration file to use. This overrides any
+ configuration file specified by :envvar:`NOTMUCH_CONFIG`. The empty
+ string is a permitted and sometimes useful value of *FILE*, which
+ tells ``notmuch`` to use only configuration metadata from the database.
+
+.. option:: --uuid=HEX
+
+ Enforce that the database UUID (a unique identifier which persists
+ until e.g. the database is compacted) is HEX; exit with an error
+ if it is not. This is useful to detect rollover in modification
+ counts on messages. You can find this UUID using e.g. ``notmuch
+ count --lastmod``
+
+All global options except ``--config`` can also be specified after the
+command. For example, ``notmuch subcommand --uuid=HEX`` is equivalent
+to ``notmuch --uuid=HEX subcommand``.
+
+COMMANDS
+========
+
+SETUP
+-----
+
+The **notmuch setup** command is used to configure Notmuch for first
+use, (or to reconfigure it later).
+
+The setup command will prompt for your full name, your primary email
+address, any alternate email addresses you use, and the directory
+containing your email archives. Your answers will be written to a
+configuration file in :envvar:`NOTMUCH_CONFIG` (if set) or
+${HOME}/.notmuch-config . This configuration file will be created with
+descriptive comments, making it easy to edit by hand later to change the
+configuration. Or you can run **notmuch setup** again to change the
+configuration.
+
+The mail directory you specify can contain any number of sub-directories
+and should primarily contain only files with individual email messages
+(eg. maildir or mh archives are perfect). If there are other, non-email
+files (such as indexes maintained by other email programs) then notmuch
+will do its best to detect those and ignore them.
+
+Mail storage that uses mbox format, (where one mbox file contains many
+messages), will not work with notmuch. If that's how your mail is
+currently stored, it is recommended you first convert it to maildir
+format with a utility such as :manpage:`mb2md(1)` before running
+**notmuch setup**.
+
+Invoking ``notmuch`` with no command argument will run **setup** if the
+setup command has not previously been completed.
+
+OTHER COMMANDS
+--------------
+
+Several of the notmuch commands accept search terms with a common
+syntax. See :any:`notmuch-search-terms(7)` for more details on the
+supported syntax.
+
+The :any:`notmuch-search(1)`, :any:`notmuch-show(1)`,
+:any:`notmuch-address(1)` and :any:`notmuch-count(1)` commands are
+used to query the email database.
+
+The :any:`notmuch-reply(1)` command is useful for preparing a template
+for an email reply.
+
+The :any:`notmuch-tag(1)` command is the only command available for
+manipulating database contents.
+
+The :any:`notmuch-dump(1)` and :any:`notmuch-restore(1)` commands can
+be used to create a textual dump of email tags for backup purposes,
+and to restore from that dump.
+
+The :any:`notmuch-config(1)` command can be used to get or set
+settings in the notmuch configuration file.
+
+EXTERNAL COMMANDS
+-----------------
+
+If the given command is not known to notmuch, notmuch tries to execute
+the external **notmuch-<subcommand>** in :envvar:`PATH` instead. This
+allows users to have their own notmuch related tools to be run via the
+notmuch command. By design, this does not allow notmuch's own commands
+to be overridden using external commands. The environment variable
+:envvar:`NOTMUCH_CONFIG` will be set according to :option:`--config`,
+if the latter is present.
+
+OPTION SYNTAX
+-------------
+
+All options accepting an argument can be used with '=' or ':' as a
+separator. Except for boolean options (which would be ambiguous), a
+space can also be used as a separator. The following are all
+equivalent:
+
+::
+
+ notmuch --config=alt-config config get user.name
+ notmuch --config:alt-config config get user.name
+ notmuch --config alt-config config get user.name
+
+.. _duplicate-files:
+
+DUPLICATE MESSAGE FILES
+=======================
+
+Notmuch considers the :mailheader:`Message-ID` to be the primary
+identifier of message. Per :rfc:`5322` the :mailheader:`Message-ID` is
+supposed to be globally unique, but this fails in two distinct
+ways. When you receive copies of a message via a mechanism like
+:mailheader:`Cc` or via a mailing list, the copies are typically
+interchangeable. In the case of some broken mail sending software, the
+same :mailheader:`Message-ID` is used for completely unrelated
+messages. The options :option:`search --duplicate` and :option:`show
+--duplicate` options provide the user with control over which message
+file is displayed. Front ends will need to provide their own
+interface, see e.g. the Emacs front-end :any:`emacs-show-duplicates`.
+
+ENVIRONMENT
+===========
+
+The following environment variables can be used to control the behavior
+of notmuch.
+
+.. envvar:: NOTMUCH_CONFIG
+
+ Specifies the location of the notmuch configuration file. See
+ :any:`notmuch-config(1)` for details.
+
+.. envvar:: NOTMUCH_DATABASE
+
+ Specifies the location of the notmuch database. See
+ :any:`notmuch-config(1)` for details.
+
+.. envvar:: NOTMUCH_PROFILE
+
+ Selects among notmuch configurations. See :any:`notmuch-config(1)`
+ for details.
+
+.. envvar:: NOTMUCH_TALLOC_REPORT
+
+ Location to write a talloc memory usage report. See
+ **talloc\_enable\_leak\_report\_full** in :manpage:`talloc(3)` for more
+ information.
+
+.. envvar:: NOTMUCH_DEBUG_QUERY
+
+ If set to a non-empty value, the notmuch library will print (to
+ stderr) Xapian queries it constructs.
+
+SEE ALSO
+========
+
+:any:`notmuch-address(1)`,
+:any:`notmuch-compact(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-properties(7)`,
+:any:`notmuch-reindex(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
+
+The notmuch website: **https://notmuchmail.org**
+
+CONTACT
+=======
+
+Feel free to send questions, comments, or kudos to the notmuch mailing
+list <notmuch@notmuchmail.org> . Subscription is not required before
+posting, but is available from the notmuchmail.org website.
+
+Real-time interaction with the Notmuch community is available via IRC
+(server: irc.libera.chat, channel: #notmuch).
diff --git a/doc/man5/notmuch-hooks.rst b/doc/man5/notmuch-hooks.rst
new file mode 100644
index 00000000..d778bdb8
--- /dev/null
+++ b/doc/man5/notmuch-hooks.rst
@@ -0,0 +1,64 @@
+.. _notmuch-hooks(5):
+
+=============
+notmuch-hooks
+=============
+
+SYNOPSIS
+========
+
+<hook_dir>/{pre-new, post-new, post-insert}
+
+DESCRIPTION
+===========
+
+Hooks are scripts (or arbitrary executables or symlinks to such) that
+notmuch invokes before and after certain actions. These scripts reside
+in a directory defined as described in :any:`notmuch-config(1)`. They
+must have executable permissions.
+
+The currently available hooks are described below.
+
+pre-new
+ This hook is invoked by the :any:`notmuch-new(1)` command before
+ scanning or importing new messages into the database. If this hook
+ exits with a non-zero status, notmuch will abort further
+ processing of the :any:`notmuch-new(1)` command.
+
+ Typically this hook is used for fetching or delivering new mail to
+ be imported into the database.
+
+post-new
+ This hook is invoked by the :any:`notmuch-new(1)` command after
+ any new messages have been imported into the database and initial
+ tags have been applied. The hook will not be run if there have
+ been any errors during the scan or import.
+
+ Typically this hook is used to perform additional query-based
+ tagging on the imported messages.
+
+post-insert
+ This hook is invoked by the :any:`notmuch-insert(1)` command after
+ the message has been delivered, added to the database, and initial
+ tags have been applied. The hook will not be run if there have
+ been any errors during the message delivery; what is regarded as
+ successful delivery depends on the ``--keep`` option.
+
+ Typically this hook is used to perform additional query-based
+ tagging on the delivered messages.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man7/notmuch-properties.rst b/doc/man7/notmuch-properties.rst
new file mode 100644
index 00000000..ff79f4c2
--- /dev/null
+++ b/doc/man7/notmuch-properties.rst
@@ -0,0 +1,148 @@
+.. _notmuch-properties(7):
+
+==================
+notmuch-properties
+==================
+
+SYNOPSIS
+========
+
+**notmuch** **count** **property:**\ <*key*>=<*value*>
+
+**notmuch** **search** **property:**\ <*key*>=<*value*>
+
+**notmuch** **show** **property:**\ <*key*>=<*value*>
+
+**notmuch** **reindex** **property:**\ <*key*>=<*value*>
+
+**notmuch** **tag** +<*tag*> **property:**\ <*key*>=<*value*>
+
+
+**notmuch** **dump** **--include=properties**
+
+**notmuch** **restore** **--include=properties**
+
+DESCRIPTION
+===========
+
+Several notmuch commands can search for, modify, add or remove
+properties associated with specific messages. Properties are
+key/value pairs, and a message can have more than one key/value pair
+for the same key.
+
+While users can select based on a specific property in their search
+terms with the prefix **property:**, the notmuch command-line
+interface does not provide mechanisms for modifying properties
+directly to the user.
+
+Instead, message properties are expected to be set and used
+programmatically, according to logic in notmuch itself, or in
+extensions to it.
+
+Extensions to notmuch which make use of properties are encouraged to
+report the specific properties used to the upstream notmuch project,
+as a way of avoiding collisions in the property namespace.
+
+CONVENTIONS
+===========
+
+Any property with a key that starts with "index." will be removed (and
+possibly re-set) upon reindexing (see :any:`notmuch-reindex(1)`).
+
+MESSAGE PROPERTIES
+==================
+
+The following properties are set by notmuch internally in the course
+of its normal activity.
+
+index.decryption
+ If a message contains encrypted content, and notmuch tries to
+ decrypt that content during indexing, it will add the property
+ ``index.decryption=success`` when the cleartext was successfully
+ indexed. If notmuch attempts to decrypt any part of a message
+ during indexing and that decryption attempt fails, it will add the
+ property ``index.decryption=failure`` to the message.
+
+ Note that it's possible for a single message to have both
+ ``index.decryption=success`` and ``index.decryption=failure``.
+ Consider an encrypted e-mail message that contains another
+ encrypted e-mail message as an attachment -- if the outer message
+ can be decrypted, but the attached part cannot, then both
+ properties will be set on the message as a whole.
+
+ If notmuch never tried to decrypt an encrypted message during
+ indexing (which is the default, see ``index.decrypt`` in
+ :any:`notmuch-config(1)`), then this property will not be set on that
+ message.
+
+session-key
+ When :any:`notmuch-show(1)` or :any:`notmuch-reply(1)` encounters
+ a message with an encrypted part, if notmuch finds a
+ ``session-key`` property associated with the message, it will try
+ that stashed session key for decryption.
+
+ If you do not want to use any stashed session keys that might be
+ present, you should pass those programs ``--decrypt=false``.
+
+ Using a stashed session key with "notmuch show" will speed up
+ rendering of long encrypted threads. It also allows the user to
+ destroy the secret part of any expired encryption-capable subkey
+ while still being able to read any retained messages for which
+ they have stashed the session key. This enables truly deletable
+ e-mail, since (once the session key and asymmetric subkey are both
+ destroyed) there are no keys left that can be used to decrypt any
+ copy of the original message previously stored by an adversary.
+
+ However, access to the stashed session key for an encrypted message
+ permits full byte-for-byte reconstruction of the cleartext
+ message. This includes attachments, cryptographic signatures, and
+ other material that cannot be reconstructed from the index alone.
+
+ See ``index.decrypt`` in :any:`notmuch-config(1)` for more
+ details about how to set notmuch's policy on when to store session
+ keys.
+
+ The session key should be in the ASCII text form produced by
+ GnuPG. For OpenPGP, that consists of a decimal representation of
+ the hash algorithm used (identified by number from RFC 4880,
+ e.g. 9 means AES-256) followed by a colon, followed by a
+ hexadecimal representation of the algorithm-specific key. For
+ example, an AES-128 key might be stashed in a notmuch property as:
+ ``session-key=7:14B16AF65536C28AF209828DFE34C9E0``.
+
+index.repaired
+ Some messages arrive in forms that are confusing to view; they can
+ be mangled by mail transport agents, or the sending mail user
+ agent may structure them in a way that is confusing. If notmuch
+ knows how to both detect and repair such a problematic message, it
+ will do so during indexing.
+
+ If it applies a message repair during indexing, it will use the
+ ``index.repaired`` property to note the type of repair(s) it
+ performed.
+
+ ``index.repaired=skip-protected-headers-legacy-display`` indicates
+ that when indexing the cleartext of an encrypted message, notmuch
+ skipped over a "legacy-display" text/rfc822-headers part that it
+ found in that message, since it was able to index the built-in
+ protected headers directly.
+
+ ``index.repaired=mixedup`` indicates the repair of a "Mixed Up"
+ encrypted PGP/MIME message, a mangling typically produced by
+ Microsoft's Exchange MTA. See
+ https://tools.ietf.org/html/draft-dkg-openpgp-pgpmime-message-mangling
+ for more information.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-reindex(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search-terms(7)`,
+:any:`notmuch-show(1)`
diff --git a/doc/man7/notmuch-search-terms.rst b/doc/man7/notmuch-search-terms.rst
new file mode 100644
index 00000000..acc1c967
--- /dev/null
+++ b/doc/man7/notmuch-search-terms.rst
@@ -0,0 +1,481 @@
+.. _notmuch-search-terms(7):
+
+====================
+notmuch-search-terms
+====================
+
+SYNOPSIS
+========
+
+**notmuch** **count** [option ...] <*search-term*> ...
+
+**notmuch** **dump** [--gzip] [--format=(batch-tag|sup)] [--output=<*file*>] [--] [<*search-term*> ...]
+
+**notmuch** **reindex** [option ...] <*search-term*> ...
+
+**notmuch** **search** [option ...] <*search-term*> ...
+
+**notmuch** **show** [option ...] <*search-term*> ...
+
+**notmuch** **tag** +<*tag*> ... -<*tag*> [--] <*search-term*> ...
+
+DESCRIPTION
+===========
+
+Several notmuch commands accept a common syntax for search terms.
+
+The search terms can consist of free-form text (and quoted phrases)
+which will match all messages that contain all of the given
+terms/phrases in the body, the subject, or any of the sender or
+recipient headers.
+
+As a special case, a search string consisting of exactly a single
+asterisk ("\*") will match all messages.
+
+Search prefixes
+---------------
+
+In addition to free text, the following prefixes can be used to force
+terms to match against specific portions of an email, (where <brackets>
+indicate user-supplied values).
+
+Some of the prefixes with <regex> forms can be also used to restrict
+the results to those whose value matches a regular expression (see
+:manpage:`regex(7)`) delimited with //, for example::
+
+ notmuch search 'from:"/bob@.*[.]example[.]com/"'
+
+body:<word-or-quoted-phrase>
+ Match terms in the body of messages.
+
+from:<name-or-address> or from:/<regex>/
+ The **from:** prefix is used to match the name or address of
+ the sender of an email message.
+
+to:<name-or-address>
+ The **to:** prefix is used to match the names or addresses of any
+ recipient of an email message, (whether To, Cc, or Bcc).
+
+subject:<word-or-quoted-phrase> or subject:/<regex>/
+ Any term prefixed with **subject:** will match only text from the
+ subject of an email. Searching for a phrase in the subject is
+ supported by including quotation marks around the phrase,
+ immediately following **subject:**.
+
+attachment:<word>
+ The **attachment:** prefix can be used to search for specific
+ filenames (or extensions) of attachments to email messages.
+
+mimetype:<word>
+ The **mimetype:** prefix will be used to match text from the
+ content-types of MIME parts within email messages (as specified by
+ the sender).
+
+tag:<tag> or tag:/<regex>/ or is:<tag> or is:/<regex>/
+ For **tag:** and **is:** valid tag values include **inbox** and
+ **unread** by default for new messages added by
+ :any:`notmuch-new(1)` as well as any other tag values added
+ manually with :any:`notmuch-tag(1)`.
+
+id:<message-id> or mid:<message-id> or mid:/<regex>/
+ For **id:** and **mid:**, message ID values are the literal
+ contents of the Message-ID: header of email messages, but without
+ the '<', '>' delimiters.
+
+thread:<thread-id>
+ The **thread:** prefix can be used with the thread ID values that
+ are generated internally by notmuch (and do not appear in email
+ messages). These thread ID values can be seen in the first column
+ of output from :any:`notmuch-search(1)`
+
+thread:{<notmuch query>}
+ Threads may be searched for indirectly by providing an arbitrary
+ notmuch query in **{}**. For example, the following returns
+ threads containing a message from mallory and one (not necessarily
+ the same message) with Subject containing the word "crypto".
+
+ ::
+
+ % notmuch search 'thread:"{from:mallory}" and thread:"{subject:crypto}"'
+
+ The performance of such queries can vary wildly. To understand
+ this, the user should think of the query **thread:{<something>}**
+ as expanding to all of the thread IDs which match **<something>**;
+ notmuch then performs a second search using the expanded query.
+
+path:<directory-path> or path:<directory-path>/** or path:/<regex>/
+ The **path:** prefix searches for email messages that are in
+ particular directories within the mail store. The directory must
+ be specified relative to the top-level maildir (and without the
+ leading slash). By default, **path:** matches messages in the
+ specified directory only. The "/\*\*" suffix can be used to match
+ messages in the specified directory and all its subdirectories
+ recursively. **path:""** matches messages in the root of the mail
+ store and, likewise, **path:\*\*** matches all messages.
+
+ **path:** will find a message if *any* copy of that message is in
+ the specific directory.
+
+folder:<maildir-folder> or folder:/<regex>/
+ The **folder:** prefix searches for email messages by maildir or
+ MH folder. For MH-style folders, this is equivalent to
+ **path:**. For maildir, this includes messages in the "new" and
+ "cur" subdirectories. The exact syntax for maildir folders depends
+ on your mail configuration. For maildir++, **folder:""** matches
+ the inbox folder (which is the root in maildir++), other folder
+ names always start with ".", and nested folders are separated by
+ "."s, such as **folder:.classes.topology**. For "file system"
+ maildir, the inbox is typically **folder:INBOX** and nested
+ folders are separated by slashes, such as
+ **folder:classes/topology**.
+
+ **folder:** will find a message if *any* copy of that message is
+ in the specific folder.
+
+date:<since>..<until> or date:<date>
+ The **date:** prefix can be used to restrict the results to only
+ messages within a particular time range (based on the Date:
+ header).
+
+ See **DATE AND TIME SEARCH** below for details on the range
+ expression, and supported syntax for <since> and <until> date and
+ time expressions.
+
+ The time range can also be specified using timestamps without
+ including the date prefix using a syntax of:
+
+ <initial-timestamp>..<final-timestamp>
+
+ Each timestamp is a number representing the number of seconds
+ since 1970-01-01 00:00:00 UTC. Specifying a time range this way
+ is considered legacy and predates the date prefix.
+
+lastmod:<initial-revision>..<final-revision>
+ The **lastmod:** prefix can be used to restrict the result by the
+ database revision number of when messages were last modified (tags
+ were added/removed or filenames changed). Negative revisions are
+ interpreted relative to the most recent database revision (see
+ :option:`count --lastmod`). This is usually used in conjunction
+ with the ``--uuid`` argument to :any:`notmuch-search(1)` to find
+ messages that have changed since an earlier query.
+
+query:<name>
+ The **query:** prefix allows queries to refer to previously saved
+ queries added with :any:`notmuch-config(1)`.
+
+property:<key>=<value>
+ The **property:** prefix searches for messages with a particular
+ <key>=<value> property pair. Properties are used internally by
+ notmuch (and extensions) to add metadata to messages. A given key
+ can be present on a given message with several different values.
+ See :any:`notmuch-properties(7)` for more details.
+
+sexp:<subquery>
+ The **sexp:** prefix allows subqueries in the format
+ documented in :any:`notmuch-sexp-queries(7)`. Note that subqueries containing
+ spaces must be quoted, and any embedded double quotes must be escaped
+ (see :any:`quoting`).
+
+User defined prefixes are also supported, see :any:`notmuch-config(1)` for
+details.
+
+Operators
+---------
+
+In addition to individual terms, multiple terms can be combined with
+Boolean operators (**and**, **or**, **not**, and **xor**). Each term
+in the query will be implicitly connected by a logical AND if no
+explicit operator is provided (except that terms with a common prefix
+will be implicitly combined with OR). The shorthand '-<term>' can be
+used for 'not <term>' but unfortunately this does not work at the
+start of an expression. Parentheses can also be used to control the
+combination of the Boolean operators, but will have to be protected
+from interpretation by the shell, (such as by putting quotation marks
+around any parenthesized expression).
+
+In addition to the standard boolean operators, Xapian provides several
+operators specific to text searching.
+
+::
+
+ notmuch search term1 NEAR term2
+
+will return results where term1 is within 10 words of term2. The
+threshold can be set like this:
+
+::
+
+ notmuch search term1 NEAR/2 term2
+
+The search
+
+::
+
+ notmuch search term1 ADJ term2
+
+will return results where term1 is within 10 words of term2, but in the
+same order as in the query. The threshold can be set the same as with
+NEAR:
+
+::
+
+ notmuch search term1 ADJ/7 term2
+
+
+Stemming
+--------
+
+**Stemming** in notmuch means that these searches
+
+::
+
+ notmuch search detailed
+ notmuch search details
+ notmuch search detail
+
+will all return identical results, because Xapian first "reduces" the
+term to the common stem (here 'detail') and then performs the search.
+
+There are two ways to turn this off: a search for a capitalized word
+will be performed unstemmed, so that one can search for "John" and not
+get results for "Johnson"; phrase searches are also unstemmed (see
+below for details). Stemming is currently only supported for
+English. Searches for words in other languages will be performed unstemmed.
+
+Wildcards
+---------
+
+It is possible to use a trailing '\*' as a wildcard. A search for
+'wildc\*' will match 'wildcard', 'wildcat', etc.
+
+
+Boolean and Probabilistic Prefixes
+----------------------------------
+
+Xapian (and hence notmuch) prefixes are either **boolean**, supporting
+exact matches like "tag:inbox" or **probabilistic**, supporting a more
+flexible **term** based searching. Certain **special** prefixes are
+processed by notmuch in a way not strictly fitting either of Xapian's
+built in styles. The prefixes currently supported by notmuch are as
+follows.
+
+Boolean
+ **tag:**, **id:**, **thread:**, **folder:**, **path:**, **property:**
+Probabilistic
+ **body:**, **to:**, **attachment:**, **mimetype:**
+Special
+ **from:**, **query:**, **subject:**, **sexp:**
+
+Terms and phrases
+-----------------
+
+In general Xapian distinguishes between lists of terms and
+**phrases**. Phrases are indicated by double quotes (but beware you
+probably need to protect those from your shell) and insist that those
+unstemmed words occur in that order. One useful, but initially
+surprising feature is that the following are equivalent ways to write
+the same phrase.
+
+- "a list of words"
+- a-list-of-words
+- a/list/of/words
+- a.list.of.words
+
+Both parenthesised lists of terms and quoted phrases are ok with
+probabilistic prefixes such as **to:**, **from:**, and **subject:**.
+For prefixes supporting regex search, the parenthesised list should be
+quoted. In particular
+
+::
+
+ subject:"(pizza free)"
+
+is equivalent to
+
+::
+
+ subject:pizza and subject:free
+
+Both of these will match a subject "Free Delicious Pizza" while
+
+::
+
+ subject:"pizza free"
+
+will not.
+
+.. _quoting:
+
+Quoting
+-------
+
+Double quotes are also used by the notmuch query parser to protect
+boolean terms, regular expressions, or subqueries containing spaces or
+other special characters, e.g.
+
+::
+
+ tag:"a tag"
+
+::
+
+ folder:"/^.*/(Junk|Spam)$/"
+
+::
+
+ thread:"{from:mallory and date:2009}"
+
+As with phrases, you need to protect the double quotes from the shell
+e.g.
+
+::
+
+ % notmuch search 'folder:"/^.*/(Junk|Spam)$/"'
+ % notmuch search 'thread:"{from:mallory and date:2009}" and thread:{to:mallory}'
+
+Double quotes within query strings need to be doubled to escape them.
+
+::
+
+ % notmuch search 'tag:"""quoted tag"""'
+ % notmuch search 'sexp:"(or ""wizard"" ""php"")"'
+
+DATE AND TIME SEARCH
+====================
+
+notmuch understands a variety of standard and natural ways of expressing
+dates and times, both in absolute terms ("2012-10-24") and in relative
+terms ("yesterday"). Any number of relative terms can be combined ("1
+hour 25 minutes") and an absolute date/time can be combined with
+relative terms to further adjust it. A non-exhaustive description of the
+syntax supported for absolute and relative terms is given below.
+
+The range expression
+--------------------
+
+date:<since>..<until>
+
+The above expression restricts the results to only messages from <since>
+to <until>, based on the Date: header.
+
+<since> and <until> can describe imprecise times, such as "yesterday".
+In this case, <since> is taken as the earliest time it could describe
+(the beginning of yesterday) and <until> is taken as the latest time it
+could describe (the end of yesterday). Similarly, date:january..february
+matches from the beginning of January to the end of February.
+
+If specifying a time range using timestamps in conjunction with the
+date prefix, each timestamp must be preceded by @ (ASCII hex 40). As
+above, each timestamp is a number representing the number of seconds
+since 1970-01-01 00:00:00 UTC. For example:
+
+ date:@<initial-timestamp>..@<final-timestamp>
+
+Currently, spaces in range expressions are not supported. You can
+replace the spaces with '\_', or (in most cases) '-', or (in some cases)
+leave the spaces out altogether. Examples in this man page use spaces
+for clarity.
+
+Open-ended ranges are supported. I.e. it's possible to specify
+date:..<until> or date:<since>.. to not limit the start or
+end time, respectively.
+
+Single expression
+-----------------
+
+date:<expr> works as a shorthand for date:<expr>..<expr>.
+For example, date:monday matches from the beginning of Monday until
+the end of Monday.
+
+Relative date and time
+----------------------
+
+[N\|number]
+(years\|months\|weeks\|days\|hours\|hrs\|minutes\|mins\|seconds\|secs)
+[...]
+
+All refer to past, can be repeated and will be accumulated.
+
+Units can be abbreviated to any length, with the otherwise ambiguous
+single m being m for minutes and M for months.
+
+Number can also be written out one, two, ..., ten, dozen, hundred.
+Additionally, the unit may be preceded by "last" or "this" (e.g., "last
+week" or "this month").
+
+When combined with absolute date and time, the relative date and time
+specification will be relative from the specified absolute date and
+time.
+
+Examples: 5M2d, two weeks
+
+Supported absolute time formats
+-------------------------------
+
+- H[H]:MM[:SS] [(am\|a.m.\|pm\|p.m.)]
+
+- H[H] (am\|a.m.\|pm\|p.m.)
+
+- HHMMSS
+
+- now
+
+- noon
+
+- midnight
+
+- Examples: 17:05, 5pm
+
+Supported absolute date formats
+-------------------------------
+
+- YYYY-MM[-DD]
+
+- DD-MM[-[YY]YY]
+
+- MM-YYYY
+
+- M[M]/D[D][/[YY]YY]
+
+- M[M]/YYYY
+
+- D[D].M[M][.[YY]YY]
+
+- D[D][(st\|nd\|rd\|th)] Mon[thname] [YYYY]
+
+- Mon[thname] D[D][(st\|nd\|rd\|th)] [YYYY]
+
+- Wee[kday]
+
+Month names can be abbreviated at three or more characters.
+
+Weekday names can be abbreviated at three or more characters.
+
+Examples: 2012-07-31, 31-07-2012, 7/31/2012, August 3
+
+Time zones
+----------
+
+- (+\|-)HH:MM
+
+- (+\|-)HH[MM]
+
+Some time zone codes, e.g. UTC, EET.
+
+SEE ALSO
+========
+
+:any:`notmuch(1)`,
+:any:`notmuch-config(1)`,
+:any:`notmuch-count(1)`,
+:any:`notmuch-dump(1)`,
+:any:`notmuch-hooks(5)`,
+:any:`notmuch-insert(1)`,
+:any:`notmuch-new(1)`,
+:any:`notmuch-properties(7)`,
+:any:`notmuch-reindex(1)`,
+:any:`notmuch-reply(1)`,
+:any:`notmuch-restore(1)`,
+:any:`notmuch-search(1)`,
+:any:`notmuch-show(1)`,
+:any:`notmuch-tag(1)`
diff --git a/doc/man7/notmuch-sexp-queries.rst b/doc/man7/notmuch-sexp-queries.rst
new file mode 100644
index 00000000..858ff685
--- /dev/null
+++ b/doc/man7/notmuch-sexp-queries.rst
@@ -0,0 +1,366 @@
+.. _notmuch-sexp-queries(7):
+
+====================
+notmuch-sexp-queries
+====================
+
+SYNOPSIS
+========
+
+**notmuch** *subcommand* ``--query=sexp`` [option ...] ``--`` '(and (to santa) (date december))'
+
+DESCRIPTION
+===========
+
+Notmuch supports an alternative query syntax based on `S-expressions
+<https://en.wikipedia.org/wiki/S-expression>`_ . It can be selected
+with the command line ``--query=sexp`` or with the appropriate option
+to the library function :c:func:`notmuch_query_create_with_syntax`.
+Support for this syntax is currently optional, you can test if your
+build of notmuch supports it with
+
+::
+
+ $ notmuch config get built_with.sexp_queries
+
+
+S-EXPRESSIONS
+-------------
+
+An *s-expression* is either an atom, or list of whitespace delimited
+s-expressions inside parentheses. Atoms are either
+
+*basic value*
+
+ A basic value is an unquoted string containing no whitespace, double quotes, or
+ parentheses.
+
+*quoted string*
+
+ Double quotes (") delimit strings possibly containing whitespace
+ or parentheses. These can contain double quote characters by
+ escaping with backslash. E.g. ``"this is a quote \""``.
+
+S-EXPRESSION QUERIES
+--------------------
+
+An s-expression query is either an atom, the empty list, or a
+*compound query* consisting of a prefix atom (first element) defining
+a *field*, *logical operation*, or *modifier*, and 0 or more
+subqueries.
+
+``*``
+
+ "*" matches any non-empty string in the current field.
+
+``()``
+
+ The empty list matches all messages
+
+*term*
+
+ Match all messages containing *term*, possibly after stemming or
+ phrase splitting. For discussion of stemming in notmuch see
+ :any:`notmuch-search-terms(7)`. Stemming only applies to unquoted
+ terms (basic values) in s-expression queries. For information on
+ phrase splitting see :any:`fields`.
+
+``(`` *field* |q1| |q2| ... |qn| ``)``
+
+ Restrict the queries |q1| to |qn| to *field*, and combine with *and*
+ (for most fields) or *or*. See :any:`fields` for more information.
+
+``(`` *operator* |q1| |q2| ... |qn| ``)``
+
+ Combine queries |q1| to |qn|. Currently supported operators are
+ ``and``, ``or``, and ``not``. ``(not`` |q1| ... |qn| ``)`` is equivalent
+ to ``(and (not`` |q1| ``) ... (not`` |qn| ``))``.
+
+``(`` *modifier* |q1| |q2| ... |qn| ``)``
+
+ Combine queries |q1| to |qn|, and reinterpret the result (e.g. as a regular expression).
+ See :any:`modifiers` for more information.
+
+``(macro (`` |p1| ... |pn| ``) body)``
+
+ Define saved query with parameter substitution. The syntax is
+ recognized only in saved s-expression queries (see ``squery.*`` in
+ :any:`notmuch-config(1)`). Parameter names in ``body`` must be
+ prefixed with ``,`` to be expanded (see :any:`macro_examples`).
+ Macros may refer to other macros, but only to their own
+ parameters [#macro-details]_.
+
+.. _fields:
+
+FIELDS
+``````
+
+*Fields* [#aka-pref]_
+correspond to attributes of mail messages. Some are inherent (and
+immutable) like ``subject``, while others ``tag`` and ``property`` are
+settable by the user. Each concrete field in
+:any:`the table below <field-table>`
+is discussed further under "Search prefixes" in
+:any:`notmuch-search-terms(7)`. The row *user* refers to user defined
+fields, described in :any:`notmuch-config(1)`.
+
+Most fields are either *phrase fields* [#aka-prob]_ (which match
+sequences of words), or *term fields* [#aka-bool]_ (which match exact
+strings). *Phrase splitting* breaks the term (basic value or quoted
+string) into words, ignore punctuation. Phrase splitting is applied to
+terms in phrase (probabilistic) fields. Both phrase splitting and
+stemming apply only in phrase fields.
+
+Each term or phrase field has an associated combining operator
+(``and`` or ``or``) used to combine the queries from each element of
+the tail of the list. This is generally ``or`` for those fields where
+a message has one such attribute, and ``and`` otherwise.
+
+Term or phrase fields can contain arbitrarily complex queries made up
+from terms, operators, and modifiers, but not other fields.
+
+Range fields take one or two arguments specifying lower and upper
+bounds. One argument is interpreted as identical upper and lower
+bounds. Either upper or lower bound may be specified as ``""`` or
+``*`` to specify the lowest possible lower bound or highest possible
+upper bound.
+
+``lastmod`` ranges support negative arguments, interpreted relative to
+the most recent database revision (see :option:`count --lastmod`).
+
+.. _field-table:
+
+.. table:: Fields with supported modifiers
+
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | field | combine | type | expand | wildcard | regex |
+ +============+===========+===========+===========+===========+==========+
+ | *none* | and | | no | yes | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | *user* | and | phrase | no | yes | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | attachment | and | phrase | yes | yes | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | body | and | phrase | no | no | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | date | | range | no | no | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | folder | or | phrase | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | from | and | phrase | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | id | or | term | no | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | is | and | term | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | lastmod | | range | no | no | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | mid | or | term | no | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | mimetype | or | phrase | yes | yes | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | path | or | term | no | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | property | and | term | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | subject | and | phrase | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | tag | and | term | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | thread | or | term | yes | yes | yes |
+ +------------+-----------+-----------+-----------+-----------+----------+
+ | to | and | phrase | yes | yes | no |
+ +------------+-----------+-----------+-----------+-----------+----------+
+
+.. _modifiers:
+
+MODIFIERS
+`````````
+
+*Modifiers* refer to any prefixes (first elements of compound queries)
+that are neither operators nor fields.
+
+``(infix`` *atom* ``)``
+
+ Interpret *atom* as an infix notmuch query (see
+ :any:`notmuch-search-terms(7)`). Not supported inside fields.
+
+``(matching`` |q1| |q2| ... |qn| ``)`` ``(of`` |q1| |q2| ... |qn| ``)``
+
+ Match all messages have the same values of the current field as
+ those matching all of |q1| ... |qn|. Supported in most term [#not-path]_ or
+ phrase fields. Most commonly used in the ``thread`` field.
+
+``(query`` *atom* ``)``
+
+ Expand to the saved query named by *atom*. See
+ :any:`notmuch-config(1)` for more. Note that the saved query must
+ be in infix syntax (:any:`notmuch-search-terms(7)`). Not supported
+ inside fields.
+
+``(regex`` *atom* ``)`` ``(rx`` *atom* ``)``
+
+ Interpret *atom* as a POSIX.2 regular expression (see
+ :manpage:`regex(7)`). This applies in term fields and a subset [#not-phrase]_ of
+ phrase fields (see :any:`field-table`).
+
+``(starts-with`` *subword* ``)``
+
+ Matches any term starting with *subword*. This applies in either
+ phrase or term :any:`fields <fields>`, or outside of fields [#not-body]_. Note that
+ a ``starts-with`` query cannot be part of a phrase. The
+ atom ``*`` is a synonym for ``(starts-with "")``.
+
+EXAMPLES
+========
+
+``Wizard``
+
+ Match all messages containing the word "wizard", ignoring case.
+
+``added``
+
+ Match all messages containing "added", but also those containing "add", "additional",
+ "Additional", "adds", etc... via stemming.
+
+``(and Bob Marley)``
+
+ Match messages containing words "Bob" and "Marley", or their stems
+ The words need not be adjacent.
+
+``(not Bob Marley)``
+
+ Match messages containing neither "Bob" nor "Marley", nor their stems.
+
+``"quick fox"`` ``quick-fox`` ``quick@fox``
+
+ Match the *phrase* "quick" followed by "fox" in phrase fields (or
+ outside a field). Match the literal string in a term field.
+
+``(folder (of (id 1234@invalid)))``
+
+ Match any message in the same folder as the one with Message-Id "1234\@invalid".
+
+``(id 1234@invalid blah@test)``
+
+ Matches Message-Id "1234\@invalid" *or* Message-Id "blah\@test".
+
+``(and (infix "date:2009-11-18..2009-11-18") (tag unread))``
+
+ Match messages in the given date range with tag unread.
+
+``(and (date 2009-11-18 2009-11-18) (tag unread))``
+
+ Match messages in the given date range with tag unread.
+
+``(and (date 2009-11-18 *) (tag unread))``
+
+ Match messages from 2009-11-18 or later with tag unread.
+
+``(and (date * 2009-11-18) (tag unread))``
+
+ Match messages from 2009-11-18 or earlier with tag unread.
+
+``(starts-with prelim)``
+
+ Match any words starting with "prelim".
+
+``(subject quick "brown fox")``
+
+ Match messages whose subject contains "quick" (anywhere, stemmed) and
+ the phrase "brown fox".
+
+``(subject (starts-with prelim))``
+
+ Matches any word starting with "prelim", inside a message subject.
+
+``(subject (starts-with quick) "brown fox")``
+
+ Match messages whose subject contains "quick brown fox", but also
+ "brown fox quicksand".
+
+``(thread (of (id 1234@invalid)))``
+
+ Match any message in the same thread as the one with Message-Id "1234\@invalid".
+
+``(thread (matching (from bob@example.com) (to bob@example.com)))``
+
+ Match any (messages in) a thread containing a message from
+ "bob\@example.com" and a (possibly distinct) message to
+ "bob\@example.com".
+
+``(to (or bob@example.com mallory@example.org))`` ``(or (to bob@example.com) (to mallory@example.org))``
+
+ Match in the "To" or "Cc" headers, "bob\@example.com",
+ "mallory\@example.org", and also "bob\@example.com.au" since it
+ contains the adjacent triple "bob", "example", "com".
+
+``(not (to *))``
+
+ Match messages with an empty or invalid 'To' and 'Cc' field.
+
+``(List *)``
+
+ Match messages with a non-empty List-Id header, assuming
+ configuration ``index.header.List=List-Id``.
+
+.. _macro_examples:
+
+MACRO EXAMPLES
+--------------
+
+A macro that takes two parameters and applies different fields to them.
+
+::
+
+ $ notmuch config set squery.TagSubject '(macro (tagname subj) (and (tag ,tagname) (subject ,subj)))'
+ $ notmuch search --query=sexp '(TagSubject inbox maildir)'
+
+Nested macros are allowed.
+
+::
+
+ $ notmuch config set squery.Inner '(macro (x) (subject ,x))'
+ $ notmuch config set squery.Outer '(macro (x y) (and (tag ,x) (Inner ,y)))'
+ $ notmuch search --query=sexp '(Outer inbox maildir)'
+
+Parameters can be re-used to reduce boilerplate. Any field, including
+user defined fields is permitted within a macro.
+
+::
+
+ $ notmuch config set squery.About '(macro (name) (or (subject ,name) (List ,name)))'
+ $ notmuch search --query=sexp '(About notmuch)'
+
+
+NOTES
+=====
+
+.. [#macro-details] Technically macros implement lazy evaluation and
+ lexical scope. There is one top level scope
+ containing all macro definitions, but all
+ parameter definitions are local to a given macro.
+
+.. [#aka-pref] a.k.a. prefixes
+
+.. [#aka-prob] a.k.a. probabilistic prefixes
+
+.. [#aka-bool] a.k.a. boolean prefixes
+
+.. [#not-phrase] Due to the implementation of phrase fields in Xapian,
+ regex queries could only match individual words.
+
+.. [#not-body] Due to the way ``body`` is implemented in notmuch,
+ this modifier is not supported in the ``body`` field.
+
+.. [#not-path] Due to the way recursive ``path`` queries are implemented
+ in notmuch, this modifier is not supported in the
+ ``path`` field.
+
+.. |q1| replace:: `q`\ :sub:`1`
+.. |q2| replace:: `q`\ :sub:`2`
+.. |qn| replace:: `q`\ :sub:`n`
+
+.. |p1| replace:: `p`\ :sub:`1`
+.. |p2| replace:: `p`\ :sub:`2`
+.. |pn| replace:: `p`\ :sub:`n`
diff --git a/doc/notmuch-emacs.rst b/doc/notmuch-emacs.rst
new file mode 100644
index 00000000..7dff7d64
--- /dev/null
+++ b/doc/notmuch-emacs.rst
@@ -0,0 +1,785 @@
+.. _notmuch-emacs:
+
+==========================
+Emacs Frontend for Notmuch
+==========================
+
+About this Manual
+=================
+
+This manual covers only the Emacs interface to Notmuch. For information
+on the command line interface, see section “Description” in the Notmuch
+Manual Pages. To save typing, we will sometimes use *notmuch* in this
+manual to refer to the Emacs interface to Notmuch. When this distinction
+is important, we’ll refer to the Emacs interface as
+*notmuch-emacs*.
+
+Notmuch-emacs is highly customizable via the Emacs customization
+framework (or just by setting the appropriate variables). We try to
+point out relevant variables in this manual, but in order to avoid
+duplication of information, you can usually find the most detailed
+description in the variables' docstring.
+
+notmuch-hello
+=============
+
+.. index::
+ single: notmuch-hello
+ single: notmuch
+
+``notmuch-hello`` is the main entry point for Notmuch. You can start it
+with ``M-x notmuch`` or ``M-x notmuch-hello``. The startup screen looks
+something like the following. There are some hints at the bottom of the
+screen. There are three main parts to the notmuch-hello screen,
+discussed below. The **bold** text indicates buttons you can click with
+a mouse or by positioning the cursor and pressing ``<return>``
+
+| Welcome to **notmuch** You have 52 messages.
+|
+| Saved searches: **[edit]**
+|
+| 52 **inbox** 52 **unread**
+|
+| Search: ____________________________________
+|
+| All tags: **[show]**
+|
+| Hit \`?' for context-sensitive help in any Notmuch screen.
+| Customize Notmuch or this page.
+
+You can change the overall appearance of the notmuch-hello screen by
+customizing the variables
+
+.. el:defcustom:: notmuch-hello-sections
+
+ |docstring::notmuch-hello-sections|
+
+.. el:defcustom:: notmuch-hello-thousands-separator
+
+ |docstring::notmuch-hello-thousands-separator|
+
+.. el:defcustom:: notmuch-show-logo
+
+ |docstring::notmuch-show-logo|
+
+.. el:defcustom:: notmuch-column-control
+
+ Controls the number of columns for saved searches/tags in notmuch view.
+
+ This variable has three potential types of values:
+
+ .. describe:: t
+
+ Automatically calculate the number of columns possible based
+ on the tags to be shown and the window width.
+
+ .. describe:: integer <n>
+
+ A lower bound on the number of characters that will
+ be used to display each column.
+
+ .. describe:: float <f>
+
+ A fraction of the window width that is the lower bound on the
+ number of characters that should be used for each column.
+
+ So:
+
+ - if you would like two columns of tags, set this to 0.5.
+
+ - if you would like a single column of tags, set this to 1.0.
+
+ - if you would like tags to be 30 characters wide, set this to 30.
+
+ - if you don't want to worry about all of this nonsense, leave
+ this set to `t`.
+
+.. el:defcustom:: notmuch-show-empty-saved-searches
+
+ |docstring::notmuch-show-empty-saved-searches|
+
+notmuch-hello key bindings
+--------------------------
+
+.. el:define-key:: <tab>
+
+ Move to the next widget (button or text entry field)
+
+.. el:define-key:: <backtab>
+
+ Move to the previous widget.
+
+.. el:define-key:: <return>
+
+ Activate the current widget.
+
+.. el:define-key:: g
+ =
+
+ Refresh the buffer; mainly update the counts of messages for various
+ saved searches.
+
+.. el:define-key:: G
+
+ Import mail, See :ref:`importing`
+
+.. el:define-key:: m
+
+ Compose a message
+
+.. el:define-key:: s
+
+ Search the notmuch database using :ref:`notmuch-search`
+
+.. el:define-key:: v
+
+ Print notmuch version
+
+.. el:define-key:: q
+
+ Quit
+
+.. _saved-searches:
+
+Saved Searches
+--------------
+
+Since notmuch is entirely search-based, it's often useful to organize
+mail around common searches. To facilitate this, the first section of
+notmuch-hello presents a customizable set of saved searches. Saved
+searches can also be accessed from anywhere in notmuch by pressing
+``j`` to access :ref:`notmuch-jump`.
+
+The saved searches default to various common searches such as
+``tag:inbox`` to access the inbox and ``tag:unread`` to access all
+unread mail, but there are several options for customization:
+
+.. el:defcustom:: notmuch-saved-searches
+
+ The list of saved searches, including names, queries, and
+ additional per-query options.
+
+.. el:defcustom:: notmuch-saved-search-sort-function
+
+ This variable controls how saved searches should be sorted. A value
+ of ``nil`` displays the saved searches in the order they are stored
+ in ‘notmuch-saved-searches’.
+
+Search Box
+----------
+
+The search box lets the user enter a Notmuch query. See section
+“Description” in Notmuch Query Syntax, for more info on Notmuch query
+syntax. A history of recent searches is also displayed by default. The
+latter is controlled by the variable `notmuch-hello-recent-searches-max`.
+
+.. el:defcustom:: notmuch-hello-recent-searches-max
+
+ |docstring::notmuch-hello-recent-searches-max|
+
+Known Tags
+----------
+
+One special kind of saved search provided by default is for each
+individual tag defined in the database. This can be controlled via the
+following variables.
+
+.. el:defcustom:: notmuch-hello-tag-list-make-query
+
+ Control how to construct a search (“virtual folder”) from a given
+ tag.
+
+.. el:defcustom:: notmuch-hello-hide-tags
+
+ Which tags not to display at all.
+
+.. _notmuch-search:
+
+notmuch-search
+==============
+
+``notmuch-search-mode`` is used to display the results from executing
+a query via ``notmuch-search``. The syntax for these queries is the
+the same as :ref:`saved-searches`. For details of this syntax see
+info:notmuch-search-terms
+
+By default the output approximates that of the command line See section
+“Description” in notmuch search command.
+
+The main purpose of the ``notmuch-search-mode`` buffer is to act as a
+menu of results that the user can explore further by pressing
+``<return>`` on the appropriate line.
+
+.. el:define-key:: n
+ C-n
+ <down>
+
+ Move to next line
+
+.. el:define-key::
+ p
+ C-p
+ <up>
+
+ Move to previous line
+
+.. el:define-key:: <return>
+
+ Open thread on current line in :ref:`notmuch-show` mode
+
+.. el:define-key:: g
+ =
+
+ Refresh the buffer
+
+.. el:define-key:: ?
+
+ Display full set of key bindings
+
+The presentation of results can be controlled by the following
+variables.
+
+.. el:defcustom:: notmuch-search-result-format
+
+ |docstring::notmuch-search-result-format|
+
+ If the car of an element in notmuch-search-result-format is a
+ function, insert the result of calling the function into the buffer.
+
+ This allows a user to generate custom fields in the output of a
+ search result. For example, with the following settings, the first
+ few characters on each line of the search result are used to show
+ information about some significant tags associated with the thread.
+
+ .. code:: lisp
+
+ (defun -notmuch-result-flags (format-string result)
+ (let ((tags-to-letters '(("flagged" . "!")
+ ("unread" . "u")
+ ("mine" . "m")
+ ("sent" . "s")
+ ("replied" . "r")))
+ (tags (plist-get result :tags)))
+ (format format-string
+ (mapconcat (lambda (t2l)
+ (if (member (car t2l) tags)
+ (cdr t2l)
+ " "))
+ tags-to-letters ""))))
+
+ (setq notmuch-search-result-format '((-notmuch-result-flags . "%s ")
+ ("date" . "%12s ")
+ ("count" . "%9s ")
+ ("authors" . "%-30s ")
+ ("subject" . "%s ")
+ ("tags" . "(%s)")))
+
+ See also :el:defcustom:`notmuch-tree-result-format` and
+ :el:defcustom:`notmuch-unthreaded-result-format`.
+
+.. el:defcustom:: notmuch-search-oldest-first
+
+ Display the oldest threads at the top of the buffer
+
+It is also possible to customize how the name of buffers containing
+search results is formatted using the following variables:
+
+.. el:defcustom:: notmuch-search-buffer-name-format
+
+ |docstring::notmuch-search-buffer-name-format|
+
+.. el:defcustom:: notmuch-saved-search-buffer-name-format
+
+ |docstring::notmuch-saved-search-buffer-name-format|
+
+
+.. _notmuch-show:
+
+notmuch-show
+============
+
+``notmuch-show-mode`` is used to display a single thread of email from
+your email archives.
+
+By default, various components of email messages, (citations,
+signatures, already-read messages), are hidden. You can make
+these parts visible by clicking with the mouse button or by
+pressing RET after positioning the cursor on a hidden part.
+
+.. el:define-key:: <space>
+
+ Scroll the current message (if necessary),
+ advance to the next message, or advance to the next thread (if
+ already on the last message of a thread).
+
+.. el:define-key:: c
+
+ :ref:`show-copy`
+
+.. el:define-key:: N
+
+ Move to next message
+
+.. el:define-key:: P
+
+ Move to previous message (or start of current message)
+
+.. el:define-key:: n
+
+ Move to next matching message
+
+.. el:define-key:: p
+
+ Move to previous matching message
+
+.. el:define-key:: +
+ -
+
+ Add or remove arbitrary tags from the current message.
+
+.. el:define-key:: !
+
+ |docstring::notmuch-show-toggle-elide-non-matching|
+
+.. el:define-key:: ?
+
+ Display full set of key bindings
+
+Display of messages can be controlled by the following variables; see also :ref:`show-large`.
+
+.. el:defcustom:: notmuch-message-headers
+
+ |docstring::notmuch-message-headers|
+
+.. el:defcustom:: notmuch-message-headers-visible
+
+ |docstring::notmuch-message-headers-visible|
+
+.. el:defcustom:: notmuch-show-header-line
+
+ |docstring::notmuch-show-header-line|
+
+.. el:defcustom:: notmuch-multipart/alternative-discouraged
+
+ Which mime types to hide by default for multipart messages.
+
+ Can either be a list of mime types (as strings) or a function
+ mapping a plist representing the current message to such a list.
+ The following example function would discourage `text/html` and
+ `multipart/related` generally, but discourage `text/plain` should
+ the message be sent from `whatever@example.com`.
+
+ .. code:: lisp
+
+ (defun my--determine-discouraged (msg)
+ (let* ((headers (plist-get msg :headers))
+ (from (or (plist-get headers :From) "")))
+ (cond
+ ((string-match "whatever@example.com" from)
+ (list "text/plain"))
+ (t
+ (list "text/html" "multipart/related")))))
+
+.. _show-large:
+
+Dealing with large messages and threads
+---------------------------------------
+
+If you are finding :ref:`notmuch-show` is annoyingly slow displaying
+large messages, you can customize
+:el:defcustom:`notmuch-show-max-text-part-size`. If you want to speed up the
+display of large threads (with or without large messages), there are
+several options. First, you can display the same query in one of the
+other modes. :ref:`notmuch-unthreaded` is the most robust for
+extremely large queries, but :ref:`notmuch-tree` is also be faster
+than :ref:`notmuch-show` in general, since it only renders a single
+message a time. If you prefer to stay with the rendered thread
+("conversation") view of :ref:`notmuch-show`, you can customize the
+variables :el:defcustom:`notmuch-show-depth-limit`,
+:el:defcustom:`notmuch-show-height-limit` and
+:el:defcustom:`notmuch-show-max-text-part-size` to limit the amount of
+rendering done initially. Note that these limits are implicitly
+*OR*-ed together, and combinations might have surprising effects.
+
+.. el:defcustom:: notmuch-show-depth-limit
+
+ |docstring::notmuch-show-depth-limit|
+
+.. el:defcustom:: notmuch-show-height-limit
+
+ |docstring::notmuch-show-height-limit|
+
+.. el:defcustom:: notmuch-show-max-text-part-size
+
+ |docstring::notmuch-show-max-text-part-size|
+
+.. _show-copy:
+
+Copy to kill-ring
+-----------------
+
+You can use the usually Emacs ways of copying text to the kill-ring,
+but notmuch also provides some shortcuts. These keys are available in
+:ref:`notmuch-show`, and :ref:`notmuch-tree`. A subset are available
+in :ref:`notmuch-search`.
+
+.. el:define-key:: c F
+ M-x notmuch-show-stash-filename
+
+ |docstring::notmuch-show-stash-filename|
+
+.. el:define-key:: c G
+ M-x notmuch-show-stash-git-send-email
+
+ |docstring::notmuch-show-stash-git-send-email|
+
+.. el:define-key:: c I
+ M-x notmuch-show-stash-message-id-stripped
+
+ |docstring::notmuch-show-stash-message-id-stripped|
+
+.. el:define-key:: c L
+ M-x notmuch-show-stash-mlarchive-link-and-go
+
+ |docstring::notmuch-show-stash-mlarchive-link-and-go|
+
+.. el:define-key:: c T
+ M-x notmuch-show-stash-tags
+
+ |docstring::notmuch-show-stash-tags|
+
+.. el:define-key:: c c
+ M-x notmuch-show-stash-cc
+
+ |docstring::notmuch-show-stash-cc|
+
+.. el:define-key:: c d
+ M-x notmuch-show-stash-date
+
+ |docstring::notmuch-show-stash-date|
+
+.. el:define-key:: c f
+ M-x notmuch-show-stash-from
+
+ |docstring::notmuch-show-stash-from|
+
+.. el:define-key:: c i
+ M-x notmuch-show-stash-message-id
+
+ |docstring::notmuch-show-stash-message-id|
+
+.. el:define-key:: c l
+ M-x notmuch-show-stash-mlarchive-link
+
+ |docstring::notmuch-show-stash-mlarchive-link|
+
+.. el:define-key:: c s
+ M-x notmuch-show-stash-subject
+
+ |docstring::notmuch-show-stash-subject|
+
+.. el:define-key:: c t
+ M-x notmuch-show-stash-to
+
+ |docstring::notmuch-show-stash-to|
+
+.. el:define-key:: c ?
+ M-x notmuch-subkeymap-help
+
+ Show all available copying commands
+
+.. _emacs-show-duplicates:
+
+Dealing with duplicates
+-----------------------
+
+If there are multiple files with the same :mailheader:`Message-ID`
+(see :any:`duplicate-files`), then :any:`notmuch-show` displays the
+number of duplicates and identifies the current duplicate. In the
+following example duplicate 3 of 5 is displayed.
+
+.. code-block::
+ :emphasize-lines: 1
+
+ M. Mustermann <max@example.com> (Sat, 30 Jul 2022 10:33:10 -0300) (inbox signed) 3/5
+ Subject: Re: Multiple files per message in emacs
+ To: notmuch@notmuchmail.org
+
+.. el:define-key:: %
+ M-x notmuch-show-choose-duplicate
+
+ |docstring::notmuch-show-choose-duplicate|
+
+.. _notmuch-tree:
+
+notmuch-tree
+============
+
+``notmuch-tree-mode`` displays the results of a "notmuch tree" of your
+email archives. Each line in the buffer represents a single
+message giving the relative date, the author, subject, and any
+tags.
+
+.. el:define-key:: c
+
+ :ref:`show-copy`
+
+.. el:define-key:: <return>
+
+ Displays that message.
+
+.. el:define-key:: N
+
+ Move to next message
+
+.. el:define-key:: P
+
+ Move to previous message
+
+.. el:define-key:: n
+
+ Move to next matching message
+
+.. el:define-key:: p
+
+ Move to previous matching message
+
+.. el:define-key:: o
+ M-x notmuch-tree-toggle-order
+
+ |docstring::notmuch-tree-toggle-order|
+
+.. el:define-key:: l
+ M-x notmuch-tree-filter
+
+ Filter or LIMIT the current search results based on an additional query string
+
+.. el:define-key:: t
+ M-x notmuch-tree-filter-by-tag
+
+ Filter the current search results based on an additional tag
+
+
+.. el:define-key:: g
+ =
+
+ Refresh the buffer
+
+.. el:define-key:: ?
+
+ Display full set of key bindings
+
+As is the case with :ref:`notmuch-search`, the presentation of results
+can be controlled by the variable ``notmuch-search-oldest-first``.
+
+.. el:defcustom:: notmuch-tree-result-format
+
+ |docstring::notmuch-tree-result-format|
+
+ The following example shows how to optionally display recipients instead
+ of authors for sent mail (assuming the user is named Mustermann).
+
+ .. code:: lisp
+
+ (defun -notmuch-authors-or-to (format-string result)
+ (let* ((headers (plist-get result :headers))
+ (to (plist-get headers :To))
+ (author (plist-get headers :From))
+ (face (if (plist-get result :match)
+ 'notmuch-tree-match-author-face
+ 'notmuch-tree-no-match-author-face)))
+ (propertize
+ (format format-string
+ (if (string-match "Mustermann" author)
+ (concat "To:" (notmuch-tree-clean-address to))
+ author))
+ 'face face)))
+
+ (setq notmuch-tree-result-format
+ '(("date" . "%12s ")
+ (-notmuch-authors-or-to . "%-20.20s")
+ ((("tree" . "%s")
+ ("subject" . "%s"))
+ . " %-54s ")
+ ("tags" . "(%s)")))
+
+ See also :el:defcustom:`notmuch-search-result-format` and
+ :el:defcustom:`notmuch-unthreaded-result-format`.
+
+.. _notmuch-tree-outline:
+
+notmuch-tree-outline
+--------------------
+
+When this mode is set, each thread and subthread in the results
+list is treated as a foldable section, with its first message as
+its header.
+
+The mode just makes available in the tree buffer all the
+keybindings in info:emacs#Outline_Mode, and binds the following
+additional keys:
+
+.. el:define-key:: <tab>
+
+ Cycle visibility state of the current message's tree.
+
+.. el:define-key:: <M-tab>
+
+ Cycle visibility state of all trees in the buffer.
+
+The behaviour of this minor mode is affected by the following
+customizable variables:
+
+.. el:defcustom:: notmuch-tree-outline-enabled
+
+ |docstring::notmuch-tree-outline-enabled|
+
+.. el:defcustom:: notmuch-tree-outline-visibility
+
+ |docstring::notmuch-tree-outline-visibility|
+
+.. el:defcustom:: notmuch-tree-outline-auto-close
+
+ |docstring::notmuch-tree-outline-auto-close|
+
+.. el:defcustom:: notmuch-tree-outline-open-on-next
+
+ |docstring::notmuch-tree-outline-open-on-next|
+
+.. _notmuch-unthreaded:
+
+notmuch-unthreaded
+------------------
+
+``notmuch-unthreaded-mode`` is similar to :any:`notmuch-tree` in that
+each line corresponds to a single message, but no thread information
+is presented.
+
+Keybindings are the same as :any:`notmuch-tree`.
+
+.. el:defcustom:: notmuch-unthreaded-result-format
+
+ |docstring::notmuch-unthreaded-result-format|
+
+ See also :el:defcustom:`notmuch-search-result-format` and
+ :el:defcustom:`notmuch-tree-result-format`.
+
+Global key bindings
+===================
+
+Several features are accessible from most places in notmuch through the
+following key bindings:
+
+.. el:define-key:: j
+
+ Jump to saved searches using :ref:`notmuch-jump`.
+
+.. el:define-key:: k
+
+ Tagging operations using :ref:`notmuch-tag-jump`
+
+.. el:define-key:: C-_
+ C-/
+ C-x u
+
+ Undo previous tagging operation using :any:`notmuch-tag-undo`
+
+.. _notmuch-jump:
+
+notmuch-jump
+------------
+
+Saved searches configured through :ref:`saved-searches` can
+include a "shortcut key" that's accessible through notmuch-jump.
+Pressing ``j`` anywhere in notmuch followed by the configured shortcut
+key of a saved search will immediately jump to that saved search. For
+example, in the default configuration ``j i`` jumps immediately to the
+inbox search. When you press ``j``, notmuch-jump shows the saved
+searches and their shortcut keys in the mini-buffer.
+
+.. _notmuch-tag-jump:
+
+notmuch-tag-jump
+----------------
+
+Tagging operations configured through ``notmuch-tagging-keys`` can
+be accessed via :kbd:`k` in :ref:`notmuch-show`,
+:ref:`notmuch-search` and :ref:`notmuch-tree`. With a
+prefix (:kbd:`C-u k`), notmuch displays a menu of the reverses of the
+operations specified in ``notmuch-tagging-keys``; i.e. each
+``+tag`` is replaced by ``-tag`` and vice versa.
+
+.. el:defcustom:: notmuch-tagging-keys
+
+ |docstring::notmuch-tagging-keys|
+
+
+notmuch-tag-undo
+----------------
+
+Each notmuch buffer supporting tagging operations (i.e. buffers in
+:any:`notmuch-show`, :any:`notmuch-search`, :any:`notmuch-tree`, and
+:any:`notmuch-unthreaded` mode) keeps a local stack of tagging
+operations. These can be undone via :any:`notmuch-tag-undo`. By default
+this is bound to the usual Emacs keys for undo.
+
+.. el:define-key:: C-_
+ C-/
+ C-x u
+ M-x notmuch-tag-undo
+
+ |docstring::notmuch-tag-undo|
+
+Buffer navigation
+=================
+
+.. el:define-key:: M-x notmuch-cycle-notmuch-buffers
+
+ |docstring::notmuch-cycle-notmuch-buffers|
+
+Configuration
+=============
+
+.. _importing:
+
+Importing Mail
+--------------
+
+.. el:define-key:: M-x notmuch-poll
+
+ |docstring::notmuch-poll|
+
+.. el:defcustom:: notmuch-poll-script
+
+ |docstring::notmuch-poll-script|
+
+Sending Mail
+------------
+
+.. el:defcustom:: mail-user-agent
+
+ Emacs consults the variable :code:`mail-user-agent` to choose a mail
+ sending package for commands like :code:`report-emacs-bug` and
+ :code:`compose-mail`. To use ``notmuch`` for this, customize this
+ variable to the symbol :code:`notmuch-user-agent`.
+
+.. el:defcustom:: message-dont-reply-to-names
+
+ When composing mail replies, Emacs's message mode uses the
+ variable :code:`message-dont-reply-to-names` to exclude
+ recipients matching a given collection of regular expressions
+ or satisfying an arbitrary predicate. Notmuch's MUA inherits
+ this standard mechanism and will honour your customization of
+ this variable.
+
+Init File
+---------
+
+When Notmuch is loaded, it will read the ``notmuch-init-file``
+(``~/.emacs.d/notmuch-config`` by default) file. This is normal Emacs Lisp
+file and can be used to avoid cluttering your ``~/.emacs`` with Notmuch
+stuff. If the file with ``.elc``, ``.elc.gz``, ``.el`` or ``.el.gz``
+suffix exist it will be read instead (just one of these, chosen in this
+order). Most often users create ``~/.emacs.d/notmuch-config.el`` and just
+work with it. If Emacs was invoked with the ``-q`` or ``--no-init-file``
+options, ``notmuch-init-file`` is not read.
diff --git a/doc/python-bindings.rst b/doc/python-bindings.rst
new file mode 100644
index 00000000..e1ad26ad
--- /dev/null
+++ b/doc/python-bindings.rst
@@ -0,0 +1,5 @@
+Python Bindings
+===============
+
+.. automodule:: notmuch2
+ :members:
diff --git a/doc/queries.rst b/doc/queries.rst
new file mode 100644
index 00000000..b76e71e0
--- /dev/null
+++ b/doc/queries.rst
@@ -0,0 +1,9 @@
+Notmuch Queries
+===============
+
+.. toctree::
+ :titlesonly:
+
+ man7/notmuch-search-terms
+ man7/notmuch-sexp-queries
+ man7/notmuch-properties