X-Git-Url: https://git.shemshak.org/gitweb.cgi/~bandali/configs/blobdiff_plain/6578a877a01693dcdd1e87b0ed4ba65081f26fe7..72a03130c464f49fe9aa3b50c6ec5d6c9fa4fb1c:/init.org diff --git a/init.org b/init.org index 6aebbf1..3f3bc06 100644 --- a/init.org +++ b/init.org @@ -233,6 +233,17 @@ can then be managed with the help of Magit or other tools. (expand-file-name "lib/borg" user-emacs-directory)) (require 'borg) (borg-initialize) + +(require 'borg-nix-shell) +(setq borg-build-shell-command 'borg-nix-shell-build-command) + +(with-eval-after-load 'bind-key + (bind-keys + :package borg + ("C-c B A" . borg-activate) + ("C-c B a" . borg-assimilate) + ("C-c B b" . borg-build) + ("C-c B c" . borg-clone))) #+end_src *** =use-package= @@ -268,7 +279,12 @@ database, low-level functions for querying the database, and a #+begin_src emacs-lisp (use-package epkg - :defer t) + :defer t + :bind + (("C-c B d" . epkg-describe-package) + ("C-c B p" . epkg-list-packages) + ("C-c B r" . borg-remove) + ("C-c B u" . epkg-update))) #+end_src ** No littering in =~/.emacs.d= @@ -445,14 +461,12 @@ Note: using =i3status= on sway at the moment, so disabling this. #+begin_src emacs-lisp :tangle no (use-package time - :ensure nil :init (setq display-time-default-load-average nil) :config (display-time-mode)) (use-package battery - :ensure nil :config (display-battery-mode)) #+end_src @@ -563,7 +577,8 @@ variable. #+begin_src emacs-lisp (setq backup-by-copying t - version-control t) + version-control t + delete-old-versions t) #+end_src *** Auto revert @@ -585,6 +600,26 @@ Enable automatic reloading of changed buffers and files. tab-width 4) #+end_src +*** Winner mode + +Enable =winner-mode=. + +#+begin_src emacs-lisp +(winner-mode 1) +#+end_src + +** Bindings + +#+begin_src emacs-lisp +(bind-keys + ("C-c b B" . ibuffer-list-buffers) + ("C-c b k" . kill-this-buffer) + ("C-c b s" . save-buffer) + ("C-c S" . save-buffer) + ("C-c o" . other-window) + ("C-c q q" . save-buffers-kill-terminal)) +#+end_src + ** Packages The packages in this section are absolutely essential to my everyday @@ -609,121 +644,6 @@ customizing it. 'auto-compile-inhibit-compile-detached-git-head)) #+end_src -*** [[https://github.com/noctuid/general.el][general]] - - #+begin_src emacs-lisp -(use-package general - :demand t - :config - (general-evil-setup t) - - (general-override-mode) - - (general-create-definer - amin--mode-leader-keys - :keymaps 'override - :states '(emacs normal visual motion insert) - :non-normal-prefix "C-," - :prefix ",") - - (general-create-definer - amin--leader-keys - :keymaps 'override - :states '(emacs normal visual motion insert) - :non-normal-prefix "M-m" - :prefix "SPC")) -#+end_src - -*** evil - -#+begin_src emacs-lisp -(use-package evil - :demand t - :hook (view-mode . evil-motion-state) - :config (evil-mode 1) - (general-swap-key nil '(normal motion) ";" ":") - (setq evil-want-visual-char-semi-exclusive t)) -#+end_src - -#+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 - -#+begin_src emacs-lisp -(use-package evil-org - :hook (org-mode . evil-org-mode) - :general - (nvmap evil-org-mode-map - "TAB" 'org-cycle - "S-TAB" 'org-cycle) - :config - (evil-org-set-key-theme) - (require 'evil-org-agenda) - (evil-org-agenda-set-keys) - (nmap evil-org-mode-map - [backtab] 'org-shifttab) - (after! org-src - (define-key org-src-mode-map [remap evil-write] 'org-edit-src-save) - (define-key org-src-mode-map [remap evil-save-and-close] - (lambda () (interactive) - (org-edit-src-save) - (org-edit-src-exit))) - (define-key org-src-mode-map [remap evil-save-modified-and-close] - (lambda () (interactive) - (org-edit-src-save) - (org-edit-src-exit))))) -#+end_src - -#+begin_src emacs-lisp -(amin--leader-keys - "B" '(:ignore t :wk "Borg") - "BA" 'borg-activate - "Ba" 'borg-assimilate - "Bb" 'borg-build - "Bc" 'borg-clone - "Bd" 'epkg-describe-package - "Bp" 'epkg-list-packages - "Br" 'borg-remove - "Bu" 'epkg-update - - "b" '(:ignore t :wk "buffers") - "bb" 'ibuffer-list-buffers - "bk" 'kill-this-buffer - "bs" 'save-buffer - - "f" '(:ignore t :wk "files") - - "h" '(:ignore t :wk "help") - "hc" 'describe-char - "hf" 'describe-function - "hF" 'describe-face - "hi" 'info - "hk" 'describe-key - "hl" 'view-lossage - "hv" 'describe-variable - - "o" 'other-window - - "w" '(:ignore t :wk "window") - "wo" 'other-window - - "q" '(:ignore t :wk "quit") - "qq" 'save-buffers-kill-terminal) -#+end_src - *** [[https://orgmode.org/][Org mode]] #+begin_quote @@ -736,9 +656,6 @@ In short, my favourite way of life. #+begin_src emacs-lisp (use-package org - :general - (amin--leader-keys "bt" 'org-babel-tangle) - (amin--leader-keys org-mode-map "i" 'org-edit-special) :config (setq org-src-tab-acts-natively t org-src-preserve-indentation nil @@ -749,6 +666,64 @@ In short, my favourite way of life. :after (:any org notmuch)) #+end_src +**** asynchronous tangle + +=amin/async-babel-tangle= is a function closely inspired by [[https://github.com/dieggsy/dotfiles/tree/cc10edf7701958eff1cd94d4081da544d882a28c/emacs.d#dotfiles][dieggsy's +d/async-babel-tangle]] which uses [[https://github.com/jwiegley/emacs-async][async]] to asynchronously tangle an org +file. + +#+begin_src emacs-lisp +(after! org + (defvar amin-show-async-tangle-results nil + "Keep *emacs* async buffers around for later inspection.") + + (defvar amin-show-async-tangle-time nil + "Show the time spent tangling the file.") + + (defvar amin-async-tangle-post-compile "make ti" + "If non-nil, pass to `compile' after successful tangle.") + + (defun amin/async-babel-tangle () + "Tangle org file asynchronously." + (interactive) + (let* ((file-tangle-start-time (current-time)) + (file (buffer-file-name)) + (file-nodir (file-name-nondirectory file)) + (async-quiet-switch "-q")) + (async-start + `(lambda () + (require 'org) + (org-babel-tangle-file ,file)) + (unless amin-show-async-tangle-results + `(lambda (result) + (if result + (progn + (message "Tangled %s%s" + ,file-nodir + (if amin-show-async-tangle-time + (format " (%.3fs)" + (float-time (time-subtract (current-time) + ',file-tangle-start-time))) + "")) + (when amin-async-tangle-post-compile + (compile amin-async-tangle-post-compile))) + (message "Tangling %s failed" ,file-nodir)))))))) + +(add-to-list + 'safe-local-variable-values + '(eval add-hook 'after-save-hook #'amin/async-babel-tangle 'append 'local)) + +(setq compilation-exit-message-function + (lambda (status code msg) + "Close the compilation window if successful." + ;; if M-x compile exits with 0 + (when (and (eq status 'exit) (zerop code)) + (bury-buffer) + (delete-window (get-buffer-window (get-buffer "*compilation*")))) + ;; return the result of compilation-exit-message-function + (cons msg code))) +#+end_src + *** [[https://magit.vc/][Magit]] #+begin_quote @@ -759,25 +734,25 @@ Not just how I do git, but /the/ way to do git. #+begin_src emacs-lisp (use-package magit - :general - (amin--leader-keys - "g" '(:ignore t :wk "magit") - "g SPC" 'magit-status - "gs" 'magit-status - "gS" 'magit-status-prefix - "gB" 'magit-blame - "gC" 'magit-clone - "gf" 'magit-fetch - "gF" 'magit-pull - "gP" 'magit-push - "gcc" 'magit-commit - "gca" 'magit-commit-amend - "gbb" 'magit-checkout - "gbc" 'magit-branch) :defer t - :bind (("s-g" . magit-status) - ("C-x g" . magit-status) - ("C-x M-g" . magit-dispatch-popup)) + :bind + (("s-g" . magit-dispatch-popup) + ("C-x g" . magit-status) + :prefix-map amin--magit-prefix-map + :prefix "C-c g" + ("SPC" . magit-status) + ("s" . magit-status) + ("S" . magit-status-prefix) + ("B" . magit-blame) + ("C" . magit-clone) + ("f" . magit-fetch) + ("F" . magit-pull) + ("P" . magit-push) + ("p" . magit-dispatch-popup) + ("c c" . magit-commit) + ("c a" . magit-commit-amend) + ("b b" . magit-checkout) + ("b c" . magit-branch)) :config (magit-add-section-hook 'magit-status-sections-hook 'magit-insert-modules @@ -800,14 +775,12 @@ There's no way I could top that, so I won't attempt to. (use-package ivy :defer 1 :bind - (:map ivy-minibuffer-map - ([escape] . keyboard-escape-quit) - ;; ("C-j" . ivy-next-line) - ;; ("C-k" . ivy-previous-line) - ([S-up] . ivy-previous-history-element) - ([S-down] . ivy-next-history-element) - ("DEL" . ivy-backward-delete-char)) - :general (amin--leader-keys "," 'ivy-switch-buffer) + (("C-c b b" . ivy-switch-buffer) + :map ivy-minibuffer-map + ([escape] . keyboard-escape-quit) + ([S-up] . ivy-previous-history-element) + ([S-down] . ivy-next-history-element) + ("DEL" . ivy-backward-delete-char)) :config (setq ivy-wrap t) (ivy-mode 1)) @@ -817,7 +790,6 @@ 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 @@ -827,14 +799,12 @@ There's no way I could top that, so I won't attempt to. #+begin_src emacs-lisp (use-package counsel :defer 1 - :general - (amin--leader-keys - "fr" '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) + ([remap find-file] . counsel-find-file) + ("s-r" . counsel-recentf) + ("C-c x" . counsel-M-x) + ("C-c f ." . counsel-find-file) + ("C-c f r" . counsel-recentf) :map minibuffer-local-map ("C-r" . counsel-minibuffer-history)) :config @@ -842,6 +812,33 @@ There's no way I could top that, so I won't attempt to. (defalias 'locate #'counsel-locate)) #+end_src +*** eshell + +#+begin_src emacs-lisp +(use-package eshell + :commands eshell + :config + (eval-when-compile (defvar eshell-prompt-regexp)) + (defun amin/eshell-quit-or-delete-char (arg) + (interactive "p") + (if (and (eolp) (looking-back eshell-prompt-regexp nil)) + (eshell-life-is-too-much) + (delete-char arg))) + + (defun amin/eshell-clear () + (interactive) + (let ((inhibit-read-only t)) + (erase-buffer)) + (eshell-send-input)) + + (defun amin|eshell-setup () + (bind-keys :map eshell-mode-map + ("C-d" . amin/eshell-quit-or-delete-char) + ("C-l" . amin/eshell-clear))) + + :hook (eshell-mode . amin|eshell-setup)) +#+end_src + * Borg's =layer/essentials= TODO: break this giant source block down into individual org sections. @@ -975,6 +972,7 @@ TODO: break this giant source block down into individual org sections. ** [[https://leanprover.github.io][Lean]] (with [[https://github.com/leanprover/lean-mode][lean-mode]]) #+begin_src emacs-lisp +(eval-when-compile (defvar lean-mode-map)) (use-package lean-mode :bind (:map lean-mode-map ("S-SPC" . company-complete))) @@ -1206,14 +1204,14 @@ Emacs package that displays available keybindings in popup #+begin_src emacs-lisp (use-package crux - :bind (("C-c d" . crux-duplicate-current-line-or-region) - ("C-c M-d" . crux-duplicate-and-comment-current-line-or-region)) - :general - (amin--leader-keys - "bK" 'crux-kill-other-buffers - "fc" 'crux-copy-file-preserve-attributes - "fD" 'crux-delete-file-and-buffer - "fR" 'crux-rename-file-and-buffer)) + :bind (("C-c d" . crux-duplicate-current-line-or-region) + ("C-c M-d" . crux-duplicate-and-comment-current-line-or-region) + ("C-c b K" . crux-kill-other-buffers) + ("C-c f c" . crux-copy-file-preserve-attributes) + ("C-c f D" . crux-delete-file-and-buffer) + ("C-c f R" . crux-rename-file-and-buffer) + ("C-S-j" . crux-top-join-line) + ("C-c j" . crux-top-join-line))) #+end_src ** [[https://github.com/alezost/mwim.el][mwim]] @@ -1223,32 +1221,78 @@ Emacs package that displays available keybindings in popup :bind (("C-a" . mwim-beginning-of-code-or-line) ("C-e" . mwim-end-of-code-or-line) ("" . mwim-beginning-of-line-or-code) - ("" . mwim-end-of-line-or-code)) - :general (:states '(normal visual) - "0" 'mwim-beginning-of-code-or-line - "$" 'mwim-end-of-code-or-line)) + ("" . mwim-end-of-line-or-code))) #+end_src -* Email -** [[https://notmuchmail.org][notmuch]] +** projectile -See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. +#+begin_src emacs-lisp +(use-package projectile + :defer 5 + :bind-keymap ("C-c p" . projectile-command-map) + :config + (projectile-mode) + + (defun my-projectile-invalidate-cache (&rest _args) + ;; ignore the args to `magit-checkout' + (projectile-invalidate-cache nil)) + + (eval-after-load 'magit-branch + '(progn + (advice-add 'magit-checkout + :after #'my-projectile-invalidate-cache) + (advice-add 'magit-branch-and-checkout + :after #'my-projectile-invalidate-cache)))) +#+end_src + +** [[https://github.com/wasamasa/shackle][shackle]] #+begin_src emacs-lisp -(defun amin/notmuch () - "Delete other windows, then launch `notmuch'." - (interactive) - (require 'notmuch) - (delete-other-windows) - (notmuch)) +(use-package shackle + :demand t + :commands shackle-mode + :config + (shackle-mode 1) + (setq shackle-rules + '(("*Help*" :align right :select t :size 0.5) + ("\\`\\*helm.*?\\*\\'" :regexp t :align t) + ((compilation-mode "\\`\\*magit-diff: .*?\\'") :regexp t :noselect t) + ("*magit-dispatch-popup*" :align bottom) + ((inferior-scheme-mode "*shell*" "*eshell*") :popup t)) + shackle-default-rule '(:select t) + shackle-default-size 0.4 + shackle-inhibit-window-quit-on-same-windows t)) +#+end_src -;; (map! -;; :leader -;; :desc "notmuch" :n "m" #'amin/notmuch -;; (:desc "search" :prefix "/" -;; :desc "notmuch" :n "m" #'counsel-notmuch)) +** [[https://github.com/Wilfred/helpful][helpful]] + +#+begin_src emacs-lisp +(use-package helpful + :bind + (("C-h f" . helpful-callable) + ("C-h v" . helpful-variable) + ("C-h k" . helpful-key) + ("C-c C-d" . helpful-at-point) + ("C-h F" . helpful-function) + ("C-h C" . helpful-command))) #+end_src +** [[https://github.com/kyagi/shell-pop-el][shell-pop]] + +#+begin_src emacs-lisp +(use-package shell-pop + :config + (add-to-list 'shackle-rules '("\\*eshell\\*" :regexp t :same t)) + :custom + (shell-pop-universal-key "C-c e") + (shell-pop-shell-type '("eshell" "*eshell*" (lambda nil (eshell))))) +#+end_src + +* Email +** [[https://notmuchmail.org][notmuch]] + +See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. + #+begin_src emacs-lisp (defvar amin-maildir "~/mail") @@ -1289,8 +1333,16 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. (setq mml-secure-openpgp-encrypt-to-self t mml-secure-openpgp-sign-with-sender t)) +(defun amin/notmuch () + "Delete other windows, then launch `notmuch'." + (interactive) + (delete-other-windows) + (notmuch)) + (use-package notmuch - :general (amin--leader-keys "m" 'amin/notmuch) + :commands notmuch + :bind ("C-c m" . amin/notmuch) + :custom (notmuch-always-prompt-for-sender t) :config (setq notmuch-hello-sections '(notmuch-hello-insert-header @@ -1303,18 +1355,27 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. '("Subject" "To" "Cc" "Date" "List-Id" "X-RT-Originator") notmuch-hello-thousands-separator "," notmuch-fcc-dirs - '(("amin@aminb.org" . "amin/Sent") - ("amin@gnu.org" . "gnu/Sent") - ("abandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"") - ("mab@gnu.org" . "gnu/Sent") - ("aminb@gnu.org" . "gnu/Sent") - (".*" . "sent")) + '(("amin@aminb.org" . "amin/Sent") + ("amin@gnu.org" . "gnu/Sent") + ("abandali@uwaterloo.ca" . "\"uwaterloo/Sent Items\"") + ("mab@gnu.org" . "gnu/Sent") + ("aminb@gnu.org" . "gnu/Sent") + (".*" . "sent")) notmuch-search-result-format - '(("date" . "%12s ") - ("count" . "%-7s ") + '(("date" . "%12s ") + ("count" . "%-7s ") ("authors" . "%-40s ") ("subject" . "%s ") - ("tags" . "(%s)"))) + ("tags" . "(%s)")) + notmuch-saved-searches + '((:name "inbox" :query "tag:inbox" :key "i") + (:name "unread" :query "tag:unread" :key "u") + (:name "latest" :query "tag:latest" :key "l") + (:name "encrypted" :query "tag:encrypted" :key "e") + (:name "flagged" :query "tag:flagged" :key "f") + (:name "sent" :query "tag:sent" :key "s") + (:name "drafts" :query "tag:draft" :key "d") + (:name "all mail" :query "*" :key "a"))) ;; (add-hook 'visual-fill-column-mode-hook ;; (lambda () ;; (when (string= major-mode 'notmuch-message-mode) @@ -1324,30 +1385,23 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. ;; :override #'kill-this-buffer) :bind (:map notmuch-hello-mode-map - ("g" . notmuch-poll-and-refresh-this-buffer) ("u" . (lambda () - "Search for `unread' tagged messages" + "Search for `unread'-tagged messages" (interactive) (notmuch-hello-search "tag:unread"))) ("i" . (lambda () - "Search for `inbox' tagged messages" + "Search for `inbox'-tagged messages" (interactive) (notmuch-hello-search "tag:inbox"))) ("l" . (lambda () - "Search for `latest' tagged messages" + "Search for `latest'-tagged messages" (interactive) (notmuch-hello-search "tag:latest"))) ("e" . (lambda () - "Search for `encrypted' tagged messages" - (interactive) - (notmuch-hello-search "tag:encrypted"))) - ("M" . (lambda () - "Compose new mail and prompt for sender" + "Search for `encrypted'-tagged messages" (interactive) - (let ((current-prefix-arg t)) - (call-interactively #'notmuch-mua-new-mail))))) + (notmuch-hello-search "tag:encrypted")))) (:map notmuch-search-mode-map - ("g" . notmuch-poll-and-refresh-this-buffer) ("k" . (lambda () "Mark message read" (interactive) @@ -1363,32 +1417,41 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]]. "Mark message deleted" (interactive) (notmuch-search-tag '("-unread" "-inbox" "+deleted")) - (notmuch-search-archive-thread))) + (notmuch-search-next-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 + (notmuch-search-next-thread)))) + (:map notmuch-tree-mode-map + ("k" . (lambda () + "Mark message read" + (interactive) + (notmuch-tree-tag '("-unread")) + ;; (notmuch-tree-archive-thread) + (notmuch-tree-next-message))) + ("u" . (lambda () + "Mark message unread" + (interactive) + (notmuch-tree-tag '("+unread")) + (notmuch-tree-next-message))) + ("K" . (lambda () + "Mark message deleted" + (interactive) + (notmuch-tree-tag '("-unread" "-inbox" "+deleted")) + (notmuch-tree-next-message))) ("S" . (lambda () "Mark message as spam" (interactive) (notmuch-tree-tag '("-unread" "-inbox" "-webmasters" "+spam")) - (notmuch-tree-archive-thread)))) -) + (notmuch-tree-next-message))))) -;; (use-package counsel-notmuch -;; :commands counsel-notmuch) +(use-package counsel-notmuch + :bind ("C-c s m" . 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 amin-maildir))) #+end_src @@ -1473,3 +1536,8 @@ Display how long it took to load the init file. #+begin_src emacs-lisp :comments none ;;; init.el ends here #+end_src + +* COMMENT Local Variables :ARCHIVE: +# Local Variables: +# eval: (add-hook 'after-save-hook #'amin/async-babel-tangle 'append 'local) +# End: