mirror of https://github.com/djcb/mu.git
Merge branch 'wip/djcb/modeline'
This commit is contained in:
commit
54dc5cfabe
32
NEWS.org
32
NEWS.org
|
@ -41,10 +41,19 @@
|
||||||
manual for details.
|
manual for details.
|
||||||
|
|
||||||
- One change is that ~mu4e-split-view~ can no longer be a function; the new
|
- One change is that ~mu4e-split-view~ can no longer be a function; the new
|
||||||
way is to use ~display-buffer-alist~ as explained in the [[info:mu4e:Buffer Display][manual]].
|
way is to use ~display-buffer-alist~ as explained in the [[info:mu4e:Buffer Display][manual]]
|
||||||
|
|
||||||
- ~mu4e~ now keeps track of the 'baseline' query results and shows the
|
- ~mu4e~ now keeps track of 'baseline' query results and shows the difference
|
||||||
difference from that in the main view. See the [[info:mu4e#Bookmarks and Maildirs][manual entry]] for details.
|
from that in the main view and modeline. See the [[info:mu4e#Bookmarks and Maildirs][manual entry]] for details.
|
||||||
|
|
||||||
|
- Related to that, you can now crown one of your bookmarks in =mu4e-bookmarks=
|
||||||
|
with ~:monitor t~, causing it to be highlighted in the main view and used in
|
||||||
|
the mode-line. See the new [[info:mu4e#Modeline][modeline entry]] in the manual; this uses the new
|
||||||
|
=mu4e-modeline-mode= minor-mode.
|
||||||
|
|
||||||
|
- Bookmark ~:query~ values must be strings now; earlier version half-attempted
|
||||||
|
to allow for functions to works as well, but it didn't work. So now we
|
||||||
|
officially remove this.
|
||||||
|
|
||||||
- when moving messages (which includes changing flags), file-flags changes
|
- when moving messages (which includes changing flags), file-flags changes
|
||||||
are propagated to duplicates of the messages; that is, e.g. the /Seen/ or
|
are propagated to duplicates of the messages; that is, e.g. the /Seen/ or
|
||||||
|
@ -81,7 +90,7 @@
|
||||||
further parameters ~mu~ shows both subcommands and scripts. This is a
|
further parameters ~mu~ shows both subcommands and scripts. This is a
|
||||||
work-in-progress!
|
work-in-progress!
|
||||||
|
|
||||||
- The per-(week|day|year|year-month) script have been combined into a
|
- The per-(week|day|year|year-month) scripts have been combined into a
|
||||||
~histogram~ script. If you have Guile-support enabled, and have ~gnuplot~
|
~histogram~ script. If you have Guile-support enabled, and have ~gnuplot~
|
||||||
installed, you can do e.g.,
|
installed, you can do e.g.,
|
||||||
|
|
||||||
|
@ -92,7 +101,7 @@
|
||||||
to get a histogram of such messages. Note, this area is under active
|
to get a histogram of such messages. Note, this area is under active
|
||||||
developement and will likely change.
|
developement and will likely change.
|
||||||
|
|
||||||
*** building
|
*** building and installation
|
||||||
|
|
||||||
- the autotools build (which was deprecated since 1.8) has now been removed.
|
- the autotools build (which was deprecated since 1.8) has now been removed.
|
||||||
we thank it for its services since 2008. We continue with ~meson~.
|
we thank it for its services since 2008. We continue with ~meson~.
|
||||||
|
@ -339,8 +348,12 @@
|
||||||
out on the maling list.
|
out on the maling list.
|
||||||
|
|
||||||
|
|
||||||
|
* Old news
|
||||||
|
:PROPERTIES:
|
||||||
|
:VISIBILITY: folded
|
||||||
|
:END:
|
||||||
|
|
||||||
* 1.6 (released, as of July 27 2021)
|
** 1.6 (released, as of July 27 2021)
|
||||||
|
|
||||||
NOTE: After upgrading, you need to call ~mu init~, with your prefered parameters
|
NOTE: After upgrading, you need to call ~mu init~, with your prefered parameters
|
||||||
before you can use ~mu~ / ~mu4e~. This is because the underlying database-schema
|
before you can use ~mu~ / ~mu4e~. This is because the underlying database-schema
|
||||||
|
@ -426,10 +439,7 @@
|
||||||
- Switch the context for existing draft messages using
|
- Switch the context for existing draft messages using
|
||||||
~mu4e-compose-context-switch~ or ~C-c C-;~ in ~mu4e-compose-mode~.
|
~mu4e-compose-context-switch~ or ~C-c C-;~ in ~mu4e-compose-mode~.
|
||||||
|
|
||||||
* Old news
|
|
||||||
:PROPERTIES:
|
|
||||||
:VISIBILITY: folded
|
|
||||||
:END:
|
|
||||||
** 1.4 (released, as of April 18 2020)
|
** 1.4 (released, as of April 18 2020)
|
||||||
|
|
||||||
*** mu
|
*** mu
|
||||||
|
@ -939,7 +949,7 @@ End of search results
|
||||||
- org: improve template keywords
|
- org: improve template keywords
|
||||||
- rework URL handling
|
- rework URL handling
|
||||||
|
|
||||||
** Release 0.9.5
|
** Release 0.9.10
|
||||||
|
|
||||||
*** mu
|
*** mu
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,7 @@ struct Server::Private {
|
||||||
void move_handler(const Command& cmd);
|
void move_handler(const Command& cmd);
|
||||||
void mkdir_handler(const Command& cmd);
|
void mkdir_handler(const Command& cmd);
|
||||||
void ping_handler(const Command& cmd);
|
void ping_handler(const Command& cmd);
|
||||||
|
void queries_handler(const Command& cmd);
|
||||||
void quit_handler(const Command& cmd);
|
void quit_handler(const Command& cmd);
|
||||||
void remove_handler(const Command& cmd);
|
void remove_handler(const Command& cmd);
|
||||||
void sent_handler(const Command& cmd);
|
void sent_handler(const Command& cmd);
|
||||||
|
@ -287,17 +288,20 @@ Server::Private::make_command_map()
|
||||||
[&](const auto& params) { mkdir_handler(params); }});
|
[&](const auto& params) { mkdir_handler(params); }});
|
||||||
cmap.emplace(
|
cmap.emplace(
|
||||||
"ping",
|
"ping",
|
||||||
|
CommandInfo{
|
||||||
|
ArgMap{},
|
||||||
|
"ping the mu-server and get server information in the response",
|
||||||
|
[&](const auto& params) { ping_handler(params); }});
|
||||||
|
|
||||||
|
cmap.emplace(
|
||||||
|
"queries",
|
||||||
CommandInfo{
|
CommandInfo{
|
||||||
ArgMap{
|
ArgMap{
|
||||||
{":queries",
|
{":queries",
|
||||||
ArgInfo{Type::List, false, "queries for which to get read/unread numbers"}},
|
ArgInfo{Type::List, false, "queries for which to get read/unread numbers"}},
|
||||||
{":skip-dups",
|
|
||||||
ArgInfo{Type::Symbol,
|
|
||||||
false,
|
|
||||||
"whether to exclude messages with duplicate message-ids"}},
|
|
||||||
},
|
},
|
||||||
"ping the mu-server and get information in response",
|
"get unread/totals information for a list of queries",
|
||||||
[&](const auto& params) { ping_handler(params); }});
|
[&](const auto& params) { queries_handler(params); }});
|
||||||
|
|
||||||
cmap.emplace("quit", CommandInfo{{}, "quit the mu server", [&](const auto& params) {
|
cmap.emplace("quit", CommandInfo{{}, "quit the mu server", [&](const auto& params) {
|
||||||
quit_handler(params);
|
quit_handler(params);
|
||||||
|
@ -916,9 +920,28 @@ Server::Private::ping_handler(const Command& cmd)
|
||||||
const auto storecount{store().size()};
|
const auto storecount{store().size()};
|
||||||
if (storecount == (unsigned)-1)
|
if (storecount == (unsigned)-1)
|
||||||
throw Error{Error::Code::Store, "failed to read store"};
|
throw Error{Error::Code::Store, "failed to read store"};
|
||||||
|
Sexp addrs;
|
||||||
|
for (auto&& addr : store().properties().personal_addresses)
|
||||||
|
addrs.add(addr);
|
||||||
|
|
||||||
|
output_sexp(Sexp()
|
||||||
|
.put_props(":pong", "mu")
|
||||||
|
.put_props(":props",
|
||||||
|
Sexp().put_props(
|
||||||
|
":version", VERSION,
|
||||||
|
":personal-addresses", std::move(addrs),
|
||||||
|
":database-path", store().properties().database_path,
|
||||||
|
":root-maildir", store().properties().root_maildir,
|
||||||
|
":doccount", storecount)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Server::Private::queries_handler(const Command& cmd)
|
||||||
|
{
|
||||||
const auto queries{cmd.string_vec_arg(":queries")
|
const auto queries{cmd.string_vec_arg(":queries")
|
||||||
.value_or(std::vector<std::string>{})};
|
.value_or(std::vector<std::string>{})};
|
||||||
|
|
||||||
Sexp qresults;
|
Sexp qresults;
|
||||||
for (auto&& q : queries) {
|
for (auto&& q : queries) {
|
||||||
const auto count{store_.count_query(q)};
|
const auto count{store_.count_query(q)};
|
||||||
|
@ -929,22 +952,10 @@ Server::Private::ping_handler(const Command& cmd)
|
||||||
":unread", unread));
|
":unread", unread));
|
||||||
}
|
}
|
||||||
|
|
||||||
Sexp addrs;
|
output_sexp(Sexp(":queries"_sym, std::move(qresults)));
|
||||||
for (auto&& addr : store().properties().personal_addresses)
|
|
||||||
addrs.add(addr);
|
|
||||||
|
|
||||||
auto lst = Sexp().put_props(":pong", "mu");
|
|
||||||
auto proplst = Sexp().put_props(
|
|
||||||
":version", VERSION,
|
|
||||||
":personal-addresses", std::move(addrs),
|
|
||||||
":database-path", store().properties().database_path,
|
|
||||||
":root-maildir", store().properties().root_maildir,
|
|
||||||
":doccount", storecount,
|
|
||||||
":queries", std::move(qresults));
|
|
||||||
|
|
||||||
output_sexp(lst.put_props(":props", std::move(proplst)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Server::Private::quit_handler(const Command& cmd)
|
Server::Private::quit_handler(const Command& cmd)
|
||||||
{
|
{
|
||||||
|
|
|
@ -106,8 +106,7 @@ CommandHandler::invoke(const Command& cmd, bool do_validate) const
|
||||||
const auto cmit{cmap_.find(cmd.name())};
|
const auto cmit{cmap_.find(cmd.name())};
|
||||||
if (cmit == cmap_.cend())
|
if (cmit == cmap_.cend())
|
||||||
return Err(Error::Code::Command,
|
return Err(Error::Code::Command,
|
||||||
"unknown command in command '%s'",
|
"unknown command '%s'", cmd.to_string().c_str());
|
||||||
cmd.to_string().c_str());
|
|
||||||
|
|
||||||
const auto& cmd_info{cmit->second};
|
const auto& cmd_info{cmit->second};
|
||||||
if (do_validate) {
|
if (do_validate) {
|
||||||
|
|
|
@ -45,6 +45,7 @@ mu4e_srcs=[
|
||||||
'mu4e-main.el',
|
'mu4e-main.el',
|
||||||
'mu4e-mark.el',
|
'mu4e-mark.el',
|
||||||
'mu4e-message.el',
|
'mu4e-message.el',
|
||||||
|
'mu4e-modeline.el',
|
||||||
'mu4e-obsolete.el',
|
'mu4e-obsolete.el',
|
||||||
'mu4e-org.el',
|
'mu4e-org.el',
|
||||||
'mu4e-search.el',
|
'mu4e-search.el',
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e-bookmarks.el -- part of mu4e -*- lexical-binding: t -*-
|
;;; mu4e-bookmarks.el -- part of mu4e -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
|
;; Copyright (C) 2011-2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -24,6 +24,8 @@
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
(require 'mu4e-helpers)
|
(require 'mu4e-helpers)
|
||||||
|
(require 'mu4e-server)
|
||||||
|
(require 'mu4e-modeline)
|
||||||
|
|
||||||
|
|
||||||
;;; Configuration
|
;;; Configuration
|
||||||
|
@ -50,19 +52,24 @@
|
||||||
|
|
||||||
Each of the list elements is a plist with at least:
|
Each of the list elements is a plist with at least:
|
||||||
`:name' - the name of the query
|
`:name' - the name of the query
|
||||||
`:query' - the query expression or function
|
`:query' - the query expression string (not a function)
|
||||||
`:key' - the shortcut key.
|
`:key' - the shortcut key (single character)
|
||||||
|
|
||||||
Note that the :query parameter can be a function/lambda.
|
Note that the :query parameter can be a function/lambda.
|
||||||
|
|
||||||
Optionally, you can add the following: `:hide' - if t, the
|
Optionally, you can add the following:
|
||||||
bookmark is hidden from the main-view and speedbar.
|
|
||||||
`:hide-unread' - do not show the counts of unread/total number of
|
|
||||||
matches for the query in the main-view. This can be useful if a
|
|
||||||
bookmark uses a very slow query.
|
|
||||||
|
|
||||||
`:hide-unread' is implied from `:hide'. Furthermore, it is
|
- `:favorite' - if t, monitor the results of this query, and make
|
||||||
implied when `:query' is a function.
|
it eligible for showing its status in the emacs modeline. At mose
|
||||||
|
one bookmark should have this set to t (otherwise the _first_
|
||||||
|
bookmark is the implicit favorite)
|
||||||
|
- `:hide' - if t, the bookmark is hidden from the main-view and
|
||||||
|
speedbar.
|
||||||
|
- `:hide-unread' - do not show the counts of
|
||||||
|
unread/total number of matches for the query in the main-view.
|
||||||
|
This can be useful if a bookmark uses a very slow query.
|
||||||
|
|
||||||
|
`:hide-unread' is implied from `:hide'.
|
||||||
|
|
||||||
Note: for efficiency, queries used to determine the unread/all
|
Note: for efficiency, queries used to determine the unread/all
|
||||||
counts do not discard duplicate or unreadable messages. Thus, the
|
counts do not discard duplicate or unreadable messages. Thus, the
|
||||||
|
@ -72,7 +79,7 @@ query."
|
||||||
:group 'mu4e-bookmarks)
|
:group 'mu4e-bookmarks)
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-ask-bookmark (prompt)
|
(defun mu4e-ask-bookmark (prompt)
|
||||||
"Ask the user for a bookmark (using PROMPT) as defined in
|
"Ask the user for a bookmark (using PROMPT) as defined in
|
||||||
`mu4e-bookmarks', then return the corresponding query."
|
`mu4e-bookmarks', then return the corresponding query."
|
||||||
(unless (mu4e-bookmarks) (mu4e-error "No bookmarks defined"))
|
(unless (mu4e-bookmarks) (mu4e-error "No bookmarks defined"))
|
||||||
|
@ -88,23 +95,32 @@ query."
|
||||||
(kar (read-char (concat prompt bmarks))))
|
(kar (read-char (concat prompt bmarks))))
|
||||||
(mu4e-get-bookmark-query kar)))
|
(mu4e-get-bookmark-query kar)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e--bookmark-query (bm)
|
||||||
|
"Get query string for some bookmark."
|
||||||
|
(when bm
|
||||||
|
(let* ((query (or (plist-get bm :query)
|
||||||
|
(mu4e-warn "No query in %S" bm)))
|
||||||
|
;; queries being functions is deprecated.
|
||||||
|
(query (if (functionp query) (funcall query) query)))
|
||||||
|
;; earlier, we allowed for the queries being fucntions
|
||||||
|
(unless (stringp query)
|
||||||
|
(mu4e-warn "Could not get query string from %s" bm))
|
||||||
|
;; apparently, non-UTF8 queries exist, i.e.,
|
||||||
|
;; with maild dir names.
|
||||||
|
(decode-coding-string query 'utf-8 t))))
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-get-bookmark-query (kar)
|
(defun mu4e-get-bookmark-query (kar)
|
||||||
"Get the corresponding bookmarked query for shortcut KAR.
|
"Get the corresponding bookmarked query for shortcut KAR.
|
||||||
Raise an error if none is found."
|
Raise an error if none is found."
|
||||||
(let* ((chosen-bm
|
(let ((chosen-bm
|
||||||
(or (seq-find
|
(or (seq-find
|
||||||
(lambda (bm)
|
(lambda (bm)
|
||||||
(= kar (plist-get bm :key)))
|
(= kar (plist-get bm :key)))
|
||||||
(mu4e-bookmarks))
|
(mu4e-bookmarks))
|
||||||
(mu4e-warn "Unknown shortcut '%c'" kar)))
|
(mu4e-warn "Unknown shortcut '%c'" kar))))
|
||||||
(expr (plist-get chosen-bm :query))
|
(mu4e--bookmark-query chosen-bm)))
|
||||||
(expr (if (not (functionp expr)) expr
|
|
||||||
(funcall expr)))
|
|
||||||
(query (eval expr)))
|
|
||||||
(if (stringp query)
|
|
||||||
query
|
|
||||||
(mu4e-warn "Expression must evaluate to query string ('%S')" expr))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun mu4e-bookmark-define (query name key)
|
(defun mu4e-bookmark-define (query name key)
|
||||||
"Define a bookmark for QUERY with NAME and shortcut KEY.
|
"Define a bookmark for QUERY with NAME and shortcut KEY.
|
||||||
|
@ -116,8 +132,8 @@ with KEY."
|
||||||
(= (plist-get bm :key) key))
|
(= (plist-get bm :key) key))
|
||||||
(mu4e-bookmarks)))
|
(mu4e-bookmarks)))
|
||||||
(cl-pushnew `(:name ,name
|
(cl-pushnew `(:name ,name
|
||||||
:query ,query
|
:query ,query
|
||||||
:key ,key)
|
:key ,key)
|
||||||
mu4e-bookmarks :test 'equal))
|
mu4e-bookmarks :test 'equal))
|
||||||
|
|
||||||
(defun mu4e-bookmarks ()
|
(defun mu4e-bookmarks ()
|
||||||
|
@ -125,9 +141,159 @@ with KEY."
|
||||||
Convert from the old format if needed."
|
Convert from the old format if needed."
|
||||||
(seq-map (lambda (item)
|
(seq-map (lambda (item)
|
||||||
(if (and (listp item) (= (length item) 3))
|
(if (and (listp item) (= (length item) 3))
|
||||||
`(:name ,(nth 1 item) :query ,(nth 0 item)
|
`(:name ,(nth 1 item) :query ,(nth 0 item)
|
||||||
:key ,(nth 2 item))
|
:key ,(nth 2 item))
|
||||||
item)) mu4e-bookmarks))
|
item))
|
||||||
|
mu4e-bookmarks))
|
||||||
|
|
||||||
|
(defun mu4e-favorite-bookmark ()
|
||||||
|
"Find the favorite bookmark.
|
||||||
|
The favorit bookmark is the first one that has a non-nil
|
||||||
|
':favorite' property, or the first if there is none."
|
||||||
|
(let ((bookmarks (mu4e-bookmarks)))
|
||||||
|
(or (seq-find (lambda (bm) (plist-get bm :favorite))
|
||||||
|
(mu4e-bookmarks))
|
||||||
|
(car-safe bookmarks))))
|
||||||
|
|
||||||
|
;;; Last & baseline query results for bookmarks.
|
||||||
|
|
||||||
|
(defvar mu4e--baseline nil
|
||||||
|
"Some previous version of the query-results.
|
||||||
|
This is used as the baseline to track updates by comparing it to
|
||||||
|
the latest query-results.")
|
||||||
|
(defvar mu4e--baseline-tstamp nil
|
||||||
|
"Timestamp for when the query-results baseline was updated.")
|
||||||
|
|
||||||
|
(defun mu4e--reset-baseline ()
|
||||||
|
(setq mu4e--baseline (mu4e-server-query-results)
|
||||||
|
mu4e--baseline-tstamp (current-time))
|
||||||
|
(mu4e-last-query-results 'force)) ; for side-effects
|
||||||
|
|
||||||
|
|
||||||
|
(defvar mu4e--last-query-results-cached nil)
|
||||||
|
(defun mu4e-last-query-results(&optional force)
|
||||||
|
"Get the results (counts) of the latest queries.
|
||||||
|
|
||||||
|
Either read form the cache or update them when oudated or FORCE
|
||||||
|
is non-nil.
|
||||||
|
|
||||||
|
The queries are the bookmark / maildir queries that are used to
|
||||||
|
populate the read/unread counts in the main view and modeline.
|
||||||
|
They are refreshed when calling `(mu4e)', i.e., when going to the
|
||||||
|
main view.
|
||||||
|
|
||||||
|
When available, the baseline results are added as well.
|
||||||
|
|
||||||
|
The results are a list of elements of the form
|
||||||
|
(:query \"query string\"
|
||||||
|
:count <total number matching count>
|
||||||
|
:unread <number of unread messages in count>
|
||||||
|
[:favorite t]
|
||||||
|
:baseline ( ;; baseline results
|
||||||
|
:count <total number matching count>
|
||||||
|
:unread <number of unread messages in count>)) The
|
||||||
|
baseline part is optional (see `mu4e-reset-query-results') for
|
||||||
|
more details).
|
||||||
|
|
||||||
|
Uses a cached string unless its nil or FORCE is non-nil."
|
||||||
|
(if (and mu4e--last-query-results-cached (not force))
|
||||||
|
mu4e--last-query-results-cached ;; use cache
|
||||||
|
;; otherwise, recalculate.
|
||||||
|
(let* ((favorite (mu4e-favorite-bookmark))
|
||||||
|
(favorite-query
|
||||||
|
(and favorite (mu4e--bookmark-query favorite))))
|
||||||
|
(setq mu4e--last-query-results-cached ;; walk over the remembered queries
|
||||||
|
;; and augment them with the baseline data and ':favorite' flag, if
|
||||||
|
;; any.
|
||||||
|
(seq-map
|
||||||
|
(lambda (qres)
|
||||||
|
;; note: queries can be _functions_ too; use their
|
||||||
|
;; string value.
|
||||||
|
(let* ((query (mu4e--bookmark-query qres))
|
||||||
|
(bres (seq-find ;; find the corresponding baseline entry
|
||||||
|
(lambda (bq)
|
||||||
|
(string= query (mu4e--bookmark-query bq)))
|
||||||
|
mu4e--baseline)))
|
||||||
|
(when (string= query (or favorite-query ""))
|
||||||
|
(plist-put qres :favorite t))
|
||||||
|
(when bres
|
||||||
|
(plist-put qres :baseline
|
||||||
|
`(:count ,(plist-get bres :count)
|
||||||
|
:unread ,(plist-get bres :unread))))
|
||||||
|
qres)) (mu4e-server-query-results))))))
|
||||||
|
|
||||||
|
(defun mu4e-last-query-result (query)
|
||||||
|
"Get the last result for some QUERY or nil if not found.
|
||||||
|
See `mu4e-last-query-results' for the format."
|
||||||
|
(seq-find
|
||||||
|
(lambda (elm) (string= query (mu4e--bookmark-query elm)))
|
||||||
|
(mu4e-last-query-results)))
|
||||||
|
|
||||||
|
;; for Zero-Inbox afficionados
|
||||||
|
(defvar mu4e-modeline-all-clear '("C:" . "🌀")
|
||||||
|
"No more messages at all for this query.")
|
||||||
|
(defvar mu4e-modeline-all-read '("R:" . "✅")
|
||||||
|
"No unread messages left.")
|
||||||
|
(defvar mu4e-modeline-unread-items '("U:" . "📫")
|
||||||
|
"There are some unread items.")
|
||||||
|
(defvar mu4e-modeline-new-items '("N:" . "🔥")
|
||||||
|
"There are some new items after the baseline.
|
||||||
|
I.e., very new messages.")
|
||||||
|
|
||||||
|
(declare-function mu4e-search-bookmark "mu4e-search")
|
||||||
|
(defun mu4e-jump-to-favorite ()
|
||||||
|
"Jump to to the favorite bookmark, if any."
|
||||||
|
(interactive)
|
||||||
|
(when-let ((fav (mu4e--bookmark-query (mu4e-favorite-bookmark))))
|
||||||
|
(mu4e-search-bookmark fav)))
|
||||||
|
|
||||||
|
(defvar mu4e--bookmarks-modeline-cached nil)
|
||||||
|
|
||||||
|
(defun mu4e--bookmarks-modeline-item ()
|
||||||
|
"Modeline item showing message counts for the favorite bookmark.
|
||||||
|
|
||||||
|
This uses the one special ':favorite' bookmark, and if there is
|
||||||
|
one, creates a propertized string for display in the modeline."
|
||||||
|
(or mu4e--bookmarks-modeline-cached
|
||||||
|
(setq mu4e--bookmarks-modeline-cached
|
||||||
|
(when-let ((fav ;; any results for the favorite bookmark item?
|
||||||
|
(seq-find (lambda (bm) (plist-get bm :favorite))
|
||||||
|
(mu4e-last-query-results))))
|
||||||
|
(let* ((unread (plist-get fav :unread))
|
||||||
|
(count (plist-get fav :count))
|
||||||
|
(baseline (plist-get fav :baseline))
|
||||||
|
(baseline-unread
|
||||||
|
(or (when baseline (plist-get baseline :unread)) unread))
|
||||||
|
(delta (- unread baseline-unread)))
|
||||||
|
(propertize
|
||||||
|
(format "%s%s%s/%s "
|
||||||
|
(funcall (if mu4e-use-fancy-chars 'cdr 'car)
|
||||||
|
(cond
|
||||||
|
((> delta 0) mu4e-modeline-new-items)
|
||||||
|
((> unread 0) mu4e-modeline-unread-items)
|
||||||
|
((> count 0) mu4e-modeline-all-read)
|
||||||
|
(t mu4e-modeline-all-clear)))
|
||||||
|
(propertize (number-to-string unread) 'face 'mu4e-header-key-face)
|
||||||
|
(if (<= delta 0) ""
|
||||||
|
(propertize (format "(%+d)" delta)
|
||||||
|
'face 'mu4e-unread-face))
|
||||||
|
(number-to-string count))
|
||||||
|
'help-echo (format "mu4e query: '%s'" (mu4e--bookmark-query fav))
|
||||||
|
'mouse-face 'mode-line-highlight
|
||||||
|
'keymap '(mode-line keymap
|
||||||
|
(mouse-1 . mu4e-jump-to-favorite)
|
||||||
|
(mouse-2 . mu4e-jump-to-favorite)
|
||||||
|
(mouse-3 . mu4e-jump-to-favorite))))))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e--modeline-update()
|
||||||
|
"Update the modeline and redisplay if mu4e-modeline-mode is
|
||||||
|
active."
|
||||||
|
(when mu4e-modeline-mode
|
||||||
|
(setq mu4e--bookmarks-modeline-cached nil) ;; force recalculation
|
||||||
|
(force-mode-line-update)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(provide 'mu4e-bookmarks)
|
(provide 'mu4e-bookmarks)
|
||||||
;;; mu4e-bookmarks.el ends here
|
;;; mu4e-bookmarks.el ends here
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
;;; mu4e-context.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (C) 2015-2022 Dirk-Jan C. Binnema
|
;; Copyright (C) 2015-2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'mu4e-helpers)
|
(require 'mu4e-helpers)
|
||||||
|
(require 'mu4e-modeline)
|
||||||
|
|
||||||
|
|
||||||
;;; Configuration
|
;;; Configuration
|
||||||
|
@ -82,14 +83,6 @@ none."
|
||||||
(if ctx (mu4e-context-name ctx) "<none>")))
|
(if ctx (mu4e-context-name ctx) "<none>")))
|
||||||
ctx))
|
ctx))
|
||||||
|
|
||||||
(defun mu4e-context-label ()
|
|
||||||
"Propertized string with the current context name.
|
|
||||||
An empty string \"\" if there is none."
|
|
||||||
(if (mu4e-context-current)
|
|
||||||
(concat "[" (propertize (mu4e-quote-for-modeline
|
|
||||||
(mu4e-context-name (mu4e-context-current)))
|
|
||||||
'face 'mu4e-context-face) "]") ""))
|
|
||||||
|
|
||||||
(cl-defstruct mu4e-context
|
(cl-defstruct mu4e-context
|
||||||
"A mu4e context object with the following members:
|
"A mu4e context object with the following members:
|
||||||
- `name': the name of the context, eg. \"Work\" or \"Private\".
|
- `name': the name of the context, eg. \"Work\" or \"Private\".
|
||||||
|
@ -153,8 +146,7 @@ non-nil."
|
||||||
(setq mu4e--context-current context)
|
(setq mu4e--context-current context)
|
||||||
|
|
||||||
(run-hooks 'mu4e-context-changed-hook)
|
(run-hooks 'mu4e-context-changed-hook)
|
||||||
(mu4e-message "Switched context to %s" (mu4e-context-name context))
|
(mu4e-message "Switched context to %s" (mu4e-context-name context)))
|
||||||
(force-mode-line-update))
|
|
||||||
context))
|
context))
|
||||||
|
|
||||||
(defun mu4e--context-autoswitch (&optional msg policy)
|
(defun mu4e--context-autoswitch (&optional msg policy)
|
||||||
|
@ -204,13 +196,6 @@ as it is."
|
||||||
(mu4e--context-ask-user "Select context: ")))
|
(mu4e--context-ask-user "Select context: ")))
|
||||||
(_ nil))))))
|
(_ nil))))))
|
||||||
|
|
||||||
(defun mu4e-context-in-modeline ()
|
|
||||||
"Display the mu4e-context (if any) in a (buffer-specific)
|
|
||||||
global-mode-line."
|
|
||||||
(add-to-list
|
|
||||||
(make-local-variable 'global-mode-string)
|
|
||||||
'(:eval (mu4e-context-label))))
|
|
||||||
|
|
||||||
(defmacro with-mu4e-context-vars (context &rest body)
|
(defmacro with-mu4e-context-vars (context &rest body)
|
||||||
"Evaluate BODY, with variables let-bound for CONTEXT (if any).
|
"Evaluate BODY, with variables let-bound for CONTEXT (if any).
|
||||||
`funcall'."
|
`funcall'."
|
||||||
|
@ -221,6 +206,14 @@ global-mode-line."
|
||||||
(mapcar (lambda(cell) (cdr cell)) vars)
|
(mapcar (lambda(cell) (cdr cell)) vars)
|
||||||
(eval ,@body))))
|
(eval ,@body))))
|
||||||
|
|
||||||
|
(defun mu4e--context-modeline-item ()
|
||||||
|
"Propertized string with the current context name.
|
||||||
|
An empty string \"\" if there is none."
|
||||||
|
(if (mu4e-context-current)
|
||||||
|
(concat "[" (propertize (mu4e-quote-for-modeline
|
||||||
|
(mu4e-context-name (mu4e-context-current)))
|
||||||
|
'face 'mu4e-context-face) "] " ) ""))
|
||||||
|
|
||||||
(define-minor-mode mu4e-context-minor-mode
|
(define-minor-mode mu4e-context-minor-mode
|
||||||
"Mode for switching the mu4e context."
|
"Mode for switching the mu4e context."
|
||||||
:global nil
|
:global nil
|
||||||
|
@ -231,7 +224,7 @@ global-mode-line."
|
||||||
(define-key map (kbd ";") #'mu4e-context-switch)
|
(define-key map (kbd ";") #'mu4e-context-switch)
|
||||||
map)
|
map)
|
||||||
:lighter ""
|
:lighter ""
|
||||||
(mu4e-context-in-modeline))
|
(mu4e--modeline-register #'mu4e--context-modeline-item))
|
||||||
|
|
||||||
;;;
|
;;;
|
||||||
(provide 'mu4e-context)
|
(provide 'mu4e-context)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e-headers.el -- part of mu4e -*- lexical-binding: t; coding:utf-8 -*-
|
;;; mu4e-headers.el -- part of mu4e -*- lexical-binding: t; coding:utf-8 -*-
|
||||||
|
|
||||||
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
|
;; Copyright (C) 2011-2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -812,7 +812,7 @@ true, do *not* update the query history stack."
|
||||||
(mu4e--search-push-query mu4e--search-last-query 'past)))
|
(mu4e--search-push-query mu4e--search-last-query 'past)))
|
||||||
(setq mu4e--search-last-query rewritten-expr)
|
(setq mu4e--search-last-query rewritten-expr)
|
||||||
(setq list-buffers-directory rewritten-expr)
|
(setq list-buffers-directory rewritten-expr)
|
||||||
(mu4e~headers-update-mode-line))
|
(mu4e--modeline-update))
|
||||||
|
|
||||||
;; when the buffer is already visible, select it; otherwise,
|
;; when the buffer is already visible, select it; otherwise,
|
||||||
;; switch to it.
|
;; switch to it.
|
||||||
|
@ -1178,7 +1178,10 @@ The following specs are supported:
|
||||||
(mu4e-context-minor-mode)
|
(mu4e-context-minor-mode)
|
||||||
(mu4e-update-minor-mode)
|
(mu4e-update-minor-mode)
|
||||||
(mu4e-search-minor-mode)
|
(mu4e-search-minor-mode)
|
||||||
(hl-line-mode 1))
|
(hl-line-mode 1)
|
||||||
|
|
||||||
|
(mu4e--modeline-register #'mu4e~headers-modeline-item)
|
||||||
|
(mu4e--modeline-update))
|
||||||
|
|
||||||
;;; Highlighting
|
;;; Highlighting
|
||||||
|
|
||||||
|
@ -1244,7 +1247,7 @@ message plist, or nil if not found."
|
||||||
|
|
||||||
;;; Queries & searching
|
;;; Queries & searching
|
||||||
(defvar mu4e~headers-mode-line-label "")
|
(defvar mu4e~headers-mode-line-label "")
|
||||||
(defun mu4e~headers-update-mode-line ()
|
(defun mu4e~headers-modeline-item ()
|
||||||
"Update mode-line settings."
|
"Update mode-line settings."
|
||||||
(let* ((flagstr
|
(let* ((flagstr
|
||||||
(mapconcat
|
(mapconcat
|
||||||
|
@ -1258,30 +1261,8 @@ message plist, or nil if not found."
|
||||||
(,mu4e-search-skip-duplicates
|
(,mu4e-search-skip-duplicates
|
||||||
. ,mu4e-headers-skip-duplicates-label)
|
. ,mu4e-headers-skip-duplicates-label)
|
||||||
(,mu4e-search-hide-enabled . ,mu4e-headers-hide-label))
|
(,mu4e-search-hide-enabled . ,mu4e-headers-hide-label))
|
||||||
""))
|
"")))
|
||||||
(name "mu4e-headers"))
|
(concat flagstr " " mu4e--search-last-query)))
|
||||||
|
|
||||||
(setq mode-name name)
|
|
||||||
(setq mu4e~headers-mode-line-label
|
|
||||||
(concat flagstr " " mu4e--search-last-query))
|
|
||||||
|
|
||||||
(make-local-variable 'global-mode-string)
|
|
||||||
|
|
||||||
(add-to-list 'global-mode-string
|
|
||||||
`(:eval
|
|
||||||
(concat
|
|
||||||
(propertize
|
|
||||||
(mu4e-quote-for-modeline ,mu4e~headers-mode-line-label)
|
|
||||||
'face 'mu4e-modeline-face)
|
|
||||||
" "
|
|
||||||
(if (and mu4e-display-update-status-in-modeline
|
|
||||||
(buffer-live-p mu4e--update-buffer)
|
|
||||||
(process-live-p (get-buffer-process
|
|
||||||
mu4e--update-buffer)))
|
|
||||||
(propertize " (updating)" 'face 'mu4e-modeline-face)
|
|
||||||
""))))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Search-based marking
|
;;; Search-based marking
|
||||||
|
|
||||||
|
|
|
@ -65,11 +65,6 @@ You can customize the exact fancy characters used with
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'mu4e)
|
:group 'mu4e)
|
||||||
|
|
||||||
(defcustom mu4e-display-update-status-in-modeline nil
|
|
||||||
"Non-nil value will display the update status in the modeline."
|
|
||||||
:group 'mu4e
|
|
||||||
:type 'boolean)
|
|
||||||
|
|
||||||
;; maybe move the next ones... but they're convenient
|
;; maybe move the next ones... but they're convenient
|
||||||
;; here because they're needed in multiple buffers.
|
;; here because they're needed in multiple buffers.
|
||||||
|
|
||||||
|
@ -234,101 +229,6 @@ Function returns the cdr of the list element."
|
||||||
(cdr chosen)
|
(cdr chosen)
|
||||||
(mu4e-warn "Unknown shortcut '%c'" response))))
|
(mu4e-warn "Unknown shortcut '%c'" response))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;; Server properties
|
|
||||||
(defvar mu4e--server-props nil
|
|
||||||
"Metadata we receive from the mu4e server.
|
|
||||||
Use `mu4e--update-server-props' to update.")
|
|
||||||
|
|
||||||
;; XXX: we could make these session-persistent
|
|
||||||
|
|
||||||
(defvar mu4e--baseline-query-results nil
|
|
||||||
"Some previous version of the query-results.
|
|
||||||
This is used as the baseline to track updates by comparing it to
|
|
||||||
the latest query-results.")
|
|
||||||
|
|
||||||
(defvar mu4e--baseline-query-results-tstamp nil
|
|
||||||
"Timestamp for when the query-results baseline was updated.")
|
|
||||||
|
|
||||||
(defun mu4e-reset-baseline-query-results ()
|
|
||||||
"Reset the baseline query-results."
|
|
||||||
(interactive)
|
|
||||||
(setq mu4e--baseline-query-results nil
|
|
||||||
mu4e--baseline-query-results-tstamp nil))
|
|
||||||
|
|
||||||
(defun mu4e--update-server-props (props)
|
|
||||||
"Update server props and possibly the baseline query results."
|
|
||||||
(setq mu4e--server-props props)
|
|
||||||
(when-let ((queries (plist-get mu4e--server-props :queries)))
|
|
||||||
(unless mu4e--baseline-query-results
|
|
||||||
(setq mu4e--baseline-query-results queries
|
|
||||||
mu4e--baseline-query-results-tstamp (current-time)))))
|
|
||||||
|
|
||||||
(defun mu4e-server-properties ()
|
|
||||||
"Get the server metadata plist."
|
|
||||||
mu4e--server-props)
|
|
||||||
|
|
||||||
(defun mu4e-root-maildir()
|
|
||||||
"Get the root maildir."
|
|
||||||
(or (and mu4e--server-props
|
|
||||||
(plist-get mu4e--server-props :root-maildir))
|
|
||||||
(mu4e-error "Root maildir unknown; did you start mu4e?")))
|
|
||||||
|
|
||||||
(defun mu4e-database-path()
|
|
||||||
"Get the root maildir."
|
|
||||||
(or (and mu4e--server-props
|
|
||||||
(plist-get mu4e--server-props :database-path))
|
|
||||||
(mu4e-error "Root maildir unknown; did you start mu4e?")))
|
|
||||||
|
|
||||||
(defun mu4e-server-version()
|
|
||||||
"Get the root maildir."
|
|
||||||
(or (and mu4e--server-props
|
|
||||||
(plist-get mu4e--server-props :version))
|
|
||||||
(mu4e-error "Version unknown; did you start mu4e?")))
|
|
||||||
|
|
||||||
(defun mu4e-last-query-results ()
|
|
||||||
"Get the results (counts) of the last cached queries.
|
|
||||||
|
|
||||||
The cached queries are the bookmark / maildir queries that are
|
|
||||||
used to populated the read/unread counts in the main view. They
|
|
||||||
are refreshed when calling `(mu4e)', i.e., when going to the main
|
|
||||||
view.
|
|
||||||
|
|
||||||
When available, the based-line results are added as well.
|
|
||||||
|
|
||||||
The results are a list of elements of the form
|
|
||||||
(:query \"query string\"
|
|
||||||
:count <total number matching count>
|
|
||||||
:unread <number of unread messages in count>
|
|
||||||
:baseline ( ;; baseline results
|
|
||||||
:count <total number matching count>
|
|
||||||
:unread <number of unread messages in count>)) The
|
|
||||||
baseline part is optional (see
|
|
||||||
`mu4e-reset-baseline-query-results') for more details)."
|
|
||||||
(unless mu4e--baseline-query-results
|
|
||||||
(mu4e-reset-baseline-query-results))
|
|
||||||
(seq-map (lambda (qres)
|
|
||||||
(let* ((query (plist-get qres :query))
|
|
||||||
(bres (seq-find ;; find the corresponding baseline entry
|
|
||||||
(lambda (bq) (string= query (plist-get bq :query)))
|
|
||||||
mu4e--baseline-query-results)))
|
|
||||||
(when bres
|
|
||||||
(plist-put qres :baseline
|
|
||||||
`(:count ,(plist-get bres :count)
|
|
||||||
:unread ,(plist-get bres :unread))))
|
|
||||||
qres))
|
|
||||||
(plist-get mu4e--server-props :queries)))
|
|
||||||
|
|
||||||
(defun mu4e-last-query-result (query)
|
|
||||||
"Get the last result for some QUERY or nil if not found.
|
|
||||||
See `mu4e-last-query-results' for the format."
|
|
||||||
(seq-find
|
|
||||||
(lambda (elm) ;;; XXX do we need the decoding?
|
|
||||||
(let ((qstring (decode-coding-string (plist-get elm :query) 'utf-8 t)))
|
|
||||||
(string= query qstring)))
|
|
||||||
(mu4e-last-query-results)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Logging / debugging
|
;;; Logging / debugging
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e-main.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
;;; mu4e-main.el -- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
|
;; Copyright (C) 2011-2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -24,9 +24,9 @@
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'smtpmail) ;; the queueing stuff (silence elint)
|
(require 'smtpmail)
|
||||||
(require 'mu4e-helpers) ;; utility functions
|
(require 'mu4e-helpers)
|
||||||
(require 'mu4e-context) ;; the context
|
(require 'mu4e-context)
|
||||||
(require 'mu4e-bookmarks)
|
(require 'mu4e-bookmarks)
|
||||||
(require 'mu4e-folders)
|
(require 'mu4e-folders)
|
||||||
(require 'mu4e-update)
|
(require 'mu4e-update)
|
||||||
|
@ -58,18 +58,6 @@ the personal addresses."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'mu4e-main)
|
:group 'mu4e-main)
|
||||||
|
|
||||||
(defcustom mu4e-main-hide-baseline-delta nil
|
|
||||||
"Whether to hide the baseline-from-delta from the message counts
|
|
||||||
for bookmarks and maildirs."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'mu4e-main)
|
|
||||||
|
|
||||||
(defcustom mu4e-main-auto-reset-baseline t
|
|
||||||
"Automatically reset the baseline when explicitly (interactively)
|
|
||||||
swiching to the main-view (using the `mu4e' command."
|
|
||||||
:type 'boolean
|
|
||||||
:group 'mu4e-main)
|
|
||||||
|
|
||||||
|
|
||||||
;;; Mode
|
;;; Mode
|
||||||
(define-derived-mode mu4e-org-mode org-mode "mu4e:org"
|
(define-derived-mode mu4e-org-mode org-mode "mu4e:org"
|
||||||
|
@ -99,11 +87,11 @@ swiching to the main-view (using the `mu4e' command."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mu4e-info (concat mu4e-doc-dir "/NEWS.org")))
|
(mu4e-info (concat mu4e-doc-dir "/NEWS.org")))
|
||||||
|
|
||||||
(defun mu4e--main-reset-baseline-query-results ()
|
(defun mu4e--main-reset-baseline()
|
||||||
"Main-view version of `mu4e-reset-baseline-query-results'.
|
"Main-view version of `mu4e-reset-query-results'.
|
||||||
This version handles updating the current screen as well."
|
This version handles updating the current screen as well."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mu4e-reset-baseline-query-results)
|
(mu4e--reset-baseline)
|
||||||
(revert-buffer))
|
(revert-buffer))
|
||||||
|
|
||||||
(defvar mu4e-main-mode-map
|
(defvar mu4e-main-mode-map
|
||||||
|
@ -117,7 +105,7 @@ This version handles updating the current screen as well."
|
||||||
(define-key map "f" #'smtpmail-send-queued-mail)
|
(define-key map "f" #'smtpmail-send-queued-mail)
|
||||||
;;
|
;;
|
||||||
(define-key map "U" #'mu4e-update-mail-and-index)
|
(define-key map "U" #'mu4e-update-mail-and-index)
|
||||||
(define-key map "R" #'mu4e--main-reset-baseline-query-results)
|
(define-key map "R" #'mu4e--main-reset-baseline)
|
||||||
(define-key map (kbd "C-S-u") #'mu4e-update-mail-and-index)
|
(define-key map (kbd "C-S-u") #'mu4e-update-mail-and-index)
|
||||||
;; for terminal users
|
;; for terminal users
|
||||||
(define-key map (kbd "C-c C-u") #'mu4e-update-mail-and-index)
|
(define-key map (kbd "C-c C-u") #'mu4e-update-mail-and-index)
|
||||||
|
@ -142,15 +130,16 @@ This version handles updating the current screen as well."
|
||||||
(mu4e-context-minor-mode)
|
(mu4e-context-minor-mode)
|
||||||
(mu4e-search-minor-mode)
|
(mu4e-search-minor-mode)
|
||||||
(mu4e-update-minor-mode)
|
(mu4e-update-minor-mode)
|
||||||
(set (make-local-variable 'revert-buffer-function) #'mu4e--main-view-real)
|
(setq-local revert-buffer-function
|
||||||
(add-hook 'mu4e-index-updated-hook #'mu4e--main-update-after-index))
|
(lambda (_ignore-auto _noconfirm)
|
||||||
|
(mu4e--main-view 'refresh))))
|
||||||
|
|
||||||
(defun mu4e--main-action-str (str &optional func-or-shortcut)
|
(defun mu4e--main-action-str (str &optional func-or-shortcut)
|
||||||
"Highlight the first occurrence of [.] in STR.
|
"Highlight the first occurrence of [.] in STR.
|
||||||
If FUNC-OR-SHORTCUT is non-nil and if it is a function, call it
|
If FUNC-OR-SHORTCUT is non-nil and if it is a function, call it
|
||||||
when STR is clicked (using RET or mouse-2); if FUNC-OR-SHORTCUT is
|
when STR is clicked (using RET or mouse-2); if FUNC-OR-SHORTCUT is
|
||||||
a string, execute the corresponding keyboard action when it is
|
a string, execute the corresponding keyboard action when it is
|
||||||
clicked."
|
clicked. If HIGHLIGHT is non-nil, hightlight the name."
|
||||||
(let ((newstr
|
(let ((newstr
|
||||||
(replace-regexp-in-string
|
(replace-regexp-in-string
|
||||||
"\\[\\(..?\\)\\]"
|
"\\[\\(..?\\)\\]"
|
||||||
|
@ -175,8 +164,7 @@ clicked."
|
||||||
(if (stringp func-or-shortcut)
|
(if (stringp func-or-shortcut)
|
||||||
(length newstr)
|
(length newstr)
|
||||||
(- (length newstr) 1))
|
(- (length newstr) 1))
|
||||||
'mouse-face 'highlight newstr)
|
'mouse-face 'highlight newstr) newstr))
|
||||||
newstr))
|
|
||||||
|
|
||||||
(defun mu4e--longest-of-maildirs-and-bookmarks ()
|
(defun mu4e--longest-of-maildirs-and-bookmarks ()
|
||||||
"Return the length of longest name of bookmarks and maildirs."
|
"Return the length of longest name of bookmarks and maildirs."
|
||||||
|
@ -194,7 +182,11 @@ clicked."
|
||||||
(used for alignment)."
|
(used for alignment)."
|
||||||
(concat
|
(concat
|
||||||
(mu4e--main-action-str
|
(mu4e--main-action-str
|
||||||
(concat "\t* [" fullkey "] " name) fullkey)
|
(format "\t* [%s] %s" fullkey
|
||||||
|
(propertize name 'face
|
||||||
|
(if (and qcounts (plist-get qcounts :favorite))
|
||||||
|
'mu4e-header-key-face nil)))
|
||||||
|
fullkey)
|
||||||
;; append all/unread numbers, if available.
|
;; append all/unread numbers, if available.
|
||||||
(if qcounts
|
(if qcounts
|
||||||
(let* ((unread (plist-get qcounts :unread))
|
(let* ((unread (plist-get qcounts :unread))
|
||||||
|
@ -203,32 +195,30 @@ clicked."
|
||||||
(baseline-unread
|
(baseline-unread
|
||||||
(or (when baseline (plist-get baseline :unread)) unread))
|
(or (when baseline (plist-get baseline :unread)) unread))
|
||||||
(delta (- unread baseline-unread)))
|
(delta (- unread baseline-unread)))
|
||||||
(format"%s (%s%s/%s)"
|
(format "%s (%s%s/%s)"
|
||||||
(make-string (- max-length (string-width name)) ? )
|
(make-string (- max-length (string-width name)) ? )
|
||||||
(propertize
|
(propertize
|
||||||
(number-to-string unread) 'face 'mu4e-header-key-face
|
(number-to-string unread) 'face 'mu4e-header-key-face
|
||||||
'help-echo "Number of unread messages")
|
'help-echo "Number of unread messages")
|
||||||
(if (not mu4e-main-hide-baseline-delta)
|
(if (> delta 0)
|
||||||
(propertize (format "/%+d" delta) 'face
|
(propertize (format "(%+d)" delta) 'face
|
||||||
(if (> delta 0) 'mu4e-unread-face 'default)
|
'mu4e-unread-face) "")
|
||||||
'help-echo "Unread messsages baseline-delta")
|
|
||||||
"")
|
|
||||||
(propertize (number-to-string count)
|
(propertize (number-to-string count)
|
||||||
'help-echo "Total number of messages")))
|
'help-echo "Total number of messages")))
|
||||||
"") "\n"))
|
"") "\n"))
|
||||||
|
|
||||||
(defun mu4e--main-items (shortcut items max-length)
|
(defun mu4e--main-items (shortcut items max-length)
|
||||||
"Display the entries for the bookmark/maildir menu.
|
"Display the entries for the bookmark/maildir menu
|
||||||
- SHORTCUT is a single character which is the first
|
- SHORTCUT is a single character which is the first
|
||||||
character of the keyboard shortcut
|
character of the keyboard shortcut
|
||||||
- ITEMS is a list of items, for format see `(mu4e-bookmarks)'.
|
- ITEMS is a list of items, for format see `(mu4e-bookmarks)'
|
||||||
- MAX-LENGTH is the maximum length for an item name
|
- MAX-LENGTH is the maximum length for an item name
|
||||||
(used for alignment)."
|
(used for alignment)."
|
||||||
(cl-loop for item in items
|
(cl-loop for item in items
|
||||||
for fullkey = (format "%c%c" shortcut (plist-get item :key))
|
for fullkey = (format "%c%c" shortcut (plist-get item :key))
|
||||||
for name = (plist-get item :name)
|
for name = (plist-get item :name)
|
||||||
for query = (funcall (or mu4e-query-rewrite-function #'identity)
|
for query = (funcall (or mu4e-query-rewrite-function #'identity)
|
||||||
(plist-get item :query))
|
(mu4e--bookmark-query item))
|
||||||
for qcounts = (mu4e-last-query-result query)
|
for qcounts = (mu4e-last-query-result query)
|
||||||
for unread = (and qcounts (plist-get (car qcounts) :unread))
|
for unread = (and qcounts (plist-get (car qcounts) :unread))
|
||||||
when (not (plist-get item :hide))
|
when (not (plist-get item :hide))
|
||||||
|
@ -246,22 +236,17 @@ character of the keyboard shortcut
|
||||||
(propertize (concat " " unit) 'face 'mu4e-header-title-face)
|
(propertize (concat " " unit) 'face 'mu4e-header-title-face)
|
||||||
"") "\n"))
|
"") "\n"))
|
||||||
|
|
||||||
;; NEW This is the old `mu4e--main-view' function but without
|
(defun mu4e--baseline-time-string ()
|
||||||
;; buffer switching at the end.
|
"Calculate the baseline time string."
|
||||||
(defun mu4e--main-view-real (_ignore-auto _noconfirm)
|
(let* ((baseline-t mu4e--baseline-tstamp)
|
||||||
"The revert buffer function for `mu4e-main-mode'."
|
(updated-t (plist-get mu4e-index-update-status :tstamp))
|
||||||
(mu4e--main-view-real-1 'refresh))
|
(delta-t (and baseline-t updated-t
|
||||||
|
(float-time (time-subtract updated-t baseline-t)))))
|
||||||
(declare-function mu4e--start "mu4e")
|
(if (and delta-t (> delta-t 0))
|
||||||
|
(format-seconds "%Y %D %H %M %z%S ago" delta-t)
|
||||||
(defun mu4e--main-view-real-1 (&optional refresh)
|
(if baseline-t
|
||||||
"Create `mu4e-main-buffer-name' and set it up.
|
(current-time-string baseline-t)
|
||||||
When REFRESH is non nil refresh infos from server."
|
"Never"))))
|
||||||
(let ((inhibit-read-only t))
|
|
||||||
;; Maybe refresh infos from server.
|
|
||||||
(if refresh
|
|
||||||
(mu4e--start 'mu4e--main-redraw-buffer)
|
|
||||||
(mu4e--main-redraw-buffer))))
|
|
||||||
|
|
||||||
(defun mu4e--main-redraw-buffer ()
|
(defun mu4e--main-redraw-buffer ()
|
||||||
"Redraw the main buffer."
|
"Redraw the main buffer."
|
||||||
|
@ -276,7 +261,7 @@ When REFRESH is non nil refresh infos from server."
|
||||||
(propertize "mu4e" 'face 'mu4e-header-key-face)
|
(propertize "mu4e" 'face 'mu4e-header-key-face)
|
||||||
(propertize " - mu for emacs version " 'face 'mu4e-title-face)
|
(propertize " - mu for emacs version " 'face 'mu4e-title-face)
|
||||||
(propertize mu4e-mu-version 'face 'mu4e-header-key-face)
|
(propertize mu4e-mu-version 'face 'mu4e-header-key-face)
|
||||||
"\n\n"
|
"\n\n"
|
||||||
(propertize " Basics\n\n" 'face 'mu4e-title-face)
|
(propertize " Basics\n\n" 'face 'mu4e-title-face)
|
||||||
(mu4e--main-action-str
|
(mu4e--main-action-str
|
||||||
"\t* [j]ump to some maildir\n" #'mu4e~headers-jump-to-maildir)
|
"\t* [j]ump to some maildir\n" #'mu4e~headers-jump-to-maildir)
|
||||||
|
@ -294,13 +279,12 @@ When REFRESH is non nil refresh infos from server."
|
||||||
(propertize " Misc\n\n" 'face 'mu4e-title-face)
|
(propertize " Misc\n\n" 'face 'mu4e-title-face)
|
||||||
|
|
||||||
(mu4e--main-action-str "\t* [;]Switch context\n"
|
(mu4e--main-action-str "\t* [;]Switch context\n"
|
||||||
(lambda()(interactive)
|
(lambda()(interactive)
|
||||||
(mu4e-context-switch)(revert-buffer)))
|
(mu4e-context-switch)(revert-buffer)))
|
||||||
|
|
||||||
(mu4e--main-action-str "\t* [U]pdate email & database\n"
|
(mu4e--main-action-str "\t* [U]pdate email & database\n"
|
||||||
#'mu4e-update-mail-and-index)
|
#'mu4e-update-mail-and-index)
|
||||||
(mu4e--main-action-str "\t* [R]eset query-results baseline\n"
|
(mu4e--main-action-str "\t* [R]eset baseline\n" #'mu4e--reset-baseline)
|
||||||
#'mu4e--main-reset-baseline-query-results)
|
|
||||||
|
|
||||||
;; show the queue functions if `smtpmail-queue-dir' is defined
|
;; show the queue functions if `smtpmail-queue-dir' is defined
|
||||||
(if (file-directory-p smtpmail-queue-dir)
|
(if (file-directory-p smtpmail-queue-dir)
|
||||||
|
@ -317,19 +301,17 @@ When REFRESH is non nil refresh infos from server."
|
||||||
(mu4e--key-val "last updated"
|
(mu4e--key-val "last updated"
|
||||||
(current-time-string
|
(current-time-string
|
||||||
(plist-get mu4e-index-update-status :tstamp)))
|
(plist-get mu4e-index-update-status :tstamp)))
|
||||||
(if (and (not mu4e-main-hide-baseline-delta)
|
(if mu4e--baseline-tstamp
|
||||||
mu4e--baseline-query-results-tstamp)
|
(mu4e--key-val "baseline" (mu4e--baseline-time-string))
|
||||||
(mu4e--key-val "baseline"
|
|
||||||
(current-time-string mu4e--baseline-query-results-tstamp))
|
|
||||||
"")
|
"")
|
||||||
(mu4e--key-val "database-path" (mu4e-database-path))
|
(mu4e--key-val "database-path" (mu4e-database-path))
|
||||||
(mu4e--key-val "maildir" (mu4e-root-maildir))
|
(mu4e--key-val "maildir" (mu4e-root-maildir))
|
||||||
(mu4e--key-val "in store"
|
(mu4e--key-val "in store"
|
||||||
(format "%d" (plist-get mu4e--server-props :doccount))
|
(format "%d" (plist-get mu4e--server-props :doccount))
|
||||||
"messages")
|
"messages")
|
||||||
(if mu4e-main-hide-personal-addresses ""
|
(if mu4e-main-hide-personal-addresses ""
|
||||||
(mu4e--key-val "personal addresses"
|
(mu4e--key-val "personal addresses"
|
||||||
(if addrs (mapconcat #'identity addrs ", " ) "none"))))
|
(if addrs (mapconcat #'identity addrs ", " ) "none"))))
|
||||||
|
|
||||||
(if mu4e-main-hide-personal-addresses ""
|
(if mu4e-main-hide-personal-addresses ""
|
||||||
(unless (mu4e-personal-address-p user-mail-address)
|
(unless (mu4e-personal-address-p user-mail-address)
|
||||||
|
@ -368,26 +350,31 @@ When REFRESH is non nil refresh infos from server."
|
||||||
(count-lines (point-min) (point-max)))
|
(count-lines (point-min) (point-max)))
|
||||||
(error 0)))
|
(error 0)))
|
||||||
|
|
||||||
|
(declare-function mu4e--start "mu4e")
|
||||||
|
|
||||||
(defun mu4e--main-view (&optional refresh)
|
(defun mu4e--main-view (&optional refresh)
|
||||||
"Create the mu4e main-view, and switch to it or show the menu.
|
"Create or refresh the mu4e main-view, and switch to it.
|
||||||
When REFRESH is non nil refresh infos from server.
|
When REFRESH is non nil refresh infos from server.
|
||||||
|
|
||||||
If `mu4e-split-view' equals \='single-window, show a mu4e menu
|
If `mu4e-split-view' equals \='single-window, show a mu4e menu
|
||||||
instead."
|
instead."
|
||||||
|
(mu4e--reset-baseline)
|
||||||
(if (eq mu4e-split-view 'single-window)
|
(if (eq mu4e-split-view 'single-window)
|
||||||
(mu4e--main-menu)
|
(mu4e--main-menu)
|
||||||
(let ((buf (get-buffer-create mu4e-main-buffer-name)))
|
(let ((buf (get-buffer-create mu4e-main-buffer-name))
|
||||||
|
(inhibit-read-only t))
|
||||||
;; `mu4e--main-view' is called from `mu4e--start', so don't call it
|
;; `mu4e--main-view' is called from `mu4e--start', so don't call it
|
||||||
;; a second time here i.e. do not refresh unless specified
|
;; a second time here i.e. do not refresh unless specified
|
||||||
;; explicitly with REFRESH arg.
|
;; explicitly with REFRESH arg.
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(mu4e--main-view-real-1 refresh))
|
(if refresh
|
||||||
|
(mu4e--start 'mu4e--main-redraw-buffer)
|
||||||
|
(mu4e--main-redraw-buffer)))
|
||||||
(mu4e-display-buffer buf t)
|
(mu4e-display-buffer buf t)
|
||||||
(goto-char (point-min)))))
|
(goto-char (point-min)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Interactive functions
|
;; Interactive functions
|
||||||
;; NEW
|
|
||||||
;; Toggle mail sending mode without switching
|
;; Toggle mail sending mode without switching
|
||||||
(defun mu4e--main-toggle-mail-sending-mode ()
|
(defun mu4e--main-toggle-mail-sending-mode ()
|
||||||
"Toggle sending mail mode, either queued or direct."
|
"Toggle sending mail mode, either queued or direct."
|
||||||
|
@ -409,7 +396,7 @@ instead."
|
||||||
'(("jump" . mu4e~headers-jump-to-maildir)
|
'(("jump" . mu4e~headers-jump-to-maildir)
|
||||||
("search" . mu4e-search)
|
("search" . mu4e-search)
|
||||||
("Compose" . mu4e-compose-new)
|
("Compose" . mu4e-compose-new)
|
||||||
("bookmarks" . mu4e-headers-search-bookmark)
|
("bookmarks" . mu4e-search-bookmark)
|
||||||
(";Switch context" . mu4e-context-switch)
|
(";Switch context" . mu4e-context-switch)
|
||||||
("Update" . mu4e-update-mail-and-index)
|
("Update" . mu4e-update-mail-and-index)
|
||||||
("News" . mu4e-news)
|
("News" . mu4e-news)
|
||||||
|
@ -420,11 +407,5 @@ instead."
|
||||||
(sit-for 1)
|
(sit-for 1)
|
||||||
(mu4e--main-menu))))
|
(mu4e--main-menu))))
|
||||||
|
|
||||||
(defun mu4e--main-update-after-index ()
|
|
||||||
"Update the main view buffer after indexing."
|
|
||||||
(when (buffer-live-p mu4e-main-buffer-name)
|
|
||||||
(with-current-buffer mu4e-main-buffer-name
|
|
||||||
(revert-buffer))))
|
|
||||||
|
|
||||||
(provide 'mu4e-main)
|
(provide 'mu4e-main)
|
||||||
;;; mu4e-main.el ends here
|
;;; mu4e-main.el ends here
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
;;; mu4e-modeline.el -- part of mu4e -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
;; Copyright (C) 2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
|
||||||
|
;; mu4e 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.
|
||||||
|
|
||||||
|
;; mu4e 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 mu4e. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; This file contains functionality for putting mu4e-related information
|
||||||
|
;; in the emacs modeline, both buffer-specific and globally.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'cl-lib)
|
||||||
|
|
||||||
|
(defvar-local mu4e--modeline-buffer-items nil
|
||||||
|
"List of buffer-local items for the mu4e modeline.
|
||||||
|
Each element is function that evaluates to a string.")
|
||||||
|
|
||||||
|
(defvar mu4e--modeline-global-items nil
|
||||||
|
"List of items for the global modeline.
|
||||||
|
Each element is function that evaluates to a string.")
|
||||||
|
|
||||||
|
(defun mu4e--modeline-register (func &optional global)
|
||||||
|
"Register a function for calculating some mu4e modeline part.
|
||||||
|
If GLOBAL is non-nil, add to the global-modeline; otherwise use
|
||||||
|
the buffer-local one."
|
||||||
|
(add-to-list
|
||||||
|
(if global 'mu4e--modeline-global-items 'mu4e--modeline-buffer-items)
|
||||||
|
func))
|
||||||
|
|
||||||
|
(defvar mu4e--modeline-item nil
|
||||||
|
"Mu4e item for the global-mode-line.")
|
||||||
|
|
||||||
|
(defun mu4e--modeline-string ()
|
||||||
|
"Calculate the current mu4e modeline string."
|
||||||
|
(mapconcat
|
||||||
|
(lambda (item)
|
||||||
|
(if (functionp item)
|
||||||
|
(or (funcall item) "")
|
||||||
|
""))
|
||||||
|
(append mu4e--modeline-buffer-items mu4e--modeline-global-items) " "))
|
||||||
|
|
||||||
|
(define-minor-mode mu4e-modeline-mode
|
||||||
|
"Minor mode for showing mu4e information on the modeline."
|
||||||
|
;; This is a bit special 'global' mode, since it consists of both
|
||||||
|
;; buffer-specific parts (mu4e--modeline-buffer-items) and global items
|
||||||
|
;; (mu4e--modeline-global-items).
|
||||||
|
:global t
|
||||||
|
:group 'mu4e
|
||||||
|
:lighter nil
|
||||||
|
(if mu4e-modeline-mode
|
||||||
|
(progn
|
||||||
|
(setq mu4e--modeline-item '(:eval (mu4e--modeline-string)))
|
||||||
|
(add-to-list 'global-mode-string mu4e--modeline-item))
|
||||||
|
(progn
|
||||||
|
(setq global-mode-string
|
||||||
|
(seq-remove (lambda (item) (equal item mu4e--modeline-item))
|
||||||
|
global-mode-string))))
|
||||||
|
(force-mode-line-update))
|
||||||
|
|
||||||
|
(provide 'mu4e-modeline)
|
||||||
|
;; mu4e-modeline.el ends here
|
|
@ -148,6 +148,8 @@
|
||||||
(define-obsolete-function-alias 'mu4e-read-query
|
(define-obsolete-function-alias 'mu4e-read-query
|
||||||
'mu4e-search-read-query "1.7.0")
|
'mu4e-search-read-query "1.7.0")
|
||||||
|
|
||||||
|
(make-obsolete-variable 'mu4e-display-update-status-in-modeline
|
||||||
|
"No longer used" "1.9.11")
|
||||||
|
|
||||||
;; mu4e-headers
|
;; mu4e-headers
|
||||||
(make-obsolete-variable 'mu4e-headers-field-properties-function
|
(make-obsolete-variable 'mu4e-headers-field-properties-function
|
||||||
|
|
|
@ -165,8 +165,7 @@ but also manually invoked searches."
|
||||||
;;; History
|
;;; History
|
||||||
(defvar mu4e--search-query-past nil
|
(defvar mu4e--search-query-past nil
|
||||||
"Stack of queries before the present one.")
|
"Stack of queries before the present one.")
|
||||||
(defvar mu4e--search-query-future nil
|
(defvar mu4e--search-query-future nil "Stack of queries after the present one.")
|
||||||
"Stack of queries after the present one.")
|
|
||||||
(defvar mu4e--search-query-stack-size 20
|
(defvar mu4e--search-query-stack-size 20
|
||||||
"Maximum size for the query stacks.")
|
"Maximum size for the query stacks.")
|
||||||
(defvar mu4e--search-last-query nil
|
(defvar mu4e--search-last-query nil
|
||||||
|
@ -217,9 +216,14 @@ show the message with MSGID."
|
||||||
If EDIT is non-nil, let the user edit the bookmark before starting
|
If EDIT is non-nil, let the user edit the bookmark before starting
|
||||||
the search."
|
the search."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((expr
|
(let* ((expr
|
||||||
(or expr
|
(or expr
|
||||||
(mu4e-ask-bookmark (if edit "Select bookmark: " "Bookmark: ")))))
|
(mu4e-ask-bookmark (if edit "Select bookmark: " "Bookmark: "))))
|
||||||
|
(fav (mu4e--bookmark-query (mu4e-favorite-bookmark))))
|
||||||
|
;; reset baseline when searching for bookmark query
|
||||||
|
(when (and fav (string= fav expr))
|
||||||
|
(mu4e--reset-baseline))
|
||||||
|
|
||||||
(run-hook-with-args 'mu4e-search-bookmark-hook expr)
|
(run-hook-with-args 'mu4e-search-bookmark-hook expr)
|
||||||
(mu4e-search expr (when edit "Edit bookmark: ") edit)))
|
(mu4e-search expr (when edit "Edit bookmark: ") edit)))
|
||||||
|
|
||||||
|
|
|
@ -132,12 +132,55 @@ from the server process.")
|
||||||
(defvar mu4e-pong-func nil
|
(defvar mu4e-pong-func nil
|
||||||
"Function called for each (:pong type ....) sexp received.")
|
"Function called for each (:pong type ....) sexp received.")
|
||||||
|
|
||||||
|
(defvar mu4e-queries-func nil
|
||||||
|
"Function called for each (:queries type ....) sexp received.")
|
||||||
|
|
||||||
(defvar mu4e-contacts-func nil
|
(defvar mu4e-contacts-func nil
|
||||||
"A function called for each (:contacts (<list-of-contacts>))
|
"A function called for each (:contacts (<list-of-contacts>))
|
||||||
sexp received from the server process.")
|
sexp received from the server process.")
|
||||||
|
|
||||||
|
|
||||||
;;; Internal vars
|
;;; Dealing with Server properties
|
||||||
|
(defvar mu4e--server-props nil
|
||||||
|
"Metadata we receive from the mu4e server.")
|
||||||
|
|
||||||
|
(defun mu4e-server-properties ()
|
||||||
|
"Get the server metadata plist."
|
||||||
|
mu4e--server-props)
|
||||||
|
|
||||||
|
(defun mu4e-root-maildir()
|
||||||
|
"Get the root maildir."
|
||||||
|
(or (and mu4e--server-props
|
||||||
|
(plist-get mu4e--server-props :root-maildir))
|
||||||
|
(mu4e-error "Root maildir unknown; did you start mu4e?")))
|
||||||
|
|
||||||
|
(defun mu4e-database-path()
|
||||||
|
"Get the root maildir."
|
||||||
|
(or (and mu4e--server-props
|
||||||
|
(plist-get mu4e--server-props :database-path))
|
||||||
|
(mu4e-error "Root maildir unknown; did you start mu4e?")))
|
||||||
|
|
||||||
|
(defun mu4e-server-version()
|
||||||
|
"Get the root maildir."
|
||||||
|
(or (and mu4e--server-props
|
||||||
|
(plist-get mu4e--server-props :version))
|
||||||
|
(mu4e-error "Version unknown; did you start mu4e?")))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; server-query-results are the results from the counting-queries
|
||||||
|
;; we do for bookmarks etc. to populate the main view with unread
|
||||||
|
;; counts.
|
||||||
|
|
||||||
|
;;; remember queries result.
|
||||||
|
(defvar mu4e--server-query-results nil
|
||||||
|
"Metadata we receive from the mu4e server.")
|
||||||
|
|
||||||
|
(defun mu4e-server-query-results ()
|
||||||
|
"Get the latest server queries list."
|
||||||
|
mu4e--server-query-results)
|
||||||
|
|
||||||
|
|
||||||
|
;;; Handling raw server data
|
||||||
|
|
||||||
(defvar mu4e--server-buf nil
|
(defvar mu4e--server-buf nil
|
||||||
"Buffer (string) for data received from the backend.")
|
"Buffer (string) for data received from the backend.")
|
||||||
|
@ -164,8 +207,7 @@ Match 1 will be the length (in hex).")
|
||||||
Checks whether the server process is live."
|
Checks whether the server process is live."
|
||||||
(and mu4e--server-process
|
(and mu4e--server-process
|
||||||
(memq (process-status mu4e--server-process)
|
(memq (process-status mu4e--server-process)
|
||||||
'(run open listen connect stop))
|
'(run open listen connect stop)) t))
|
||||||
t))
|
|
||||||
|
|
||||||
(defsubst mu4e--server-eat-sexp-from-buf ()
|
(defsubst mu4e--server-eat-sexp-from-buf ()
|
||||||
"'Eat' the next s-expression from `mu4e--server-buf'.
|
"'Eat' the next s-expression from `mu4e--server-buf'.
|
||||||
|
@ -286,9 +328,14 @@ The server output is as follows:
|
||||||
|
|
||||||
;; received a pong message
|
;; received a pong message
|
||||||
((plist-get sexp :pong)
|
((plist-get sexp :pong)
|
||||||
(mu4e--update-server-props (plist-get sexp :props))
|
(setq mu4e--server-props (plist-get sexp :props))
|
||||||
(funcall mu4e-pong-func sexp))
|
(funcall mu4e-pong-func sexp))
|
||||||
|
|
||||||
|
;; receive queries info
|
||||||
|
((plist-get sexp :queries)
|
||||||
|
(setq mu4e--server-query-results (plist-get sexp :queries))
|
||||||
|
(funcall mu4e-queries-func sexp))
|
||||||
|
|
||||||
;; received a contacts message
|
;; received a contacts message
|
||||||
;; note: we use 'member', to match (:contacts nil)
|
;; note: we use 'member', to match (:contacts nil)
|
||||||
((plist-member sexp :contacts)
|
((plist-member sexp :contacts)
|
||||||
|
@ -562,11 +609,15 @@ Returns either (:update ... ) or (:error ) sexp, which are handled my
|
||||||
:rename ,(and maildir mu4e-change-filenames-when-moving t)
|
:rename ,(and maildir mu4e-change-filenames-when-moving t)
|
||||||
:no-view ,(and no-view t))))
|
:no-view ,(and no-view t))))
|
||||||
|
|
||||||
(defun mu4e--server-ping (&optional queries)
|
(defun mu4e--server-ping ()
|
||||||
"Sends a ping to the mu server, expecting a (:pong ...) in response.
|
"Sends a ping to the mu server, expecting a (:pong ...) in response."
|
||||||
|
(mu4e--server-call-mu `(ping)))
|
||||||
|
|
||||||
|
(defun mu4e--server-queries (queries)
|
||||||
|
"Sends queries to the mu server, expecting a (:queries ...) in response.
|
||||||
QUERIES is a list of queries for the number of results with
|
QUERIES is a list of queries for the number of results with
|
||||||
read/unread status are returned in the pong-response."
|
read/unread status are returned in the pong-response."
|
||||||
(mu4e--server-call-mu `(ping :queries ,queries)))
|
(mu4e--server-call-mu `(queries :queries ,queries)))
|
||||||
|
|
||||||
(defun mu4e--server-remove (docid)
|
(defun mu4e--server-remove (docid)
|
||||||
"Remove message with DOCID.
|
"Remove message with DOCID.
|
||||||
|
|
|
@ -311,7 +311,6 @@ run in the background; otherwise, pop up a window."
|
||||||
:lighter ""
|
:lighter ""
|
||||||
:keymap
|
:keymap
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map (kbd "C-c C-r") #'mu4e-reset-baseline-query-results)
|
|
||||||
(define-key map (kbd "C-S-u") #'mu4e-update-mail-and-index)
|
(define-key map (kbd "C-S-u") #'mu4e-update-mail-and-index)
|
||||||
;; for terminal users
|
;; for terminal users
|
||||||
(define-key map (kbd "C-c C-u") #'mu4e-update-mail-and-index)
|
(define-key map (kbd "C-c C-u") #'mu4e-update-mail-and-index)
|
||||||
|
|
78
mu4e/mu4e.el
78
mu4e/mu4e.el
|
@ -1,6 +1,6 @@
|
||||||
;;; mu4e.el --- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
;;; mu4e.el --- part of mu4e, the mu mail user agent -*- lexical-binding: t -*-
|
||||||
|
|
||||||
;; Copyright (C) 2011-2022 Dirk-Jan C. Binnema
|
;; Copyright (C) 2011-2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Author: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
;; Maintainer: Dirk-Jan C. Binnema <djcb@djcbsoftware.nl>
|
||||||
|
@ -48,6 +48,11 @@
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
:group 'mu4e)
|
:group 'mu4e)
|
||||||
|
|
||||||
|
(defcustom mu4e-modeline-support t
|
||||||
|
"Support for shoiwing information in the modeline."
|
||||||
|
:type 'boolean
|
||||||
|
:group 'mu4e)
|
||||||
|
|
||||||
(defcustom mu4e-org-support t
|
(defcustom mu4e-org-support t
|
||||||
"Support Org-mode links."
|
"Support Org-mode links."
|
||||||
:type 'boolean
|
:type 'boolean
|
||||||
|
@ -68,6 +73,7 @@
|
||||||
(with-eval-after-load 'desktop
|
(with-eval-after-load 'desktop
|
||||||
(eval '(add-to-list 'desktop-modes-not-to-save 'mu4e-compose-mode)))
|
(eval '(add-to-list 'desktop-modes-not-to-save 'mu4e-compose-mode)))
|
||||||
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mu4e (&optional background)
|
(defun mu4e (&optional background)
|
||||||
"If mu4e is not running yet, start it.
|
"If mu4e is not running yet, start it.
|
||||||
|
@ -76,12 +82,11 @@ is non-nil."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
;; start mu4e, then show the main view
|
;; start mu4e, then show the main view
|
||||||
(mu4e--init-handlers)
|
(mu4e--init-handlers)
|
||||||
|
|
||||||
;; i.e., only auto update baseline when user explicitly requested
|
;; i.e., only auto update baseline when user explicitly requested
|
||||||
(when (and mu4e-main-auto-reset-baseline
|
(when (or (not mu4e--baseline-tstamp)
|
||||||
(not background) (called-interactively-p 'interactive))
|
(and (not background) (called-interactively-p 'interactive)))
|
||||||
(mu4e-reset-baseline-query-results))
|
(mu4e--reset-baseline))
|
||||||
|
(mu4e--modeline-update)
|
||||||
(mu4e--start (unless background 'mu4e--main-view)))
|
(mu4e--start (unless background 'mu4e--main-view)))
|
||||||
|
|
||||||
(defun mu4e-quit()
|
(defun mu4e-quit()
|
||||||
|
@ -133,6 +138,34 @@ Invoke FUNC if non-nil."
|
||||||
(lambda () (mu4e-update-mail-and-index
|
(lambda () (mu4e-update-mail-and-index
|
||||||
mu4e-index-update-in-background)))))))
|
mu4e-index-update-in-background)))))))
|
||||||
|
|
||||||
|
(defun mu4e--server-bookmarks-queries()
|
||||||
|
(mu4e--server-queries
|
||||||
|
(mapcar ;; send it a list of queries we'd like to see read/unread info for
|
||||||
|
(lambda (bm)
|
||||||
|
(funcall (or mu4e-query-rewrite-function #'identity)
|
||||||
|
(mu4e--bookmark-query bm)))
|
||||||
|
;; exclude bookmarks with certain flags
|
||||||
|
(seq-filter (lambda (bm)
|
||||||
|
(and (not (or (plist-get bm :hide)
|
||||||
|
(plist-get bm :hide-unread)))))
|
||||||
|
(append (mu4e-bookmarks)
|
||||||
|
(mu4e--maildirs-with-query))))))
|
||||||
|
|
||||||
|
(defun mu4e--queries-handler (_sexp)
|
||||||
|
;; we've received new server-queries; so update the main view
|
||||||
|
;; (if any) and the modeline.
|
||||||
|
|
||||||
|
;; 1. update the query results (i.e. process the new server queries)
|
||||||
|
(mu4e-last-query-results 'force-update)
|
||||||
|
(unless mu4e--baseline
|
||||||
|
(mu4e--reset-baseline))
|
||||||
|
(mu4e--modeline-update)
|
||||||
|
|
||||||
|
;; 2. update the main view, if any
|
||||||
|
(when (buffer-live-p mu4e-main-buffer-name)
|
||||||
|
(with-current-buffer mu4e-main-buffer-name
|
||||||
|
(revert-buffer))))
|
||||||
|
|
||||||
(defun mu4e--start (&optional func)
|
(defun mu4e--start (&optional func)
|
||||||
"Start mu4e.
|
"Start mu4e.
|
||||||
If `mu4e-contexts' have been defined, but we don't have a context
|
If `mu4e-contexts' have been defined, but we don't have a context
|
||||||
|
@ -144,18 +177,10 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
|
||||||
(unless (mu4e-context-current)
|
(unless (mu4e-context-current)
|
||||||
(mu4e--context-autoswitch nil mu4e-context-policy))
|
(mu4e--context-autoswitch nil mu4e-context-policy))
|
||||||
(setq mu4e-pong-func (lambda (info) (mu4e--pong-handler info func)))
|
(setq mu4e-pong-func (lambda (info) (mu4e--pong-handler info func)))
|
||||||
(mu4e--server-ping
|
(mu4e--modeline-register #'mu4e--bookmarks-modeline-item 'global)
|
||||||
(mapcar ;; send it a list of queries we'd like to see read/unread info for
|
(mu4e-modeline-mode (if mu4e-modeline-support 1 -1))
|
||||||
(lambda (bm)
|
(mu4e--server-bookmarks-queries)
|
||||||
(funcall (or mu4e-query-rewrite-function #'identity)
|
(mu4e--server-ping)
|
||||||
(plist-get bm :query)))
|
|
||||||
;; exclude bookmarks that are not strings, and with certain flags
|
|
||||||
(seq-filter (lambda (bm)
|
|
||||||
(and (stringp (plist-get bm :query))
|
|
||||||
(not (or (plist-get bm :hide)
|
|
||||||
(plist-get bm :hide-unread)))))
|
|
||||||
(append (mu4e-bookmarks)
|
|
||||||
(mu4e--maildirs-with-query)))))
|
|
||||||
;; maybe request the list of contacts, automatically refreshed after
|
;; maybe request the list of contacts, automatically refreshed after
|
||||||
;; reindexing
|
;; reindexing
|
||||||
(unless mu4e--contacts-set (mu4e--request-contacts-maybe)))
|
(unless mu4e--contacts-set (mu4e--request-contacts-maybe)))
|
||||||
|
@ -166,6 +191,8 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
|
||||||
(cancel-timer mu4e--update-timer)
|
(cancel-timer mu4e--update-timer)
|
||||||
(setq mu4e--update-timer nil))
|
(setq mu4e--update-timer nil))
|
||||||
(mu4e-clear-caches)
|
(mu4e-clear-caches)
|
||||||
|
|
||||||
|
(mu4e-modeline-mode -1)
|
||||||
(mu4e--server-kill)
|
(mu4e--server-kill)
|
||||||
;; kill all mu4e buffers
|
;; kill all mu4e buffers
|
||||||
(mapc
|
(mapc
|
||||||
|
@ -185,7 +212,7 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
|
||||||
;;; Handlers
|
;;; Handlers
|
||||||
(defun mu4e--default-handler (&rest args)
|
(defun mu4e--default-handler (&rest args)
|
||||||
"Dummy handler function with arbitrary ARGS."
|
"Dummy handler function with arbitrary ARGS."
|
||||||
(mu4e-error "Not handled: %S" args))
|
(mu4e-error "Not handled: %s" args))
|
||||||
|
|
||||||
(defun mu4e--error-handler (errcode errmsg)
|
(defun mu4e--error-handler (errcode errmsg)
|
||||||
"Handler function for showing an error with ERRCODE and ERRMSG."
|
"Handler function for showing an error with ERRCODE and ERRMSG."
|
||||||
|
@ -222,6 +249,8 @@ Otherwise, check requirements, then start mu4e. When successful, invoke
|
||||||
"%s completed; checked %d, updated %d, cleaned-up %d"
|
"%s completed; checked %d, updated %d, cleaned-up %d"
|
||||||
(if mu4e-index-lazy-check "Lazy indexing" "Indexing")
|
(if mu4e-index-lazy-check "Lazy indexing" "Indexing")
|
||||||
checked updated cleaned-up)
|
checked updated cleaned-up)
|
||||||
|
;; index done; grab updated queries
|
||||||
|
(mu4e--server-bookmarks-queries)
|
||||||
(run-hooks 'mu4e-index-updated-hook)
|
(run-hooks 'mu4e-index-updated-hook)
|
||||||
;; backward compatibility...
|
;; backward compatibility...
|
||||||
(unless (zerop (+ updated cleaned-up))
|
(unless (zerop (+ updated cleaned-up))
|
||||||
|
@ -248,11 +277,12 @@ chance."
|
||||||
(mu4e-setq-if-nil mu4e-found-func #'mu4e~headers-found-handler)
|
(mu4e-setq-if-nil mu4e-found-func #'mu4e~headers-found-handler)
|
||||||
(mu4e-setq-if-nil mu4e-erase-func #'mu4e~headers-clear)
|
(mu4e-setq-if-nil mu4e-erase-func #'mu4e~headers-clear)
|
||||||
|
|
||||||
(mu4e-setq-if-nil mu4e-sent-func #'mu4e--default-handler)
|
(mu4e-setq-if-nil mu4e-sent-func #'mu4e--default-handler)
|
||||||
(mu4e-setq-if-nil mu4e-compose-func #'mu4e~compose-handler)
|
(mu4e-setq-if-nil mu4e-compose-func #'mu4e~compose-handler)
|
||||||
(mu4e-setq-if-nil mu4e-contacts-func #'mu4e--update-contacts)
|
(mu4e-setq-if-nil mu4e-contacts-func #'mu4e--update-contacts)
|
||||||
(mu4e-setq-if-nil mu4e-info-func #'mu4e--info-handler)
|
(mu4e-setq-if-nil mu4e-info-func #'mu4e--info-handler)
|
||||||
(mu4e-setq-if-nil mu4e-pong-func #'mu4e--default-handler))
|
(mu4e-setq-if-nil mu4e-pong-func #'mu4e--default-handler)
|
||||||
|
(mu4e-setq-if-nil mu4e-queries-func #'mu4e--queries-handler))
|
||||||
|
|
||||||
(defun mu4e-clear-caches ()
|
(defun mu4e-clear-caches ()
|
||||||
"Clear any cached resources."
|
"Clear any cached resources."
|
||||||
|
|
452
mu4e/mu4e.texi
452
mu4e/mu4e.texi
|
@ -12,7 +12,7 @@
|
||||||
@c %**end of header
|
@c %**end of header
|
||||||
|
|
||||||
@copying
|
@copying
|
||||||
Copyright @copyright{} 2012-2022 Dirk-Jan C. Binnema
|
Copyright @copyright{} 2012-2023 Dirk-Jan C. Binnema
|
||||||
|
|
||||||
@quotation
|
@quotation
|
||||||
Permission is granted to copy, distribute and/or modify this document
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
|
@ -80,7 +80,7 @@ basic configuration and explain its daily use. We also show you how you
|
||||||
can customize @t{mu4e} for your special needs.
|
can customize @t{mu4e} for your special needs.
|
||||||
|
|
||||||
At the end of the manual, there are some example configurations, to get
|
At the end of the manual, there are some example configurations, to get
|
||||||
you up to speed quickly: @ref{Example configs}. There's also a section
|
you up to speed quickly: @ref{Example configurations}. There's also a section
|
||||||
with answers to frequently asked questions, @ref{FAQ}.
|
with answers to frequently asked questions, @ref{FAQ}.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
@ -99,25 +99,24 @@ with answers to frequently asked questions, @ref{FAQ}.
|
||||||
|
|
||||||
Appendices
|
Appendices
|
||||||
* Other tools:: mu4e and the rest of the world
|
* Other tools:: mu4e and the rest of the world
|
||||||
* Example configs:: Some examples to set you up quickly
|
* Example configurations:: Some examples to set you up quickly
|
||||||
* FAQ:: Common questions and answers
|
* FAQ:: Common questions and answers
|
||||||
* Tips and Tricks:: Useful tips
|
* Tips and Tricks:: Useful tips
|
||||||
* How it works:: Some notes about the implementation of @t{mu4e}
|
* How it works:: Some notes about the implementation of @t{mu4e}
|
||||||
* Debugging:: How to debug problems in @t{mu4e}
|
* Debugging:: How to debug problems in @t{mu4e}
|
||||||
* GNU Free Documentation License:: The license of this manual
|
* GNU Free Documentation License:: The license of this manual
|
||||||
|
|
||||||
@c Indices
|
Indices
|
||||||
@c * Command Index:: An item for each standard command name.
|
@c * Command Index:: An item for each standard command name.
|
||||||
@c * Variable Index:: An item for each variable documented in this manual.
|
@c * Variable Index:: An item for each variable documented in this manual.
|
||||||
@c * Concept Index:: An item for concepts and other general subjects.
|
* Concept Index:: Index of @t{mu4e} concepts and other general subjects.
|
||||||
|
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Introduction
|
@node Introduction
|
||||||
@chapter Introduction
|
@chapter Introduction
|
||||||
|
|
||||||
Let's get started!
|
Let's get started!q
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Why another e-mail client::Aren't there enough already
|
* Why another e-mail client::Aren't there enough already
|
||||||
* Other mail clients::Where @t{mu4e} takes its inspiration from
|
* Other mail clients::Where @t{mu4e} takes its inspiration from
|
||||||
|
@ -316,7 +315,7 @@ Note: if you are familiar with @t{meson}, you can of course use its
|
||||||
commands directly; the @t{make} commands are just a thin wrapper around
|
commands directly; the @t{make} commands are just a thin wrapper around
|
||||||
that.
|
that.
|
||||||
|
|
||||||
@subsection Installing
|
@subsection Installation
|
||||||
|
|
||||||
After this, @t{mu} and @t{mu4e} should be installed @footnote{there's a
|
After this, @t{mu} and @t{mu4e} should be installed @footnote{there's a
|
||||||
hard dependency between versions of @t{mu4e} and @t{mu} --- you cannot
|
hard dependency between versions of @t{mu4e} and @t{mu} --- you cannot
|
||||||
|
@ -337,7 +336,7 @@ configuration before trying again:
|
||||||
|
|
||||||
There is some support for using the Emacs customization system in
|
There is some support for using the Emacs customization system in
|
||||||
@t{mu4e}, but for now, we recommend setting the values manually. Please
|
@t{mu4e}, but for now, we recommend setting the values manually. Please
|
||||||
refer to @ref{Example configs} for a couple of examples of this; here we
|
refer to @ref{Example configurations} for a couple of examples of this; here we
|
||||||
go through things step-by-step.
|
go through things step-by-step.
|
||||||
|
|
||||||
@node Getting mail
|
@node Getting mail
|
||||||
|
@ -394,7 +393,7 @@ You can add some e-mail addresses, so @t{mu} recognizes them as yours:
|
||||||
indexing messages. If you want to change them, you need to @t{init}
|
indexing messages. If you want to change them, you need to @t{init}
|
||||||
once again.
|
once again.
|
||||||
|
|
||||||
The addresses may also be basic POSIX regular expressions, wrapped in
|
The addresses may also be basic PCRE regular expressions, wrapped in
|
||||||
slashes, for example:
|
slashes, for example:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
|
@ -603,7 +602,7 @@ For sending mail using @abbr{SMTP}, @t{mu4e} uses @t{smtpmail}
|
||||||
send mail; please refer to its documentation for the details.
|
send mail; please refer to its documentation for the details.
|
||||||
|
|
||||||
Here, we only provide some simple examples --- for more, see
|
Here, we only provide some simple examples --- for more, see
|
||||||
@ref{Example configs}.
|
@ref{Example configurations}.
|
||||||
|
|
||||||
A very minimal setup:
|
A very minimal setup:
|
||||||
|
|
||||||
|
@ -716,18 +715,18 @@ The main view looks something like the following:
|
||||||
|
|
||||||
Bookmarks
|
Bookmarks
|
||||||
|
|
||||||
* [bu] Unread messages (13085/+3/13085)
|
* [bu] Unread messages (13085(+3)/13085)
|
||||||
* [bt] Today's messages
|
* [bt] Today's messages
|
||||||
* [bw] Last 7 days (53/+3/128)
|
* [bw] Last 7 days (53(+3)/128)
|
||||||
* [bp] Messages with images (75/-2/2441)
|
* [bp] Messages with images (75/2441)
|
||||||
|
|
||||||
Maildirs
|
Maildirs
|
||||||
|
|
||||||
* [ja] /archive (2101/0/18837)
|
* [ja] /archive (2101/18837)
|
||||||
* [ji] /inbox (8/+2/10)
|
* [ji] /inbox (8(+2)/10)
|
||||||
* [jb] /bulk (33/+0/35)
|
* [jb] /bulk (33/35)
|
||||||
* [jB] /bulkarchive (179/+0/2090)
|
* [jB] /bulkarchive (179/2090)
|
||||||
* [jm] /mu (694/+1/17687)
|
* [jm] /mu (694(+1)/17687)
|
||||||
* [jn] /sauron
|
* [jn] /sauron
|
||||||
* [js] /sent
|
* [js] /sent
|
||||||
|
|
||||||
|
@ -780,26 +779,30 @@ the @ref{Editor view} to write a new message.
|
||||||
|
|
||||||
The next two items in the Main view are @emph{Bookmarks} and @emph{Maildirs}.
|
The next two items in the Main view are @emph{Bookmarks} and @emph{Maildirs}.
|
||||||
|
|
||||||
Bookmarks are predefined queries with a descriptive name and a
|
Bookmarks are predefined queries with a descriptive name and a shortcut --- in
|
||||||
shortcut --- in the example above, we see the default bookmarks. You
|
the example above, we see the default bookmarks. You can view the list of
|
||||||
can view the list of messages matching a certain bookmark by pressing
|
messages matching a certain bookmark by pressing @key{b} followed by the
|
||||||
@key{b} followed by the bookmark's shortcut. If you'd like to edit the
|
bookmark's shortcut. If you want to edit the bookmarked query before invoking
|
||||||
bookmarked query first before invoking it, use @key{B}.
|
it, use @key{B}.
|
||||||
|
|
||||||
Next to each bookmark there is the number of (unread/delta/all) messages that
|
Next to each bookmark are some numbers that indicate the (unread(delta)/all)
|
||||||
match.
|
matching messages for the given query, with the delta being the difference in
|
||||||
|
unread count since some ``baseline'', and only shown when this delta > 0.
|
||||||
|
|
||||||
The ``unread'' and ``all'' have their obvious meaning; the @emph{delta} is the
|
Note that the ``delta'' has its limitations: if you, for instance, deleted 5
|
||||||
difference in unread messages since ``baseline'', which is the state at some
|
messages and received 5 new one, the ``delta'' would be 0, although there were
|
||||||
point in the past. This delta is useful to quickly see what changed since the
|
changes indeed. So it is mostly useful for tracking changes while you are
|
||||||
last time you looked.
|
@emph{not} using @t{mu4e}.
|
||||||
|
|
||||||
By default, the baseline is automatically reset when switching to the main view
|
This delta is useful to quickly see that there are new messages since the last
|
||||||
explicitly; otherwise the baseline can be reset with
|
time you looked. Imagine switching to another buffer to work on something or
|
||||||
@code{mu4e-reset-baseline-query-results}, which is bound to @kbd{R} in the
|
even (!) stepping away from your computer to return later: the baseline allows
|
||||||
main-view, and @kbd{C-c C-R} throughout @t{mu4e}. You can customize the behavior
|
you to quickly see what changed.
|
||||||
using @var{mu4e-main-hide-baseline-delta} and
|
|
||||||
@var{mu4e-main-auto-reset-baseline}.
|
By default, the baseline is reset automatically when switching to the main view
|
||||||
|
explicitly (but see @code{mu4e-main-auto-reset-baseline}. It can also be reset
|
||||||
|
explicitly using @code{mu4e-reset-baseline-query-results}, which is bound to
|
||||||
|
@kbd{R} in the main-view.
|
||||||
|
|
||||||
Bookmarks are stored in the variable @code{mu4e-bookmarks}; you can add
|
Bookmarks are stored in the variable @code{mu4e-bookmarks}; you can add
|
||||||
your own and/or replace the default ones; @xref{Bookmarks}. For
|
your own and/or replace the default ones; @xref{Bookmarks}. For
|
||||||
|
@ -812,14 +815,17 @@ instance:
|
||||||
:query "list:mu-discuss.googlegroups.com AND date:7d..now"))
|
:query "list:mu-discuss.googlegroups.com AND date:7d..now"))
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
There are optional keys @t{:hide} to hide the bookmark from the main
|
There are optional keys @t{:hide} to hide the bookmark from the main menu, but
|
||||||
menu, but still have it available (using @key{b})) and
|
still have it available (using @key{b})) and @t{:hide-unread} to avoid
|
||||||
@t{:hide-unread} to avoid generating the unread-number; that can be
|
generating the unread-number; that can be useful if you have bookmarks for slow
|
||||||
useful if you have bookmarks for slow queries. Note that
|
queries. Note that @t{:hide-unread} is implied when the query is not a string;
|
||||||
@t{:hide-unread} is implied when the query is not a string; this for
|
this for the common case where the query function involves some user input,
|
||||||
the common case where the query function involves some user input,
|
|
||||||
which would be disruptive in this case.
|
which would be disruptive in this case.
|
||||||
|
|
||||||
|
There is also the optional @code{:favorite} property, which at most one bookmark
|
||||||
|
should have; this bookmark is highlighted in the main view, and its
|
||||||
|
unread-status is shown in the modeline; @xref{Modeline}.
|
||||||
|
|
||||||
The Maildirs item is very similar to Bookmarks, when you consider maildirs here
|
The Maildirs item is very similar to Bookmarks, when you consider maildirs here
|
||||||
as being special kind of bookmark that matches some Maildir.
|
as being special kind of bookmark that matches some Maildir.
|
||||||
|
|
||||||
|
@ -1071,7 +1077,7 @@ Note that with threading enabled, the sorting is exclusively by date,
|
||||||
regardless of the column clicked.
|
regardless of the column clicked.
|
||||||
|
|
||||||
If you want to change the defaults for these settings, you can use the variables
|
If you want to change the defaults for these settings, you can use the variables
|
||||||
@var{mu4e-search-sort-field} and @var{mu4e-search-show-threads}, as well as
|
@code{mu4e-search-sort-field} and @code{mu4e-search-show-threads}, as well as
|
||||||
@code{mu4e-search-change-sorting} to change the sorting of the current search
|
@code{mu4e-search-change-sorting} to change the sorting of the current search
|
||||||
results.
|
results.
|
||||||
|
|
||||||
|
@ -1740,7 +1746,7 @@ then still include the signature manually, using the function
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
@item If you want use @t{mu4e} as Emacs' default program for sending mail,
|
@item If you want use @t{mu4e} as Emacs' default program for sending mail,
|
||||||
see @ref{Emacs default}.
|
see @ref{Default email client}.
|
||||||
@item Normally, @t{mu4e} @emph{buries} the message buffer after sending; if you want
|
@item Normally, @t{mu4e} @emph{buries} the message buffer after sending; if you want
|
||||||
to kill the buffer instead, add something like the following to your
|
to kill the buffer instead, add something like the following to your
|
||||||
configuration:
|
configuration:
|
||||||
|
@ -2099,7 +2105,7 @@ query, so, effectively `widens' the search. Technically, narrowing the results
|
||||||
of query @t{x} with expression @t{y} implies doing a search @t{(x) AND (y)}.
|
of query @t{x} with expression @t{y} implies doing a search @t{(x) AND (y)}.
|
||||||
|
|
||||||
Note that messages that were not in your original search results because of
|
Note that messages that were not in your original search results because of
|
||||||
@var{mu4e-search-results-limit} may show up in the narrowed query.
|
@code{mu4e-search-results-limit} may show up in the narrowed query.
|
||||||
|
|
||||||
@subsection Including related messages
|
@subsection Including related messages
|
||||||
@anchor{Including related messages}
|
@anchor{Including related messages}
|
||||||
|
@ -2108,7 +2114,7 @@ It can be useful to not only show the messages that directly match a certain
|
||||||
query, but also include messages that are related to these messages. That is,
|
query, but also include messages that are related to these messages. That is,
|
||||||
messages that belong to the same discussion threads are included in the results,
|
messages that belong to the same discussion threads are included in the results,
|
||||||
just like e.g. Gmail does it. You can enable this behavior by setting
|
just like e.g. Gmail does it. You can enable this behavior by setting
|
||||||
@var{mu4e-search-include-related} to @code{t}, and you can toggle between
|
@code{mu4e-search-include-related} to @code{t}, and you can toggle between
|
||||||
including/not-including with @key{W}.
|
including/not-including with @key{W}.
|
||||||
|
|
||||||
Be careful though when e.g. deleting ranges of messages from a certain
|
Be careful though when e.g. deleting ranges of messages from a certain
|
||||||
|
@ -2123,7 +2129,7 @@ copies of messages, there's usually little value in including more than one in
|
||||||
search results. A common reason for having multiple copies of messages is the
|
search results. A common reason for having multiple copies of messages is the
|
||||||
combination of Gmail and @t{offlineimap}, since that is the way the labels /
|
combination of Gmail and @t{offlineimap}, since that is the way the labels /
|
||||||
virtual folders in Gmail are represented. You can enable skipping duplicates by
|
virtual folders in Gmail are represented. You can enable skipping duplicates by
|
||||||
setting @var{mu4e-search-skip-duplicates} to @code{t}, and you can toggle
|
setting @code{mu4e-search-skip-duplicates} to @code{t}, and you can toggle
|
||||||
between the skipping/not skipping with @key{V}.
|
between the skipping/not skipping with @key{V}.
|
||||||
|
|
||||||
Note, messages are considered duplicates when they have the same
|
Note, messages are considered duplicates when they have the same
|
||||||
|
@ -2265,8 +2271,8 @@ Custom mark functions are to be appended to the list
|
||||||
@item The name of the marker --- a short string describing this marker. The
|
@item The name of the marker --- a short string describing this marker. The
|
||||||
first character of this string determines its shortcut, so these should be
|
first character of this string determines its shortcut, so these should be
|
||||||
unique. If necessary, simply prefix the name with a unique character.
|
unique. If necessary, simply prefix the name with a unique character.
|
||||||
@item a predicate function, taking two arguments @var{msg} and @var{param}.
|
@item a predicate function, taking two arguments @code{msg} and @code{param}.
|
||||||
@var{msg} is the message plist (see @ref{Message functions}) and @var{param} is
|
@code{msg} is the message plist (see @ref{Message functions}) and @code{param} is
|
||||||
a parameter provided by the third of the marker elements (see the next
|
a parameter provided by the third of the marker elements (see the next
|
||||||
item). The predicate function should return non-@t{nil} if the message
|
item). The predicate function should return non-@t{nil} if the message
|
||||||
matches.
|
matches.
|
||||||
|
@ -2575,8 +2581,8 @@ when starting; see the discussion in the previous section.
|
||||||
A couple of notes about this example:
|
A couple of notes about this example:
|
||||||
@itemize
|
@itemize
|
||||||
@item You can manually switch the context use @code{M-x mu4e-context-switch},
|
@item You can manually switch the context use @code{M-x mu4e-context-switch},
|
||||||
by default bound to @kbd{;} in headers, view and main mode.
|
by default bound to @kbd{;} in headers, view and main mode. The current context
|
||||||
The current context appears in the mode-line.
|
appears in the modeline by default; see @ref{Modeline} for details.
|
||||||
@item Normally, @code{M-x mu4e-context-switch} does not call the enter or
|
@item Normally, @code{M-x mu4e-context-switch} does not call the enter or
|
||||||
leave functions if the 'new' context is the same as the old one.
|
leave functions if the 'new' context is the same as the old one.
|
||||||
However, with a prefix-argument (@kbd{C-u}), you can force @t{mu4e} to
|
However, with a prefix-argument (@kbd{C-u}), you can force @t{mu4e} to
|
||||||
|
@ -2713,11 +2719,10 @@ work-email. You can achieve this with something like:
|
||||||
@noindent
|
@noindent
|
||||||
Good to remember:
|
Good to remember:
|
||||||
@itemize
|
@itemize
|
||||||
@item The @var{msg} parameter you receive in the function refers to the
|
@item The @code{msg} parameter you receive in the function refers to the
|
||||||
@emph{original message}, that is, the message being replied to or
|
@emph{original message}, that is, the message being replied to or forwarded.
|
||||||
forwarded. When re-editing a message, it refers to the message being
|
When re-editing a message, it refers to the message being edited. When you
|
||||||
edited. When you compose a totally new message, the @var{msg} parameter is
|
compose a totally new message, the @code{msg} parameter is @code{nil}.
|
||||||
@code{nil}.
|
|
||||||
@item When re-editing messages, the value of @code{mu4e-drafts-folder} is ignored.
|
@item When re-editing messages, the value of @code{mu4e-drafts-folder} is ignored.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
|
@ -3052,32 +3057,84 @@ see @code{mu4e-toggle-logging}.
|
||||||
@code{user-error} and @code{error} functions.
|
@code{user-error} and @code{error} functions.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
@node Other tools
|
@node Integrating with Emacs
|
||||||
@appendix Other tools
|
@chapter Integrating with Emacs
|
||||||
|
|
||||||
In this chapter, we discuss some ways in which @t{mu4e} can cooperate
|
In this chapter, we discuss how you can integrate @t{mu4e} with Emacs in various
|
||||||
with other tools.
|
ways. Here we focus on Emacs built-ins; for dealing with external tools,
|
||||||
|
@xref{Other tools}.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Emacs default::Making mu4e the default emacs e-mail program
|
* Modeline::Showing mu4e's status in the modeline
|
||||||
* Emacs bookmarks::Using Emacs' bookmark system
|
* Default email client::Making mu4e the default emacs e-mail program
|
||||||
|
* Using bookmarks::Using Emacs' bookmark system
|
||||||
* Org-mode links::Adding mu4e to your organized life
|
* Org-mode links::Adding mu4e to your organized life
|
||||||
* Org-contacts::Hooking up with org-contacts
|
|
||||||
* BBDB::Hooking up with the Insidious Big Brother Database
|
|
||||||
* iCalendar::Enabling iCalendar invite processing
|
* iCalendar::Enabling iCalendar invite processing
|
||||||
* Sauron::Getting new mail notifications with Sauron
|
|
||||||
* Speedbar::A special frame with your folders
|
* Speedbar::A special frame with your folders
|
||||||
* Dired:: Attaching files using @t{dired}
|
* Dired:: Attaching files using @t{dired}
|
||||||
* Hydra:: Custom shortcut menus
|
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Emacs default
|
@node Modeline
|
||||||
@section Emacs default
|
@section Modeline
|
||||||
|
@cindex modeline
|
||||||
|
|
||||||
Emacs allows you to select an e-mail program as the default
|
One of the most visible ways in which @t{mu4e} integrates with Emacs is through
|
||||||
program it uses when you press @key{C-x m} (@code{compose-mail}), call
|
the @emph{modeline} @xref{Mode Line,,,emacs}. The @t{mu4e} support for that is
|
||||||
@code{report-emacs-bug} and so on. If you want to use @t{mu4e} for this,
|
handled through a minor-mode @code{mu4e-modeline-mode}, which is enabled by
|
||||||
you can do so by adding the following to your configuration:
|
default when @t{mu4e} is running.
|
||||||
|
|
||||||
|
To completely turn off the modeline support, set @code{mu4e-support-modeline} to
|
||||||
|
@t{nil} before starting @t{mu4e}.
|
||||||
|
|
||||||
|
@t{mu4e} shares information on the modeline in two ways:
|
||||||
|
@itemize
|
||||||
|
@item buffer-specific: information about the search parameters and the current context
|
||||||
|
@item global: information about unread messages
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
The buffer-specific items should be fairly self-explanatory - they show,
|
||||||
|
respectively, your search parameters and the current context.
|
||||||
|
|
||||||
|
@cindex favorite bookmark
|
||||||
|
Since @t{mu4e} is a query-based email-client, there a lot of flexibilty in what
|
||||||
|
you want to consider ``interesting new mail'', that is the, the query we want to
|
||||||
|
monitor for changes.
|
||||||
|
|
||||||
|
The global modeline contains the results of some specific ``favorite'' bookmark
|
||||||
|
query from @code{mu4e-bookmarks}. By default, the @emph{first} one in chosen,
|
||||||
|
but you may want change that by using the @code{:favorite} property for a
|
||||||
|
particular query, e.g., as part of @var{mu4e-bookmarks}:
|
||||||
|
@example
|
||||||
|
;; Monitor the inbox folder in the modeline
|
||||||
|
(:query "maildir:/inbox" :name "Inbox" :key ?i :favorite t)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
The results of this query (the last time it was updated) is shows as some
|
||||||
|
character or emoji (depending on @var{mu4e-use-fancy-chars}) and 2 or 3 numbers,
|
||||||
|
just like what we saw in @xref{Bookmarks and Maildirs}, e.g.,
|
||||||
|
@example
|
||||||
|
N:10(+5)/15
|
||||||
|
@end example
|
||||||
|
|
||||||
|
@cindex baseline query results
|
||||||
|
this means there are 10 unread messages, with 5 new messages since the baseline,
|
||||||
|
and in total 15 messages.
|
||||||
|
|
||||||
|
You can also customize the icon; see @var{mu4e-modeline-all-clear},
|
||||||
|
@var{mu4e-modeline-all-read}, @var{mu4e-modeline-all-clear} and
|
||||||
|
@var{mu4e-modeline-all-clear}
|
||||||
|
|
||||||
|
Due to the way queries work, the modeline is @emph{not} immediately updated when
|
||||||
|
you read messages; but going back to the main view (with @kbd{M-x mu4e} restores
|
||||||
|
things.
|
||||||
|
|
||||||
|
@node Default email client
|
||||||
|
@section Default email client
|
||||||
|
|
||||||
|
Emacs allows you to select an e-mail program as the default program it uses when
|
||||||
|
you press @key{C-x m} (@code{compose-mail}), call @code{report-emacs-bug} and so
|
||||||
|
on. If you want to use @t{mu4e} for this, you can do so by adding the following
|
||||||
|
to your configuration:
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
(setq mail-user-agent 'mu4e-user-agent)
|
(setq mail-user-agent 'mu4e-user-agent)
|
||||||
|
@ -3092,15 +3149,15 @@ mail, customize the variable @code{read-mail-command}.
|
||||||
|
|
||||||
(@pxref{Top,,Emacs,Sending Mail, Mail Methods})
|
(@pxref{Top,,Emacs,Sending Mail, Mail Methods})
|
||||||
|
|
||||||
|
@node Using bookmarks
|
||||||
|
@section Using bookmarks
|
||||||
|
|
||||||
@node Emacs bookmarks
|
Note, emacs bookmarks are not to be confused with mu4e's bookmarks; the former
|
||||||
@section Emacs bookmarks
|
are a generic linking system, while the latter are remember stored queries.
|
||||||
|
|
||||||
@t{mu4e} supports linking to the message-at-point through the normal
|
|
||||||
Emacs built-in bookmark system. The links are based on the message's
|
|
||||||
message-id, and thus the bookmarks stay valid even if you move the
|
|
||||||
message around.
|
|
||||||
|
|
||||||
|
@t{mu4e} supports linking to the message-at-point through the normal Emacs
|
||||||
|
built-in bookmark system. The links are based on the message's message-id, and
|
||||||
|
thus the bookmarks stay valid even if you move the message around.
|
||||||
|
|
||||||
@node Org-mode links
|
@node Org-mode links
|
||||||
@section Org-mode links
|
@section Org-mode links
|
||||||
|
@ -3164,71 +3221,6 @@ key-bindings for that in headers and view mode:
|
||||||
(define-key mu4e-view-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
|
(define-key mu4e-view-mode-map (kbd "C-c c") 'mu4e-org-store-and-capture)
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
|
|
||||||
@node Org-contacts
|
|
||||||
@section Org-contacts
|
|
||||||
|
|
||||||
Note, @t{mu4e} supports built-in address autocompletion; @ref{Address
|
|
||||||
autocompletion}, and that is the recommended way to do this. However, it
|
|
||||||
is also possible to manage your addresses with @t{org-mode}, using
|
|
||||||
@t{org-contacts}@footnote{@url{https://julien.danjou.info/projects/emacs-packages#org-contacts}}.
|
|
||||||
|
|
||||||
@t{mu4e-actions} defines a useful action (@ref{Actions}) for adding a
|
|
||||||
contact based on the @t{From:}-address in the message at point. To
|
|
||||||
enable this, add to your configuration something like:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
(setq mu4e-org-contacts-file <full-path-to-your-org-contacts-file>)
|
|
||||||
(add-to-list 'mu4e-headers-actions
|
|
||||||
'("org-contact-add" . mu4e-action-add-org-contact) t)
|
|
||||||
(add-to-list 'mu4e-view-actions
|
|
||||||
'("org-contact-add" . mu4e-action-add-org-contact) t)
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
@noindent
|
|
||||||
After this, you should be able to add contacts using @key{a o} in the
|
|
||||||
headers view and the message view, using the @t{org-capture} mechanism.
|
|
||||||
Note, the shortcut character @key{o} is due to the first character of
|
|
||||||
@t{org-contact-add}.
|
|
||||||
|
|
||||||
@node BBDB
|
|
||||||
@section BBDB
|
|
||||||
|
|
||||||
Note, @t{mu4e} supports built-in address autocompletion; @ref{Address
|
|
||||||
autocompletion}, and that is the recommended way to do this. However, it
|
|
||||||
is also possible to manage your addresses with the current (2015-06-23)
|
|
||||||
development release of @t{BBDB}, or releases of @t{BBDB} after
|
|
||||||
3.1.2.@footnote{@url{https://savannah.nongnu.org/projects/bbdb/}}.
|
|
||||||
|
|
||||||
To enable BBDB, add to your @file{~/.emacs} (or its moral equivalent,
|
|
||||||
such as @file{~/.emacs.d/init.el}) the following @emph{after} the
|
|
||||||
@code{(require 'mu4e)} line:
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
;; Load BBDB (Method 1)
|
|
||||||
(require 'bbdb-loaddefs)
|
|
||||||
;; OR (Method 2)
|
|
||||||
;; (require 'bbdb-loaddefs "/path/to/bbdb/lisp/bbdb-loaddefs.el")
|
|
||||||
;; OR (Method 3)
|
|
||||||
;; (autoload 'bbdb-insinuate-mu4e "bbdb-mu4e")
|
|
||||||
;; (bbdb-initialize 'message 'mu4e)
|
|
||||||
|
|
||||||
(setq bbdb-mail-user-agent 'mu4e-user-agent)
|
|
||||||
(setq mu4e-view-rendered-hook 'bbdb-mua-auto-update)
|
|
||||||
(setq mu4e-compose-complete-addresses nil)
|
|
||||||
(setq bbdb-mua-pop-up t)
|
|
||||||
(setq bbdb-mua-pop-up-window-size 5)
|
|
||||||
(setq mu4e-view-show-addresses t)
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
@noindent
|
|
||||||
After this, you should be able to:
|
|
||||||
@itemize
|
|
||||||
@item In mu4e-view mode, add the sender of the email to BBDB with @key{C-u :}
|
|
||||||
@item Tab-complete addresses from BBDB when composing emails
|
|
||||||
@item View the BBDB contact while viewing a message
|
|
||||||
@end itemize
|
|
||||||
|
|
||||||
@node iCalendar
|
@node iCalendar
|
||||||
@section iCalendar
|
@section iCalendar
|
||||||
|
|
||||||
|
@ -3320,6 +3312,120 @@ functions use that to set the @code{datetree} location:
|
||||||
If you do this, you'll want to omit the @code{:timeprompt t} setting
|
If you do this, you'll want to omit the @code{:timeprompt t} setting
|
||||||
from your capture template.
|
from your capture template.
|
||||||
|
|
||||||
|
|
||||||
|
@node Speedbar
|
||||||
|
@section Speedbar
|
||||||
|
@cindex speedbar
|
||||||
|
|
||||||
|
@code{speedbar} is an Emacs-extension that shows navigational
|
||||||
|
information for an Emacs buffer in a separate frame. Using
|
||||||
|
@code{mu4e-speedbar}, @t{mu4e} lists your bookmarks and maildir
|
||||||
|
folders and allows for one-click access to them.
|
||||||
|
|
||||||
|
To enable this, add @t{(require 'mu4e-speedbar)} to your configuration;
|
||||||
|
then, all you need to do to activate it is @kbd{M-x speedbar}. Then,
|
||||||
|
when then switching to the @ref{Main view}, the speedbar-frame is
|
||||||
|
updated with your bookmarks and maildirs.
|
||||||
|
|
||||||
|
For speed reasons, the list of maildirs is determined when @t{mu4e}
|
||||||
|
starts; if the list of maildirs changes while @t{mu4e} is running, you
|
||||||
|
need to restart @t{mu4e} to have those changes reflected in the speedbar
|
||||||
|
and in other places that use this list, such as auto-completion when
|
||||||
|
jumping to a maildir.
|
||||||
|
|
||||||
|
@node Dired
|
||||||
|
@section Dired
|
||||||
|
|
||||||
|
It is possible to attach files to @t{mu4e} messages using @t{dired}
|
||||||
|
(@ref{Dired,,emacs}), using the following steps (based on a post on
|
||||||
|
the @t{mu-discuss} mailing list by @emph{Stephen Eglen}).
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
Then, mark the file(s) in @t{dired} you would like to attach and press
|
||||||
|
@t{C-c RET C-a}, and you'll be asked whether to attach them to an
|
||||||
|
existing message, or create a new one.
|
||||||
|
|
||||||
|
@node Other tools
|
||||||
|
@appendix Other tools
|
||||||
|
|
||||||
|
In this chapter, we discuss some ways in which @t{mu4e} can cooperate
|
||||||
|
with other tools.
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* Org-contacts::Hooking up with org-contacts
|
||||||
|
* BBDB::Hooking up with the Insidious Big Brother Database
|
||||||
|
* Sauron::Getting new mail notifications with Sauron
|
||||||
|
* Hydra:: Custom shortcut menus
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node Org-contacts
|
||||||
|
@section Org-contacts
|
||||||
|
|
||||||
|
Note, @t{mu4e} supports built-in address autocompletion; @ref{Address
|
||||||
|
autocompletion}, and that is the recommended way to do this. However, it
|
||||||
|
is also possible to manage your addresses with @t{org-mode}, using
|
||||||
|
@t{org-contacts}@footnote{@url{https://julien.danjou.info/projects/emacs-packages#org-contacts}}.
|
||||||
|
|
||||||
|
@t{mu4e-actions} defines a useful action (@ref{Actions}) for adding a
|
||||||
|
contact based on the @t{From:}-address in the message at point. To
|
||||||
|
enable this, add to your configuration something like:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
(setq mu4e-org-contacts-file <full-path-to-your-org-contacts-file>)
|
||||||
|
(add-to-list 'mu4e-headers-actions
|
||||||
|
'("org-contact-add" . mu4e-action-add-org-contact) t)
|
||||||
|
(add-to-list 'mu4e-view-actions
|
||||||
|
'("org-contact-add" . mu4e-action-add-org-contact) t)
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
After this, you should be able to add contacts using @key{a o} in the
|
||||||
|
headers view and the message view, using the @t{org-capture} mechanism.
|
||||||
|
Note, the shortcut character @key{o} is due to the first character of
|
||||||
|
@t{org-contact-add}.
|
||||||
|
|
||||||
|
@node BBDB
|
||||||
|
@section BBDB
|
||||||
|
|
||||||
|
Note, @t{mu4e} supports built-in address autocompletion; @ref{Address
|
||||||
|
autocompletion}, and that is the recommended way to do this. However, it
|
||||||
|
is also possible to manage your addresses with the current (2015-06-23)
|
||||||
|
development release of @t{BBDB}, or releases of @t{BBDB} after
|
||||||
|
3.1.2.@footnote{@url{https://savannah.nongnu.org/projects/bbdb/}}.
|
||||||
|
|
||||||
|
To enable BBDB, add to your @file{~/.emacs} (or its moral equivalent,
|
||||||
|
such as @file{~/.emacs.d/init.el}) the following @emph{after} the
|
||||||
|
@code{(require 'mu4e)} line:
|
||||||
|
|
||||||
|
@lisp
|
||||||
|
;; Load BBDB (Method 1)
|
||||||
|
(require 'bbdb-loaddefs)
|
||||||
|
;; OR (Method 2)
|
||||||
|
;; (require 'bbdb-loaddefs "/path/to/bbdb/lisp/bbdb-loaddefs.el")
|
||||||
|
;; OR (Method 3)
|
||||||
|
;; (autoload 'bbdb-insinuate-mu4e "bbdb-mu4e")
|
||||||
|
;; (bbdb-initialize 'message 'mu4e)
|
||||||
|
|
||||||
|
(setq bbdb-mail-user-agent 'mu4e-user-agent)
|
||||||
|
(setq mu4e-view-rendered-hook 'bbdb-mua-auto-update)
|
||||||
|
(setq mu4e-compose-complete-addresses nil)
|
||||||
|
(setq bbdb-mua-pop-up t)
|
||||||
|
(setq bbdb-mua-pop-up-window-size 5)
|
||||||
|
(setq mu4e-view-show-addresses t)
|
||||||
|
@end lisp
|
||||||
|
|
||||||
|
@noindent
|
||||||
|
After this, you should be able to:
|
||||||
|
@itemize
|
||||||
|
@item In mu4e-view mode, add the sender of the email to BBDB with @key{C-u :}
|
||||||
|
@item Tab-complete addresses from BBDB when composing emails
|
||||||
|
@item View the BBDB contact while viewing a message
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
|
||||||
@node Sauron
|
@node Sauron
|
||||||
@section Sauron
|
@section Sauron
|
||||||
|
|
||||||
|
@ -3377,40 +3483,6 @@ You might want to put:
|
||||||
in your setup, to allow the script to find the D-Bus session bus, even when
|
in your setup, to allow the script to find the D-Bus session bus, even when
|
||||||
running outside its session.
|
running outside its session.
|
||||||
|
|
||||||
@node Speedbar
|
|
||||||
@section Speedbar
|
|
||||||
|
|
||||||
@code{speedbar} is an Emacs-extension that shows navigational
|
|
||||||
information for an Emacs buffer in a separate frame. Using
|
|
||||||
@code{mu4e-speedbar}, @t{mu4e} lists your bookmarks and maildir
|
|
||||||
folders and allows for one-click access to them.
|
|
||||||
|
|
||||||
To enable this, add @t{(require 'mu4e-speedbar)} to your configuration;
|
|
||||||
then, all you need to do to activate it is @kbd{M-x speedbar}. Then,
|
|
||||||
when then switching to the @ref{Main view}, the speedbar-frame is
|
|
||||||
updated with your bookmarks and maildirs.
|
|
||||||
|
|
||||||
For speed reasons, the list of maildirs is determined when @t{mu4e}
|
|
||||||
starts; if the list of maildirs changes while @t{mu4e} is running, you
|
|
||||||
need to restart @t{mu4e} to have those changes reflected in the speedbar
|
|
||||||
and in other places that use this list, such as auto-completion when
|
|
||||||
jumping to a maildir.
|
|
||||||
|
|
||||||
@node Dired
|
|
||||||
@section Dired
|
|
||||||
|
|
||||||
It is possible to attach files to @t{mu4e} messages using @t{dired}
|
|
||||||
(@ref{Dired,,emacs}), using the following steps (based on a post on
|
|
||||||
the @t{mu-discuss} mailing list by @emph{Stephen Eglen}).
|
|
||||||
|
|
||||||
|
|
||||||
@lisp
|
|
||||||
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
|
|
||||||
@end lisp
|
|
||||||
|
|
||||||
Then, mark the file(s) in @t{dired} you would like to attach and press
|
|
||||||
@t{C-c RET C-a}, and you'll be asked whether to attach them to an
|
|
||||||
existing message, or create a new one.
|
|
||||||
|
|
||||||
@node Hydra
|
@node Hydra
|
||||||
@section Hydra
|
@section Hydra
|
||||||
|
@ -3439,8 +3511,8 @@ With Hydra installed, we can add multi-character shortcuts, for instance:
|
||||||
Now, you can bind a convenient key to my-mu4e-bookmarks/body.
|
Now, you can bind a convenient key to my-mu4e-bookmarks/body.
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
@node Example configs
|
@node Example configurations
|
||||||
@appendix Example configs
|
@appendix Example configurations
|
||||||
|
|
||||||
In this chapter, we show some example configurations. While it is very useful
|
In this chapter, we show some example configurations. While it is very useful
|
||||||
to see some working settings, we'd like to warn against blindly copying such
|
to see some working settings, we'd like to warn against blindly copying such
|
||||||
|
@ -3511,7 +3583,7 @@ customize.
|
||||||
mu4e-trash-folder "/trash")
|
mu4e-trash-folder "/trash")
|
||||||
|
|
||||||
;; the maildirs you use frequently; access them with 'j' ('jump')
|
;; the maildirs you use frequently; access them with 'j' ('jump')
|
||||||
(setq mu4e-maildir-shortcuts
|
(setq mu4e-maildir-shortcuts
|
||||||
'((:maildir "/archive" :key ?a)
|
'((:maildir "/archive" :key ?a)
|
||||||
(:maildir "/inbox" :key ?i)
|
(:maildir "/inbox" :key ?i)
|
||||||
(:maildir "/work" :key ?w)
|
(:maildir "/work" :key ?w)
|
||||||
|
@ -3527,6 +3599,10 @@ customize.
|
||||||
(:from . 22)
|
(:from . 22)
|
||||||
(:subject . nil))) ;; alternatively, use :thread-subject
|
(:subject . nil))) ;; alternatively, use :thread-subject
|
||||||
|
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
;; ':favorite t' i.e, use this one for the modeline
|
||||||
|
'(:query "maildir:/inbox" :name "Inbox" :key ?i :favorite t))
|
||||||
|
|
||||||
;; program to get mail; alternatives are 'fetchmail', 'getmail'
|
;; program to get mail; alternatives are 'fetchmail', 'getmail'
|
||||||
;; isync or your own shellscript. called when 'U' is pressed in
|
;; isync or your own shellscript. called when 'U' is pressed in
|
||||||
;; main view.
|
;; main view.
|
||||||
|
@ -3688,6 +3764,10 @@ Next step: let's make a @t{mu4e} configuration for this:
|
||||||
(:maildir "/[Gmail].Trash" :key ?t)
|
(:maildir "/[Gmail].Trash" :key ?t)
|
||||||
(:maildir "/[Gmail].All Mail" :key ?a)))
|
(:maildir "/[Gmail].All Mail" :key ?a)))
|
||||||
|
|
||||||
|
(add-to-list 'mu4e-bookmarks
|
||||||
|
;; ':favorite t' i.e, use this one for the modeline
|
||||||
|
'(:query "maildir:/inbox" :name "Inbox" :key ?i :favorite t))
|
||||||
|
|
||||||
;; allow for updating mail using 'U' in the main view:
|
;; allow for updating mail using 'U' in the main view:
|
||||||
(setq mu4e-get-mail-command "offlineimap")
|
(setq mu4e-get-mail-command "offlineimap")
|
||||||
|
|
||||||
|
@ -3801,7 +3881,7 @@ Yes you can --- see the documentation for the variable
|
||||||
@t{mu4e-headers-leave-behavior}.
|
@t{mu4e-headers-leave-behavior}.
|
||||||
|
|
||||||
@subsection How can I set @t{mu4e} as the default e-mail client in Emacs?
|
@subsection How can I set @t{mu4e} as the default e-mail client in Emacs?
|
||||||
See @ref{Emacs default}.
|
See @ref{Default email client}.
|
||||||
|
|
||||||
@subsection Can @t{mu4e} use some fancy Unicode instead of these boring plain-ASCII ones?
|
@subsection Can @t{mu4e} use some fancy Unicode instead of these boring plain-ASCII ones?
|
||||||
Glad you asked! Yes, if you set @code{mu4e-use-fancy-chars} to @t{t},
|
Glad you asked! Yes, if you set @code{mu4e-use-fancy-chars} to @t{t},
|
||||||
|
@ -4619,7 +4699,7 @@ to provide this information (this is implemented in
|
||||||
@file{mu-cmd-server.c}).
|
@file{mu-cmd-server.c}).
|
||||||
|
|
||||||
We start this sequence when @t{mu4e} is invoked (when the program is
|
We start this sequence when @t{mu4e} is invoked (when the program is
|
||||||
started). It calls @t{mu4e-server-ping}, and registers a (lambda)
|
started). It calls @t{mu4e--server-ping}, and registers a (lambda)
|
||||||
function for @t{mu4e-server-pong-func}, to handle the response.
|
function for @t{mu4e-server-pong-func}, to handle the response.
|
||||||
|
|
||||||
@verbatim
|
@verbatim
|
||||||
|
@ -4667,9 +4747,9 @@ it on all the time. By default, the log only maintains the most recent
|
||||||
@c @unnumbered Variable Index
|
@c @unnumbered Variable Index
|
||||||
@c @printindex vr
|
@c @printindex vr
|
||||||
|
|
||||||
@c @node Concept Index
|
@node Concept Index
|
||||||
@c @unnumbered Concept Index
|
@unnumbered Concept Index
|
||||||
@c @printindex cp
|
@printindex cp
|
||||||
|
|
||||||
@bye
|
@bye
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue