Compare commits

..
42 Commits
Author SHA1 Message Date
JosephFerano 69af07dc49 emacs: require org? 2026-05-11 13:22:02 +07:00
JosephFerano 017c4b0b7d emacs: guard against missing gptel keys 2026-05-11 13:19:52 +07:00
JosephFerano 77b1b6f999 emacs: comment out dotenv 2026-05-11 13:14:37 +07:00
JosephFerano 5c4d83590c emacs: centaur tabs package 2026-05-11 13:10:11 +07:00
JosephFerano a949d2b57b emacs: C-x b 2026-05-11 13:07:22 +07:00
JosephFerano 45ed3a8081 script: battery-notify check if we are already on AC 2026-05-09 18:02:46 +07:00
JosephFerano eebfbdf622 fish: I don't know 2026-05-09 18:02:43 +07:00
JosephFerano 508bdeb553 qtile: Move to corners 2026-05-09 18:02:01 +07:00
JosephFerano 6511ef9860 emacs: centaur-tabs, fix some gptel stuff 2026-05-09 18:00:12 +07:00
JosephFerano a5a40d6636 emacs: Use expand-file-name, fix truncate-lines, better keybindings 2026-05-09 17:59:51 +07:00
JosephFerano 7fdcfa458c emacs: emacs style for remaining SPC keybindings, fix nano-calendar scaling, use emacs for magit 2026-04-13 10:46:10 +08:00
JosephFerano b6aec65c87 emacs: emacs style ergonomic buffer keybindings, more clean up 2026-04-12 20:49:13 +08:00
JosephFerano d4879ef719 emacs: Fix olivetti mode issue, add a manual toggle check 2026-04-11 18:37:32 +08:00
JosephFerano d199950bc3 emacs: Get rid of unused stuff, use more default or emacs style keybindings 2026-04-11 17:18:22 +08:00
JosephFerano e9a736f9c2 emacs: clojure stuff, magit functions, lsp, cider error stuff 2026-02-23 14:15:01 +07:00
JosephFerano 9cb8126a8c emacs: Fix clojure nesting 2025-11-17 09:27:33 +07:00
JosephFerano 95c69be2c6 scripts: power-profile-switch.sh 2025-11-16 15:14:39 +07:00
JosephFerano 3c6e2521b0 qtile: mod + hjkl with emacs, s-mod + s for fullscreen screenshot to clipboard 2025-11-16 15:12:53 +07:00
JosephFerano 858d26129b emacs: Update mu4e, remove fast folding since it's now a built-in feature 2025-11-16 15:11:49 +07:00
JosephFerano 367b17ea20 emacs: Disable lingering popper stuff, lsp prefix 2025-11-16 15:10:21 +07:00
JosephFerano a3977ac72c emacs: gptel clean up, comment 2025-11-16 15:09:05 +07:00
JosephFerano 6a47cd3960 emacs: clojure config, vcs modeline, kill-current-buffer 2025-11-16 15:06:33 +07:00
JosephFerano 06ba9c724f scripts: Add odin upgrade 2025-10-13 11:09:40 +07:00
JosephFerano 9937e9db3f emacs: joe/org-clock-project-heading, expand-region keybindings, pyenv package 2025-10-13 10:45:56 +07:00
JosephFerano fe4ae5a7b1 emacs: Thread folding for mu4e 2025-10-13 10:45:22 +07:00
JosephFerano 0a0f6dc2de qtile:Add defold window rules 2025-10-13 10:44:49 +07:00
JosephFerano ba998e252c scripts: battery-notify and view-md-in-browser 2025-10-13 10:44:00 +07:00
JosephFerano 8213453bce emacs: better sly setup with faster loading, add chatgtp as model 2025-09-04 13:41:47 +07:00
JosephFerano 4725492a7d emacs: better mu4e-get-mail-command, better daily entry capture, book subtitle, calfw junctions 2025-09-04 13:33:30 +07:00
JosephFerano 2820ec5f84 mbsync: reorganize channels so we can parallelize syncing 2025-09-04 13:25:23 +07:00
JosephFerano 40be300bf4 emacs: gptel enhancements including gptel-ask and keybindings 2025-06-24 18:56:59 +07:00
JosephFerano ec98d3bfab emacs: Revamp mu4e config to make gmail work better 2025-06-24 18:56:30 +07:00
JosephFerano e51d89105d emacs: Programming enhancements to Lisp, C, Rust, and Clojure 2025-06-24 18:55:01 +07:00
JosephFerano 3dc1582585 emacs: joe/project-vterm and joe/project-silent-shell-command with binding 2025-06-24 18:53:38 +07:00
JosephFerano 2e7c33bef4 emacs: Remove popper and related functions, add more harpoon bindings 2025-06-24 18:52:34 +07:00
JosephFerano 81ec6fa96c emacs: Toggle olivetti mode when resizing windows, comment out stuff, formatting 2025-06-24 18:49:33 +07:00
JosephFerano 49552caea9 mbsync: Fix gmail 2025-06-24 18:43:51 +07:00
JosephFerano dd61440e6a qtile: Fix pinned screen, add trackball keybinding 2025-06-24 18:43:22 +07:00
JosephFerano 17a4592aa9 fish: Add android sdk paths 2025-06-24 18:41:48 +07:00
JosephFerano 21d00a7cf2 scripts: show-wifi-password & trackball.sh 2025-06-24 18:41:27 +07:00
JosephFerano a84025dce4 kitty: Maybe fix copy/paste? 2025-04-22 22:02:09 +08:00
JosephFerano ed1ae747fe fish: Update exercism completions 2025-04-22 22:02:00 +08:00
16 changed files with 1635 additions and 1129 deletions

No files matched your search

+197
View File
@@ -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)
+382
View File
@@ -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
+1 -1
View File
@@ -101,7 +101,7 @@
(buffer-size)
(erase-buffer)
(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 "Welcome to Emacs!\n\n")
;; (dashboard-insert-center "testing this thing out\n\n")
+830 -1085
View File
File diff suppressed because it is too large. Load diff
+7 -3
View File
@@ -15,16 +15,20 @@ complete -f -c exercism -n "__fish_seen_subcommand_from download" -s u -l uuid -
# 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_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
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"
# 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"
# 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
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)"
+3 -5
View File
@@ -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_DATA_HOME /home/joe/.local/share
set -gx XDG_CACHE_HOME /home/joe/.cache
@@ -76,12 +73,13 @@ end
fish_ssh_agent
# 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
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"
source "/home/joe/Repositories/emsdk/emsdk_env.fish"
set -gx EMSDK_QUIET 1
end
alias claude="/home/joe/.claude/local/claude"
+7 -3
View File
@@ -1,9 +1,13 @@
# This file contains fish universal variable definitions.
# 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 EDITOR:hx
SETUVAR --export LC_COLLATE:C
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 RUSTUP_HOME:/home/joe/\x2elocal/share/rustup/
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_CONFIG_HOME:/home/joe/\x2econfig
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_plugins:ankitsumitg/docker\x2dfish\x2dcompletions
SETUVAR fish_color_autosuggestion:969896
@@ -32,7 +36,7 @@ SETUVAR fish_color_operator:00a6b2
SETUVAR fish_color_param:81a2be
SETUVAR fish_color_quote:b5bd68
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_status:red
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_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan
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
+2 -1
View File
@@ -56,7 +56,8 @@ map kitty_mod+j neighboring_window down
map kitty_mod+k neighboring_window up
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+n next_tab
+74 -26
View File
@@ -13,21 +13,45 @@ Subfolders Verbatim
Path ~/.mail/ferano.io/
Inbox ~/.mail/ferano.io/Inbox
Channel ferano.io
Far :ferano.io.remote:
Near :ferano.io.local:
# Include everything
Patterns *
Channel ferano.io-inbox
Far :ferano.io.remote:INBOX
Near :ferano.io.local:INBOX
Sync All
Create Both
Remove Both
Expunge Both
SyncState *
Channel ferano.io.inbox
Far :ferano.io.remote:
Near :ferano.io.local:
Patterns INBOX
Channel ferano.io-drafts
Far :ferano.io.remote:Drafts
Near :ferano.io.local:Drafts
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
Create Both
Remove Both
@@ -45,42 +69,66 @@ Account gmail
MaildirStore gmail.local
Subfolders Verbatim
# The trailing "/" is important
Path ~/.mail/gmail/
Inbox ~/.mail/gmail/Inbox
Inbox ~/.mail/gmail/INBOX
Channel gmail
Far :gmail.remote:
Near :gmail.local:
# Include everything
Patterns *
Channel gmail-inbox
Far :gmail.remote:INBOX
Near :gmail.local:INBOX
Sync All
Create Both
Remove Both
Expunge Both
SyncState *
Channel gmail.inbox
Far :gmail.remote:
Near :gmail.local:
Patterns INBOX
Channel gmail-drafts
Far :gmail.remote:"[Gmail]/Drafts"
Near :gmail.local:"[Gmail]/Drafts"
Sync All
Create Both
Remove Both
Expunge Both
SyncState *
Channel gmail.allmail
Far :gmail.remote:
Near :gmail.local:
Patterns *All*
Channel gmail-sent
Far :gmail.remote:"[Gmail]/Sent Mail"
Near :gmail.local:"[Gmail]/Sent Mail"
Sync All
Create Both
Remove Both
Expunge Both
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
Channel ferano.io
Channel gmail
Channel ferano.io-inbox
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
View File
@@ -84,16 +84,44 @@ def new_client(client):
y = client.group.screen.height - client.height - padding - 22
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 = [
# 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
# Switch between windows
# .when(wm_class != 'kitty')
# 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], "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([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, "control"], "w", lazy.function(get_current_window_info), desc="Get window info"),
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
# 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, "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, alt], "space", lazy.function(toggle_language), desc="Toggle Language Layout"),
Key([mod], "r", lazy.spawncmd(), desc="Spawn a command using a prompt widget"),
Key([], "XF86AudioLowerVolume", lazy.spawn("amixer sset Master 5%-")),
Key([], "XF86AudioRaiseVolume", lazy.spawn("amixer sset Master 5%+")),
Key([], "XF86Launch1", lazy.spawn("playerctl play-pause")),
Key([], "XF86AudioMicMute", lazy.spawn("playerctl play-pause")),
Key([], "XF86AudioPlay", lazy.spawn("playerctl play-pause")),
Key([], "XF86MonBrightnessDown", lazy.spawn("brightnessctl set 5%-")),
Key([], "XF86MonBrightnessUp", lazy.spawn("brightnessctl set +5%")),
# This uses discrete values
Key([], "XF86KbdBrightnessDown", lazy.function(kbd_brightness_down)),
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/'
@@ -257,11 +292,10 @@ groups[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 _inner(qtile) -> None:
if num_monitors > 1:
if name == '1':
if name == '0':
qtile.focus_screen(0)
else:
qtile.focus_screen(1)
@@ -364,6 +398,14 @@ floating_layout = layout.Floating(
Match(wm_class="maketag"), # gitk
Match(wm_class="ssh-askpass"), # 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
Match(title="Alert!"),
Match(title="Please Confirm..."),
+16
View File
@@ -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
+9
View File
@@ -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
+20
View File
@@ -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
+13
View File
@@ -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
+12
View File
@@ -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
+15
View File
@@ -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