From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp1 ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms0.migadu.com with LMTPS id mO9KABEMLmFRwAAAgWs5BA (envelope-from ) for ; Tue, 31 Aug 2021 13:01:37 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:bcc0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp1 with LMTPS id uI1BNxAMLmHkEgAAbx9fmQ (envelope-from ) for ; Tue, 31 Aug 2021 11:01:36 +0000 Received: from mail.notmuchmail.org (nmbug.tethera.net [144.217.243.247]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 5B368115C2 for ; Tue, 31 Aug 2021 13:01:36 +0200 (CEST) Received: from nmbug.tethera.net (localhost [127.0.0.1]) by mail.notmuchmail.org (Postfix) with ESMTP id 9390F205F9; Tue, 31 Aug 2021 07:01:32 -0400 (EDT) Received: from anarres.sindominio.net (anarres.sindominio.net [88.99.208.38]) by mail.notmuchmail.org (Postfix) with ESMTPS id EA1F92058D for ; Tue, 31 Aug 2021 07:01:29 -0400 (EDT) Received: from localhost (localhost.localdomain [127.0.0.1]) by lesnaus.sindominio.net (Postfix) with ESMTP id 147AD364E56 for ; Tue, 31 Aug 2021 13:01:29 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 lesnaus.sindominio.net 147AD364E56 Received: from anarres.sindominio.net ([127.0.0.1]) by localhost (lesnaus.sindominio.net [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3C5Xdu-3xwk8 for ; Tue, 31 Aug 2021 13:01:27 +0200 (CEST) Received: by lesnaus.sindominio.net (Postfix, from userid 108) id D6468364E34; Tue, 31 Aug 2021 13:01:26 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 lesnaus.sindominio.net D6468364E34 Received: from bisio.uned.es (235.red-176-83-109.dynamicip.rima-tde.net [176.83.109.235]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lesnaus.sindominio.net (Postfix) with ESMTPSA id 98A34364E34; Tue, 31 Aug 2021 13:01:24 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 lesnaus.sindominio.net 98A34364E34 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sindominio.net; s=mail; t=1630407684; bh=dC7vmgsX+q2SA2fj8s1VqiY6TZG3Ks+ZCeDNZAyFueQ=; h=From:To:Cc:Subject:Date:From; b=fcIyJVmSffz2EP9KddEe+2FYsDNAo69pFkrP7WkSKVoyt9BpTXMjO/ZkGX7doaKCd JXlhu05Kj16gUo4nAdLzJk8nIXgkNDjg038Ipi11Gu/gXw/8BHdJ6/xinglG4QFs/n 5ejsZjFJZcnqrL/iQNK4x0a3WHnfyxeMxjI1z1WaF/AmP9jMhR4c3QuUHeeH8e5qMJ hbm1pyKPRc5JpxVTCmMaF6i7fuEme3HIM5B7RhOeBVzrLrVLhTDaQpERZ1e9ZTUbw+ 9K+PccAC3nZHNmecJ9Po3OX3S0Sb8X/PZODdigK2QsW06KEwYf6DroiSXdkaURHQXH hfDucedAIQJPf3k+r6VNhm1cwb9JSz836en3ZIdw6EEjE3LbyUkLtjJDm+b00isQcx MSMc2kfCTc5DgseEUGo8GVx4s/z9AWBgLHe8jyc1BqMFvCxraagcNCMXCsEMergHYP y2S0dSjMFUYiRf6C9G6fOQqDgdQOPOJjmZpQkG/F375cCE1kcyDrCza8KhHNpXwXkY Y+Kiy1wgvv/59/8THyOvIGu5frNpVsdYU4HsaW3XHU1jZApnukjcqdQ/jRNy8hu5jk ZFINwb9QpgYAn8iDkQVwiNKjmVRVY7kQxrHFcwK4SoxukQy+41tFnPQw0gzuufzvF0 LeVtrA6lzv55EyzJSeMGB0wc= From: inwit To: notmuch@notmuchmail.org Subject: [PATCH] emacs: Re-apply an old patch to fold/unfold threads in tree-view Date: Tue, 31 Aug 2021 13:01:11 +0200 Message-Id: <20210831110111.3148499-1-inwit@sindominio.net> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Message-ID-Hash: SBXARDLDOECD5J75SKWRHGXAVOOY3XQT X-Message-ID-Hash: SBXARDLDOECD5J75SKWRHGXAVOOY3XQT X-MailFrom: inwit@sindominio.net X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-notmuch.notmuchmail.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header CC: inwit X-Mailman-Version: 3.2.1 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Help: List-Post: List-Subscribe: List-Unsubscribe: Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1630407696; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding:list-id:list-help: list-unsubscribe:list-subscribe:list-post:dkim-signature; bh=U66+NCFe/lx4XNgqcLWCiBrLbomT0SDGV598lO3hKbA=; b=pucTk5/6nzzw89AvRbH9fsmJGrijZXtuNVvtWqRD3a9lRQMyRJ5BV3SfRTbTTKWAo33kOR FXVSTyqBAp/rfGaT9TsbuC7cCu2IB70jV3+C+WNPrEkO9lkO0B6rnkqWo+7y3ZZsA0RjWr xM+Hfm4+0Bg4FHkSkLSqXt/uy3DLzMk21IYkbnLejvw0iiQwH6guRgazJUYpXxtyCuTy8v Zwmk+eRl1AlmdLbWoccxKkJE6wfXsvt1MpaxkCHYq0QiyrZki4Grs8tz0YMvG5rKRNdXVC d01qu/85CaxHsdj2cBwCkgUhDrwVeChP+R1vq5ztr7C/0RJ4ZOg984O3D9lxyA== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1630407696; a=rsa-sha256; cv=none; b=AN1UNgjDJLFHNqdciekzwbyBKDLwRMWPxLzAhcPw3xMVEgOQxaDPtdyOU+A1O/H5nKlX2G 1PDhZzZFye8z4HuYsg1nPKS8UdqzVR7U/t0+itzqLZt+l67L5iAZaTRZ2OXcLpFzjPyhz2 M4JpMTT2iGjIVc++wDakwwDlob9ldVY4EU7xl/NPJxqv0ka//QiWu96brBIkM6KFlIWefM wlL3UvdMucsb930sP+d32W9vRdBPoJODYL1UicZR8U4j9dHCYoBzyNlNYtKqWftWzKK1Te gExepHoT7nzeekVXKawPHlEq5O3lwy4+cbp9w+FQpirgor7a9Y3rA7hkdqnd2Q== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=sindominio.net header.s=mail header.b=fcIyJVmS; dmarc=fail reason="SPF not aligned (relaxed)" header.from=sindominio.net (policy=none); spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 144.217.243.247 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Spam-Score: 0.04 Authentication-Results: aspmx1.migadu.com; dkim=fail ("body hash did not verify") header.d=sindominio.net header.s=mail header.b=fcIyJVmS; dmarc=fail reason="SPF not aligned (relaxed)" header.from=sindominio.net (policy=none); spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 144.217.243.247 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Queue-Id: 5B368115C2 X-Spam-Score: 0.04 X-Migadu-Scanner: scn0.migadu.com X-TUID: CDPN+Ssir6Ok --- emacs/notmuch-tree.el | 92 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/emacs/notmuch-tree.el b/emacs/notmuch-tree.el index b48a132d..24b4105b 100644 --- a/emacs/notmuch-tree.el +++ b/emacs/notmuch-tree.el @@ -131,6 +131,11 @@ Note that the author string should not contain whitespace notmuch-unthreaded-result-format notmuch-tree-result-format)) +(defcustom notmuch-tree-overlay-string " [...]" + "String displayed at the beginning of the overlay" + :type 'string + :group 'notmuch-tree) + ;;; Faces ;;;; Faces for messages that match the query @@ -222,10 +227,18 @@ Note that the author string should not contain whitespace :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) + ;;; Variables (defvar-local notmuch-tree-previous-subject "The subject of the most recent result shown during the async display.") +(make-variable-buffer-local 'notmuch-tree-previous-subject) (defvar-local notmuch-tree-basic-query nil "A buffer local copy of argument query to the function notmuch-tree.") @@ -256,6 +269,9 @@ This is used to try and make sure we don't close the message pane if the user has loaded a different buffer in that window.") (put 'notmuch-tree-message-buffer 'permanent-local t) +(defvar notmuch-tree-overlays nil + "List of overlays used to fold/unfold thread") + ;;; Tree wrapper commands (defmacro notmuch-tree--define-do-in-message-window (name cmd) @@ -385,6 +401,7 @@ then NAME behaves like CMD." (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) "Keymap for \"notmuch tree\" buffers.") @@ -513,6 +530,80 @@ 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." + (cl-find-if (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 (cl-remove-if #'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-sub-thread-range () + "Return list of Start and End position of the current sub-thread" + (if (notmuch-tree-get-prop :first) + (notmuch-tree-thread-range) + (let ((level (length (notmuch-tree-get-prop :tree-status))) + (start (line-end-position)) + end) + ;; find end position + (save-excursion + (forward-line) + (while (and (< level (length (notmuch-tree-get-prop :tree-status))) + (not (eobp))) + (forward-line)) + (setq end (- (point) 1))) + (list start end)))) + +(defun notmuch-tree-toggle-folding-thread (&optional arg) + "Fold / Unfold the current thread or sub-thread. + +With prefix arg (C-u) the whole thread is folded" + (interactive "p") + (cl-multiple-value-bind (start end) + (if (and arg (= arg 1)) + (notmuch-tree-sub-thread-range) + (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 @@ -1173,6 +1264,7 @@ The arguments are: (pop-to-buffer-same-window buffer)) ;; Don't track undo information for this buffer (setq buffer-undo-list t) + (notmuch-tree-clean-up-overlays) (notmuch-tree-worker query query-context target open-target unthreaded oldest-first) (setq notmuch-tree-parent-buffer parent-buffer) (setq truncate-lines t)) -- 2.30.2