From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by arlo.cworth.org (Postfix) with ESMTP id 7C9936DE0F22 for ; Thu, 21 Mar 2019 07:43:46 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at cworth.org X-Spam-Flag: NO X-Spam-Score: -0.201 X-Spam-Level: X-Spam-Status: No, score=-0.201 tagged_above=-999 required=5 tests=[DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_PASS=-0.001] autolearn=disabled Received: from arlo.cworth.org ([127.0.0.1]) by localhost (arlo.cworth.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id nsVCykfJvkH9 for ; Thu, 21 Mar 2019 07:43:45 -0700 (PDT) Received: from mail-ed1-f52.google.com (mail-ed1-f52.google.com [209.85.208.52]) by arlo.cworth.org (Postfix) with ESMTPS id EC36C6DE0F2E for ; Thu, 21 Mar 2019 07:43:44 -0700 (PDT) Received: by mail-ed1-f52.google.com with SMTP id m16so5180954edd.12 for ; Thu, 21 Mar 2019 07:43:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version; bh=Bbite7w2k4uFIquqhwxcZx3cSDFkkyj22AygEnxanBA=; b=oXoW2w1v7E85KWImdGDk0ec6G8mWuoNDiopN8hx2UDLrN0wmo6zYl4S4KzZ1jZHzoi a3Il/61Lb23ViYOOxTq5bItxvbDvXE9YDLwGbzZxlm30irkbfO7ZwbhdZBsRUkJzTjGc sVXvB8qSxrkxJivw5JxI86q8MUp0Qpw+RTBb09ZNo3Pa86z7qP8rhzS6YGTzlTFclSR9 x7VLuVGntoFiwwESYa4tB34Yfnfnf5Sw7ZpvrFW9kzA3BAZn+n9XFC5W8oz3o96BV3+D FUX4st1+hI9Cj5gerIIj3wBf7ttRd3pGVnIbhoUIZyZ143ZpEWY4JWOTJnflOabG5xYS zkbQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version; bh=Bbite7w2k4uFIquqhwxcZx3cSDFkkyj22AygEnxanBA=; b=Rg00nhgLcM5XAVHwP7P+V3b7TQO0nGZLb9iWSDeGoJvSh/JsxcyYeDJ4HQdRn1Cf9M pcFEzh3AcToL9qaqQv6cokNovK/e/wOq7LDGB4oqNbox8Rz5bb9hKS9gxPAgAd+ZS/4L 4u/a3BkmQFhb8kys9O3b0NsZeyzOwGxLkmWYTg/msY5W7SWFlxaG8py2pebOzu1iAxZe zF/E3A5P7sSXum5YuPed5ro4sxEyWkWHQ9FEGl8LlBP2fxC2C17isPiyP+xLgzgx8BqV rPl1Km1E6lRLXWebF35oQcYHVdOd1DF6f+LuDaKxQ5hJYYdIXrOwtXqBja9c55sITtPW zVpw== X-Gm-Message-State: APjAAAVHy8mrRPE9a4T9/P4POEAvXgBAbNK6qhLLY6fUQ/yYr7TyiRtx coI8w+lJpRI9KWfvm53c7RFIOfL2B5k= X-Google-Smtp-Source: APXvYqxZiX+aa+Qd3H6HWAKix+HulZX9o2D5dmZ5x4QPwyiASOCpot+c12RqGxip2bnkB26QEUTEOg== X-Received: by 2002:a17:906:63ca:: with SMTP id u10mr2542454ejk.127.1553179422485; Thu, 21 Mar 2019 07:43:42 -0700 (PDT) Received: from localhost ([2620:10d:c092:180::1:49b]) by smtp.gmail.com with ESMTPSA id w9sm1789312edw.41.2019.03.21.07.43.41 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 21 Mar 2019 07:43:41 -0700 (PDT) From: Julien Masson To: notmuch@notmuchmail.org Cc: Subject: [PATCH] emacs: tree: support fold/unfold thread Date: Thu, 21 Mar 2019 15:26:44 +0100 Message-ID: <86h8bwgueb.fsf@julienm-ubuntu-20JES0UQ00.i-did-not-set--mail-host-address--so-tickle-me> MIME-Version: 1.0 Content-Type: text/plain X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Mar 2019 14:43:46 -0000 This patch allow the user to fold/unfold a thread in the current tree buffer by pressing "t" key. By default a string is displayed at the beginning of the overlay to indicate that this thread is folded. Pressing again "t" on a folded thread will unfold it. This feature works accross all the queries which are in Tree View. Signed-off-by: Julien Masson --- I started to write this feature only for myself and some people around me were interested so I thought it might be interesting to share with you as well :) Please tell me if you want to change some default value: -> notmuch-tree-overlay-string -> notmuch-tree-overlay-fold-face -> "t" key bind to notmuch-tree-toggle-folding-thread I personnaly bind to notmuch-tree-toggle-folding-thread emacs/notmuch-tree.el | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el index c00315e..7227692 100644 --- a/emacs/notmuch-tree.el +++ b/emacs/notmuch-tree.el @@ -71,6 +71,11 @@ Note the author string should not contain :type '(alist :key-type (string) :value-type (string)) :group 'notmuch-tree) +(defcustom notmuch-tree-overlay-string " [...]" + "String displayed at the beginning of the overlay" + :type 'string + :group 'notmuch-tree) + ;; Faces for messages that match the query. (defface notmuch-tree-match-face '((t :inherit default)) @@ -159,6 +164,13 @@ Note the author string should not contain :group 'notmuch-tree :group 'notmuch-faces) +;; Faces for overlays +(defface notmuch-tree-overlay-fold-face + '((t :inherit 'font-lock-keyword-face)) + "Default face used to display `notmuch-tree-overlay-string'" + :group 'notmuch-tree + :group 'notmuch-faces) + (defvar notmuch-tree-previous-subject "The subject of the most recent result shown during the async display") (make-variable-buffer-local 'notmuch-tree-previous-subject) @@ -196,6 +208,9 @@ if the user has loaded a different buffer in that window.") (make-variable-buffer-local 'notmuch-tree-message-buffer) (put 'notmuch-tree-message-buffer 'permanent-local t) +(defvar notmuch-tree-overlays nil + "List of overlays used to fold/unfold thread") + (defun notmuch-tree-to-message-pane (func) "Execute FUNC in message pane. @@ -294,6 +309,7 @@ FUNC." (define-key map " " 'notmuch-tree-scroll-or-next) (define-key map (kbd "DEL") 'notmuch-tree-scroll-message-window-back) (define-key map "e" 'notmuch-tree-resume-message) + (define-key map "t" 'notmuch-tree-toggle-folding-thread) map)) (fset 'notmuch-tree-mode-map notmuch-tree-mode-map) @@ -415,6 +431,60 @@ NOT change the database." (notmuch-draft-resume id) (message "No message to resume!")))) +(defun notmuch-tree-find-overlay (buffer start end) + "Return the first overlay found in `notmuch-tree-overlays'. + +The overlay found is located between START and END position in BUFFER." + (seq-find (lambda (ov) + (and (eq (overlay-buffer ov) buffer) + (<= (overlay-start ov) start) + (>= (overlay-end ov) end))) + notmuch-tree-overlays)) + +(defun notmuch-tree-clean-up-overlays () + "Remove overlays not referenced to any buffer" + (setq notmuch-tree-overlays (seq-filter #'overlay-buffer notmuch-tree-overlays))) + +(defun notmuch-tree-remove-overlay (overlay) + "Delete OVERLAY and remove it from `notmuch-tree-overlays' list" + (setq notmuch-tree-overlays (remove overlay notmuch-tree-overlays)) + (delete-overlay overlay)) + +(defun notmuch-tree-add-overlay (start end) + "Add an overlay from START to END in the current buffer. + +If non nil, `notmuch-tree-overlay-string' is added at the end of the line. +The overlay created is added to `notmuch-tree-overlays' list" + (let ((overlay (make-overlay start end))) + (add-to-list 'notmuch-tree-overlays overlay) + (overlay-put overlay 'invisible t) + (when notmuch-tree-overlay-string + (overlay-put overlay 'before-string + (propertize notmuch-tree-overlay-string + 'face 'notmuch-tree-overlay-fold-face))))) + +(defun notmuch-tree-thread-range () + "Return list of Start and End position of the current thread" + (let (start end) + (save-excursion + (while (not (or (notmuch-tree-get-prop :first) (eobp))) + (forward-line -1)) + (setq start (line-end-position)) + (notmuch-tree-next-thread) + (setq end (- (point) 1)) + (list start end)))) + +(defun notmuch-tree-toggle-folding-thread () + "Fold / Unfold the current thread" + (interactive) + (cl-multiple-value-bind (start end) + (notmuch-tree-thread-range) + (unless (= start end) + (let ((overlay (notmuch-tree-find-overlay (current-buffer) start end))) + (if overlay + (notmuch-tree-remove-overlay overlay) + (notmuch-tree-add-overlay start end)))))) + ;; The next two functions close the message window before calling ;; notmuch-search or notmuch-tree but they do so after the user has ;; entered the query (in case the user was basing the query on @@ -966,6 +1036,9 @@ The arguments are: ;; Don't track undo information for this buffer (set 'buffer-undo-list t) + ;; clean-up overlays in case where some overlays reference to no buffer + (notmuch-tree-clean-up-overlays) + (notmuch-tree-worker query query-context target open-target) (setq truncate-lines t)) -- 2.7.4