X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch.el;h=040997eeaf00eaf4e1cf5a3c604a8fcdf0bb9f71;hp=c2e0899e5c8e7a1787c179439a530a6952127423;hb=2174adf374370135061bd80db21cbd43bbac95ab;hpb=78c85f053b28be0ed6c42981bc028739a98d3d93 diff --git a/notmuch.el b/notmuch.el index c2e0899e..040997ee 100644 --- a/notmuch.el +++ b/notmuch.el @@ -94,9 +94,27 @@ for indentation at the beginning of the line. But notmuch will move past the indentation when testing this pattern, (so that the pattern can still test against the entire line).") +(defvar notmuch-show-signature-button-format + "[ %d-line signature. Click/Enter to toggle visibility. ]" + "String used to construct button text for hidden signatures + +Can use up to one integer format parameter, i.e. %d") + +(defvar notmuch-show-citation-button-format + "[ %d more citation lines. Click/Enter to toggle visibility. ]" + "String used to construct button text for hidden citations. + +Can use up to one integer format parameter, i.e. %d") + (defvar notmuch-show-signature-lines-max 12 "Maximum length of signature that will be hidden by default.") +(defvar notmuch-show-citation-lines-prefix 4 + "Always show at least this many lines of a citation. + +If there is one more line, show that, otherwise collapse +remaining lines into a button.") + (defvar notmuch-command "notmuch" "Command to run the notmuch binary.") @@ -115,6 +133,8 @@ pattern can still test against the entire line).") (defvar notmuch-show-id-regexp "\\(id:[^ ]*\\)") (defvar notmuch-show-depth-match-regexp " depth:\\([0-9]*\\).*match:\\([01]\\) ") (defvar notmuch-show-filename-regexp "filename:\\(.*\\)$") +(defvar notmuch-show-contentype-regexp "Content-type: \\(.*\\)") + (defvar notmuch-show-tags-regexp "(\\([^)]*\\))$") (defvar notmuch-show-parent-buffer nil) @@ -301,13 +321,28 @@ buffer." (with-current-buffer buf (insert-file-contents filename nil nil nil t) ,@body) - (kill-buffer buf))))) + (kill-buffer buf))))) (defun notmuch-show-view-all-mime-parts () "Use external viewers to view all attachments from the current message." (interactive) (with-current-notmuch-show-message - (mm-display-parts (mm-dissect-buffer)))) + ; We ovverride the mm-inline-media-tests to indicate which message + ; parts are already sufficiently handled by the original + ; presentation of the message in notmuch-show mode. These parts + ; will be inserted directly into the temporary buffer of + ; with-current-notmuch-show-message and silently discarded. + ; + ; Any MIME part not explicitly mentioned here will be handled by an + ; external viewer as configured in the various mailcap files. + (let ((mm-inline-media-tests '( + ("text/.*" ignore identity) + ("application/pgp-signature" ignore identity) + ("multipart/alternative" ignore identity) + ("multipart/mixed" ignore identity) + ("multipart/related" ignore identity) + ))) + (mm-display-parts (mm-dissect-buffer))))) (defun notmuch-foreach-mime-part (function mm-handle) (cond ((stringp (car mm-handle)) @@ -564,12 +599,12 @@ which this thread was originally shown." (defun notmuch-show-next-button () "Advance point to the next button in the buffer." (interactive) - (goto-char (button-start (next-button (point))))) + (forward-button 1)) (defun notmuch-show-previous-button () "Move point back to the previous button in the buffer." (interactive) - (goto-char (button-start (previous-button (point))))) + (backward-button 1)) (defun notmuch-toggle-invisible-action (cite-button) (let ((invis-spec (button-get cite-button 'invisibility-spec))) @@ -604,7 +639,7 @@ which this thread was originally shown." (define-button-type 'notmuch-button-invisibility-toggle-type 'action 'notmuch-toggle-invisible-action 'follow-link t - 'face "default") + 'face 'font-lock-comment-face) (define-button-type 'notmuch-button-citation-toggle-type 'help-echo "mouse-1, RET: Show citation" :supertype 'notmuch-button-invisibility-toggle-type) (define-button-type 'notmuch-button-signature-toggle-type 'help-echo "mouse-1, RET: Show signature" @@ -616,71 +651,123 @@ which this thread was originally shown." 'face 'notmuch-message-summary-face :supertype 'notmuch-button-invisibility-toggle-type) +(defun notmuch-show-citation-regexp (depth) + "Build a regexp for matching citations at a given DEPTH (indent)" + (let ((line-regexp (format "[[:space:]]\\{%d\\}>.*\n" depth))) + (concat "\\(?:^" line-regexp + "\\(?:[[:space:]]*\n" line-regexp + "\\)?\\)+"))) + +(defun notmuch-show-region-to-button (beg end type prefix button-text) + "Auxilary function to do the actual making of overlays and buttons + +BEG and END are buffer locations. TYPE should a string, either +\"citation\" or \"signature\". PREFIX is some arbitrary text to +insert before the button, probably for indentation. BUTTON-TEXT +is what to put on the button." + +;; This uses some slightly tricky conversions between strings and +;; symbols because of the way the button code works. Note that +;; replacing intern-soft with make-symbol will cause this to fail, +;; since the newly created symbol has no plist. + + (let ((overlay (make-overlay beg end)) + (invis-spec (make-symbol (concat "notmuch-" type "-region"))) + (button-type (intern-soft (concat "notmuch-button-" + type "-toggle-type")))) + (add-to-invisibility-spec invis-spec) + (overlay-put overlay 'invisible invis-spec) + (goto-char (1+ end)) + (save-excursion + (goto-char (1- beg)) + (insert prefix) + (insert-button button-text + 'invisibility-spec invis-spec + :type button-type) + ))) + + (defun notmuch-show-markup-citations-region (beg end depth) - (goto-char beg) - (beginning-of-line) - (while (< (point) end) - (let ((beg-sub (point-marker)) - (indent (make-string depth ? )) - (citation ">")) - (move-to-column depth) - (if (looking-at citation) - (progn - (while (looking-at citation) - (forward-line) - (move-to-column depth)) - (let ((overlay (make-overlay beg-sub (point))) - (invis-spec (make-symbol "notmuch-citation-region"))) - (add-to-invisibility-spec invis-spec) - (overlay-put overlay 'invisible invis-spec) - (let ((p (point-marker)) - (cite-button-text - (concat "[" (number-to-string (count-lines beg-sub (point))) - "-line citation. Click/Enter to show.]"))) - (goto-char (- beg-sub 1)) - (insert (concat "\n" indent)) - (insert-button cite-button-text - 'invisibility-spec invis-spec - :type 'notmuch-button-citation-toggle-type) - (forward-line) - )))) - (move-to-column depth) - (if (looking-at notmuch-show-signature-regexp) - (let ((sig-lines (- (count-lines beg-sub end) 1))) - (if (<= sig-lines notmuch-show-signature-lines-max) - (progn - (let ((invis-spec (make-symbol "notmuch-signature-region"))) - (add-to-invisibility-spec invis-spec) - (overlay-put (make-overlay beg-sub end) - 'invisible invis-spec) - - (goto-char (- beg-sub 1)) - (insert (concat "\n" indent)) - (let ((sig-button-text (concat "[" (number-to-string sig-lines) - "-line signature. Click/Enter to show.]"))) - (insert-button sig-button-text 'invisibility-spec invis-spec - :type 'notmuch-button-signature-toggle-type) - ) - (insert "\n") - (goto-char end)))))) - (forward-line)))) + "Markup citations, and up to one signature in the given region" + ;; it would be nice if the untabify was not required, but + ;; that would require notmuch to indent with spaces. + (untabify beg end) + (let ((citation-regexp (notmuch-show-citation-regexp depth)) + (signature-regexp (concat (format "^[[:space:]]\\{%d\\}" depth) + notmuch-show-signature-regexp)) + (indent (concat "\n" (make-string depth ? )))) + (goto-char beg) + (beginning-of-line) + (while (and (< (point) end) + (re-search-forward citation-regexp end t)) + (let* ((cite-start (match-beginning 0)) + (cite-end (match-end 0)) + (cite-lines (count-lines cite-start cite-end))) + (when (> cite-lines (1+ notmuch-show-citation-lines-prefix)) + (goto-char cite-start) + (forward-line notmuch-show-citation-lines-prefix) + (notmuch-show-region-to-button + (point) cite-end + "citation" + indent + (format notmuch-show-citation-button-format + (- cite-lines notmuch-show-citation-lines-prefix)) + )))) + (if (and (< (point) end) + (re-search-forward signature-regexp end t)) + (let* ((sig-start (match-beginning 0)) + (sig-end (match-end 0)) + (sig-lines (1- (count-lines sig-start end)))) + (if (<= sig-lines notmuch-show-signature-lines-max) + (notmuch-show-region-to-button + sig-start + end + "signature" + indent + (format notmuch-show-signature-button-format sig-lines) + )))))) (defun notmuch-show-markup-part (beg end depth) (if (re-search-forward notmuch-show-part-begin-regexp nil t) (progn - (forward-line) - (let ((beg (point-marker))) - (re-search-forward notmuch-show-part-end-regexp) - (let ((end (copy-marker (match-beginning 0)))) - (goto-char end) - (if (not (bolp)) - (insert "\n")) - (indent-rigidly beg end depth) - (notmuch-show-markup-citations-region beg end depth) - ; Advance to the next part (if any) (so the outer loop can - ; determine whether we've left the current message. - (if (re-search-forward notmuch-show-part-begin-regexp nil t) - (beginning-of-line))))) + (let (mime-message mime-type) + (save-excursion + (re-search-forward notmuch-show-contentype-regexp end t) + (setq mime-type (car (split-string (buffer-substring + (match-beginning 1) (match-end 1)))))) + + (if (equal mime-type "text/html") + (let ((filename (notmuch-show-get-filename))) + (with-temp-buffer + (insert-file-contents filename nil nil nil t) + (setq mime-message (mm-dissect-buffer))))) + (forward-line) + (let ((beg (point-marker))) + (re-search-forward notmuch-show-part-end-regexp) + (let ((end (copy-marker (match-beginning 0)))) + (goto-char end) + (if (not (bolp)) + (insert "\n")) + (indent-rigidly beg end depth) + (if (not (eq mime-message nil)) + (save-excursion + (goto-char beg) + (forward-line -1) + (let ((handle-type (mm-handle-type mime-message)) + mime-type) + (if (sequencep (car handle-type)) + (setq mime-type (car handle-type)) + (setq mime-type (car (car (cdr handle-type)))) + ) + (if (equal mime-type "text/html") + (mm-display-part mime-message)))) + ) + (notmuch-show-markup-citations-region beg end depth) + ; Advance to the next part (if any) (so the outer loop can + ; determine whether we've left the current message. + (if (re-search-forward notmuch-show-part-begin-regexp nil t) + (beginning-of-line))))) + (goto-char end)) (goto-char end))) (defun notmuch-show-markup-parts-region (beg end depth) @@ -961,7 +1048,7 @@ The optional PARENT-BUFFER is the notmuch-search buffer from which this notmuch-show command was executed, (so that the next thread from that buffer can be show when done with this one). -The optional QUERY-CONTEXT is a notmuch search term. Only messages from the thread +The optional QUERY-CONTEXT is a notmuch search term. Only messages from the thread matching this search term are shown if non-nil. " (interactive "sNotmuch show: ") (let ((buffer (get-buffer-create (concat "*notmuch-show-" thread-id "*")))) @@ -1401,12 +1488,15 @@ current search results AND that are tagged with the given tag." (define-key map "?" 'notmuch-help) (define-key map "x" 'kill-this-buffer) (define-key map "q" 'kill-this-buffer) + (define-key map "m" 'message-mail) + (define-key map "e" 'notmuch-folder-show-empty-toggle) (define-key map ">" 'notmuch-folder-last) (define-key map "<" 'notmuch-folder-first) (define-key map "=" 'notmuch-folder) (define-key map "s" 'notmuch-search) (define-key map [mouse-1] 'notmuch-folder-show-search) (define-key map (kbd "RET") 'notmuch-folder-show-search) + (define-key map " " 'notmuch-folder-show-search) (define-key map "p" 'notmuch-folder-previous) (define-key map "n" 'notmuch-folder-next) map) @@ -1476,22 +1566,40 @@ Currently available key bindings: (goto-char (point-max)) (forward-line -1)) +(defun notmuch-folder-count (search) + (car (process-lines notmuch-command "count" search))) + +(setq notmuch-folder-show-empty t) + +(defun notmuch-folder-show-empty-toggle () + "Toggle the listing of empty folders" + (interactive) + (setq notmuch-folder-show-empty (not notmuch-folder-show-empty)) + (notmuch-folder)) + (defun notmuch-folder-add (folders) (if folders - (let ((name (car (car folders))) + (let* ((name (car (car folders))) (inhibit-read-only t) - (search (cdr (car folders)))) - (insert name) - (indent-to 16 1) - (call-process notmuch-command nil t nil "count" search) + (search (cdr (car folders))) + (count (notmuch-folder-count search))) + (if (or notmuch-folder-show-empty + (not (equal count "0"))) + (progn + (insert name) + (indent-to 16 1) + (insert count) + (insert "\n") + ) + ) (notmuch-folder-add (cdr folders))))) (defun notmuch-folder-find-name () (save-excursion (beginning-of-line) (let ((beg (point))) - (forward-word) - (filter-buffer-substring beg (point))))) + (re-search-forward "\\([ \t]*[^ \t]+\\)") + (filter-buffer-substring (match-beginning 1) (match-end 1))))) (defun notmuch-folder-show-search (&optional folder) "Show a search window for the search related to the specified folder."