Compare commits
42
Commits
54b841ec81
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69af07dc49 | ||
|
|
017c4b0b7d | ||
|
|
77b1b6f999 | ||
|
|
5c4d83590c | ||
|
|
a949d2b57b | ||
|
|
45ed3a8081 | ||
|
|
eebfbdf622 | ||
|
|
508bdeb553 | ||
|
|
6511ef9860 | ||
|
|
a5a40d6636 | ||
|
|
7fdcfa458c | ||
|
|
b6aec65c87 | ||
|
|
d4879ef719 | ||
|
|
d199950bc3 | ||
|
|
e9a736f9c2 | ||
|
|
9cb8126a8c | ||
|
|
95c69be2c6 | ||
|
|
3c6e2521b0 | ||
|
|
858d26129b | ||
|
|
367b17ea20 | ||
|
|
a3977ac72c | ||
|
|
6a47cd3960 | ||
|
|
06ba9c724f | ||
|
|
9937e9db3f | ||
|
|
fe4ae5a7b1 | ||
|
|
0a0f6dc2de | ||
|
|
ba998e252c | ||
|
|
8213453bce | ||
|
|
4725492a7d | ||
|
|
2820ec5f84 | ||
|
|
40be300bf4 | ||
|
|
ec98d3bfab | ||
|
|
e51d89105d | ||
|
|
3dc1582585 | ||
|
|
2e7c33bef4 | ||
|
|
81ec6fa96c | ||
|
|
49552caea9 | ||
|
|
dd61440e6a | ||
|
|
17a4592aa9 | ||
|
|
21d00a7cf2 | ||
|
|
a84025dce4 | ||
|
|
ed1ae747fe |
No files matched your search
@@ -0,0 +1,197 @@
|
|||||||
|
;; mu4e thread fast folding -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;; This program 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.
|
||||||
|
;;
|
||||||
|
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
(require 'mu4e)
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-info (msg)
|
||||||
|
(let* ((thread (mu4e-message-field msg :meta))
|
||||||
|
(prefix (mu4e~headers-thread-prefix thread))
|
||||||
|
(unread (memq 'unread (mu4e-message-field msg :flags))))
|
||||||
|
(concat
|
||||||
|
(if (= (length prefix) 0) " " " ") ;; Normal space vs Non-breaking space
|
||||||
|
(if unread "•" " ")))) ;; Specific character to later detect unread
|
||||||
|
|
||||||
|
(add-to-list 'mu4e-header-info-custom
|
||||||
|
'(:fast-folding . (:name "fast-folding"
|
||||||
|
:shortname ""
|
||||||
|
:function mu4e-fast-folding-info)))
|
||||||
|
|
||||||
|
(setq mu4e-headers-fields '((:fast-folding . 2)
|
||||||
|
(:human-date . 12)
|
||||||
|
(:flags . 6)
|
||||||
|
(:mailing-list . 10)
|
||||||
|
(:from . 22)
|
||||||
|
(:subject)))
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-is-unfolded-child ()
|
||||||
|
"Check if the line at point is an unfolded thread child.
|
||||||
|
This is detected by the presence of non-breaking space."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(and (not (mu4e-fast-folding-is-folded-children))
|
||||||
|
(search-forward " " (line-end-position) t))))
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-is-folded-children ()
|
||||||
|
"Check if the line at point is a folded thread.
|
||||||
|
This is detected by the presence of an overlay with value 'overlay."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(let ((overlays (overlays-at (point)))
|
||||||
|
(found nil))
|
||||||
|
(while overlays
|
||||||
|
(if (overlay-get (car overlays) 'overlay)
|
||||||
|
(setq found t))
|
||||||
|
(setq overlays (cdr overlays)))
|
||||||
|
found)))
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-is-root ()
|
||||||
|
"Check if the line at point is a thread root."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(and (not (mu4e-fast-folding-is-unfolded-child))
|
||||||
|
(not (mu4e-fast-folding-is-folded-children))))
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-is-unread ()
|
||||||
|
"Check if the line at point is an unread message."
|
||||||
|
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(search-forward "•" (line-end-position) t)))
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-toggle ()
|
||||||
|
"Toggle thread at point."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(if (mu4e-fast-folding-is-root)
|
||||||
|
(forward-line))
|
||||||
|
(cond ((mu4e-fast-folding-is-folded-children)
|
||||||
|
(mu4e-fast-folding-thread-unfold))
|
||||||
|
((mu4e-fast-folding-is-unfolded-child)
|
||||||
|
(mu4e-fast-folding-thread-fold)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-unfold ()
|
||||||
|
"Unfold thread at point."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(if (mu4e-fast-folding-is-root)
|
||||||
|
(forward-line))
|
||||||
|
|
||||||
|
(let ((overlays (overlays-at (point))))
|
||||||
|
(while overlays
|
||||||
|
(let ((overlay (car overlays)))
|
||||||
|
(if (overlay-get overlay 'overlay)
|
||||||
|
(delete-overlay (overlay-get overlay 'overlay))))
|
||||||
|
(setq overlays (cdr overlays)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-fold ()
|
||||||
|
"Fold thread at point."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
|
||||||
|
;; Move to thread start
|
||||||
|
(beginning-of-line)
|
||||||
|
(while (and (> (point) (point-min))
|
||||||
|
(mu4e-fast-folding-is-unfolded-child))
|
||||||
|
(forward-line -1))
|
||||||
|
(forward-line +1)
|
||||||
|
|
||||||
|
;; Hide all children, count them and count unread
|
||||||
|
(beginning-of-line)
|
||||||
|
(let ((start (point))
|
||||||
|
(end (+ (point) 1))
|
||||||
|
(unread 0)
|
||||||
|
(count 0))
|
||||||
|
(while (and (< (point) (point-max))
|
||||||
|
(mu4e-fast-folding-is-unfolded-child))
|
||||||
|
|
||||||
|
;; Count unread
|
||||||
|
(beginning-of-line)
|
||||||
|
(if (mu4e-fast-folding-is-unread)
|
||||||
|
(setq unread (+ unread 1)))
|
||||||
|
|
||||||
|
;; Count thread
|
||||||
|
(setq count (+ count 1))
|
||||||
|
|
||||||
|
;; Set new end for the overlay
|
||||||
|
(setq end (+ (line-end-position) 1))
|
||||||
|
(forward-line +1)
|
||||||
|
(beginning-of-line))
|
||||||
|
|
||||||
|
;; Add overlay
|
||||||
|
(let* ((overlay (make-overlay start (- end 1)))
|
||||||
|
(face (if (> unread 0) 'mu4e-unread-face 'mu4e-system-face))
|
||||||
|
(text (if (> unread 0)
|
||||||
|
(format " --- %d hidden messages (%d unread) --- " count unread)
|
||||||
|
(format " --- %d hidden messages --- " count))))
|
||||||
|
|
||||||
|
;; No overlay if only 1 child
|
||||||
|
(when (> count 1)
|
||||||
|
(overlay-put overlay 'display (propertize text 'face face))
|
||||||
|
(overlay-put overlay 'overlay overlay)))))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-fold-all ()
|
||||||
|
"Fold all threads independently of their current state."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (not (eobp))
|
||||||
|
(mu4e-fast-folding-thread-fold)
|
||||||
|
(forward-line))))
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-unfold-all ()
|
||||||
|
"Unfold all threads, independently of their current state."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(while (not (eobp))
|
||||||
|
(mu4e-fast-folding-thread-unfold)
|
||||||
|
(forward-line))))
|
||||||
|
|
||||||
|
(defvar mu4e-fast-folding-thread-folding-state nil
|
||||||
|
"Global folding state")
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-toggle-all ()
|
||||||
|
"Toggle global folding state."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(when mu4e-headers-include-related
|
||||||
|
(setq mu4e-fast-folding-thread-folding-state
|
||||||
|
(not mu4e-fast-folding-thread-folding-state))
|
||||||
|
(mu4e-fast-folding-thread-apply-folding)))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-fast-folding-thread-apply-folding ()
|
||||||
|
"Apply folding according to the global folding state."
|
||||||
|
|
||||||
|
(interactive)
|
||||||
|
(if mu4e-fast-folding-thread-folding-state
|
||||||
|
(mu4e-fast-folding-thread-fold-all)
|
||||||
|
(mu4e-fast-folding-thread-unfold-all)))
|
||||||
|
|
||||||
|
(add-hook 'mu4e-headers-found-hook
|
||||||
|
#'mu4e-fast-folding-thread-fold-all)
|
||||||
|
|
||||||
@@ -0,0 +1,382 @@
|
|||||||
|
;;; mu4e-thread-folding.el --- Thread folding support for mu4e -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
;; Copyright (C) 2021 Nicolas P. Rougier
|
||||||
|
;;
|
||||||
|
;; Author: Nicolas P. Rougier <Nicolas.Rougier@inria.fr>
|
||||||
|
;; Homepage: https://github.com/rougier/mu4e-thread-folding
|
||||||
|
;; Keywords: mail
|
||||||
|
;; Version: 0.2
|
||||||
|
;; Package-Requires: ((emacs "26.1"))
|
||||||
|
|
||||||
|
;; This file is not part of GNU Emacs.
|
||||||
|
;;
|
||||||
|
;; This program 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.
|
||||||
|
;;
|
||||||
|
;; This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; mu4e-thread-folding.el is a small library to enable threads folding in
|
||||||
|
;; mu4e. This works by using overlays with an invisible property and
|
||||||
|
;; setting hooks at the right place. It is possible to configure colors
|
||||||
|
;; to better highlight a thread and also to have a prefix string
|
||||||
|
;; indicating if a thread is folded or not. Note that when a thread is
|
||||||
|
;; folded, any unread child remains visible.
|
||||||
|
|
||||||
|
;; Usage:
|
||||||
|
|
||||||
|
;; The prefix string is displayed over the header line and it is thus
|
||||||
|
;; recommended to have an empty field at the start of an header line.
|
||||||
|
;; Have a look at ~mu4e-headers-fields~.
|
||||||
|
;;
|
||||||
|
;; (require 'mu4e-thread-folding)
|
||||||
|
;; (add-to-list 'mu4e-header-info-custom
|
||||||
|
;; '(:empty . (:name "Empty"
|
||||||
|
;; :shortname ""
|
||||||
|
;; :function (lambda (msg) " "))))
|
||||||
|
;; (setq mu4e-headers-fields '((:empty . 2)
|
||||||
|
;; (:human-date . 12)
|
||||||
|
;; (:flags . 6)
|
||||||
|
;; (:mailing-list . 10)
|
||||||
|
;; (:from . 22)
|
||||||
|
;; (:subject . nil)))
|
||||||
|
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
(require 'mu4e)
|
||||||
|
|
||||||
|
(defvar mu4e-thread-folding-mode nil)
|
||||||
|
(defvar mu4e-headers--folded-items nil)
|
||||||
|
|
||||||
|
(defgroup mu4e-thread-folding '()
|
||||||
|
"Group for mu4e thread folding options"
|
||||||
|
:group 'mu4e)
|
||||||
|
|
||||||
|
(defface mu4e-thread-folding-root-unfolded-face
|
||||||
|
`((t :inherit 'default))
|
||||||
|
"Face for the root node thread when it is unfolded."
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defface mu4e-thread-folding-root-folded-face
|
||||||
|
`((t :inherit 'default))
|
||||||
|
"Face for the root node of a thread when it is folded."
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defface mu4e-thread-folding-child-face
|
||||||
|
`((t :inherit 'default))
|
||||||
|
"Face for a thread when it is unfolded (child node)"
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defface mu4e-thread-folding-root-prefix-face
|
||||||
|
`((t :inherit default))
|
||||||
|
"Face for the root node thread when it is unfolded."
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defcustom mu4e-thread-folding-default-view 'folded
|
||||||
|
"Initial folding status ('folded or 'unfolded)."
|
||||||
|
:type 'string
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defcustom mu4e-thread-folding-root-unfolded-prefix-string
|
||||||
|
"[%2d] ▾"
|
||||||
|
"Prefix for the root node thread when it is unfolded."
|
||||||
|
:type 'string
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defcustom mu4e-thread-folding-root-folded-prefix-string
|
||||||
|
"[%2d] ▸"
|
||||||
|
"Prefix for the root node (when folded)"
|
||||||
|
:type 'string
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defcustom mu4e-thread-folding-child-prefix-string
|
||||||
|
" "
|
||||||
|
"Prefix for a child node."
|
||||||
|
:type 'string
|
||||||
|
:group 'mu4e-thread-folding)
|
||||||
|
|
||||||
|
(defvar mu4e-thread-folding-all-folded nil
|
||||||
|
"Record whether last fold-all state was folded.")
|
||||||
|
|
||||||
|
(defun mu4e-headers-get-thread-id (msg)
|
||||||
|
"Retrieve the thread-id of a msg.
|
||||||
|
This uses the mu4e private API and this might break in future releases."
|
||||||
|
(mu4e~headers-get-thread-info msg 'thread-id))
|
||||||
|
|
||||||
|
|
||||||
|
(defun mu4e-headers-mark-threads (&optional no-reset)
|
||||||
|
"Mark line in headers view with various information contained in overlays."
|
||||||
|
(when (and (get-buffer "*mu4e-headers*") mu4e-headers-show-threads)
|
||||||
|
(with-current-buffer "*mu4e-headers*"
|
||||||
|
(setq-local line-move-visual t
|
||||||
|
line-move-ignore-invisible t)
|
||||||
|
;; turn on minor mode for key bindings
|
||||||
|
(unless mu4e-thread-folding-mode (mu4e-thread-folding-mode 1))
|
||||||
|
;; Remove all overlays
|
||||||
|
(cl-loop with names = '(thread-child thread-root root-prefix)
|
||||||
|
for ov being the overlays
|
||||||
|
when (cl-loop for name in names
|
||||||
|
thereis (overlay-get ov name))
|
||||||
|
do (delete-overlay ov))
|
||||||
|
(unless no-reset (setq mu4e-headers--folded-items nil))
|
||||||
|
(setq-local left-margin-width 1)
|
||||||
|
(if (get-buffer-window "*mu4e-headers*")
|
||||||
|
(set-window-margins (get-buffer-window "*mu4e-headers*")
|
||||||
|
(max (length mu4e-thread-folding-root-folded-prefix-string)
|
||||||
|
(length mu4e-thread-folding-root-unfolded-prefix-string))))
|
||||||
|
(let ((overlay-priority -60)
|
||||||
|
(folded (string= mu4e-thread-folding-default-view 'folded))
|
||||||
|
(child-face 'mu4e-thread-folding-child-face)
|
||||||
|
(children-number 1)
|
||||||
|
(root-id nil)
|
||||||
|
(root-overlay nil)
|
||||||
|
(root-unread-child nil)
|
||||||
|
docid-overlay
|
||||||
|
(root-folded-face 'mu4e-thread-folding-root-folded-face)
|
||||||
|
(root-unfolded-face 'mu4e-thread-folding-root-unfolded-face)
|
||||||
|
(root-folded-prefix mu4e-thread-folding-root-folded-prefix-string)
|
||||||
|
(root-unfolded-prefix mu4e-thread-folding-root-unfolded-prefix-string))
|
||||||
|
;; store initial folded state
|
||||||
|
(setq mu4e-thread-folding-all-folded folded)
|
||||||
|
(setq-local buffer-invisibility-spec '(docid t))
|
||||||
|
;; Iterate over each header
|
||||||
|
(mu4e-headers-for-each
|
||||||
|
(lambda (msg)
|
||||||
|
(let* ((docid (mu4e-message-field msg :docid))
|
||||||
|
(docid-pos (cons (mu4e~headers-goto-docid docid)
|
||||||
|
(mu4e~headers-goto-docid docid t)))
|
||||||
|
(id (mu4e-headers-get-thread-id msg))
|
||||||
|
(flagged (member 'flagged (mu4e-message-field msg :flags)))
|
||||||
|
(unread (member 'unread (mu4e-message-field msg :flags)))
|
||||||
|
(child-overlay (make-overlay
|
||||||
|
(line-beginning-position)
|
||||||
|
(+ 1 (line-end-position)))))
|
||||||
|
;; (setq folded (or (and (member id mu4e-headers--folded-items) t)
|
||||||
|
;; mu4e-thread-folding-all-folded))
|
||||||
|
(setq folded (member id mu4e-headers--folded-items))
|
||||||
|
;; We mark the root thread if and only if there's child
|
||||||
|
(if (string= root-id id)
|
||||||
|
(progn
|
||||||
|
(setq children-number (+ children-number 1))
|
||||||
|
|
||||||
|
;; unread-child indicates that there's at least one unread child
|
||||||
|
(setq root-unread-child (or root-unread-child unread))
|
||||||
|
;; Child
|
||||||
|
(when (and (not unread) (not flagged))
|
||||||
|
(overlay-put child-overlay 'face child-face))
|
||||||
|
(overlay-put child-overlay 'invisible (and folded (not unread)))
|
||||||
|
(overlay-put child-overlay 'priority overlay-priority)
|
||||||
|
(overlay-put child-overlay 'unread unread)
|
||||||
|
(overlay-put child-overlay 'thread-child t)
|
||||||
|
(overlay-put child-overlay 'thread-id id)
|
||||||
|
;; Root
|
||||||
|
(overlay-put
|
||||||
|
root-overlay 'face (if (or root-unread-child (not folded))
|
||||||
|
root-unfolded-face
|
||||||
|
root-folded-face))
|
||||||
|
(overlay-put root-overlay 'thread-root t)
|
||||||
|
(overlay-put root-overlay 'thread-id id)
|
||||||
|
(overlay-put root-overlay 'folded folded)
|
||||||
|
(overlay-put root-overlay 'priority overlay-priority)
|
||||||
|
(overlay-put root-overlay 'invisible 'root)
|
||||||
|
(overlay-put root-overlay 'prefix-docid docid-overlay)
|
||||||
|
(overlay-put
|
||||||
|
docid-overlay 'before-string
|
||||||
|
(propertize
|
||||||
|
" " 'display
|
||||||
|
`((margin left-margin)
|
||||||
|
,(propertize
|
||||||
|
(if (or root-unread-child (not folded))
|
||||||
|
(format root-unfolded-prefix children-number)
|
||||||
|
(format root-folded-prefix children-number))
|
||||||
|
'face 'mu4e-thread-folding-root-prefix-face))))
|
||||||
|
(overlay-put docid-overlay 'invisible 'docid)
|
||||||
|
(overlay-put docid-overlay 'priority 1)
|
||||||
|
(overlay-put docid-overlay 'root-prefix t))
|
||||||
|
;; Else, set the new root (this relies on default message order in header's view)
|
||||||
|
(progn
|
||||||
|
(if (> children-number 1)
|
||||||
|
(overlay-put root-overlay 'children-number children-number))
|
||||||
|
(setq root-id id
|
||||||
|
root-unread-child nil
|
||||||
|
children-number 1
|
||||||
|
root-overlay (make-overlay
|
||||||
|
(line-beginning-position)
|
||||||
|
(1+ (line-end-position)))
|
||||||
|
docid-overlay (make-overlay
|
||||||
|
(car docid-pos)
|
||||||
|
(cdr docid-pos))))))))))))
|
||||||
|
|
||||||
|
(defun mu4e-headers-mark-threads-no-reset ()
|
||||||
|
"Same as `mu4e-headers-mark-threads' but don't reset `mu4e-headers--folded-items'."
|
||||||
|
(mu4e-headers-mark-threads 'no-reset))
|
||||||
|
|
||||||
|
(defun mu4e-headers-overlay-set-visibility (value &optional thread-id)
|
||||||
|
"Set the invisible property for all thread children or only the ones matching thread-id.
|
||||||
|
Unread message are not folded."
|
||||||
|
(when (and (get-buffer "*mu4e-headers*") mu4e-headers-show-threads)
|
||||||
|
(with-current-buffer "*mu4e-headers*"
|
||||||
|
(unless thread-id
|
||||||
|
(setq mu4e-thread-folding-all-folded value))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let ((root-overlay nil)
|
||||||
|
(child-overlay nil)
|
||||||
|
(root-folded-face 'mu4e-thread-folding-root-folded-face)
|
||||||
|
(root-unfolded-face 'mu4e-thread-folding-root-unfolded-face)
|
||||||
|
(root-folded-prefix mu4e-thread-folding-root-folded-prefix-string)
|
||||||
|
(root-unfolded-prefix mu4e-thread-folding-root-unfolded-prefix-string))
|
||||||
|
|
||||||
|
(mu4e-headers-for-each
|
||||||
|
(lambda (_msg)
|
||||||
|
(let (local-child-overlay local-root-overlay)
|
||||||
|
(cl-loop for ov in (overlays-in (point-at-bol) (point-at-eol))
|
||||||
|
when (overlay-get ov 'thread-child)
|
||||||
|
do (setq local-child-overlay ov)
|
||||||
|
when (overlay-get ov 'thread-root)
|
||||||
|
do (setq local-root-overlay ov))
|
||||||
|
;; Child
|
||||||
|
(when local-child-overlay
|
||||||
|
(let ((id (overlay-get local-child-overlay 'thread-id))
|
||||||
|
(unread (overlay-get local-child-overlay 'unread)))
|
||||||
|
(setq child-overlay local-child-overlay)
|
||||||
|
(when (or (not thread-id) (string= id thread-id))
|
||||||
|
(if (and root-overlay unread)
|
||||||
|
(overlay-put root-overlay 'face root-unfolded-face)
|
||||||
|
(overlay-put child-overlay 'invisible value)))))
|
||||||
|
;; Root
|
||||||
|
(when local-root-overlay
|
||||||
|
(let ((children-number (or (overlay-get local-root-overlay 'children-number) 1))
|
||||||
|
(id (overlay-get local-root-overlay 'thread-id)))
|
||||||
|
(setq root-overlay local-root-overlay)
|
||||||
|
(when (or (not thread-id) (string= id thread-id))
|
||||||
|
(if (and (overlay-get root-overlay 'folded) (null value))
|
||||||
|
(setq mu4e-headers--folded-items
|
||||||
|
(delete id mu4e-headers--folded-items))
|
||||||
|
(push id mu4e-headers--folded-items))
|
||||||
|
(overlay-put root-overlay 'folded value)
|
||||||
|
(overlay-put
|
||||||
|
(overlay-get root-overlay 'prefix-docid) 'before-string
|
||||||
|
(propertize
|
||||||
|
" " 'display
|
||||||
|
`((margin left-margin)
|
||||||
|
,(propertize
|
||||||
|
(if value
|
||||||
|
(format root-folded-prefix children-number)
|
||||||
|
(format root-unfolded-prefix children-number))
|
||||||
|
'face 'mu4e-thread-folding-root-prefix-face))))
|
||||||
|
(overlay-put
|
||||||
|
root-overlay 'face (if value
|
||||||
|
root-folded-face
|
||||||
|
root-unfolded-face)))))
|
||||||
|
;; Not a root, not a child, we reset the root overlay
|
||||||
|
(when (and (not local-child-overlay) (not local-root-overlay))
|
||||||
|
(setq root-overlay nil))))))))))
|
||||||
|
|
||||||
|
(defun mu4e-headers-get-overlay (prop &optional index)
|
||||||
|
"Get overlay at point having the PROP property"
|
||||||
|
(let* ((index (or index 0))
|
||||||
|
(overlays (overlays-at (+ (point) index)))
|
||||||
|
found)
|
||||||
|
(while (and overlays (not found))
|
||||||
|
(let ((overlay (car overlays)))
|
||||||
|
(if (overlay-get overlay prop)
|
||||||
|
(setq found overlay)))
|
||||||
|
(setq overlays (cdr overlays)))
|
||||||
|
found))
|
||||||
|
|
||||||
|
(defun mu4e-headers-toggle-at-point ()
|
||||||
|
"Toggle visibility of the thread at point"
|
||||||
|
(interactive)
|
||||||
|
(when (get-buffer "*mu4e-headers*")
|
||||||
|
(with-current-buffer "*mu4e-headers*"
|
||||||
|
(catch 'break
|
||||||
|
(while (and (not (mu4e-headers--toggle-internal))
|
||||||
|
(not (bobp)))
|
||||||
|
(forward-line -1))))))
|
||||||
|
|
||||||
|
(defun mu4e-headers--toggle-internal ()
|
||||||
|
"Toggle visibility of the thread at point"
|
||||||
|
(let (child-overlay root-overlay)
|
||||||
|
(cl-loop for ov in (overlays-in (point-at-bol) (point-at-eol))
|
||||||
|
when (overlay-get ov 'thread-child)
|
||||||
|
return (setq child-overlay ov)
|
||||||
|
when (overlay-get ov 'thread-root)
|
||||||
|
return (setq root-overlay ov))
|
||||||
|
(cond (root-overlay
|
||||||
|
(let ((id (overlay-get root-overlay 'thread-id))
|
||||||
|
(folded (overlay-get root-overlay 'folded)))
|
||||||
|
(mu4e-headers-overlay-set-visibility (not folded) id)
|
||||||
|
(throw 'break t)))
|
||||||
|
((not child-overlay)
|
||||||
|
(throw 'break t)))))
|
||||||
|
|
||||||
|
(defun mu4e-headers-toggle-fold-all ()
|
||||||
|
"Toggle between all threads unfolded and all threads folded."
|
||||||
|
(interactive)
|
||||||
|
(mu4e-headers-overlay-set-visibility
|
||||||
|
(not mu4e-thread-folding-all-folded)))
|
||||||
|
|
||||||
|
(defun mu4e-headers-fold-all ()
|
||||||
|
"Fold all threads"
|
||||||
|
(interactive)
|
||||||
|
(mu4e-headers-overlay-set-visibility t))
|
||||||
|
|
||||||
|
(defun mu4e-headers-unfold-all ()
|
||||||
|
"Unfold all threads"
|
||||||
|
(interactive)
|
||||||
|
(mu4e-headers-overlay-set-visibility nil))
|
||||||
|
|
||||||
|
(defun mu4e-headers-fold-at-point ()
|
||||||
|
"Fold current thread at point"
|
||||||
|
(interactive)
|
||||||
|
(if (get-buffer "*mu4e-headers*")
|
||||||
|
(with-current-buffer "*mu4e-headers*"
|
||||||
|
(let ((overlay (mu4e-headers-get-overlay 'thread-id)))
|
||||||
|
(mu4e-headers-overlay-set-visibility t (overlay-get overlay 'thread-id))))))
|
||||||
|
|
||||||
|
(defun mu4e-headers-unfold-at-point ()
|
||||||
|
"Unfold current thread at point"
|
||||||
|
(interactive)
|
||||||
|
(if (get-buffer "*mu4e-headers*")
|
||||||
|
(with-current-buffer "*mu4e-headers*"
|
||||||
|
(let ((overlay (mu4e-headers-get-overlay 'thread-id)))
|
||||||
|
(mu4e-headers-overlay-set-visibility nil (overlay-get overlay 'thread-id))))))
|
||||||
|
|
||||||
|
(defvar mu4e-thread-folding-mode-map
|
||||||
|
(let ((map (make-sparse-keymap)))
|
||||||
|
(set-keymap-parent map mu4e-headers-mode-map)
|
||||||
|
(define-key map (kbd "TAB") 'mu4e-headers-toggle-at-point)
|
||||||
|
(define-key map (kbd "<backtab>") 'mu4e-headers-toggle-fold-all)
|
||||||
|
map))
|
||||||
|
|
||||||
|
;; Install hooks
|
||||||
|
(defun mu4e-thread-folding-load ()
|
||||||
|
"Install hooks."
|
||||||
|
(add-hook 'mu4e-index-updated-hook #'mu4e-headers-mark-threads)
|
||||||
|
(add-hook 'mu4e-headers-found-hook #'mu4e-headers-mark-threads)
|
||||||
|
(add-hook 'mu4e-view-mode-hook 'mu4e-headers-mark-threads-no-reset))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode mu4e-thread-folding-mode
|
||||||
|
"Minor mode for folding threads in mu4e-headers view."
|
||||||
|
:group 'mu4e-thread-folding
|
||||||
|
:lighter " Threads"
|
||||||
|
(if mu4e-thread-folding-mode
|
||||||
|
(mu4e-thread-folding-load)
|
||||||
|
(remove-hook 'mu4e-index-updated-hook #'mu4e-headers-mark-threads)
|
||||||
|
(remove-hook 'mu4e-headers-found-hook #'mu4e-headers-mark-threads)
|
||||||
|
(remove-hook 'mu4e-view-mode-hook 'mu4e-headers-mark-threads-no-reset)))
|
||||||
|
|
||||||
|
|
||||||
|
(provide 'mu4e-thread-folding)
|
||||||
|
;;; mu4e-thread-folding.el ends here
|
||||||
@@ -101,7 +101,7 @@
|
|||||||
(buffer-size)
|
(buffer-size)
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(insert-image (create-image "/home/joe/.config/emacs/Emacs@256.png"))
|
(insert-image (create-image (expand-file-name "Emacs@256.png" user-emacs-directory)))
|
||||||
(insert "\n\n\n")
|
(insert "\n\n\n")
|
||||||
(insert "Welcome to Emacs!\n\n")
|
(insert "Welcome to Emacs!\n\n")
|
||||||
;; (dashboard-insert-center "testing this thing out\n\n")
|
;; (dashboard-insert-center "testing this thing out\n\n")
|
||||||
|
|||||||
+830
-1085
File diff suppressed because it is too large.
Load diff
@@ -15,16 +15,20 @@ complete -f -c exercism -n "__fish_seen_subcommand_from download" -s u -l uuid -
|
|||||||
|
|
||||||
# Help
|
# Help
|
||||||
complete -f -c exercism -n "__fish_use_subcommand" -a "help" -d "Shows a list of commands or help for one command"
|
complete -f -c exercism -n "__fish_use_subcommand" -a "help" -d "Shows a list of commands or help for one command"
|
||||||
complete -f -c exercism -n "__fish_seen_subcommand_from help" -a "configure download help open submit troubleshoot upgrade version workspace"
|
complete -f -c exercism -n "__fish_seen_subcommand_from help" -a "configure download help open submit test troubleshoot upgrade version workspace"
|
||||||
|
|
||||||
# Open
|
# Open
|
||||||
complete -f -c exercism -n "__fish_use_subcommand" -a "open" -d "Opens a browser to exercism.io for the specified submission."
|
complete -f -c exercism -n "__fish_use_subcommand" -a "open" -d "Opens a browser to exercism.org for the specified submission."
|
||||||
complete -f -c exercism -n "__fish_seen_subcommand_from open" -s h -l help -d "help for open"
|
complete -f -c exercism -n "__fish_seen_subcommand_from open" -s h -l help -d "help for open"
|
||||||
|
|
||||||
# Submit
|
# Submit
|
||||||
complete -f -c exercism -n "__fish_use_subcommand" -a "submit" -d "Submits a new iteration to a problem on exercism.io."
|
complete -f -c exercism -n "__fish_use_subcommand" -a "submit" -d "Submits a new iteration to a problem on exercism.org."
|
||||||
complete -f -c exercism -n "__fish_seen_subcommand_from submit" -s h -l help -d "help for submit"
|
complete -f -c exercism -n "__fish_seen_subcommand_from submit" -s h -l help -d "help for submit"
|
||||||
|
|
||||||
|
# Test
|
||||||
|
complete -f -c exercism -n "__fish_use_subcommand" -a "test" -d "Run the exercise's tests."
|
||||||
|
complete -f -c exercism -n "__fish_seen_subcommand_from submit" -s h -l help -d "help for test"
|
||||||
|
|
||||||
# Troubleshoot
|
# Troubleshoot
|
||||||
complete -f -c exercism -n "__fish_use_subcommand" -a "troubleshoot" -d "Outputs useful debug information."
|
complete -f -c exercism -n "__fish_use_subcommand" -a "troubleshoot" -d "Outputs useful debug information."
|
||||||
complete -f -c exercism -n "__fish_seen_subcommand_from troubleshoot" -s f -l full-api-key -d "display full API key (censored by default)"
|
complete -f -c exercism -n "__fish_seen_subcommand_from troubleshoot" -s f -l full-api-key -d "display full API key (censored by default)"
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
if status is-interactive
|
|
||||||
# Commands to run in interactive sessions can go here
|
|
||||||
end
|
|
||||||
set -gx XDG_CONFIG_HOME /home/joe/.config
|
set -gx XDG_CONFIG_HOME /home/joe/.config
|
||||||
set -gx XDG_DATA_HOME /home/joe/.local/share
|
set -gx XDG_DATA_HOME /home/joe/.local/share
|
||||||
set -gx XDG_CACHE_HOME /home/joe/.cache
|
set -gx XDG_CACHE_HOME /home/joe/.cache
|
||||||
@@ -76,12 +73,13 @@ end
|
|||||||
|
|
||||||
fish_ssh_agent
|
fish_ssh_agent
|
||||||
# The next line updates PATH for the Google Cloud SDK.
|
# The next line updates PATH for the Google Cloud SDK.
|
||||||
if [ -f '/home/joe/Downloads/google-cloud-sdk/path.fish.inc' ]; . '/home/joe/Downloads/google-cloud-sdk/path.fish.inc'; end
|
# if [ -f '/home/joe/Downloads/google-cloud-sdk/path.fish.inc' ]; . '/home/joe/Downloads/google-cloud-sdk/path.fish.inc'; end
|
||||||
|
|
||||||
# opam configuration
|
# opam configuration
|
||||||
source /home/joe/.opam/opam-init/init.fish > /dev/null 2> /dev/null; or true
|
# source /home/joe/.opam/opam-init/init.fish > /dev/null 2> /dev/null; or true
|
||||||
|
|
||||||
if test -e "/home/joe/Repositories/emsdk/emsdk_env.fish"
|
if test -e "/home/joe/Repositories/emsdk/emsdk_env.fish"
|
||||||
source "/home/joe/Repositories/emsdk/emsdk_env.fish"
|
source "/home/joe/Repositories/emsdk/emsdk_env.fish"
|
||||||
set -gx EMSDK_QUIET 1
|
set -gx EMSDK_QUIET 1
|
||||||
end
|
end
|
||||||
|
alias claude="/home/joe/.claude/local/claude"
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
# This file contains fish universal variable definitions.
|
# This file contains fish universal variable definitions.
|
||||||
# VERSION: 3.0
|
# VERSION: 3.0
|
||||||
|
SETUVAR --export ANDROID_AVD_HOME:/home/joe/\x2econfig/\x2eandroid/avd
|
||||||
|
SETUVAR --export ANDROID_HOME:/home/joe/Android/Sdk/
|
||||||
SETUVAR --export CARGO_HOME:/home/joe/\x2elocal/share/bin/cargo/
|
SETUVAR --export CARGO_HOME:/home/joe/\x2elocal/share/bin/cargo/
|
||||||
SETUVAR EDITOR:hx
|
SETUVAR EDITOR:hx
|
||||||
SETUVAR --export LC_COLLATE:C
|
SETUVAR --export LC_COLLATE:C
|
||||||
SETUVAR --export --path LD_LIBRARY_PATH:/usr/local/lib
|
SETUVAR --export --path LD_LIBRARY_PATH:/usr/local/lib
|
||||||
|
SETUVAR --export NDK_HOME:/home/joe/Android/Sdk/ndk/29\x2e0\x2e13599879/
|
||||||
|
SETUVAR --export PYENV_ROOT:/home/joe/\x2epyenv
|
||||||
SETUVAR --export PYTHONSTARTUP:/etc/python/pythonrc
|
SETUVAR --export PYTHONSTARTUP:/etc/python/pythonrc
|
||||||
SETUVAR --export RUSTUP_HOME:/home/joe/\x2elocal/share/rustup/
|
SETUVAR --export RUSTUP_HOME:/home/joe/\x2elocal/share/rustup/
|
||||||
SETUVAR SSH_AUTH_SOCK:/run/user/1000/ssh\x2dagent\x2esocket
|
SETUVAR SSH_AUTH_SOCK:/run/user/1000/ssh\x2dagent\x2esocket
|
||||||
@@ -11,7 +15,7 @@ SETUVAR WINEPREFIX:/home/joe/\x2elocal/share/wine
|
|||||||
SETUVAR XDG_CACHE_HOME:/home/joe/\x2ecache
|
SETUVAR XDG_CACHE_HOME:/home/joe/\x2ecache
|
||||||
SETUVAR XDG_CONFIG_HOME:/home/joe/\x2econfig
|
SETUVAR XDG_CONFIG_HOME:/home/joe/\x2econfig
|
||||||
SETUVAR XDG_DATA_HOME:/home/joe/\x2elocal/share
|
SETUVAR XDG_DATA_HOME:/home/joe/\x2elocal/share
|
||||||
SETUVAR __fish_initialized:3400
|
SETUVAR __fish_initialized:3800
|
||||||
SETUVAR _fisher_ankitsumitg_2F_docker_2D_fish_2D_completions_files:/home/joe/\x2econfig/fish/completions/docker\x2efish
|
SETUVAR _fisher_ankitsumitg_2F_docker_2D_fish_2D_completions_files:/home/joe/\x2econfig/fish/completions/docker\x2efish
|
||||||
SETUVAR _fisher_plugins:ankitsumitg/docker\x2dfish\x2dcompletions
|
SETUVAR _fisher_plugins:ankitsumitg/docker\x2dfish\x2dcompletions
|
||||||
SETUVAR fish_color_autosuggestion:969896
|
SETUVAR fish_color_autosuggestion:969896
|
||||||
@@ -32,7 +36,7 @@ SETUVAR fish_color_operator:00a6b2
|
|||||||
SETUVAR fish_color_param:81a2be
|
SETUVAR fish_color_param:81a2be
|
||||||
SETUVAR fish_color_quote:b5bd68
|
SETUVAR fish_color_quote:b5bd68
|
||||||
SETUVAR fish_color_redirection:8abeb7
|
SETUVAR fish_color_redirection:8abeb7
|
||||||
SETUVAR fish_color_search_match:bryellow\x1e\x2d\x2dbackground\x3dbrblack
|
SETUVAR fish_color_search_match:white\x1e\x2d\x2dbackground\x3dbrblack
|
||||||
SETUVAR fish_color_selection:white\x1e\x2d\x2dbold\x1e\x2d\x2dbackground\x3dbrblack
|
SETUVAR fish_color_selection:white\x1e\x2d\x2dbold\x1e\x2d\x2dbackground\x3dbrblack
|
||||||
SETUVAR fish_color_status:red
|
SETUVAR fish_color_status:red
|
||||||
SETUVAR fish_color_user:brgreen
|
SETUVAR fish_color_user:brgreen
|
||||||
@@ -44,4 +48,4 @@ SETUVAR fish_pager_color_description:B3A06D\x1eyellow
|
|||||||
SETUVAR fish_pager_color_prefix:normal\x1e\x2d\x2dbold\x1e\x2d\x2dunderline
|
SETUVAR fish_pager_color_prefix:normal\x1e\x2d\x2dbold\x1e\x2d\x2dunderline
|
||||||
SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan
|
SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan
|
||||||
SETUVAR fish_pager_color_selected_background:\x2dr
|
SETUVAR fish_pager_color_selected_background:\x2dr
|
||||||
SETUVAR --export fish_user_paths:/home/joe/\x2edotnet/tools\x1e/home/joe/Repositories/emsdk\x1e/home/joe/Repositories/emsdk/node/18\x2e20\x2e3_64bit/bin\x1e/home/joe/Repositories/emsdk/upstream/emscripten\x1e/home/joe/\x2elocal/bin/odin\x1e/home/joe/\x2elocal/scripts\x1e/home/joe/\x2elocal/opt/JetBrains\x20Rider\x2d2024\x2e1\x2e4/bin\x1e/home/joe/\x2elocal/share/bin/fasm\x1e/home/joe/\x2elocal/share/bin/zig\x1e/home/joe/\x2elocal/share/bin/cargo/bin\x1e/home/joe/\x2elocal/bin\x1e/home/joe/\x2enimble/bin
|
SETUVAR --export fish_user_paths:/opt/Defold\x1e/home/joe/\x2edotnet\x1e/home/joe/\x2elocal/share/qlot/bin\x1e/home/joe/\x2elocal/bin/elm\x1e/home/joe/\x2epyenv/bin\x1e/home/joe/Android/Sdk/build\x2dtools\x1e/home/joe/Android/Sdk/emulator\x1e/home/joe/Android/Sdk/cmdline\x2dtools/latest/bin\x1e/home/joe/\x2elocal/android\x2dstudio/bin\x1e/home/joe/\x2edotnet/tools\x1e/home/joe/Repositories/emsdk\x1e/home/joe/Repositories/emsdk/node/18\x2e20\x2e3_64bit/bin\x1e/home/joe/Repositories/emsdk/upstream/emscripten\x1e/home/joe/\x2elocal/bin/odin\x1e/home/joe/\x2elocal/scripts\x1e/home/joe/\x2elocal/opt/JetBrains\x20Rider\x2d2024\x2e1\x2e4/bin\x1e/home/joe/\x2elocal/share/bin/fasm\x1e/home/joe/\x2elocal/share/bin/zig\x1e/home/joe/\x2elocal/share/bin/cargo/bin\x1e/home/joe/\x2elocal/bin\x1e/home/joe/\x2enimble/bin
|
||||||
@@ -56,7 +56,8 @@ map kitty_mod+j neighboring_window down
|
|||||||
map kitty_mod+k neighboring_window up
|
map kitty_mod+k neighboring_window up
|
||||||
map kitty_mod+l neighboring_window right
|
map kitty_mod+l neighboring_window right
|
||||||
|
|
||||||
map ctrl+y paste_from_clipboard
|
map alt+y paste_from_clipboard
|
||||||
|
map alt+c copy_to_clipboard
|
||||||
|
|
||||||
map kitty_mod+p previous_tab
|
map kitty_mod+p previous_tab
|
||||||
map kitty_mod+n next_tab
|
map kitty_mod+n next_tab
|
||||||
|
|||||||
+74
-26
@@ -13,21 +13,45 @@ Subfolders Verbatim
|
|||||||
Path ~/.mail/ferano.io/
|
Path ~/.mail/ferano.io/
|
||||||
Inbox ~/.mail/ferano.io/Inbox
|
Inbox ~/.mail/ferano.io/Inbox
|
||||||
|
|
||||||
Channel ferano.io
|
Channel ferano.io-inbox
|
||||||
Far :ferano.io.remote:
|
Far :ferano.io.remote:INBOX
|
||||||
Near :ferano.io.local:
|
Near :ferano.io.local:INBOX
|
||||||
# Include everything
|
|
||||||
Patterns *
|
|
||||||
Sync All
|
Sync All
|
||||||
Create Both
|
Create Both
|
||||||
Remove Both
|
Remove Both
|
||||||
Expunge Both
|
Expunge Both
|
||||||
SyncState *
|
SyncState *
|
||||||
|
|
||||||
Channel ferano.io.inbox
|
Channel ferano.io-drafts
|
||||||
Far :ferano.io.remote:
|
Far :ferano.io.remote:Drafts
|
||||||
Near :ferano.io.local:
|
Near :ferano.io.local:Drafts
|
||||||
Patterns INBOX
|
Sync All
|
||||||
|
Create Both
|
||||||
|
Remove Both
|
||||||
|
Expunge Both
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
Channel ferano.io-sent
|
||||||
|
Far :ferano.io.remote:Sent
|
||||||
|
Near :ferano.io.local:Sent
|
||||||
|
Sync All
|
||||||
|
Create Both
|
||||||
|
Remove Both
|
||||||
|
Expunge Both
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
Channel ferano.io-junk
|
||||||
|
Far :ferano.io.remote:Junk
|
||||||
|
Near :ferano.io.local:Junk
|
||||||
|
Sync All
|
||||||
|
Create Both
|
||||||
|
Remove Both
|
||||||
|
Expunge Both
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
Channel ferano.io-trash
|
||||||
|
Far :ferano.io.remote:Trash
|
||||||
|
Near :ferano.io.local:Trash
|
||||||
Sync All
|
Sync All
|
||||||
Create Both
|
Create Both
|
||||||
Remove Both
|
Remove Both
|
||||||
@@ -45,42 +69,66 @@ Account gmail
|
|||||||
|
|
||||||
MaildirStore gmail.local
|
MaildirStore gmail.local
|
||||||
Subfolders Verbatim
|
Subfolders Verbatim
|
||||||
# The trailing "/" is important
|
|
||||||
Path ~/.mail/gmail/
|
Path ~/.mail/gmail/
|
||||||
Inbox ~/.mail/gmail/Inbox
|
Inbox ~/.mail/gmail/INBOX
|
||||||
|
|
||||||
Channel gmail
|
Channel gmail-inbox
|
||||||
Far :gmail.remote:
|
Far :gmail.remote:INBOX
|
||||||
Near :gmail.local:
|
Near :gmail.local:INBOX
|
||||||
# Include everything
|
|
||||||
Patterns *
|
|
||||||
Sync All
|
Sync All
|
||||||
Create Both
|
Create Both
|
||||||
Remove Both
|
Remove Both
|
||||||
Expunge Both
|
Expunge Both
|
||||||
SyncState *
|
SyncState *
|
||||||
|
|
||||||
Channel gmail.inbox
|
Channel gmail-drafts
|
||||||
Far :gmail.remote:
|
Far :gmail.remote:"[Gmail]/Drafts"
|
||||||
Near :gmail.local:
|
Near :gmail.local:"[Gmail]/Drafts"
|
||||||
Patterns INBOX
|
|
||||||
Sync All
|
Sync All
|
||||||
Create Both
|
Create Both
|
||||||
Remove Both
|
Remove Both
|
||||||
Expunge Both
|
Expunge Both
|
||||||
SyncState *
|
SyncState *
|
||||||
|
|
||||||
Channel gmail.allmail
|
Channel gmail-sent
|
||||||
Far :gmail.remote:
|
Far :gmail.remote:"[Gmail]/Sent Mail"
|
||||||
Near :gmail.local:
|
Near :gmail.local:"[Gmail]/Sent Mail"
|
||||||
Patterns *All*
|
|
||||||
Sync All
|
Sync All
|
||||||
Create Both
|
Create Both
|
||||||
Remove Both
|
Remove Both
|
||||||
Expunge Both
|
Expunge Both
|
||||||
SyncState *
|
SyncState *
|
||||||
|
|
||||||
|
Channel gmail-trash
|
||||||
|
Far :gmail.remote:"[Gmail]/Trash"
|
||||||
|
Near :gmail.local:"[Gmail]/Trash"
|
||||||
|
Sync All
|
||||||
|
Create Both
|
||||||
|
Remove Both
|
||||||
|
Expunge Both
|
||||||
|
SyncState *
|
||||||
|
|
||||||
|
|
||||||
|
Group ferano.io
|
||||||
|
Channel ferano.io-inbox
|
||||||
|
Channel ferano.io-drafts
|
||||||
|
Channel ferano.io-sent
|
||||||
|
Channel ferano.io-junk
|
||||||
|
Channel ferano.io-trash
|
||||||
|
|
||||||
|
Group gmail
|
||||||
|
Channel gmail-inbox
|
||||||
|
Channel gmail-drafts
|
||||||
|
Channel gmail-sent
|
||||||
|
Channel gmail-trash
|
||||||
|
|
||||||
Group all
|
Group all
|
||||||
Channel ferano.io
|
Channel ferano.io-inbox
|
||||||
Channel gmail
|
Channel ferano.io-drafts
|
||||||
|
Channel ferano.io-sent
|
||||||
|
Channel ferano.io-junk
|
||||||
|
Channel ferano.io-trash
|
||||||
|
Channel gmail-inbox
|
||||||
|
Channel gmail-drafts
|
||||||
|
Channel gmail-sent
|
||||||
|
Channel gmail-trash
|
||||||
+47
-5
@@ -84,16 +84,44 @@ def new_client(client):
|
|||||||
y = client.group.screen.height - client.height - padding - 22
|
y = client.group.screen.height - client.height - padding - 22
|
||||||
client.set_position_floating(x,y)
|
client.set_position_floating(x,y)
|
||||||
|
|
||||||
|
def move_to_corner(corner: str) -> Callable:
|
||||||
|
def _inner(qtile) -> None:
|
||||||
|
win = qtile.current_window
|
||||||
|
if win is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not win.floating:
|
||||||
|
win.toggle_floating()
|
||||||
|
|
||||||
|
screen = qtile.current_screen
|
||||||
|
padding = 0
|
||||||
|
bar_height = 24
|
||||||
|
|
||||||
|
w = win.width
|
||||||
|
h = win.height
|
||||||
|
sw = screen.width
|
||||||
|
sh = screen.height
|
||||||
|
|
||||||
|
positions = {
|
||||||
|
"top-left": (padding, bar_height + padding),
|
||||||
|
"top-right": (sw - w - padding, bar_height + padding),
|
||||||
|
"bottom-left": (padding, sh - h - padding),
|
||||||
|
"bottom-right": (sw - w - padding, sh - h - padding),
|
||||||
|
}
|
||||||
|
x, y = positions[corner]
|
||||||
|
win.set_position_floating(x, y)
|
||||||
|
return _inner
|
||||||
|
|
||||||
keys = [
|
keys = [
|
||||||
# A list of available commands that can be bound to keys can be found
|
# A list of available commands that can be bound to keys can be found
|
||||||
# at https://docs.qtile.org/en/latest/manual/config/lazy.html
|
# at https://docs.qtile.org/en/latest/manual/config/lazy.html
|
||||||
# Switch between windows
|
# Switch between windows
|
||||||
# .when(wm_class != 'kitty')
|
# .when(wm_class != 'kitty')
|
||||||
# Key([mod], "h", lazy.function(move_focus, direction='left'), desc="Move focus to left"),
|
# Key([mod], "h", lazy.function(move_focus, direction='left'), desc="Move focus to left"),
|
||||||
# Key([mod], "h", lazy.layout.left().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
Key([mod], "h", lazy.layout.left().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
||||||
# Key([mod], "j", lazy.layout.down().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
# Key([mod], "j", lazy.layout.down().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
||||||
# Key([mod], "k", lazy.layout.up().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
# Key([mod], "k", lazy.layout.up().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
||||||
# Key([mod], "l", lazy.layout.right().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
Key([mod], "l", lazy.layout.right().when(focused=Match(wm_class=re.compile('(?![Ee]macs)'))), desc="Move focus to left"),
|
||||||
# Key([alt], "tab", lazy.layout.next(), desc="Move window focus to other window"),
|
# Key([alt], "tab", lazy.layout.next(), desc="Move window focus to other window"),
|
||||||
|
|
||||||
Key([mod], "o", lazy.layout.normalize(), desc="Move window focus to other window"),
|
Key([mod], "o", lazy.layout.normalize(), desc="Move window focus to other window"),
|
||||||
@@ -131,6 +159,7 @@ keys = [
|
|||||||
Key([mod], "w", lazy.next_layout(), desc="Toggle between layouts"),
|
Key([mod], "w", lazy.next_layout(), desc="Toggle between layouts"),
|
||||||
Key([mod, "control"], "w", lazy.function(get_current_window_info), desc="Get window info"),
|
Key([mod, "control"], "w", lazy.function(get_current_window_info), desc="Get window info"),
|
||||||
Key([mod], "s", lazy.spawn("flameshot gui"), desc="Flameshot screenshot"),
|
Key([mod], "s", lazy.spawn("flameshot gui"), desc="Flameshot screenshot"),
|
||||||
|
Key([mod, "shift"], "s", lazy.spawn("flameshot screen -n 0 -c"), desc="Flameshot screenshot screen to clipboard"),
|
||||||
|
|
||||||
# TODO: Figure out another binding for this
|
# TODO: Figure out another binding for this
|
||||||
# Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
|
# Key([mod], "n", lazy.layout.normalize(), desc="Reset all window sizes"),
|
||||||
@@ -160,19 +189,25 @@ keys = [
|
|||||||
),
|
),
|
||||||
Key([mod], "t", lazy.window.toggle_floating(), desc="Toggle floating on the focused window"),
|
Key([mod], "t", lazy.window.toggle_floating(), desc="Toggle floating on the focused window"),
|
||||||
Key([mod, "control"], "r", lazy.reload_config(), desc="Reload the config"),
|
Key([mod, "control"], "r", lazy.reload_config(), desc="Reload the config"),
|
||||||
|
Key([mod, "shift"], "r", lazy.spawn("reload_wm.sh"), desc="Kill Unity"),
|
||||||
Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown Qtile"),
|
Key([mod, "control"], "q", lazy.shutdown(), desc="Shutdown Qtile"),
|
||||||
Key([mod, alt], "space", lazy.function(toggle_language), desc="Toggle Language Layout"),
|
Key([mod, alt], "space", lazy.function(toggle_language), desc="Toggle Language Layout"),
|
||||||
Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
|
Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
|
||||||
Key([], "XF86AudioLowerVolume", lazy.spawn("amixer sset Master 5%-")),
|
Key([], "XF86AudioLowerVolume", lazy.spawn("amixer sset Master 5%-")),
|
||||||
Key([], "XF86AudioRaiseVolume", lazy.spawn("amixer sset Master 5%+")),
|
Key([], "XF86AudioRaiseVolume", lazy.spawn("amixer sset Master 5%+")),
|
||||||
Key([], "XF86Launch1", lazy.spawn("playerctl play-pause")),
|
Key([], "XF86Launch1", lazy.spawn("playerctl play-pause")),
|
||||||
|
Key([], "XF86AudioMicMute", lazy.spawn("playerctl play-pause")),
|
||||||
Key([], "XF86AudioPlay", lazy.spawn("playerctl play-pause")),
|
Key([], "XF86AudioPlay", lazy.spawn("playerctl play-pause")),
|
||||||
Key([], "XF86MonBrightnessDown", lazy.spawn("brightnessctl set 5%-")),
|
Key([], "XF86MonBrightnessDown", lazy.spawn("brightnessctl set 5%-")),
|
||||||
Key([], "XF86MonBrightnessUp", lazy.spawn("brightnessctl set +5%")),
|
Key([], "XF86MonBrightnessUp", lazy.spawn("brightnessctl set +5%")),
|
||||||
# This uses discrete values
|
# This uses discrete values
|
||||||
Key([], "XF86KbdBrightnessDown", lazy.function(kbd_brightness_down)),
|
Key([], "XF86KbdBrightnessDown", lazy.function(kbd_brightness_down)),
|
||||||
Key([], "XF86KbdBrightnessUp", lazy.function(kbd_brightness_up)),
|
Key([], "XF86KbdBrightnessUp", lazy.function(kbd_brightness_up)),
|
||||||
Key([mod, "control", "shift", alt], "1", lazy.window.set_position_floating(5, 28), desc="Put the window in the corner"),
|
|
||||||
|
Key([mod, alt, "control", "shift"], "q", lazy.function(move_to_corner("top-left")), desc="Move float to top-left"),
|
||||||
|
Key([mod, alt, "control", "shift"], "w", lazy.function(move_to_corner("top-right")), desc="Move float to top-right"),
|
||||||
|
Key([mod, alt, "control", "shift"], "a", lazy.function(move_to_corner("bottom-left")), desc="Move float to bottom-left"),
|
||||||
|
Key([mod, alt, "control", "shift"], "s", lazy.function(move_to_corner("bottom-right")), desc="Move float to bottom-right"),
|
||||||
]
|
]
|
||||||
|
|
||||||
pape_dir = '/home/joe/Pictures/Wallpapers/'
|
pape_dir = '/home/joe/Pictures/Wallpapers/'
|
||||||
@@ -257,11 +292,10 @@ groups[0].label = '🎵'
|
|||||||
|
|
||||||
# groups.insert(0, Group('1', screen_affinity=0, label='🎵'))
|
# groups.insert(0, Group('1', screen_affinity=0, label='🎵'))
|
||||||
|
|
||||||
# This likely won't work when we only have 1 monitor
|
|
||||||
def go_to_group(name: str) -> Callable:
|
def go_to_group(name: str) -> Callable:
|
||||||
def _inner(qtile) -> None:
|
def _inner(qtile) -> None:
|
||||||
if num_monitors > 1:
|
if num_monitors > 1:
|
||||||
if name == '1':
|
if name == '0':
|
||||||
qtile.focus_screen(0)
|
qtile.focus_screen(0)
|
||||||
else:
|
else:
|
||||||
qtile.focus_screen(1)
|
qtile.focus_screen(1)
|
||||||
@@ -364,6 +398,14 @@ floating_layout = layout.Floating(
|
|||||||
Match(wm_class="maketag"), # gitk
|
Match(wm_class="maketag"), # gitk
|
||||||
Match(wm_class="ssh-askpass"), # ssh-askpass
|
Match(wm_class="ssh-askpass"), # ssh-askpass
|
||||||
Match(title="SimpleScreenRecorder"), # ssh-askpass
|
Match(title="SimpleScreenRecorder"), # ssh-askpass
|
||||||
|
# Defold
|
||||||
|
Match(wm_class="com.defold.editor.Start", func=lambda c: c.is_transient_for()),
|
||||||
|
Match(wm_class="Tinyswords"),
|
||||||
|
Match(func=lambda c:
|
||||||
|
(c.window.get_wm_normal_hints() is not None and
|
||||||
|
c.window.get_wm_normal_hints().get('flags') == {'PWinGravity'}) and
|
||||||
|
(c.window.get_wm_class() is not None and
|
||||||
|
any("defold" in cls.lower() for cls in c.window.get_wm_class()))),
|
||||||
# Godot
|
# Godot
|
||||||
Match(title="Alert!"),
|
Match(title="Alert!"),
|
||||||
Match(title="Please Confirm..."),
|
Match(title="Please Confirm..."),
|
||||||
|
|||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
BATTERY_LEVEL=$(upower -i $(upower -e | grep 'BAT') | grep -E "percentage" | awk '{print $2}' | sed 's/%//')
|
||||||
|
|
||||||
|
AC_POWER=$(cat /sys/class/power_supply/AC0/online)
|
||||||
|
if [ $AC_POWER -eq 1 ]; then
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $BATTERY_LEVEL -le 5 ]; then
|
||||||
|
notify-send "Low Battery" "Battery level is ${BATTERY_LEVEL}%" -u critical
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $BATTERY_LEVEL -le 10 ]; then
|
||||||
|
notify-send "Low Battery" "Battery level is ${BATTERY_LEVEL}%" -u normal
|
||||||
|
fi
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
AC_STATE=$(cat /sys/class/power_supply/AC0/online)
|
||||||
|
|
||||||
|
if [ "$AC_STATE" -eq 1 ]; then
|
||||||
|
asusctl profile -P Balanced
|
||||||
|
else
|
||||||
|
asusctl profile -P Quiet
|
||||||
|
fi
|
||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
curr_network=$(nmcli device wifi | rg "^\*" | awk '{print $3}')
|
||||||
|
if [ -z "$curr_network" ]; then
|
||||||
|
echo "Looks like we're not connected to any network"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
path_to_net_conns="/etc/NetworkManager/system-connections"
|
||||||
|
fullpath="${path_to_net_conns}/${curr_network}.nmconnection"
|
||||||
|
|
||||||
|
if [ ! -f "$fullpath" ]; then
|
||||||
|
echo "Could not find this wifi's Network Manager entry"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
password=$(sudo cat $fullpath | rg "^psk" | cut -d "=" -f 2)
|
||||||
|
|
||||||
|
echo Name: \ \ \ $curr_network
|
||||||
|
echo Password: $password
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Set mouse buttons for elecom
|
||||||
|
# 3 = 9 (forward)
|
||||||
|
# 8 = 3 (right click)
|
||||||
|
# 9 = 2 (middle click)
|
||||||
|
# 10 = 8 (back)
|
||||||
|
dev_id=$(xinput | rg "slave\s+pointer" | rg ELECOM | rg -o "id=(\d+)" -r '$1')
|
||||||
|
if [ -n "$dev_id" ]; then
|
||||||
|
xinput set-button-map $dev_id 1 2 9 4 5 6 7 2 3 8
|
||||||
|
echo "Button mapping applied" >> /tmp/trackball.log
|
||||||
|
else
|
||||||
|
echo "No device found" >> /tmp/trackball.log
|
||||||
|
fi
|
||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
odin_path="/home/joe/.local/bin/odin"
|
||||||
|
|
||||||
|
# git pull
|
||||||
|
|
||||||
|
make -j15 release-native
|
||||||
|
|
||||||
|
rm -rf $odin_path/core $odin_path/base $odin_path/vendor
|
||||||
|
cp -r -t $odin_path ./core ./base ./vendor ./odin
|
||||||
Executable
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "Error: Please provide a path to the markdown file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
basename="${1##*/}"
|
||||||
|
basename="${basename%.*}"
|
||||||
|
echo $basename
|
||||||
|
TMPFILE=$(mktemp /tmp/XXXXXXXXXX-${basename}.html)
|
||||||
|
pandoc -f markdown -t html -o "$TMPFILE" "$1" --embed-resources --standalone --css="https://cdn.jsdelivr.net/npm/sakura.css/css/sakura.css"
|
||||||
|
xdg-open $TMPFILE
|
||||||
Reference in new issue
Block a user