[emacs] disable borg-nix-shell for now
[~bandali/configs] / init.org
index 87b9f02..68877ef 100644 (file)
--- a/init.org
+++ b/init.org
@@ -234,6 +234,9 @@ can then be managed with the help of Magit or other tools.
 (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
@@ -399,6 +402,12 @@ Font stack with better unicode support, around =Ubuntu Mono= and
    'prepend))
 #+end_src
 
+** Gentler font resizing
+
+#+begin_src emacs-lisp
+(setq text-scale-mode-step 1.05)
+#+end_src
+
 ** Libraries
 
 #+begin_src emacs-lisp
@@ -441,6 +450,15 @@ compilation."
                `(after! (:all ,@features) ,@body)))))
 #+end_src
 
+Convenience macro for =setq='ing multiple variables to the same value:
+
+#+begin_src emacs-lisp
+(defmacro setq-every! (value &rest vars)
+  "Set all the variables from VARS to value VALUE."
+  (declare (indent defun) (debug t))
+  `(progn ,@(mapcar (lambda (x) (list 'setq x value)) vars)))
+#+end_src
+
 * Core
 :PROPERTIES:
 :CUSTOM_ID: core
@@ -574,7 +592,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
@@ -604,12 +623,26 @@ Enable =winner-mode=.
 (winner-mode 1)
 #+end_src
 
+*** Close =*compilation*= on success
+
+#+begin_src emacs-lisp
+(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
+
 ** Bindings
 
 #+begin_src emacs-lisp
 (bind-keys
- ("C-c b B" . ibuffer-list-buffers)
  ("C-c b k" . kill-this-buffer)
+ ("C-c s s" . save-buffer)
  ("C-c b s" . save-buffer)
  ("C-c S"   . save-buffer)
  ("C-c o"   . other-window)
@@ -655,11 +688,62 @@ In short, my favourite way of life.
   :config
   (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-log-done 'time)
   :hook (org-mode . org-indent-mode))
 
 (use-package org-notmuch
   :after (:any org notmuch))
+
+(use-package orgalist)
+#+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))
 #+end_src
 
 *** [[https://magit.vc/][Magit]]
@@ -750,6 +834,93 @@ 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
+
+*** Ibuffer
+
+#+begin_src emacs-lisp
+(use-package ibuffer
+  :bind
+  (("C-x C-b" . ibuffer-other-window)
+   ("C-c b B" . ibuffer-other-window)
+   :map ibuffer-mode-map
+   ("P"   . ibuffer-backward-filter-group)
+   ("N"   . ibuffer-forward-filter-group)
+   ("M-p" . ibuffer-do-print)
+   ("M-n" . ibuffer-do-shell-command-pipe-replace))
+  :config
+  ;; Use human readable Size column instead of original one
+  (define-ibuffer-column size-h
+    (:name "Size" :inline t)
+    (cond
+     ((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
+     ((> (buffer-size) 100000) (format "%7.0fk" (/ (buffer-size) 1000.0)))
+     ((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
+     (t (format "%8d" (buffer-size)))))
+  :custom
+  (ibuffer-saved-filter-groups
+   '(("default"
+      ("dired" (mode . dired-mode))
+      ("org"   (name . "^.*org$"))
+      ("web"
+       (or
+        (mode . web-mode)
+        (mode . css-mode)
+        (mode . scss-mode)
+        (mode . js2-mode)))
+      ("shell"
+       (or
+        (mode . eshell-mode)
+        (mode . shell-mode)))
+      ("notmuch" (name . "\*notmuch\*"))
+      ("programming"
+       (or
+        (mode . python-mode)
+        (mode . c++-mode)
+        (mode . emacs-lisp-mode)))
+      ("emacs"
+       (or
+        (name . "^\\*scratch\\*$")
+        (name . "^\\*Messages\\*$"))))))
+  (ibuffer-formats
+   '((mark modified read-only locked " "
+           (name 18 18 :left :elide)
+           " "
+           (size-h 9 -1 :right)
+           " "
+           (mode 16 16 :left :elide)
+           " " filename-and-process)
+     (mark " "
+           (name 16 -1)
+           " " filename)))
+  :hook (ibuffer . (lambda () (ibuffer-switch-to-saved-filter-groups "default"))))
+#+end_src
+
 * Borg's =layer/essentials=
 
 TODO: break this giant source block down into individual org sections.
@@ -802,7 +973,9 @@ TODO: break this giant source block down into individual org sections.
 
 (use-package recentf
   :demand t
-  :config (add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:"))
+  :config
+  (add-to-list 'recentf-exclude "^/\\(?:ssh\\|su\\|sudo\\)?:")
+  (setq recentf-max-saved-items 40))
 
 (use-package savehist
   :config (savehist-mode))
@@ -849,6 +1022,8 @@ TODO: break this giant source block down into individual org sections.
   (company-minimum-prefix-length 1)
   (company-selection-wrap-around t)
   (company-dabbrev-char-regexp "\\sw\\|\\s_\\|[-_]")
+  (company-dabbrev-downcase nil)
+  (company-dabbrev-ignore-case nil)
   :config
   (global-company-mode t))
 #+end_src
@@ -1074,6 +1249,56 @@ instead.
   :bind (:map haskell-mode-map
               ("C-c l l" . hs-lint)))
 #+end_src
+
+** Web dev
+
+*** SGML and HTML
+
+#+begin_src emacs-lisp
+(use-package sgml-mode
+  :config
+  (setq sgml-basic-offset 2))
+#+end_src
+
+*** CSS and SCSS
+
+#+begin_src emacs-lisp
+(use-package css-mode
+  :config
+  (setq css-indent-offset 2))
+#+end_src
+
+*** Web mode
+
+#+begin_src emacs-lisp
+(use-package web-mode
+  :mode "\\.html\\'"
+  :config
+  (setq-every! 2
+    web-mode-code-indent-offset
+    web-mode-css-indent-offset
+    web-mode-markup-indent-offset))
+#+end_src
+
+*** Emmet mode
+
+#+begin_src emacs-lisp
+(use-package emmet-mode
+  :bind* (("C-)" . emmet-next-edit-point)
+          ("C-(" . emmet-prev-edit-point))
+  :config
+  (unbind-key "C-j" emmet-mode-keymap)
+  (setq emmet-move-cursor-between-quotes t)
+  :hook (web-mode css-mode html-mode sgml-mode))
+#+end_src
+
+** Nix
+
+#+begin_src emacs-lisp
+(use-package nix-mode
+  :mode "\\.nix\\'")
+#+end_src
+
 * Emacs Enhancements
 
 ** [[https://github.com/justbur/emacs-which-key][which-key]]
@@ -1120,7 +1345,9 @@ Emacs package that displays available keybindings in popup
          ("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-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]]
@@ -1154,43 +1381,127 @@ Emacs package that displays available keybindings in popup
                    :after #'my-projectile-invalidate-cache))))
 #+end_src
 
-* Email
-** [[https://notmuchmail.org][notmuch]]
+** [[https://github.com/Wilfred/helpful][helpful]]
 
-See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
+#+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
+  :custom
+  (shell-pop-universal-key "C-c e")
+  (shell-pop-shell-type '("eshell" "*eshell*" (lambda nil (eshell)))))
+#+end_src
+
+** [[https://github.com/EricCrosson/unkillable-scratch][unkillable-scratch]]
+
+Make =*scratch*= and =*Messages*= unkillable.
 
 #+begin_src emacs-lisp
-(defvar amin-maildir "~/mail")
+(use-package unkillable-scratch
+  :config
+  (unkillable-scratch 1)
+  :custom
+  (unkillable-buffers '("^\\*scratch\\*$" "^\\*Messages\\*$")))
+#+end_src
+
+** [[https://github.com/davep/boxquote.el][boxquote.el]]
 
+#+begin_example
+,----
+| make pretty boxed quotes like this
+`----
+#+end_example
+
+#+begin_src emacs-lisp
+(use-package boxquote
+  :bind
+  (:prefix-map amin--boxquote-prefix-map
+   :prefix "C-c q"
+   ("b"   . boxquote-buffer)
+   ("B"   . boxquote-insert-buffer)
+   ("d"   . boxquote-defun)
+   ("F"   . boxquote-insert-file)
+   ("hf"  . boxquote-describe-function)
+   ("hk"  . boxquote-describe-key)
+   ("hv"  . boxquote-describe-variable)
+   ("hw"  . boxquote-where-is)
+   ("k"   . boxquote-kill)
+   ("p"   . boxquote-paragraph)
+   ("q"   . boxquote-boxquote)
+   ("r"   . boxquote-region)
+   ("s"   . boxquote-shell-command)
+   ("t"   . boxquote-text)
+   ("T"   . boxquote-title)
+   ("u"   . boxquote-unbox)
+   ("U"   . boxquote-unbox-region)
+   ("y"   . boxquote-yank)
+   ("M-q" . boxquote-fill-paragraph)
+   ("M-w" . boxquote-kill-ring-save)))
+#+end_src
+
+Also see [[https://www.emacswiki.org/emacs/rebox2][rebox2]].
+
+** [[https://github.com/DarthFennec/highlight-indent-guides][highlight-indent-guides]]
+
+#+begin_src emacs-lisp
+(use-package highlight-indent-guides
+  :demand t
+  :hook ((prog-mode . highlight-indent-guides-mode)
+         (org-mode  . highlight-indent-guides-mode))
+  :config
+  (setq highlight-indent-guides-character ?\|)
+  (setq highlight-indent-guides-auto-enabled nil)
+  (setq highlight-indent-guides-method 'character)
+  (setq highlight-indent-guides-responsive 'top)
+  (set-face-foreground 'highlight-indent-guides-character-face "gainsboro")
+  (set-face-foreground 'highlight-indent-guides-top-character-face "grey40")) ; grey13 is nice too
+#+end_src
+
+* Email
+
+#+begin_src emacs-lisp
+(defvar amin-maildir (expand-file-name "~/mail/"))
+(after! recentf
+  (add-to-list 'recentf-exclude amin-maildir))
+#+end_src
+
+** sendmail
+
+#+begin_src emacs-lisp
 (use-package sendmail
-  ;; :ensure nil
   :config
   (setq sendmail-program "/usr/bin/msmtp"
-        ; message-sendmail-extra-arguments '("-v" "-d")
+        ;; message-sendmail-extra-arguments '("-v" "-d")
         mail-specify-envelope-from t
         mail-envelope-from 'header))
+#+end_src
+
+** message
 
+#+begin_src emacs-lisp
 (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-directory "drafts"
         message-user-fqdn "aminb.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)
   )
@@ -1198,7 +1509,13 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
 (after! mml-sec
   (setq mml-secure-openpgp-encrypt-to-self t
         mml-secure-openpgp-sign-with-sender t))
+#+end_src
 
+** [[https://notmuchmail.org][notmuch]]
+
+See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
+
+#+begin_src emacs-lisp
 (defun amin/notmuch ()
   "Delete other windows, then launch `notmuch'."
   (interactive)
@@ -1207,7 +1524,7 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
 
 (use-package notmuch
   :commands notmuch
-  :bind ("C-c m" . amin/notmuch)
+  :bind ("C-c n" . amin/notmuch)
   :custom (notmuch-always-prompt-for-sender t)
   :config
   (setq notmuch-hello-sections
@@ -1250,8 +1567,6 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
   ;; (advice-add #'notmuch-bury-or-kill-this-buffer
   ;;             :override #'kill-this-buffer)
   :bind
-  (:map notmuch-common-keymap
-        ("g" . notmuch-poll-and-refresh-this-buffer))
   (:map notmuch-hello-mode-map
         ("u" . (lambda ()
                  "Search for `unread'-tagged messages"
@@ -1319,9 +1634,6 @@ See [[notmuch:id:87muuqsvci.fsf@fencepost.gnu.org][bug follow-up]].
 
 (after! notmuch-crypto
   (setq notmuch-crypto-process-mime t))
-
-(after! recentf
-  (add-to-list 'recentf-exclude (expand-file-name amin-maildir)))
 #+end_src
 
 ** supercite
@@ -1381,6 +1693,9 @@ nil))
 #+begin_src emacs-lisp
 (use-package ox-hugo
   :after ox)
+
+(use-package ox-hugo-auto-export
+  :load-path "lib/ox-hugo")
 #+end_src
 
 * Post initialization
@@ -1404,3 +1719,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: