This provides library functions for unified handling of errors from
the notmuch CLI. Follow-up patches will convert some scattered error
handling to use this and add error handling where we currently ignore
errors.
Previously, if the input stream consisted only of an error message,
notmuch-json-begin-compound would signal a (wrong-type-argument
number-or-marker-p nil) error when reaching the end of the error
message. This happened because notmuch-json-scan-to-value would think
that it reached a value and put the parser into the 'value state.
Even after notmuch-json-begin-compound signaled the syntax error, the
parser would remain in this state and when the resynchronization logic
reached the end of the buffer, the parser would fail because the
'value state indicates that characters are available.
This fixes this problem by restoring the parser's previous state if it
encounters a syntax error.
Previously refreshing the notmuch show buffer did not remove overlays
which meant that if the user refreshed a message with images the
images would remain and then the new text was added after.
One might have guessed that erase-buffer would have removed them but
it seems not. Thus force the removal of overlays with remove-overlays.
Remove notmuch-folders which has been deprecated since
commit a466921760
Author: Carl Worth <cworth@cworth.org>
Date: Mon Apr 26 22:42:07 2010 -0700
emacs: Rip out all of the notmuch-folder code.
This lets us simplify the notmuch-saved-searches code slightly.
This function is also used by pick so split it out in preperation for
moving to lib. In fact, pick and show want a slightly different
combination of name and email on return so make the separated function
return them as a pair, and let show or pick extract the combination
they want from that.
The macro with-current-notmuch-show-message executes command
`notmuch show --format=raw id:...` which just outputs the contents
of the mail file verbatim (into temporary buffer). In case e.g. utf-8
locale is used the temporary buffer has buffer-file-coding-system as
utf-8. In this case Emacs converts the data to multibyte format, guessing
that input is in utf-8.
However, the "raw" (MIME) message may contain octet data in any other
8bit format, and as no (MIME-)content spesific handling to the message
is done at this point, conversion to other formats may lose information.
By setting coding-system-for-read 'no-conversion drops the conversion part
and makes this handle input as notmuch-get-bodypart-internal() does.
This marks the broken test in previous change fixed.
icalendar-import-buffer can fail by an error signal (which have been
witnessed) but according to its docstring it can also return nil
when failing (it returns t when succeeding).
Now that the error is caught by the caller of notmuch-show-inset-part-*
functions in case icalendar-import-buffer returns nil an explicit
error is signaled and unwind-protect takes care of deleting the
temporary file (just in case, it is usually not written to the fs yet).
notmuch-get-bodypart-content provides raw data to its caller so
that it can be stored verbatim whenever needed. icalendar functions
expect Emacs to do EOL conversion for the data given to these. Therefore
it the CRLF -> LF conversion is now done explicitly.
The calls to private functions icalendar--convert-ical-to-diary and
icalendar--read-element are replaced with call to public function
icalendar-import-buffer.
This regexp agrees with Xapian query syntax much more closely, though
we specifically disallow various cases that would be confusing in the
context of an email body (e.g., punctuation at the end of an id: link
is not considered part of the id: link because it's probably part of
the surrounding text).
In particular, this handles id: links that are not surrounded by
quotes much better, which stash is much more likely to generate now
that we don't quote id's that don't need to be quoted. It also
handles quoted id: links better.
We update the buttonization test to reflect the new pattern.
When inserting of email bodypart failes, insert a failure message
to the buffer (and continue) instead of halting the insertion of
the rest of that email thread in question.
This patch just renames the internal variables for the JSON parser now
it is no longer specific to search mode. It also fixes up the white
space after the previous patch. There should be no functional changes.
This patch splits out the incremental json parser into its own
function.
It moves the main logic of the parser to happen inside the parse
buffer rather than inside the results buffer, but makes sure all
results and all errors are displayed in the results buffer.
It also changes the local parser variables from being buffer
local to the results buffer to being buffer local to the parse buffer,
and sets them up automatically so the caller does not need to.
Finally to keep the diff small this patch does not fix the whitespace,
nor complete the code movement (these are done in subsequent patches)
but it should contain all the functional changes.
Currently, we only properly escape stashed id queries, but there are
other places where the Emacs UI constructs queries for boolean terms.
Since this escaping function is meant to be used in other places, it
avoids escaping strings that don't need escaping.
Emacs 24's mm-shr HTML email renderer fails to load gnus-art before
referencing gnus-inhibit-images, resulting in a void-variable error
when notmuch attempts to render an HTML email with inline images.
This works around this bug by advising mm-shr to load gnus-art.
mm-shr is the only function outside of gnus-art itself that references
gnus-inhibit-images, so this workaround should be correct. If this
ever changes, hopefully they will have fixed this bug upstream first.
This fixes the "Rendering HTML mail with images" test for Emacs 24.
notmuch-hello (called also through notmuch-hello-update, bound to '='
by default) tries to find the widget under or following point before
refresh, and put the point back to the widget afterwards. The code has
grown quite complicated, and has at least the following issues:
1) All the individual section functions have to include code to
support point placement. If there is no such support, point is
dropped to the search box. Only saved searches and all tags
sections support point placement.
2) Point placement is based on widget-value. If there are two widgets
with the same widget-value (for example a saved search with the
same name as a tag) the point is moved to the earlier one, even if
point was on the later one.
3) When first entering notmuch-hello notmuch-hello-target is nil, and
point is dropped to the search box.
Moving the point to the search box is annoying because the user is
required to move the point before being able to enter key bindings.
Simplify the code by removing all point placement based on widgets, as
it does not work properly, and trying to fix that would unnecessarily
complicate the code.
Save current line and column before refresh, and restore them
afterwards. Sometimes, if notmuch-show-empty-saved-searches is nil,
and the refresh adds or removes saved searches from the list, this has
the appearance of moving the point relative to the nearest
widgets. This is a much smaller and less frequent problem than the
ones listed above.
Since marking a message as read can now be a user customized set of
tag changes, make reversing this easier. Allow a prefix argument to
notmuch-show-mark-read to reverse the marking as read, similar to the
unarchiving in notmuch-show-archive-message.
While at it, update the relevant documentation to match that of other
automatic tagging (i.e. archive and reply).
Since archiving a thread can now be a user customized set of tag
changes, make reversing this easier. Allow a prefix argument to
notmuch-search-archive-thread to reverse the archiving, similar to the
unarchiving in notmuch-show-archive-message.
Add support for customization of the tag changes that are applied when
a message or a thread is archived. Instead of hard-coded removal of
the "inbox" tag, the user can now specify a list of tag changes to
perform.
* emacs/notmuch.el (notmuch-search-mode):
`notmuch-search-tag-all' currently uses the current query string
instead of `notmuch-search-find-thread-id-region-search', which
might cause a race condition.
The `notmuch-show-mark-read-tags' lists tags that are to be applied when
message is read. By default, the only value is "-unread" which will remove
the unread tag. Among other uses, this variable can be used to stop
notmuch-show from modifying tags when message is shown (by setting the
variable to an empty list).
Previously, notmuch-show-previous-message would move to the beginning
of the message before the message containing point. This patch makes
it instead move to the previous message *boundary*. That is, if point
isn't already at the beginning of the message, it moves to the
beginning of the current message. This is consistent with
notmuch-show-next-message, which can be thought of as moving to the
next message boundary. Several people have expressed a preference for
this.
The recent change to use json for notmuch-search.el introduced a bug
in the code for keeping position on refresh. The problem is a
comparison between (plist-get result :thread) and a thread-id returned
by notmuch-search-find-thread-id: the latter is prefixed with
"thread:"
We fix this by adding an option to notmuch-search-find-thread-id to
return the bare thread-id. It appears that notmuch-search-refresh-view
is the only caller of notmuch-search that supplies a thread-id so this
change should be safe (but could theoretically break users .emacs
functions).
Previously, the Emacs byte compiler produced the warning
the function `remove-if-not' might not be defined at runtime.
because we only required cl at compile-time (not runtime). This fixes
this warning by requiring cl at runtime, ensuring that the definition
of remove-if-not is available.
The pipe message function (when used with a prefix) uses a search of
the form "id:<id1> or id:<id2>" etc. Since the user says precisely
which messages are wanted by opening them it should not use excludes.
In commit 5d0883e the function notmuch-search-next-thread was changed.
In particular it only goes to the next message if there is a next
message. This breaks notmuch-show-archive-thread-then-next. Fix this
by going to the "next" message whenever we are on a current message.
At this point, the only remaining functions that don't support
multi-line search result formats are the thread navigation functions.
This patch fixes that by rewriting them in terms of
notmuch-search-result-{beginning,end}.
This changes the behavior of notmuch-search-previous-thread slightly
so that if point isn't at the beginning of a result, it first moves
point to the beginning of the result.
Previously we ignored any notmuch-search-result-format customizations
for tag formatting because we needed to be able to parse back in the
result line and update the tags in place. We no longer do either of
these things, so we can allow customization of this format.
(Coincidentally, previously we still allowed too much customization of
the tags format, since moving it earlier on the line or removing it
from the line would interfere with the tagging mechanism. There is
now no problem with doing such things.)
Since the result object contains everything that the other text
properties recorded, we can remove the other text properties and
simply look in the plist of the appropriate result object.
This simplifies the traversal of regions of results and eliminates the
need for save-excursions (which tend to get in the way of maintaining
point when we make changes to the buffer). It also fixes some strange
corner cases in the old line-based code where results that bordered
the region but were not included in it could be affected by region
commands. Coincidentally, this also essentially enables multi-line
search result formats; the only remaining non-multi-line-capable
functions are notmuch-search-{next,previous}-thread, which are only
used for interactive navigation.
Now that we keep the full thread result object, we can refresh a
result after any changes by simply deleting and reconstructing the
result line from scratch.
A convenient side-effect of this wholesale replacement is that search
now re-applies notmuch-search-line-faces when tags change.
Previously, tag-based search result highlighting was done by creating
an overlay over each search result. However, overlays have annoying
front- and rear-advancement semantics that make it difficult to
manipulate text at their boundaries, which the next patch will do.
They also have performance problems (creating an overlay is linear in
the number of overlays between point and the new overlay, making
highlighting a search buffer quadratic in the number of results).
Text properties have neither problem. However, text properties make
it more difficult to apply multiple faces since, unlike with overlays,
a given character can only have a single 'face text property. Hence,
we introduce a utility function that combines faces into any existing
'face text properties.
Using this utility function, it's straightforward to apply all of the
appropriate tag faces in notmuch-search-color-line.
notmuch-message-mark-replied used "apply" to change message tags
according to notmuch-message-replied-tags after sending a reply. This
works if the latter is a single-element list. But with the recently
changed format of tag changes, it breaks for multiple-element lists.
Use "funcall" to properly pass the list of tag changes as a single
argument.
The JSON format eliminates the complex escaping issues that have
plagued the text search format. This uses the incremental JSON parser
so that, like the text parser, it can output search results
incrementally.
This slows down the parser by about ~4X, but puts us in a good
position to optimize either by improving the JSON parser (evidence
suggests this can reduce the overhead to ~40% over the text format) or
by switching to S-expressions (evidence suggests this will more than
double performance over the text parser). [1]
This also fixes the incremental search parsing test.
This has one minor side-effect on search result formatting.
Previously, the date field was always padded to a fixed width of 12
characters because of how the text parser's regexp was written. The
JSON format doesn't do this. We could pad it out in Emacs before
formatting it, but, since all of the other fields are variable width,
we instead fix notmuch-search-result-format to take the variable-width
field and pad it out. For users who have customized this variable,
we'll mention in the NEWS how to fix this slight format change.
[1] id:"20110720205007.GB21316@mit.edu"
This parser is designed to read streaming JSON whose structure is
known to the caller. Like a typical JSON parsing interface, it
provides a function to read a complete JSON value from the input.
However, it extends this with an additional function that
requires the next value in the input to be a compound value and
descends into it, allowing its elements to be read one at a time
or further descended into. Both functions can return 'retry to
indicate that not enough input is available.
The parser supports efficient partial parsing, so there's no need to
frame the input for correctness or performance.
The bulk of the parsing is still done by Emacs' json.el, so any
improvements or optimizations to that will benefit the incremental
parser as well.
Currently only descending into JSON lists is supported because that's
all we need, but support for descending into JSON objects can be added
in the future.
Rather than passing lots of arguments and then further passing those
to `notmuch-search-insert-field', pass a plist containing all of the
search result information. This plist is compatible with the JSON
format search results.
This is a simpler place to do this, since we can avoid any point
motion and hence any save-excursions in
`notmuch-search-process-filter', which in turn lets us put all of the
search-target logic outside of any save-excursions.
`notmuch-search-show-{result,error}' are now responsible for their own
point motion.
`notmuch-search-process-filter' could use some reindentation after
this, but we're about to rewrite it entirely, so we won't bother.
This removes the last bit of direct output from the parsing function.
With the parser now responsible solely for parsing, we can swap it out
for another parser.