;;; -*- lexical-binding: t; -*- ;;; ace window (use-package ace-window :ensure t :demand t :init (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l) aw-char-position 'top-left aw-ignore-current nil aw-dispatch-when-more-than 2 aw-leading-char-style 'path aw-display-mode-overlay t aw-scope 'frame) :config (defun jao-ace-consult-buffer-other-window (w) (interactive) (aw-switch-to-window w) (consult-buffer)) (setf (alist-get ?b aw-dispatch-alist) '(jao-ace-consult-buffer-other-window "Consult buffer")) (setf (alist-get ?B aw-dispatch-alist) (alist-get ?u aw-dispatch-alist)) :bind (("M-o" . ace-window) ("M-O" . ace-swap-window) ("C-x 4 t" . ace-swap-window))) ;;; sway (defun jao-swaymsg (msg) (shell-command (format "swaymsg '%s' >/dev/null" msg))) (defmacro jao-def-swaymsg (name msg) `(defun ,(intern (format "jao-sway-%s" name)) () (interactive) (jao-swaymsg ,msg))) (jao-def-swaymsg firefox "[app_id=firefox] focus") (defvar jao-sway-enabled (and (eq window-system 'pgtk) (not jao-xmonad-enabled))) (defun jao-sway-set-wallpaper (f) (jao-swaymsg (format "output * bg %s fill" f)) (make-symbolic-link f "~/.wallpaper.sway" t)) (defun jao-sway-run-or-focus (cmd &optional ws) (if (jao-shell-running-p "firefox") (jao-swaymsg (format "[app_id=%s] focus" cmd)) (jao-swaymsg (format "workspace %s" (or ws 2))) (start-process-shell-command cmd nil cmd))) (defun jao-sway-run-or-focus-tidal () (interactive) (if (jao-shell-running-p "tidal-hifi") (jao-swaymsg "[app_id=tidal-hifi] scratchpad show") (start-process-shell-command "tidal-hifi" nil "tidal-hifi &") (jao-sway-run-or-focus-tidal))) (defun jao-sway-run-or-focus-firefox () (interactive) (jao-sway-run-or-focus "firefox")) (defun jao-sway-enable () (setq jao-browse-doc-use-emacs-p t) (setq jao-wallpaper-random-wake nil) (jao-trisect) (jao-set-transparency 85) (jao-themes-setup) ;; (display-time-mode 1) (global-set-key (kbd "s-f") #'jao-sway-run-or-focus-firefox) (defalias 'jao-streaming-list #'jao-sway-run-or-focus-tidal) (message "Welcome to sway")) (when jao-sway-enabled (defalias 'x-change-window-property #'ignore) (add-hook 'after-init-hook #'jao-sway-enable)) ;;; time display (setq display-time-world-list '(("Europe/Paris" "Barcelona") ("America/Los_Angeles" "Los Angeles") ("America/New_York" "New York") ("Europe/London" "London") ("Asia/Calcutta" "Bangalore") ("Asia/Tokyo" "Tokyo"))) (defun jao-time--pdt-hour () (jao-time-at-zone "%H" "America/Los_Angeles")) (defun jao-time--chicago-hour () (jao-time-at-zone "%H" "America/Chicago")) (defun jao-time-at-zone (format zone) (set-time-zone-rule zone) (prog1 (format-time-string format) (set-time-zone-rule nil))) (defun jao-time-echo-la-time () (interactive) (message (jao-time-at-zone "LA %H:%M" "America/Los_Angeles"))) (defun jao-time-echo-times () (interactive) (let ((msg (format "%s (%s)" (format-time-string "%a, %e %B - %H:%M") (jao-time-at-zone "%H:%M" "America/Los_Angeles")))) (jao-notify msg "" (jao-data-file "clock-world-icon.png")))) (defun jao-time-to-epoch (&optional s) "Transform a time string to an epoch integer in milliseconds." (interactive) (let ((s (or s (read-string "Time string: " (thing-at-point 'string))))) (message "%s = %s" s (round (* 1000 (time-to-seconds (parse-time-string s))))))) (defun jao-epoch-to-time (&optional v) "Transform an epoch, given in milliseconds, to a time string." (interactive) (let ((v (or v (read-number "Milliseconds: " (thing-at-point 'number))))) (message "%s = %s" v (format-time-string "%Y-%m-%d %H:%M:%S" (seconds-to-time (/ v 1000.0)))))) ;;; twtxt (use-package twtxt :ensure t :init (setq twtxt-file (expand-file-name "~/doc/jao.io/twtxt") twtxt-following '(("yarn" "https://twtxt.net/user/news/twtxt.txt")))) ;;; corfu bits (defun jao-corfu-enable-no-auto () (setq-local corfu-auto nil) (corfu-mode 1)) (defmacro jao-corfu-no-auto (mode) (let ((mode-name (intern (format "%s-mode" mode))) (hook-name (intern (format "%s-mode-hook" mode)))) `(with-eval-after-load ',mode (add-to-list 'corfu-excluded-modes ',mode-name) (add-hook ',hook-name #'jao-corfu-enable-no-auto)))) (jao-corfu-no-auto eshell) ;;; gnus bits (jao-transient-major-mode gnus-group ["Search" ("zc" "consult search" consult-notmuch) ("zf" "consult folder search" jao-consult-notmuch-folder) ("g" "gnus search" gnus-group-read-ephemeral-search-group)]) (defun jao-gnus-restart-servers () (interactive) (message "Restarting all servers...") (gnus-group-enter-server-mode) (gnus-server-close-all-servers) (gnus-server-open-all-servers) (gnus-server-exit) (message "Restarting all servers... done")) ;;;; delayed expiry (defvar jao-gnus--expire-every 50) (defvar jao-gnus--get-count (1+ jao-gnus--expire-every)) (defun jao-gnus-get-new-news (&optional arg) (interactive "p") (when (and jao-gnus--expire-every (> jao-gnus--get-count jao-gnus--expire-every)) (when jao-gnus-use-pm-imap (gnus-group-catchup "nnimap:pm/spam" t)) (gnus-group-expire-all-groups) (setq jao-gnus--get-count 0)) (setq jao-gnus--get-count (1+ jao-gnus--get-count)) (gnus-group-get-new-news (max (if (= 1 jao-gnus--get-count) 4 3) (or arg 0)))) (define-key gnus-group-mode-map "g" 'jao-gnus-get-new-news) (define-key gnus-group-mode-map "\C-x\C-s" #'gnus-group-save-newsrc) (defun jao-gnus--first-group () (when (derived-mode-p 'gnus-group-mode) (gnus-group-first-unread-group))) (with-eval-after-load "jao-afio" (add-hook 'jao-afio-switch-hook #'jao-gnus--first-group)) ;;;; remove HTML from From contents (arxiv with r2e) (require 'shr) (defvar jao-gnus--from-rx (concat "From: \\\"?\\( " jao-gnus--news-rx "\\)")) (defun jao-gnus-remove-anchors () (save-excursion (goto-char (point-min)) (cond ((re-search-forward jao-gnus--from-rx nil t) (replace-match "" nil nil nil 1)) ((re-search-forward "[gq].+ updates on arXiv.org: " nil t) (replace-match "") (let ((begin (point))) (when (re-search-forward "^\\(To\\|Subject\\):" nil t) (beginning-of-line) (let ((shr-width 10000)) (shr-render-region begin (1- (point)))))))))) (add-hook 'gnus-part-display-hook 'jao-gnus-remove-anchors) ;;;; find message id (defun jao-gnus-file-message-id (filename) (with-temp-buffer (insert-file filename) (goto-char (point-min)) (when (re-search-forward "^[Mm]essage-[Ii][Dd]: <]+\\)>?" nil t) (match-string 1)))) ;;; company (use-package company :ensure t :custom ((company-backends '(company-capf ;; company-bbdb company-files company-dabbrev company-keywords)) (company-global-modes '(not slack-message-buffer-mode circe-channel-mode telega-chat-mode)) (company-format-margin-function nil) ;; #'company-text-icons-margin (company-idle-delay 0.2) (company-lighter "") (company-lighter-base "") (company-show-numbers nil) (company-selection-wrap-around t) (company-tooltip-limit 15) (company-tooltip-align-annotations t) (company-tooltip-offset-display 'lines)) ;; 'scrollbar :config (defun jao-complete-at-point () "Complete using company unless we're in the minibuffer." (interactive) (if (or (not company-mode) (window-minibuffer-p)) (completion-at-point) (company-manual-begin))) (defun jao-company-use-in-tab () (global-set-key [remap completion-at-point] #'jao-complete-at-point) (global-set-key [remap completion-symbol] #'jao-complete-at-point) (global-set-key (kbd "M-TAB") #'jao-complete-at-point)) (jao-company-use-in-tab) :bind (:map company-active-map ("" . company-complete-common-or-cycle) ("TAB" . company-complete-common-or-cycle) ("C-h" . company-show-doc-buffer) ("M-." . company-show-location) ("C-" . company-complete-selection) ([remap return] . company-abort) ("RET" . company-abort) :filter (or (not (derived-mode-p 'eshell-mode)) (company-explicit-action-p)) ("" . company-complete-selection) ("RET" . company-complete-selection)) :diminish) (global-company-mode 1) ;;; mu4e (jao-load-path "mu4e") (use-package mu4e :init (setq mu4e-attachment-dir (expand-file-name "~/var/download/attachments") mu4e-change-filenames-when-moving nil mu4e-completing-read-function 'completing-read mu4e-display-update-status-in-modeline nil mu4e-get-mail-command "true" ;; "run-mb.sh || [ $? -eq 1 ]" mu4e-headers-show-threads t mu4e-headers-sort-direction 'ascending mu4e-headers-visible-columns 100 mu4e-headers-visible-lines 12 mu4e-hide-index-messages t mu4e-index-cleanup t ;; don't do a full cleanup check mu4e-index-lazy-check t ;; don't consider up-to-date dirs mu4e-maildir "~/var/mail" mu4e-split-view 'horizontal ;; 'vertical mu4e-update-interval 300 mu4e-use-fancy-chars nil mu4e-user-mail-address-list jao-mails mu4e-view-show-addresses t mu4e-view-show-images t mu4e-maildir-shortcuts '((:maildir "/jao/inbox" :key ?j) (:maildir "/bigml/inbox" :key ?b)) jao-mu4e-uninteresting-mail-query (concat "flag:unread AND NOT flag:trashed" " AND NOT (maildir:/bigml/inbox OR maildir:/bigml/bugs OR" " maildir:/bigml/support OR maildir:/jao/inbox)") jao-mu4e-interesting-mail-query (concat "flag:unread AND NOT flag:trashed" " AND (maildir:/bigml/inbox OR maildir:/bigml/bugs OR" " maildir:/bigml/support OR maildir:/jao/inbox)") mu4e-bookmarks `((:name "Inbox" :query ,jao-mu4e-interesting-mail-query :key ?i) (:name "Other messages" :query ,jao-mu4e-uninteresting-mail-query :key 117) (:name "Today's messages" :query "date:today..now" :key 116) (:name "Last 7 days" :query "date:7d..now" :hide-unread t :key 119) (:name "Messages with PDFs" :query "mime:application/pdf OR mime:x-application/pdf" :key 112))) :config (defun jao-mu4e--maildir (msg) (when msg (let ((md (mu4e-message-field msg :maildir))) (when (string-match "/\\([^/]+\\)/.*" md) (match-string 1 md))))) (defun jao-mu4e--refile-folder (name) (lambda (msg) (let ((md (jao-mu4e--maildir msg))) (if (string= md name) (concat "/jao/" name) (format "/%s/%s" md name))))) (setq mu4e-sent-folder (jao-mu4e--refile-folder "sent")) (setq mu4e-drafts-folder (jao-mu4e--refile-folder "drafts")) (setq mu4e-trash-folder (jao-mu4e--refile-folder "trash")) (setq mu4e-refile-folder (jao-mu4e--refile-folder "trove")) (setq mu4e-contexts nil) (setq mu4e-view-show-images t) (when (fboundp 'imagemagick-register-types) (imagemagick-register-types)) (define-key mu4e-view-mode-map [remap mu4e-view-verify-msg-popup] 'epa-mail-verify) ;; View html message in browser (type aV) (add-to-list 'mu4e-view-actions '("ViewInBrowser" . mu4e-action-view-in-browser) t))