]> git.notmuchmail.org Git - notmuch/blobdiff - emacs/notmuch-wash.el
Use different labels for wash buttons when text is visible or hidden.
[notmuch] / emacs / notmuch-wash.el
index 5ca567f59be6ad1cc43a4864253e1e9f44979012..8455eee0998f05e6e22bd2b81ee050cdcc29f698 100644 (file)
@@ -1,6 +1,7 @@
 ;; notmuch-wash.el --- cleaning up message bodies
 ;;
 ;; Copyright © Carl Worth
+;; Copyright © David Edmondson
 ;;
 ;; This file is part of Notmuch.
 ;;
 ;; along with Notmuch.  If not, see <http://www.gnu.org/licenses/>.
 ;;
 ;; Authors: Carl Worth <cworth@cworth.org>
+;;          David Edmondson <dme@dme.org>
+
+(require 'coolj)
+
+(declare-function notmuch-show-insert-bodypart "notmuch-show" (msg part depth))
+
+;;
 
 (defvar notmuch-wash-signature-regexp
   "^\\(-- ?\\|_+\\)$"
   "\\(^[[:space:]]*>.*\n\\)+"
   "Pattern to match citation lines.")
 
-(defvar notmuch-wash-signature-button-format
-  "[ %d-line signature. Click/Enter to toggle visibility. ]"
+(defvar notmuch-wash-button-signature-hidden-format
+  "[ %d-line signature. Click/Enter to show. ]"
   "String used to construct button text for hidden signatures.
 Can use up to one integer format parameter, i.e. %d")
 
-(defvar notmuch-wash-citation-button-format
-  "[ %d more citation lines. Click/Enter to toggle visibility. ]"
+(defvar notmuch-wash-button-signature-visible-format
+  "[ %d-line signature. Click/Enter to hide. ]"
+  "String used to construct button text for visible signatures.
+Can use up to one integer format parameter, i.e. %d")
+
+(defvar notmuch-wash-button-citation-hidden-format
+  "[ %d more citation lines. Click/Enter to show. ]"
   "String used to construct button text for hidden citations.
 Can use up to one integer format parameter, i.e. %d")
 
+(defvar notmuch-wash-button-citation-visible-format
+  "[ %d more citation lines. Click/Enter to hide. ]"
+  "String used to construct button text for visible citations.
+Can use up to one integer format parameter, i.e. %d")
+
 (defvar notmuch-wash-signature-lines-max 12
   "Maximum length of signature that will be hidden by default.")
 
@@ -61,6 +79,16 @@ collapse the remaining lines into a button.")
     (if (invisible-p invis-spec)
        (remove-from-invisibility-spec invis-spec)
       (add-to-invisibility-spec invis-spec)))
+  (let* ((new-start (button-start cite-button))
+        (overlay (button-get cite-button 'overlay))
+        (button-label (notmuch-wash-button-label overlay))
+        (inhibit-read-only t))
+    (save-excursion
+      (goto-char new-start)
+      (insert button-label)
+      (let ((old-end (button-end cite-button)))
+       (move-overlay cite-button new-start (point))
+       (delete-region (point) old-end))))
   (force-window-update)
   (redisplay t))
 
@@ -80,13 +108,21 @@ collapse the remaining lines into a button.")
 (defun notmuch-wash-region-isearch-show (overlay)
   (remove-from-invisibility-spec (overlay-get overlay 'invisible)))
 
-(defun notmuch-wash-region-to-button (beg end type prefix button-text)
+(defun notmuch-wash-button-label (overlay)
+  (let* ((type (overlay-get overlay 'type))
+        (invis-spec (overlay-get overlay 'invisible))
+        (state (if (invisible-p invis-spec) "hidden" "visible"))
+        (label-format (symbol-value (intern-soft (concat "notmuch-wash-button-"
+                                                         type "-" state "-format"))))
+        (lines-count (count-lines (overlay-start overlay) (overlay-end overlay))))
+    (format label-format lines-count)))
+
+(defun notmuch-wash-region-to-button (beg end type prefix)
   "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."
+insert before the button, probably for indentation."
 
   ;; This uses some slightly tricky conversions between strings and
   ;; symbols because of the way the button code works. Note that
@@ -100,16 +136,18 @@ is what to put on the button."
     (add-to-invisibility-spec invis-spec)
     (overlay-put overlay 'invisible invis-spec)
     (overlay-put overlay 'isearch-open-invisible #'notmuch-wash-region-isearch-show)
+    (overlay-put overlay 'type type)
     (goto-char (1+ end))
     (save-excursion
       (goto-char (1- beg))
       (insert prefix)
-      (insert-button button-text
+      (insert-button (notmuch-wash-button-label overlay)
                     'invisibility-spec invis-spec
+                    'overlay overlay
                     :type button-type))))
 
-(defun notmuch-wash-text/plain-citations (depth)
-  "Markup citations, and up to one signature in the buffer."
+(defun notmuch-wash-excerpt-citations (depth)
+  "Excerpt citations and up to one signature."
   (goto-char (point-min))
   (beginning-of-line)
   (while (and (< (point) (point-max))
@@ -128,16 +166,12 @@ is what to put on the button."
          (forward-line (- notmuch-wash-citation-lines-suffix))
          (notmuch-wash-region-to-button
           hidden-start (point-marker)
-          "citation" "\n"
-          (format notmuch-wash-citation-button-format
-                  (- cite-lines
-                     notmuch-wash-citation-lines-prefix
-                     notmuch-wash-citation-lines-suffix)))))))
+          "citation" "\n")))))
   (if (and (not (eobp))
           (re-search-forward notmuch-wash-signature-regexp nil t))
       (let* ((sig-start (match-beginning 0))
             (sig-end (match-end 0))
-            (sig-lines (1- (count-lines sig-start (point-max)))))
+            (sig-lines (count-lines sig-start (point-max))))
        (if (<= sig-lines notmuch-wash-signature-lines-max)
            (let ((sig-start-marker (make-marker))
                  (sig-end-marker (make-marker)))
@@ -146,8 +180,117 @@ is what to put on the button."
              (overlay-put (make-overlay sig-start-marker sig-end-marker) 'face 'message-cited-text-face)
              (notmuch-wash-region-to-button
               sig-start-marker sig-end-marker
-              "signature" "\n"
-              (format notmuch-wash-signature-button-format sig-lines)))))))
+              "signature" "\n"))))))
+
+;;
+
+(defun notmuch-wash-elide-blank-lines (depth)
+  "Elide leading, trailing and successive blank lines."
+
+  ;; Algorithm derived from `article-strip-multiple-blank-lines' in
+  ;; `gnus-art.el'.
+
+  ;; Make all blank lines empty.
+  (goto-char (point-min))
+  (while (re-search-forward "^[[:space:]\t]+$" nil t)
+    (replace-match "" nil t))
+
+  ;; Replace multiple empty lines with a single empty line.
+  (goto-char (point-min))
+  (while (re-search-forward "^\n\\(\n+\\)" nil t)
+    (delete-region (match-beginning 1) (match-end 1)))
+
+  ;; Remove a leading blank line.
+  (goto-char (point-min))
+  (if (looking-at "\n")
+      (delete-region (match-beginning 0) (match-end 0)))
+
+  ;; Remove a trailing blank line.
+  (goto-char (point-max))
+  (if (looking-at "\n")
+      (delete-region (match-beginning 0) (match-end 0))))
+
+;;
+
+(defun notmuch-wash-tidy-citations (depth)
+  "Improve the display of cited regions of a message.
+
+Perform several transformations on the message body:
+
+- Remove lines of repeated citation leaders with no other
+  content,
+- Remove citation leaders standing alone before a block of cited
+  text,
+- Remove citation trailers standing alone after a block of cited
+  text."
+
+  ;; Remove lines of repeated citation leaders with no other content.
+  (goto-char (point-min))
+  (while (re-search-forward "\\(^>[> ]*\n\\)\\{2,\\}" nil t)
+    (replace-match "\\1"))
+
+  ;; Remove citation leaders standing alone before a block of cited
+  ;; text.
+  (goto-char (point-min))
+  (while (re-search-forward "\\(\n\\|^[^>].*\\)\n\\(^>[> ]*\n\\)" nil t)
+    (replace-match "\\1\n"))
+
+  ;; Remove citation trailers standing alone after a block of cited
+  ;; text.
+  (goto-char (point-min))
+  (while (re-search-forward "\\(^>[> ]*\n\\)\\(^$\\|^[^>].*\\)" nil t)
+    (replace-match "\\2")))
+
+;;
+
+(defun notmuch-wash-wrap-long-lines (depth)
+  "Wrap any long lines in the message to the width of the window.
+
+When doing so, maintaining citation leaders in the wrapped text."
+
+  (let ((coolj-wrap-follows-window-size nil)
+       (fill-column (- (window-width)
+                       depth
+                       ;; 2 to avoid poor interaction with
+                       ;; `word-wrap'.
+                       2)))
+    (coolj-wrap-region (point-min) (point-max))))
+
+;;
+
+(require 'diff-mode)
+
+(defvar diff-file-header-re) ; From `diff-mode.el'.
+
+(defun notmuch-wash-convert-inline-patch-to-part (depth)
+  "Convert an inline patch into a fake 'text/x-diff' attachment.
+
+Given that this function guesses whether a buffer includes a
+patch and then guesses the extent of the patch, there is scope
+for error."
+
+  (goto-char (point-min))
+  (if (re-search-forward diff-file-header-re nil t)
+      (progn
+       (beginning-of-line -1)
+       (let ((patch-start (point))
+             (patch-end (point-max))
+             part)
+         (goto-char patch-start)
+         (if (or
+              ;; Patch ends with signature.
+              (re-search-forward notmuch-wash-signature-regexp nil t)
+              ;; Patch ends with bugtraq comment.
+              (re-search-forward "^\\*\\*\\* " nil t))
+             (setq patch-end (match-beginning 0)))
+         (save-restriction
+           (narrow-to-region patch-start patch-end)
+           (setq part (plist-put part :content-type "text/x-diff"))
+           (setq part (plist-put part :content (buffer-string)))
+           (setq part (plist-put part :id -1))
+           (setq part (plist-put part :filename "inline patch"))
+           (delete-region (point-min) (point-max))
+           (notmuch-show-insert-bodypart nil part depth))))))
 
 ;;