Update primary Canonical mail and a few other small tweaks
[~bandali/configs] / .emacs.d / init.el
index 4183865..f4d7259 100644 (file)
@@ -1,6 +1,6 @@
 ;;; init.el --- bandali's emacs configuration -*- lexical-binding: t -*-
 
-;; Copyright (C) 2018-2022  Amin Bandali <bandali@gnu.org>
+;; Copyright (c) 2018-2023 Amin Bandali <bandali@gnu.org>
 
 ;; 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
@@ -60,9 +60,8 @@
   ;;    (debbugs "0.29")
   ;;    (delight "1.7")
   ;;    (emms "7.7")
-  ;;    (rt-liberation "2.4")
-  ;;    (yasnippet "0.14.0")))
-(package-initialize))
+  ;;    (rt-liberation "2.4")))
+  (package-initialize))
 
 (setq package-archive-upload-base "/ssh:caffeine:~/www/p/elpa")
 
 (defalias 'yes-or-no-p #'y-or-n-p)
 
 (when (display-graphic-p)
-  (set-fontset-font t 'arabic "Vazir"))
-;; ;; (set-frame-font "Drafting Mono-14:weight=light" nil t)
-;; (set-frame-font "Drafting Mono:pixelsize=16" nil t)
-;; (set-face-attribute 'bold nil :weight 'semi-bold)
+  ;; (set-frame-font "Source Code Pro-10.5:weight=medium" nil t)
+  ;; (set-frame-font "FreeSans" nil t)
+  (set-fontset-font t 'arabic "Sahel WOL"))
 
 ;;;; Elisp-level customizations
 
   (setq read-file-name-completion-ignore-case t))
 
 ;; `startup'
-;; don't need to see the startup echo area message
-(advice-add #'display-startup-echo-area-message :override #'ignore)
-(setq
- auto-save-list-file-prefix (b/var "auto-save/sessions/")
- ;; i want *scratch* as my startup buffer
- initial-buffer-choice t
- ;; i don't need the default hint
- initial-scratch-message nil
- ;; use customizable text-mode as major mode for *scratch*
- ;; (initial-major-mode 'text-mode)
- ;; inhibit buffer list when more than 2 files are loaded
- inhibit-startup-buffer-menu t
- ;; don't need to see the startup screen or echo area message
- inhibit-startup-screen t
- inhibit-startup-echo-area-message user-login-name)
+(setq auto-save-list-file-prefix (b/var "auto-save/sessions/"))
 
 (with-eval-after-load 'files
   (setq
 (with-eval-after-load 'time
   (setq
    display-time-default-load-average nil
-   display-time-format " %a %b %-e %-l:%M%P"
+   display-time-format " %a %Y-%m-%d %-l:%M%P"
    display-time-mail-icon '(image :type xpm
                                   :file "gnus/gnus-pointer.xpm"
                                   :ascent center)
 
 (run-with-idle-timer 0.1 nil #'require 'battery)
 (with-eval-after-load 'battery
-  (setq battery-mode-line-format " %p%% %t")
+  (setq battery-mode-line-format " [%p%% %t]")
   (display-battery-mode))
 
+(progn ; display system volume in mode-line
+  (defvar b/volume-level 0)
+  (defvar b/volume-mute nil)
+  (defvar b/volume-level-mic 0)
+  (defvar b/volume-mute-mic nil)
+
+  (defun b/volume-get (&optional use-default-source)
+    "Get the default sink volume and mute state.
+If USE-DEFAULT-SOURCE is non-nill, use the default source (e.g. a
+microphone) instead of the default sink."
+    (pcase (split-string   ; expecting: <mute> <volume> (e.g. true 15)
+            (string-trim
+             (shell-command-to-string
+              (mapconcat
+               #'identity
+               `("pamixer"
+                 ,(when use-default-source "--default-source")
+                 "--get-volume"
+                 "--get-mute")
+               " "))))
+      (`(,m ,v)
+       (let ((mute (string= "true" m))
+             (volume (string-to-number v)))
+         `(,mute ,volume)))))
+
+  (defun b/volume-update ()
+    "Update system sound volume as displayed in mode-line."
+    (let ((changed))
+      (pcase (b/volume-get)
+        (`(,mute ,volume)
+         (unless (eq mute b/volume-mute)
+           (setq b/volume-mute mute
+                 changed t))
+         (unless (= volume b/volume-level)
+           (setq b/volume-level volume
+                 changed t))))
+      (pcase (b/volume-get 'mic)
+        (`(,mute ,volume)
+         (unless (eq mute b/volume-mute-mic)
+           (setq b/volume-mute-mic mute
+                 changed t))
+         (unless (= volume b/volume-level-mic)
+           (setq b/volume-level-mic volume
+                 changed t))))
+      (when changed
+        (force-mode-line-update))))
+
+  (defvar b/volume-timer (run-at-time nil 5 #'b/volume-update))
+
+  (setq-default
+   mode-line-format
+   (append
+    mode-line-format
+    '((:eval
+       (format
+        " [%s%%%%%s %s%%%%%s]"
+        (number-to-string b/volume-level)
+        (if b/volume-mute "-" "+")
+        (number-to-string b/volume-level-mic)
+        (if b/volume-mute-mic "-" "+")))))))
+
 ;; (with-eval-after-load 'fringe
 ;;   ;; smaller fringe
 ;;   (fringe-mode '(3 . 1)))
 
 (run-with-idle-timer 0.5 nil #'require 'winner)
 (with-eval-after-load 'winner
-  (winner-mode 1))
+  (winner-mode 1)
+  (when (featurep 'exwm)
+    ;; prevent a bad interaction between EXWM and winner-mode, where
+    ;; sometimes closing a window (like closing a terminal after
+    ;; entering a GPG password via pinentry-gnome3's floating window)
+    ;; results in a dead frame somewhere and effectively freezes EXWM.
+    (advice-add
+     'winner-insert-if-new
+     :around
+     (lambda (orig-fun &rest args)
+       ;; only add the frame if it's live
+       (when (frame-live-p (car args))
+         (apply orig-fun args))))))
 
 (run-with-idle-timer 0.5 nil #'require 'windmove)
 (with-eval-after-load 'windmove
 
 (with-eval-after-load 'ediff
   (setq ediff-window-setup-function 'ediff-setup-windows-plain
-        ediff-split-window-function 'split-window-horizontally)
-  (add-hook 'ediff-after-quit-hook-internal #'winner-undo))
+        ediff-split-window-function 'split-window-horizontally))
 
 (with-eval-after-load 'face-remap
   (setq
 (when (display-graphic-p)
   (with-eval-after-load 'faces
     (let ((grey "#e7e7e7"))
-      (set-face-attribute 'fixed-pitch nil :family "Source Code Pro")
+      (set-face-attribute 'fixed-pitch nil
+                          :font "Source Code Pro"
+                          :weight 'medium)
       (set-face-attribute 'mode-line nil
                           :background grey
                           :inherit 'fixed-pitch))))
@@ -389,16 +447,16 @@ For disabling the behaviour for certain buffers and/or modes."
   (make-local-variable 'mouse-autoselect-window)
   (setq mouse-autoselect-window nil))
 
-(defun b/move-indentation-or-beginning-of-line (arg)
-  "Move to the indentation or to the beginning of line."
-  (interactive "^p")
-  ;; (if (bolp)
-  ;;     (back-to-indentation)
-  ;;   (move-beginning-of-line arg))
-  (if (= (point)
-         (progn (back-to-indentation)
-                (point)))
-      (move-beginning-of-line arg)))
+;; (defun b/move-indentation-or-beginning-of-line (arg)
+;;   "Move to the indentation or to the beginning of line."
+;;   (interactive "^p")
+;;   ;; (if (bolp)
+;;   ;;     (back-to-indentation)
+;;   ;;   (move-beginning-of-line arg))
+;;   (if (= (point)
+;;          (progn (back-to-indentation)
+;;                 (point)))
+;;       (move-beginning-of-line arg)))
 
 (defun b/join-line-top ()
   "Like `join-line', but join next line to the current line."
@@ -432,13 +490,19 @@ Make N (default: 1) copies of the current line or region."
         (dotimes (_ (abs n1))
           (insert text))))))
 
-(defun b/invert-default-face ()
-  "Invert the `default' face (swap its background and foreground).
-Effectively a very simple light/dark theme toggle switch."
-  (interactive)
-  (invert-face 'default)
-  (when (display-graphic-p)
-    (invert-face 'mode-line)))
+(defun b/invert-default-face (arg)
+  "Invert the `default' and `mode-line' faces for the current frame.
+Swap the background and foreground for the two `default' and
+`mode-line' faces, effectively acting like a simple light/dark
+theme toggle.  If prefix argument ARG is given, invert the faces
+for all frames."
+  (interactive "P")
+  (let ((frame (unless arg
+                 (selected-frame))))
+    (invert-face 'default frame)
+    (invert-face 'mode-line frame))
+  (when (fboundp #'exwm-systemtray--refresh-background-color)
+    (exwm-systemtray--refresh-background-color 'remap)))
 
 (defun b/export-frame ()
   (interactive)
@@ -453,12 +517,12 @@ Effectively a very simple light/dark theme toggle switch."
 \f
 ;;; General key bindings
 
-(global-set-key (kbd "C-a") #'b/move-indentation-or-beginning-of-line)
-(global-set-key (kbd "C-c i") #'ielm)
+;; (global-set-key (kbd "C-a") #'b/move-indentation-or-beginning-of-line)
+(global-set-key (kbd "C-c i") #'ielm)
 (global-set-key (kbd "C-c d") #'b/duplicate-line-or-region)
 (global-set-key (kbd "C-c j") #'b/join-line-top)
 (global-set-key (kbd "C-S-j") #'b/join-line-top)
-(global-set-key (kbd "C-c s") #'b/*scratch*)
+(global-set-key (kbd "C-c s c") #'b/*scratch*)
 (global-set-key (kbd "C-c x") #'execute-extended-command)
 (global-set-key (kbd "C-c v") #'b/invert-default-face)
 
@@ -499,7 +563,14 @@ Effectively a very simple light/dark theme toggle switch."
  (expand-file-name
   (convert-standard-filename "lisp") user-emacs-directory))
 
-;; (require 'bandali-exwm)
+(when
+    (and
+     (display-graphic-p)
+     ;; we're not running in another WM/DE
+     (not (getenv "XDG_CURRENT_DESKTOP"))
+     (member (system-name) '("chaman" "langa")))
+  (require 'bandali-exwm)
+  (global-set-key (kbd "C-x b") #'exwm-workspace-switch-to-buffer))
 
 (require 'bandali-org)
 
@@ -601,8 +672,8 @@ Effectively a very simple light/dark theme toggle switch."
         scpaste-scp-destination "p:~"))
 (autoload 'scpaste "scpaste" nil t)
 (autoload 'scpaste-region "scpaste" nil t)
-(global-set-key (kbd "C-c p p") #'scpaste)
-(global-set-key (kbd "C-c p r") #'scpaste-region)
+(global-set-key (kbd "C-c p p") #'scpaste)
+(global-set-key (kbd "C-c p r") #'scpaste-region)
 
 \f
 ;;; Editing
@@ -761,7 +832,6 @@ Effectively a very simple light/dark theme toggle switch."
 ;; ,----
 ;; | make pretty boxed quotes like this
 ;; `----
-(add-to-list 'load-path (b/lisp "boxquote"))
 (run-with-idle-timer 0.6 nil #'require 'boxquote)
 (with-eval-after-load 'boxquote
   (defvar b/boxquote-prefix-map)
@@ -788,37 +858,6 @@ Effectively a very simple light/dark theme toggle switch."
   (define-key b/boxquote-prefix-map (kbd "M-q") #'boxquote-fill-paragraph)
   (define-key b/boxquote-prefix-map (kbd "M-w") #'boxquote-kill-ring-save))
 
-(add-to-list 'load-path (b/lisp "hl-todo"))
-(run-with-idle-timer 0.5 nil #'require 'hl-todo)
-(with-eval-after-load 'hl-todo
-  ;; Highlight TODO in buffers.
-  (global-hl-todo-mode))
-
-(run-with-idle-timer 0.6 nil #'require 'yasnippet)
-(with-eval-after-load 'yasnippet
-  (declare-function yas-reload-all
-                    "yasnippet" (&optional no-jit interactive))
-  (declare-function yas-maybe-expand-abbrev-key-filter
-                    "yasnippet" (cmd))
-
-  (defconst yas-verbosity-cur yas-verbosity)
-  (setq yas-verbosity 2
-        yas-snippet-dirs `(,(b/etc "yasnippet/snippets")))
-  ;; (add-to-list 'yas-snippet-dirs "~/src/git/guix/etc/snippets" t)
-  (yas-reload-all)
-  (setq yas-verbosity yas-verbosity-cur)
-
-  (defun b/yas-maybe-expand-abbrev-key-filter (cmd)
-    (when (and (yas-maybe-expand-abbrev-key-filter cmd)
-               (not (bound-and-true-p git-commit-mode)))
-      cmd))
-  (defconst b/yas-maybe-expand
-    '(menu-item "" yas-expand
-                :filter b/yas-maybe-expand-abbrev-key-filter))
-  (define-key yas-minor-mode-map (kbd "SPC") b/yas-maybe-expand)
-
-  (yas-global-mode))
-
 ;; `debbugs'
 (global-set-key (kbd "C-c D d") #'debbugs-gnu)
 (global-set-key (kbd "C-c D b") #'debbugs-gnu-bugs)
@@ -845,7 +884,7 @@ Effectively a very simple light/dark theme toggle switch."
   (setq
    eww-download-directory
    (file-name-as-directory (getenv "XDG_DOWNLOAD_DIR"))))
-(global-set-key (kbd "C-c e w") #'eww)
+(global-set-key (kbd "C-c e w") #'eww)
 
 ;; (with-eval-after-load 'org-ref
 ;;   (setq
@@ -854,11 +893,10 @@ Effectively a very simple light/dark theme toggle switch."
 ;;    org-ref-bibliography-notes "~/usr/org/notes.org"
 ;;    org-ref-pdf-directory "~/usr/org/bibtex-pdfs/"))
 
-(when (featurep 'display-fill-column-indicator)
-  (run-with-idle-timer
-   0.2 nil #'require 'display-fill-column-indicator)
-  (with-eval-after-load 'display-fill-column-indicator
-    (global-display-fill-column-indicator-mode 1)))
+(run-with-idle-timer
+ 0.2 nil #'require 'display-fill-column-indicator nil 'noerror)
+(with-eval-after-load 'display-fill-column-indicator
+  (global-display-fill-column-indicator-mode 1))
 
 (with-eval-after-load 'window
   (setq split-width-threshold 150)
@@ -897,8 +935,7 @@ Effectively a very simple light/dark theme toggle switch."
 (with-eval-after-load 'delight
   (delight 'auto-fill-function " f" "simple")
   (delight 'abbrev-mode "" "abbrev")
-  (delight 'mml-mode " mml" "mml")
-  (delight 'yas-minor-mode "" "yasnippet"))
+  (delight 'mml-mode " mml" "mml"))
 
 (require 'bandali-po)
 
@@ -910,4 +947,24 @@ Effectively a very simple light/dark theme toggle switch."
 (with-eval-after-load 'ffs
   (global-set-key (kbd "C-c f s") #'ffs))
 
+(add-to-list 'load-path (b/lisp "debian-el"))
+(run-with-idle-timer 0.5 nil #'require 'debian-el)
+(with-eval-after-load 'debian-el
+  (require 'apt-sources)
+  (require 'apt-utils)
+  (require 'debian-bug)
+  (require 'deb-view)
+  (require 'gnus-BTS)
+  (require 'preseed))
+
+(add-to-list 'load-path (b/lisp "dpkg-dev-el"))
+(run-with-idle-timer 0.5 nil #'require 'dpkg-dev-el)
+(with-eval-after-load 'dpkg-dev-el
+  (require 'debian-changelog-mode)
+  (require 'debian-bts-control)
+  (require 'debian-changelog-mode)
+  (require 'debian-control-mode)
+  (require 'debian-copyright)
+  (require 'readme-debian))
+
 ;;; init.el ends here