X-Git-Url: https://git.shemshak.org/gitweb.cgi/~bandali/configs/blobdiff_plain/f76bdaa8303e6353103e94792e4275a6a6bab58c..fdcac86a345fe80043e56d5b8defd6b9fb744d22:/init.org?ds=sidebyside diff --git a/init.org b/init.org index 6be9194..b7506e1 100644 --- a/init.org +++ b/init.org @@ -319,6 +319,14 @@ in my shell. (exec-path-from-shell-copy-env "SSH_AUTH_SOCK")) #+end_src +** Only one custom theme at a time + +#+begin_src emacs-lisp +(defadvice load-theme (before clear-previous-themes activate) + "Clear existing theme settings instead of layering them" + (mapc #'disable-theme custom-enabled-themes)) +#+end_src + ** Server Start server if not already running. Alternatively, can be done by @@ -372,6 +380,48 @@ Font stack with better unicode support, around =Ubuntu Mono= and 'prepend)) #+end_src +** Libraries + +#+begin_src emacs-lisp +(require 'cl-lib) +(require 'subr-x) +#+end_src + +** Useful utilities + +#+begin_src emacs-lisp +(defun ab-enlist (exp) + "Return EXP wrapped in a list, or as-is if already a list." +(if (listp exp) exp (list exp))) + +; from https://github.com/hlissner/doom-emacs/commit/589108fdb270f24a98ba6209f6955fe41530b3ef +(defmacro after! (features &rest body) + "A smart wrapper around `with-eval-after-load'. Supresses warnings during +compilation." + (declare (indent defun) (debug t)) + (list (if (or (not (bound-and-true-p byte-compile-current-file)) + (dolist (next (ab-enlist features)) + (if (symbolp next) + (require next nil :no-error) + (load next :no-message :no-error)))) + #'progn + #'with-no-warnings) + (cond ((symbolp features) + `(eval-after-load ',features '(progn ,@body))) + ((and (consp features) + (memq (car features) '(:or :any))) + `(progn + ,@(cl-loop for next in (cdr features) + collect `(after! ,next ,@body)))) + ((and (consp features) + (memq (car features) '(:and :all))) + (dolist (next (cdr features)) + (setq body `(after! ,next ,@body))) + body) + ((listp features) + `(after! (:all ,@features) ,@body))))) +#+end_src + * Core :PROPERTIES: :CUSTOM_ID: core @@ -532,236 +582,59 @@ customizing it. 'auto-compile-inhibit-compile-detached-git-head)) #+end_src -*** TODO [[https://github.com/Kungsgeten/ryo-modal][ryo-modal]] +*** [[https://github.com/noctuid/general.el][general]] #+begin_quote Roll your own modal mode #+end_quote -*** [[https://github.com/ch11ng/exwm][EXWM]] (window manager) - -#+begin_src emacs-lisp :tangle no -(use-package exwm +#+begin_src emacs-lisp +(use-package general :demand t :config - (require 'exwm-config) - - ;; Set the initial workspace number. - (setq exwm-workspace-number 4) - - ;; Make class name the buffer name, truncating beyond 50 characters - (defun exwm-rename-buffer () - (interactive) - (exwm-workspace-rename-buffer - (concat exwm-class-name ":" - (if (<= (length exwm-title) 50) exwm-title - (concat (substring exwm-title 0 49) "..."))))) - (add-hook 'exwm-update-class-hook 'exwm-rename-buffer) - (add-hook 'exwm-update-title-hook 'exwm-rename-buffer) - - ;; 's-R': Reset - (exwm-input-set-key (kbd "s-R") #'exwm-reset) - ;; 's-\': Switch workspace - (exwm-input-set-key (kbd "s-\\") #'exwm-workspace-switch) - ;; 's-N': Switch to certain workspace - (dotimes (i 10) - (exwm-input-set-key (kbd (format "s-%d" i)) - (lambda () - (interactive) - (exwm-workspace-switch-create i)))) - ;; 's-SPC': Launch application - ;; (exwm-input-set-key - ;; (kbd "s-SPC") - ;; (lambda (command) - ;; (interactive (list (read-shell-command "➜ "))) - ;; (start-process-shell-command command nil command))) - - (exwm-input-set-key (kbd "M-s-SPC") #'counsel-linux-app) - - ;; Shorten 'C-c C-q' to 'C-q' - (define-key exwm-mode-map [?\C-q] #'exwm-input-send-next-key) - - ;; Line-editing shortcuts - (setq exwm-input-simulation-keys - '(;; movement - ([?\C-b] . [left]) - ([?\M-b] . [C-left]) - ([?\C-f] . [right]) - ([?\M-f] . [C-right]) - ([?\C-p] . [up]) - ([?\C-n] . [down]) - ([?\C-a] . [home]) - ([?\C-e] . [end]) - ([?\M-v] . [prior]) - ([?\C-v] . [next]) - ([?\C-d] . [delete]) - ([?\C-k] . [S-end delete]) - ;; cut/copy/paste - ;; ([?\C-w] . [?\C-x]) - ([?\M-w] . [?\C-c]) - ([?\C-y] . [?\C-v]) - ;; search - ([?\C-s] . [?\C-f]))) - - ;; Enable EXWM - (exwm-enable) - - (add-hook 'exwm-init-hook #'exwm-config--fix/ido-buffer-window-other-frame) - - (require 'exwm-systemtray) - (exwm-systemtray-enable) - - (require 'exwm-randr) - (exwm-randr-enable) - - ;; (exwm-input-set-key - ;; (kbd "s-") - ;; (lambda () - ;; (interactive) - ;; (start-process "urxvt" nil "urxvt"))) - - ;; (exwm-input-set-key - ;; (kbd "s-SPC") ;; rofi doesn't properly launch programs when started from emacs - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "rofi-run" nil "rofi -show run -display-run '> ' -display-window ' 🗔 '"))) - - ;; (exwm-input-set-key - ;; (kbd "s-/") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "rofi-win" nil "rofi -show window -display-run '> ' -display-window ' 🗔 '"))) - - ;; (exwm-input-set-key - ;; (kbd "M-SPC") - ;; (lambda () - ;; (interactive) - ;; (start-process "rofi-pass" nil "rofi-pass"))) - - ;; (exwm-input-set-key - ;; (kbd "") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "pamixer" nil "pamixer --toggle-mute"))) - - ;; (exwm-input-set-key - ;; (kbd "") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "pamixer" nil "pamixer --allow-boost --decrease 5"))) - - ;; (exwm-input-set-key - ;; (kbd "") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "pamixer" nil "pamixer --allow-boost --increase 5"))) - - ;; (exwm-input-set-key - ;; (kbd "") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "mpc" nil "mpc toggle"))) - - ;; (exwm-input-set-key - ;; (kbd "") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "mpc" nil "mpc prev"))) - - ;; (exwm-input-set-key - ;; (kbd "") - ;; (lambda () - ;; (interactive) - ;; (start-process-shell-command "mpc" nil "mpv next"))) - - (defun ab--exwm-pasystray () - "A command used to start pasystray." - (interactive) - (if (executable-find "pasystray") - (progn - (message "EXWM: starting pasystray ...") - (start-process-shell-command "pasystray" nil "pasystray --notify=all")) - (message "EXWM: pasystray is not installed, abort!"))) - - (add-hook 'exwm-init-hook #'ab--exwm-pasystray) - - (exwm-input-set-key - (kbd "s-t") - (lambda () - (interactive) - (exwm-floating-toggle-floating))) - - (exwm-input-set-key - (kbd "s-f") - (lambda () - (interactive) - (exwm-layout-toggle-fullscreen))) - - (exwm-input-set-key - (kbd "s-w") - (lambda () - (interactive) - (kill-buffer (current-buffer)))) - - (exwm-input-set-key - (kbd "s-q") - (lambda () - (interactive) - (exwm-manage--kill-client)))) -#+end_src - -**** sxhkdrc -:PROPERTIES: -:header-args+: :tangle ~/.config/sxhkd/sxhkdrc :mkdirp yes -:END: - -#+begin_src conf :tangle no -# terminal emulator -super + Return - urxvt - -# program launcher -super + space - rofi -show run -display-run '> ' -display-window ' 🗔 ' - -# window finder -super + slash - rofi -show window -display-run '> ' -display-window ' 🗔 ' - -# password manager -alt + space - rofi-pass - -# make sxhkd reload its configuration files: -super + Escape - pkill -USR1 -x sxhkd - -# volume {up,down} -XF86Audio{Raise,Lower}Volume - pamixer --allow-boost --{in,de}crease 5 - -# mute -XF86AudioMute - pamixer --toggle-mute - -# playback control -XF86Audio{Play,Prev,Next} - mpc {toggle,prev,next} - -# Toggle keyboard layout -# super + F7 -# toggle-layout + (general-evil-setup t) + + (general-override-mode) + + (general-create-definer + ab--mode-leader-keys + :keymaps 'override + :states '(emacs normal visual motion insert) + :non-normal-prefix "C-," + :prefix ",") + + (general-create-definer + ab--leader-keys + :keymaps 'override + :states '(emacs normal visual motion insert) + :non-normal-prefix "M-m" + :prefix "SPC")) +#+end_src -# Toggle Xfce presentation mode -# XF86LaunchB -# toggle-presentation-mode +*** evil -# monitor brightness -XF86MonBrightness{Up,Down} - light -{A,U} 5 +#+begin_src emacs-lisp +(use-package evil + :demand t + :hook (view-mode . evil-motion-state) + :config (evil-mode 1)) +#+end_src -super + apostrophe - rofi-light +#+begin_src emacs-lisp +(use-package evil-escape + :demand t + :init + (setq evil-escape-excluded-states '(normal visual multiedit emacs motion) + evil-escape-excluded-major-modes '(neotree-mode) + evil-escape-key-sequence "jk" + evil-escape-delay 0.25) + :general + (:states '(insert replace visual operator) + "C-g" #'evil-escape) + :config + (evil-escape-mode 1) + ;; no `evil-escape' in minibuffer + (push #'minibufferp evil-escape-inhibit-functions)) #+end_src *** [[https://orgmode.org/][Org mode]] @@ -777,7 +650,15 @@ In short, my favourite way of life. #+begin_src emacs-lisp (setq org-src-tab-acts-natively t org-src-preserve-indentation nil - org-edit-src-content-indentation 0) + org-edit-src-content-indentation 0 + org-html-divs '((preamble "header" "preamble") + (content "main" "content") + (postamble "footer" "postamble")) + org-html-doctype "html5" + org-html-html5-fancy t + org-html-postamble nil) +(add-hook 'org-mode-hook 'org-indent-mode) +(use-package htmlize) #+end_src *** [[https://magit.vc/][Magit]] @@ -790,6 +671,7 @@ Not just how I do git, but /the/ way to do git. #+begin_src emacs-lisp (use-package magit + :general (ab--leader-keys "g s" 'magit-status) :defer t :bind (("s-g" . magit-status) ("C-x g" . magit-status) @@ -814,6 +696,7 @@ There's no way I could top that, so I won't attempt to. #+begin_src emacs-lisp (use-package ivy + :defer 1 :bind (:map ivy-minibuffer-map ([escape] . keyboard-escape-quit) @@ -831,6 +714,7 @@ There's no way I could top that, so I won't attempt to. #+begin_src emacs-lisp (use-package swiper + :general (:states 'normal "/" 'swiper) :bind (([remap isearch-forward] . swiper) ([remap isearch-backward] . swiper))) #+end_src @@ -840,6 +724,10 @@ There's no way I could top that, so I won't attempt to. #+begin_src emacs-lisp (use-package counsel :defer 1 + :general (ab--leader-keys + "f r" 'counsel-recentf + "SPC" 'counsel-M-x + "." 'counsel-find-file) :bind (([remap execute-extended-command] . counsel-M-x) ([remap find-file] . counsel-find-file) ("s-r" . counsel-recentf) @@ -931,6 +819,36 @@ TODO: break this giant source block down into individual org sections. (setq undo-tree-mode-lighter "")) #+end_src +* Editing + +** Company + +#+begin_src emacs-lisp +(use-package company + :defer 5 + :bind + (:map company-active-map + ([tab] . company-complete-common-or-cycle)) + :custom + (company-idle-delay 0.3) + (company-minimum-prefix-length 1) + (company-selection-wrap-around t) + (company-dabbrev-char-regexp "\\sw\\|\\s_\\|[-_]") + :config + (global-company-mode t)) +#+end_src + +** Customizations + +#+begin_src emacs-lisp +(ab--leader-keys + "b s" 'save-buffer + "b b" 'ivy-switch-buffer + "," 'ivy-switch-buffer + "b k" 'kill-this-buffer + "q q" 'evil-save-and-quit) +#+end_src + * Syntax and spell checking #+begin_src emacs-lisp (use-package flycheck @@ -944,7 +862,21 @@ TODO: break this giant source block down into individual org sections. #+end_src * Programming modes -** [[https://github.com/leanprover/lean-mode][Lean]] +** [[http://alloytools.org][Alloy]] (with [[https://github.com/dwwmmn/alloy-mode][alloy-mode]]) + +#+begin_src emacs-lisp +(use-package alloy-mode + :config (setq alloy-basic-offset 2)) +#+end_src + +** [[https://coq.inria.fr][Coq]] (with [[https://github.com/ProofGeneral/PG][Proof General]]) + +#+begin_src emacs-lisp +(use-package proof-site ; Proof General + :load-path "lib/proof-site/generic/") +#+end_src + +** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]]) #+begin_src emacs-lisp (use-package lean-mode @@ -965,6 +897,15 @@ TODO: break this giant source block down into individual org sections. flycheck-disabled-checkers '(haskell-stack-ghc haskell-ghc))) #+end_src +*** [[https://github.com/jyp/dante][dante]] + +#+begin_src emacs-lisp +(use-package dante + :after haskell-mode + :commands dante-mode + :hook (haskell-mode . dante-mode)) +#+end_src + *** [[https://github.com/mpickering/hlint-refactor-mode][hlint-refactor]] Emacs bindings for [[https://github.com/ndmitchell/hlint][hlint]]'s refactor option. This requires the refact @@ -1128,6 +1069,248 @@ instead. :bind (:map haskell-mode-map ("C-c l l" . hs-lint))) #+end_src +* Emacs Enhancements + +** [[https://github.com/justbur/emacs-which-key][which-key]] + +#+begin_quote +Emacs package that displays available keybindings in popup +#+end_quote + +#+begin_src emacs-lisp +(use-package which-key + :defer 1 + :config (which-key-mode)) +#+end_src + +** [[https://github.com/seagle0128/doom-modeline][doom-modeline]] + +#+begin_src emacs-lisp +(use-package doom-modeline + :demand t + :config (setq doom-modeline-height 32) + :hook (after-init . doom-modeline-init)) +#+end_src + +** [[https://github.com/11111000000/tao-theme-emacs][tao-theme]] + +#+begin_src emacs-lisp :tangle no +(use-package tao-theme + :demand t + :config (load-theme 'tao-yang t)) +#+end_src + +** [[https://github.com/maio/eink-emacs][eink-theme]] + +#+begin_src emacs-lisp +(load-theme 'eink t) +#+end_src + +* Email +** [[https://notmuchmail.org][notmuch]] + +#+begin_src emacs-lisp +(defun ab/notmuch () + "Delete other windows, then launch `notmuch'." + (interactive) + (require 'notmuch) + (delete-other-windows) + (notmuch)) + +;; (ab--leader-keys +;; "m" 'ab/notmuch +;; "s" 'save-buffer +;; "SPC" 'counsel-M-x) + +;; (map! +;; :leader +;; :desc "notmuch" :n "m" #'ab/notmuch +;; (:desc "search" :prefix "/" +;; :desc "notmuch" :n "m" #'counsel-notmuch)) +#+end_src + +#+begin_src emacs-lisp +(defvar ab-maildir "~/mail") + +(use-package sendmail + ;; :ensure nil + :config + (setq sendmail-program "/usr/bin/msmtp" + mail-specify-envelope-from t + mail-envelope-from 'header)) + +(use-package message + ;; :ensure nil + :config + (setq message-kill-buffer-on-exit t + message-send-mail-function 'message-send-mail-with-sendmail + message-sendmail-envelope-from 'header + message-directory "drafts" + message-user-fqdn "fencepost.gnu.org") + (add-hook 'message-mode-hook + (lambda () (setq fill-column 65 + message-fill-column 65))) + (add-hook 'message-mode-hook + #'flyspell-mode) + ;; (add-hook 'notmuch-message-mode-hook #'+doom-modeline|set-special-modeline) + ;; TODO: is there a way to only run this when replying and not composing? + ;; (add-hook 'notmuch-message-mode-hook + ;; (lambda () (progn + ;; (newline) + ;; (newline) + ;; (forward-line -1) + ;; (forward-line -1)))) + ;; (add-hook 'message-setup-hook + ;; #'mml-secure-message-sign-pgpmime) + ) + +(after! mml-sec + (setq mml-secure-openpgp-encrypt-to-self t + mml-secure-openpgp-sign-with-sender t)) + +(use-package notmuch + :general (ab--leader-keys "m" 'ab/notmuch) + :config + (setq notmuch-hello-sections + '(notmuch-hello-insert-header + notmuch-hello-insert-saved-searches + ;; notmuch-hello-insert-search + notmuch-hello-insert-alltags) + notmuch-search-oldest-first nil + notmuch-show-all-tags-list t + notmuch-hello-thousands-separator "," + notmuch-fcc-dirs + '(("amin@aminb.org" . "amin/Sent") + ("abandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"") + ("amin.bandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"") + ("aminb@gnu.org" . "gnu/Sent") + (".*" . "sent")) + notmuch-search-result-format + '(("date" . "%12s ") + ("count" . "%-7s ") + ("authors" . "%-40s ") + ("subject" . "%s ") + ("tags" . "(%s)"))) + ;; (add-hook 'visual-fill-column-mode-hook + ;; (lambda () + ;; (when (string= major-mode 'notmuch-message-mode) + ;; (setq visual-fill-column-width 70)))) + ;; (set! :evil-state 'notmuch-message-mode 'insert) + ;; (advice-add #'notmuch-bury-or-kill-this-buffer + ;; :override #'kill-this-buffer) + :bind + (:map notmuch-hello-mode-map + ("g" . notmuch-poll-and-refresh-this-buffer) + ("i" . (lambda () + "Search for `inbox' tagged messages" + (interactive) + (notmuch-hello-search "tag:inbox"))) + ("u" . (lambda () + "Search for `unread' tagged messages" + (interactive) + (notmuch-hello-search "tag:unread"))) + ("M" . (lambda () + "Compose new mail and prompt for sender" + (interactive) + (let ((current-prefix-arg t)) + (call-interactively #'notmuch-mua-new-mail))))) + (:map notmuch-search-mode-map + ("g" . notmuch-poll-and-refresh-this-buffer) + ("k" . (lambda () + "Mark message read" + (interactive) + (notmuch-search-tag '("-unread")) + ;; (notmuch-search-archive-thread) + (notmuch-search-next-thread))) + ("u" . (lambda () + "Mark message unread" + (interactive) + (notmuch-search-tag '("+unread")) + (notmuch-search-next-thread))) + ("K" . (lambda () + "Mark message deleted" + (interactive) + (notmuch-search-tag '("-unread" "-inbox" "+deleted")) + (notmuch-search-archive-thread))) + ("S" . (lambda () + "Mark message as spam" + (interactive) + (notmuch-search-tag '("-unread" "-inbox" "-webmasters" "+spam")) + (notmuch-search-archive-thread)))) + (:map notmuch-tree-mode-map ; TODO: additional bindings + ("S" . (lambda () + "Mark message as spam" + (interactive) + (notmuch-tree-tag '("-unread" "-inbox" "-webmasters" "+spam")) + (notmuch-tree-archive-thread)))) +) + +;; (use-package counsel-notmuch +;; :commands counsel-notmuch) + +(after! notmuch-crypto + (setq notmuch-crypto-process-mime t)) + +;; (after! evil +;; (mapc (lambda (str) (evil-set-initial-state (car str) (cdr str))) +;; '((notmuch-hello-mode . emacs) +;; (notmuch-search-mode . emacs) +;; (notmuch-tree-mode . emacs)))) + +(after! recentf + (add-to-list 'recentf-exclude (expand-file-name ab-maildir))) +#+end_src + +** supercite + +#+begin_src emacs-lisp :tangle no +(use-package supercite + :commands sc-cite-original + :init + (add-hook 'mail-citation-hook 'sc-cite-original) + + (defun sc-remove-existing-signature () + (save-excursion + (goto-char (region-beginning)) + (when (re-search-forward message-signature-separator (region-end) t) + (delete-region (match-beginning 0) (region-end))))) + + (add-hook 'mail-citation-hook 'sc-remove-existing-signature) + + (defun sc-remove-if-not-mailing-list () + (unless (assoc "list-id" sc-mail-info) + (setq attribution sc-default-attribution + citation (concat sc-citation-delimiter + sc-citation-separator)))) + + (add-hook 'sc-attribs-postselect-hook 'sc-remove-if-not-mailing-list) + + :config + (defun sc-fill-if-different (&optional prefix) + "Fill the region bounded by `sc-fill-begin' and point. +Only fill if optional PREFIX is different than +`sc-fill-line-prefix'. If `sc-auto-fill-region-p' is nil, do not +fill region. If PREFIX is not supplied, initialize fill +variables. This is useful for a regi `begin' frame-entry." + (if (not prefix) + (setq sc-fill-line-prefix "" + sc-fill-begin (line-beginning-position)) + (if (and sc-auto-fill-region-p + (not (string= prefix sc-fill-line-prefix))) + (let ((fill-prefix sc-fill-line-prefix)) + (unless (or (string= fill-prefix "") + (save-excursion + (goto-char sc-fill-begin) + (or (looking-at ">+ +") + (< (length + (buffer-substring (point) + (line-end-position))) + 65)))) + (fill-region sc-fill-begin (line-beginning-position))) + (setq sc-fill-line-prefix prefix + sc-fill-begin (line-beginning-position))))) +nil)) +#+end_src * Post initialization :PROPERTIES: