These are noisy, but more importantly I'm worried I might accidentally commit a secret at some point Change-Id: If6f2c358f2803af25ea27ef34d39c7f2108d4186 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11299 Reviewed-by: aspen <root@gws.fyi> Autosubmit: aspen <root@gws.fyi> Tested-by: BuildkiteCI
		
			
				
	
	
		
			1393 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
			
		
		
	
	
			1393 lines
		
	
	
	
		
			42 KiB
		
	
	
	
		
			Org Mode
		
	
	
	
	
	
| # Local variables:
 | |
| # lexical-binding: t
 | |
| # eval: (paxedit-mode 1)
 | |
| # eval: (display-line-numbers-mode 1)
 | |
| # eval: (flyspell-mode -1)
 | |
| # eval: (org-config-mode 1)
 | |
| # End:
 | |
| 
 | |
| #+title: Emacs Config
 | |
| #+PROPERTY: header-args:emacs-lisp :results silent
 | |
| #+PROPERTY: header-args:elisp :results silent
 | |
| 
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| ;; -*- lexical-binding: t; -*-
 | |
| #+end_src
 | |
| 
 | |
| * Utils
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! dash)
 | |
| #+end_src
 | |
| 
 | |
| ** Elisp extras
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (defmacro comment (&rest _body)
 | |
|   "Comment out one or more s-expressions"
 | |
|   nil)
 | |
| 
 | |
| (defun inc (x) "Returns x + 1" (+ 1 x))
 | |
| (defun dec (x) "Returns x - 1" (- x 1))
 | |
| 
 | |
| (defun average (ns)
 | |
|   "Arithmetic mean of xs"
 | |
|   (if (null ns) nil
 | |
|     (/ (apply #'+ ns)
 | |
|        (length ns))))
 | |
| 
 | |
| (defun alist-set (alist-symbol key value)
 | |
|   "Set VALUE of a KEY in ALIST-SYMBOL."
 | |
|   (set alist-symbol (cons (list key value) (assq-delete-all key (eval alist-symbol)))))
 | |
| 
 | |
| (defun rx-words (&rest words)
 | |
|   (rx-to-string
 | |
|    `(and symbol-start (group (or ,@words)) symbol-end)))
 | |
| #+end_src
 | |
| 
 | |
| #+begin_src elisp :tangle no :results example
 | |
| (average (list 1 2 3 4))
 | |
| #+end_src
 | |
| 
 | |
| ** Text editing utils
 | |
| *** Reading strings
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun get-char (&optional point)
 | |
|   "Get the character at the given `point' (defaulting to the current point),
 | |
| without properties"
 | |
|   (let ((point (or point (point))))
 | |
|     (buffer-substring-no-properties point (+ 1 point))))
 | |
| 
 | |
| (defun get-line (&optional lineno)
 | |
|   "Read the line number `lineno', or the current line if `lineno' is nil, and
 | |
| return it as a string stripped of all text properties"
 | |
|   (let ((current-line (line-number-at-pos)))
 | |
|     (if (or (not lineno)
 | |
|             (= current-line lineno))
 | |
|         (thing-at-point 'line t)
 | |
|       (save-mark-and-excursion
 | |
|        (line-move (- lineno (line-number-at-pos)))
 | |
|        (thing-at-point 'line t)))))
 | |
| 
 | |
| (defun get-line-point ()
 | |
|   "Get the position in the current line of the point"
 | |
|   (- (point) (line-beginning-position)))
 | |
| 
 | |
| ;; Moving in the file
 | |
| 
 | |
| (defun goto-line-char (pt)
 | |
|   "Moves the point to the given position expressed as an offset from the start
 | |
| of the line"
 | |
|   (goto-char (+ (line-beginning-position) pt)))
 | |
| 
 | |
| (defun goto-eol ()
 | |
|   "Moves to the end of the current line"
 | |
|   (goto-char (line-end-position)))
 | |
| 
 | |
| (defun goto-regex-on-line (regex)
 | |
|   "Moves the point to the first occurrence of `regex' on the current line.
 | |
| Returns nil if the regex did not match, non-nil otherwise"
 | |
|   (when-let ((current-line (get-line))
 | |
|              (line-char (string-match regex current-line)))
 | |
|     (goto-line-char line-char)))
 | |
| 
 | |
| (defun goto-regex-on-line-r (regex)
 | |
|   "Moves the point to the *last* occurrence of `regex' on the current line.
 | |
| Returns nil if the regex did not match, non-nil otherwise"
 | |
|   (when-let ((current-line (get-line))
 | |
|              (modified-regex (concat ".*\\(" regex "\\)"))
 | |
|              (_ (string-match modified-regex current-line))
 | |
|              (match-start (match-beginning 1)))
 | |
|     (goto-line-char match-start)))
 | |
| #+end_src
 | |
| 
 | |
| #+begin_src elisp :tangle no
 | |
| (progn
 | |
|   (string-match (rx (and (zero-or-more anything)
 | |
|                          (group "foo" "foo")))
 | |
|                 "foofoofoo")
 | |
|   (match-beginning 1))
 | |
| #+end_src
 | |
| 
 | |
| *** Changing file contents
 | |
| #+begin_src elisp :tangle yes
 | |
| (defmacro saving-excursion (&rest body)
 | |
|   `(λ! () (save-excursion ,@body)))
 | |
| 
 | |
| (defun delete-line ()
 | |
|   "Remove the line at the current point"
 | |
|   (delete-region (line-beginning-position)
 | |
|                  (inc (line-end-position))))
 | |
| 
 | |
| (defmacro modify-then-indent (&rest body)
 | |
|   "Modify text in the buffer according to body, then re-indent from where the
 | |
|   cursor started to where the cursor ended up, then return the cursor to where
 | |
|   it started."
 | |
|   `(let ((beg (line-beginning-position))
 | |
|          (orig-line-char (- (point) (line-beginning-position))))
 | |
|      (atomic-change-group
 | |
|        (save-mark-and-excursion
 | |
|         ,@body
 | |
|         (evil-indent beg (+ (line-end-position) 1))))
 | |
|      (goto-line-char orig-line-char)))
 | |
| 
 | |
| (pcase-defmacro s-starts-with (prefix)
 | |
|   `(pred (s-starts-with-p ,prefix)))
 | |
| 
 | |
| (pcase-defmacro s-contains (needle &optional ignore-case)
 | |
|   `(pred (s-contains-p ,needle
 | |
|                        ,@(when ignore-case (list ignore-case)))))
 | |
| #+end_src
 | |
| 
 | |
| #+begin_src elisp :tangle no
 | |
| (pcase "foo"
 | |
|   ((s-contains "bar") 1)
 | |
|   ((s-contains "o") 2))
 | |
| #+end_src
 | |
| 
 | |
| ** Evil utils
 | |
| #+begin_src elisp :tangle yes
 | |
| (defmacro define-move-and-insert
 | |
|     (name &rest body)
 | |
|   `(defun ,name (count &optional vcount skip-empty-lines)
 | |
|      ;; Following interactive form taken from the source for `evil-insert'
 | |
|      (interactive
 | |
|       (list (prefix-numeric-value current-prefix-arg)
 | |
|             (and (evil-visual-state-p)
 | |
|                  (memq (evil-visual-type) '(line block))
 | |
|                  (save-excursion
 | |
|                    (let ((m (mark)))
 | |
|                      ;; go to upper-left corner temporarily so
 | |
|                      ;; `count-lines' yields accurate results
 | |
|                      (evil-visual-rotate 'upper-left)
 | |
|                      (prog1 (count-lines evil-visual-beginning evil-visual-end)
 | |
|                        (set-mark m)))))
 | |
|             (evil-visual-state-p)))
 | |
|      (atomic-change-group
 | |
|        ,@body
 | |
|        (evil-insert count vcount skip-empty-lines))))
 | |
| #+end_src
 | |
| 
 | |
| * Name and email
 | |
| #+begin_src emacs-lisp
 | |
| (setq user-full-name "Aspen Smith"
 | |
|       user-mail-address "root@gws.fyi")
 | |
| #+end_src
 | |
| 
 | |
| * Visual style
 | |
| #+begin_src elisp :tangle yes
 | |
| (let ((font-family (pcase system-type
 | |
|                      ('darwin "MesloLGSDZ NF")
 | |
|                      ('gnu/linux "Meslo LGSDZ Nerd Font"))))
 | |
|   (setq doom-font (font-spec :family font-family :height 113)
 | |
|         doom-big-font (font-spec :family font-family :size 24)
 | |
|         doom-big-font-increment 5
 | |
|         doom-variable-pitch-font (font-spec :family font-family)
 | |
|         doom-theme 'doom-solarized-light))
 | |
| 
 | |
| (setq display-line-numbers-type t)
 | |
| 
 | |
| (setq doom-modeline-buffer-file-name-style 'relative-to-project
 | |
|       doom-modeline-modal-icon nil
 | |
|       doom-modeline-github t
 | |
|       doom-modeline-height 12)
 | |
| #+end_src
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (setq whitespace-style '(face lines-tail))
 | |
| (global-whitespace-mode t)
 | |
| (add-hook 'org-mode-hook (lambda () (whitespace-mode -1)) t)
 | |
| #+end_src
 | |
| 
 | |
| ** Theme
 | |
| [[https://davidjohnstone.net/lch-lab-colour-gradient-picker][LAB colour gradient picker]] is a good tool for trying to find "halfway points" between two colours
 | |
| 
 | |
| *** Variables
 | |
| #+begin_src elisp :tangle no
 | |
| (rainbow-mode)
 | |
| #+end_src
 | |
| 
 | |
| #+name: solarized-vars
 | |
| #+begin_src elisp :tangle yes
 | |
| (setq +solarized-s-base03    "#002b36"
 | |
|       +solarized-s-base02    "#073642"
 | |
|       ;; emphasized content
 | |
|       +solarized-s-base01    "#586e75"
 | |
|       ;; primary content
 | |
|       +solarized-s-base00    "#657b83"
 | |
|       +solarized-s-base0     "#839496"
 | |
|       ;; comments
 | |
|       +solarized-s-base1     "#93a1a1"
 | |
|       ;; background highlight light
 | |
|       +solarized-s-base2     "#eee8d5"
 | |
|       ;; background light
 | |
|       +solarized-s-base3     "#fdf6e3"
 | |
| 
 | |
|       +solarized-halfway-highlight "#f5efdc"
 | |
| 
 | |
|       ;; Solarized accented colors
 | |
|       +solarized-yellow    "#b58900"
 | |
|       +solarized-orange    "#cb4b16"
 | |
|       +solarized-red       "#dc322f"
 | |
|       +solarized-magenta   "#d33682"
 | |
|       +solarized-violet    "#6c71c4"
 | |
|       +solarized-blue      "#268bd2"
 | |
|       +solarized-cyan      "#2aa198"
 | |
|       +solarized-green     "#859900"
 | |
| 
 | |
|       ;; Darker and lighter accented colors
 | |
|       ;; Only use these in exceptional circumstances!
 | |
|       +solarized-yellow-d  "#7B6000"
 | |
|       +solarized-yellow-l  "#DEB542"
 | |
|       +solarized-orange-d  "#8B2C02"
 | |
|       +solarized-orange-l  "#F2804F"
 | |
|       +solarized-red-d     "#990A1B"
 | |
|       +solarized-red-l     "#FF6E64"
 | |
|       +solarized-magenta-d "#93115C"
 | |
|       +solarized-magenta-l "#F771AC"
 | |
|       +solarized-violet-d  "#3F4D91"
 | |
|       +solarized-violet-l  "#9EA0E5"
 | |
|       +solarized-blue-d    "#00629D"
 | |
|       +solarized-blue-l    "#69B7F0"
 | |
|       +solarized-cyan-d    "#00736F"
 | |
|       +solarized-cyan-l    "#69CABF"
 | |
|       +solarized-green-d   "#546E00"
 | |
|       +solarized-green-l   "#B4C342")
 | |
| #+end_src
 | |
| 
 | |
| *** Overrides
 | |
| 
 | |
| #+name: overrides-for-solarized-light
 | |
| #+begin_src elisp :tangle yes
 | |
| (custom-set-faces!
 | |
|   `(cursor :background ,+solarized-s-base00)
 | |
|   `(font-lock-doc-face :foreground ,+solarized-s-base1)
 | |
|   `(font-lock-preprocessor-face :foreground ,+solarized-red :bold nil)
 | |
|   `(font-lock-keyword-face :foreground ,+solarized-green :bold nil)
 | |
|   `(font-lock-builtin-face :foreground ,+solarized-s-base01 :bold t)
 | |
|   `(font-lock-function-name-face :foreground ,+solarized-blue)
 | |
|   `(font-lock-constant-face :foreground ,+solarized-blue)
 | |
|   `(font-lock-type-face :italic nil)
 | |
|   `(highlight-numbers-number :bold nil)
 | |
|   `(highlight :background ,+solarized-s-base2)
 | |
|   `(solaire-hl-line-face :background ,+solarized-halfway-highlight)
 | |
|   `(hl-line :background ,+solarized-s-base2)
 | |
| 
 | |
|   `(linum :background ,+solarized-s-base2 :foreground ,+solarized-s-base1)
 | |
|   `(line-number :background ,+solarized-s-base2 :foreground ,+solarized-s-base1)
 | |
|   `(line-number-current-line :background ,+solarized-s-base2 :foreground ,+solarized-s-base1)
 | |
|   `(fringe :background ,+solarized-s-base2)
 | |
| 
 | |
|   `(whitespace-line :foreground ,+solarized-red :underline t)
 | |
| 
 | |
|   `(haskell-operator-face :foreground ,+solarized-green)
 | |
|   `(haskell-keyword-face :foreground ,+solarized-cyan)
 | |
| 
 | |
|   `(magit-branch-local :foreground ,+solarized-blue :bold t)
 | |
|   `(magit-branch-remote :foreground ,+solarized-green :bold t)
 | |
|   `(magit-branch-remote-head :foreground ,+solarized-green :bold t :box t)
 | |
|   `(magit-branch-current :box t :bold t)
 | |
|   `(magit-header-line :background nil :foreground ,+solarized-yellow :bold t :box nil)
 | |
|   `(diff-refine-added :foreground "#dbdb9c" :background "#5b6e35" :bold nil)
 | |
|   `(magit-diff-added-highlight :foreground "#657827" :background "#efeac7" :bold nil)
 | |
|   `(diff-refine-removed :background "#8e433d" :foreground "#ffb9a1" :bold nil)
 | |
|   `(magit-diff-removed-highlight :foreground "#a33c35" :background "#ffdec8" :bold nil)
 | |
|   `(magit-diff-hunk-heading :background "#f8e8c6" :foreground "#876d26" :bold nil)
 | |
|   `(magit-diff-hunk-heading-highlight :background "#f1d49b" :foreground "#766634" :bold nil)
 | |
|   `(magit-section-heading :foreground "#b58900")
 | |
|   `(magit-filename :foreground ,+solarized-s-base00)
 | |
|   `(magit-diff-context-highlight :background ,+solarized-halfway-highlight)
 | |
| 
 | |
|   `(transient-delimiter :foreground ,+solarized-s-base1)
 | |
|   `(transient-inapt-suffix :foreground ,+solarized-s-base1)
 | |
|   `(transient-inactive-value :foreground ,+solarized-s-base1)
 | |
|   `(transient-inactive-argument :foreground ,+solarized-s-base1)
 | |
|   `(transient-key-exit :foreground ,+solarized-green :bold t)
 | |
|   `(transient-key-stay :foreground ,+solarized-blue :bold t)
 | |
|   )
 | |
|   #+end_src
 | |
| 
 | |
| * Keybindings and navigation
 | |
| Get the hell out of here, snipe!
 | |
| #+begin_src elisp :tangle yes
 | |
| (remove-hook 'doom-first-input-hook #'evil-snipe-mode)
 | |
| #+end_src
 | |
| 
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (map!
 | |
|  (:leader
 | |
|   "b" #'consult-buffer
 | |
|   "r" #'consult-recent-file))
 | |
| #+end_src
 | |
| 
 | |
| ** Flycheck
 | |
| #+begin_src elisp :tangle yes
 | |
| (evil-set-command-property 'flycheck-next-error :repeat nil)
 | |
| (evil-set-command-property 'flycheck-prev-error :repeat nil)
 | |
| (evil-set-command-property 'flycheck-previous-error :repeat nil)
 | |
| 
 | |
| (map!
 | |
|  (:map flycheck-mode-map
 | |
|   :m  "]e" #'flycheck-next-error
 | |
|   :m  "[e" #'flycheck-previous-error))
 | |
| #+end_src
 | |
| 
 | |
| ** Smerge
 | |
| #+begin_src elisp :tangle yes
 | |
| (evil-set-command-property 'smerge-next :repeat nil)
 | |
| (evil-set-command-property 'smerge-prev :repeat nil)
 | |
| 
 | |
| (map!
 | |
|  :n "] n" #'smerge-next
 | |
|  :n "[ n" #'smerge-prev
 | |
|  (:leader
 | |
|   (:desc "smerge" :prefix "g m"
 | |
|    :desc "Keep Current" :n "SPC" #'smerge-keep-current
 | |
|    :desc "Keep All"     :n "a" #'smerge-keep-all
 | |
|    :desc "Keep Upper"   :n "u" #'smerge-keep-upper
 | |
|    :desc "Keep Lower"   :n "l" #'smerge-keep-lower)))
 | |
| t
 | |
|  #+end_src
 | |
| 
 | |
| ** Vinegar-style dired
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun dired-mode-p () (eq 'dired-mode major-mode))
 | |
| 
 | |
| (defun aspen/dired-minus ()
 | |
|   (interactive)
 | |
|   (if (dired-mode-p)
 | |
|       (dired-up-directory)
 | |
|     (when buffer-file-name
 | |
|       (-> (buffer-file-name)
 | |
|           (f-dirname)
 | |
|           (dired)))))
 | |
| 
 | |
| (map!
 | |
|  :n "-" #'aspen/dired-minus
 | |
|  (:map dired-mode-map
 | |
|        "-" #'aspen/dired-minus))
 | |
| #+end_src
 | |
| 
 | |
| ** Lisp mappings
 | |
| *** Use paxedit
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! paxedit
 | |
|   :hook ((emacs-lisp-mode . paxedit-mode)
 | |
|          (clojure-mode . paxedit-mode)
 | |
|          (common-lisp-mode . paxedit-mode)))
 | |
| #+end_src
 | |
| 
 | |
| *** Paxedit functions
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (define-move-and-insert aspen/insert-at-sexp-end
 | |
|   (when (not (equal (get-char) "("))
 | |
|     (backward-up-list))
 | |
|   (forward-sexp)
 | |
|   (backward-char))
 | |
| 
 | |
| (define-move-and-insert aspen/insert-at-sexp-start
 | |
|   (backward-up-list)
 | |
|   (forward-char))
 | |
| 
 | |
| (define-move-and-insert aspen/insert-at-form-start
 | |
|   (backward-sexp)
 | |
|   (backward-char)
 | |
|   (insert " "))
 | |
| 
 | |
| (define-move-and-insert aspen/insert-at-form-end
 | |
|   (forward-sexp)
 | |
|   (insert " "))
 | |
| 
 | |
| (defun aspen/paxedit-kill (&optional n)
 | |
|   (interactive "p")
 | |
|   (or (paxedit-comment-kill)
 | |
|       (when (paxedit-symbol-cursor-within?)
 | |
|         (paxedit-symbol-kill))
 | |
|       (paxedit-implicit-sexp-kill n)
 | |
|       (paxedit-sexp-kill n)
 | |
|       (message paxedit-message-kill)))
 | |
| #+end_src
 | |
| 
 | |
| *** Paxedit mappings
 | |
| #+begin_src elisp :tangle yes
 | |
| (map!
 | |
|  (:after paxedit
 | |
|          (:map paxedit-mode-map
 | |
|           :i ";"                          #'paxedit-insert-semicolon
 | |
|           :i "("                          #'paxedit-open-round
 | |
|           :i "["                          #'paxedit-open-bracket
 | |
|           :i "{"                          #'paxedit-open-curly
 | |
|           :n [remap evil-yank-line]       #'paxedit-copy
 | |
|           :n [remap evil-delete-line]     #'aspen/paxedit-kill
 | |
|           :n "g o"                        #'paxedit-sexp-raise
 | |
|           :n [remap evil-join-whitespace] #'paxedit-compress
 | |
|           :n "g S"                        #'paxedit-format-1
 | |
|           :n "g k"                        #'paxedit-backward-up
 | |
|           :n "g j"                        #'paxedit-backward-end)))
 | |
| 
 | |
| (require 'general)
 | |
| (general-evil-setup t)
 | |
| 
 | |
| (nmap
 | |
|   ">" (general-key-dispatch 'evil-shift-right
 | |
|         "e" 'paxedit-transpose-forward
 | |
|         ")" 'sp-forward-slurp-sexp
 | |
|         "(" 'sp-backward-barf-sexp
 | |
|         "I" 'aspen/insert-at-sexp-end
 | |
|         ;; "a" 'grfn/insert-at-form-end
 | |
|         ))
 | |
| 
 | |
| (nmap
 | |
|   "<" (general-key-dispatch 'evil-shift-left
 | |
|         "e" 'paxedit-transpose-backward
 | |
|         ")" 'sp-forward-barf-sexp
 | |
|         "(" 'sp-backward-slurp-sexp
 | |
|         "I" 'aspen/insert-at-sexp-start
 | |
|         ;; "a" 'grfn/insert-at-form-start
 | |
|         ))
 | |
| #+end_src
 | |
| 
 | |
| *** Eval functions
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! predd)
 | |
| 
 | |
| (predd-defmulti eval-sexp (lambda (form) major-mode))
 | |
| 
 | |
| (predd-defmethod eval-sexp 'clojure-mode (form)
 | |
|   (cider-interactive-eval form))
 | |
| 
 | |
| (predd-defmethod eval-sexp 'emacs-lisp-mode (form)
 | |
|   (pp-eval-expression form))
 | |
| 
 | |
| (predd-defmulti eval-sexp-region (lambda (_beg _end) major-mode))
 | |
| 
 | |
| (predd-defmethod eval-sexp-region 'clojure-mode (beg end)
 | |
|   (cider-interactive-eval nil nil (list beg end)))
 | |
| 
 | |
| (predd-defmethod eval-sexp-region 'emacs-lisp-mode (beg end)
 | |
|   (pp-eval-expression (read (buffer-substring beg end))))
 | |
| 
 | |
| (predd-defmulti eval-sexp-region-context (lambda (_beg _end _context) major-mode))
 | |
| 
 | |
| (predd-defmethod eval-sexp-region-context 'clojure-mode (beg end context)
 | |
|   (cider--eval-in-context (buffer-substring beg end)))
 | |
| 
 | |
| (defun pp-eval-context-region (beg end context)
 | |
|   (interactive "r\nxContext: ")
 | |
|   (let* ((inner-expr (read (buffer-substring beg end)))
 | |
|          (full-expr (list 'let* context inner-expr)))
 | |
|     (pp-eval-expression full-expr)))
 | |
| 
 | |
| (predd-defmethod eval-sexp-region-context 'emacs-lisp-mode (beg end context)
 | |
|   (pp-eval-context-region beg end context))
 | |
| 
 | |
| (predd-defmulti preceding-sexp (lambda () major-mode))
 | |
| 
 | |
| (predd-defmethod preceding-sexp 'clojure-mode ()
 | |
|   (cider-last-sexp))
 | |
| 
 | |
| (predd-defmethod preceding-sexp 'emacs-lisp-mode ()
 | |
|   (elisp--preceding-sexp))
 | |
| 
 | |
| (defun eval-sexp-at-point ()
 | |
|   (interactive)
 | |
|   (let ((bounds (bounds-of-thing-at-point 'sexp)))
 | |
|     (eval-sexp-region (car bounds)
 | |
|                       (cdr bounds))))
 | |
| 
 | |
| (defun eval-last-sexp (_)
 | |
|   (interactive)
 | |
|   (eval-sexp (preceding-sexp)))
 | |
| 
 | |
| ;;;
 | |
| 
 | |
| (defun cider-insert-current-sexp-in-repl (&optional arg)
 | |
|   "Insert the expression at point in the REPL buffer.
 | |
| If invoked with a prefix ARG eval the expression after inserting it"
 | |
|   (interactive "P")
 | |
|   (cider-insert-in-repl (cider-sexp-at-point) arg))
 | |
| 
 | |
| (evil-define-operator fireplace-send (beg end)
 | |
|   (cider-insert-current-sexp-in-repl nil nil (list beg end)))
 | |
| 
 | |
| (defun +clojure-pprint-expr (form)
 | |
|   (format "(with-out-str (clojure.pprint/pprint %s))"
 | |
|           form))
 | |
| 
 | |
| (defun cider-eval-read-and-print-handler (&optional buffer)
 | |
|   "Make a handler for evaluating and reading then printing result in BUFFER."
 | |
|   (nrepl-make-response-handler
 | |
|    (or buffer (current-buffer))
 | |
|    (lambda (buffer value)
 | |
|      (let ((value* (read value)))
 | |
|        (with-current-buffer buffer
 | |
|          (insert
 | |
|           (if (derived-mode-p 'cider-clojure-interaction-mode)
 | |
|               (format "\n%s\n" value*)
 | |
|             value*)))))
 | |
|    (lambda (_buffer out) (cider-emit-interactive-eval-output out))
 | |
|    (lambda (_buffer err) (cider-emit-interactive-eval-err-output err))
 | |
|    '()))
 | |
| 
 | |
| (defun cider-eval-and-replace (beg end)
 | |
|   "Evaluate the expression in region and replace it with its result"
 | |
|   (interactive "r")
 | |
|   (let ((form (buffer-substring beg end)))
 | |
|     (cider-nrepl-sync-request:eval form)
 | |
|     (kill-region beg end)
 | |
|     (cider-interactive-eval
 | |
|      (+clojure-pprint-expr form)
 | |
|      (cider-eval-read-and-print-handler))))
 | |
| 
 | |
| (defun cider-eval-current-sexp-and-replace ()
 | |
|   "Evaluate the expression at point and replace it with its result"
 | |
|   (interactive)
 | |
|   (apply #'cider-eval-and-replace (cider-sexp-at-point 'bounds)))
 | |
| 
 | |
| ;;;
 | |
| #+end_src
 | |
| 
 | |
| *** Eval bindings
 | |
| fireplace-esque eval binding
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (evil-define-operator fireplace-eval (beg end)
 | |
|   (eval-sexp-region beg end))
 | |
| 
 | |
| (evil-define-operator fireplace-replace (beg end)
 | |
|   (cider-eval-and-replace beg end))
 | |
| 
 | |
| (evil-define-operator fireplace-eval-context (beg end)
 | |
|   (eval-sexp-region-context beg end))
 | |
| 
 | |
| (nmap :keymaps 'cider-mode-map
 | |
|   "c" (general-key-dispatch 'evil-change
 | |
|         "p" (general-key-dispatch 'fireplace-eval
 | |
|               "p" 'cider-eval-sexp-at-point
 | |
|               "c" 'cider-eval-last-sexp
 | |
|               "d" 'cider-eval-defun-at-point
 | |
|               "r" 'cider-test-run-test)
 | |
|         "q" (general-key-dispatch 'fireplace-send
 | |
|               "q" 'cider-insert-current-sexp-in-repl
 | |
|               "c" 'cider-insert-last-sexp-in-repl)
 | |
|         "x" (general-key-dispatch 'fireplace-eval-context
 | |
|               "x" 'cider-eval-sexp-at-point-in-context
 | |
|               "c" 'cider-eval-last-sexp-in-context)
 | |
|         "!" (general-key-dispatch 'fireplace-replace
 | |
|               "!" 'cider-eval-current-sexp-and-replace
 | |
|               "c" 'cider-eval-last-sexp-and-replace)
 | |
|         "y" 'cider-copy-last-result))
 | |
| 
 | |
| ;;;
 | |
| 
 | |
| (nmap :keymaps 'emacs-lisp-mode-map
 | |
|   "c" (general-key-dispatch 'evil-change
 | |
|         "p" (general-key-dispatch 'fireplace-eval
 | |
|               "p" 'eval-sexp-at-point
 | |
|               "c" 'eval-last-sexp
 | |
|               "d" 'eval-defun
 | |
|               "r" 'cider-test-run-test)
 | |
|         "x" (general-key-dispatch 'fireplace-eval-context
 | |
|               "x" 'cider-eval-sexp-at-point-in-context
 | |
|               "c" 'cider-eval-last-sexp-in-context)
 | |
|         "!" (general-key-dispatch 'fireplace-replace
 | |
|               "!" 'cider-eval-current-sexp-and-replace
 | |
|               "c" 'cider-eval-last-sexp-and-replace)
 | |
|         "y" 'cider-copy-last-result))
 | |
| 
 | |
| (nmap :keymaps 'sly-mode-map
 | |
|   "c" (general-key-dispatch 'evil-change
 | |
|         "p" (general-key-dispatch 'sly-eval
 | |
|               ;; "p" 'eval-sexp-at-point
 | |
|               "c" 'sly-eval-last-expression
 | |
|               "d" 'sly-eval-defun
 | |
|               ;; "r" 'cider-test-run-test
 | |
|               )
 | |
|         ;; "x" (general-key-dispatch 'fireplace-eval-context
 | |
|         ;;       "x" 'cider-eval-sexp-at-point-in-context
 | |
|         ;;       "c" 'cider-eval-last-sexp-in-context
 | |
|         ;;       )
 | |
|         ;; "!" (general-key-dispatch 'fireplace-replace
 | |
|         ;;       "!" 'cider-eval-current-sexp-and-replace
 | |
|         ;;       "c" 'cider-eval-last-sexp-and-replace)
 | |
|         ;; "y" 'cider-copy-last-result
 | |
|         ))
 | |
| 
 | |
| #+end_src
 | |
| 
 | |
| ** Coerce
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! string-inflection
 | |
|   :config
 | |
|   (nmap "c" (general-key-dispatch 'evil-change
 | |
|               "r c" (saving-excursion (string-inflection-lower-camelcase))
 | |
|               "r C" (saving-excursion (string-inflection-camelcase))
 | |
|               "r m" (saving-excursion (string-inflection-camelcase))
 | |
|               "r s" (saving-excursion (string-inflection-underscore))
 | |
|               "r u" (saving-excursion (string-inflection-upcase))
 | |
|               "r -" (saving-excursion (string-inflection-kebab-case))
 | |
|               "r k" (saving-excursion (string-inflection-kebab-case))
 | |
|               ;; "r ." (saving-excursion (string-inflection-dot-case))
 | |
|               ;; "r ." (saving-excursion (string-inflection-space-case))
 | |
|               ;; "r ." (saving-excursion (string-inflection-title-case))
 | |
|               )))
 | |
| #+end_src
 | |
| 
 | |
| * Mode-specific config
 | |
| ** org-mode
 | |
| #+begin_src elisp :tangle yes
 | |
| (after! org
 | |
|   (load! "org-config")
 | |
|   (load! "org-query"))
 | |
| #+end_src
 | |
| 
 | |
| *** Theme overrides
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (custom-set-faces!
 | |
|   `(org-drawer :foreground ,+solarized-s-base1 :bold t)
 | |
|   `(org-block :foreground ,+solarized-s-base00)
 | |
|   `(org-meta-line :foreground ,+solarized-s-base1 :italic t)
 | |
|   `(org-document-title :foreground ,+solarized-s-base01 :height 1.3)
 | |
|   `(org-done :foreground ,+solarized-green)
 | |
|   `(org-headline-done :foreground ,+solarized-green)
 | |
|   `(org-special-keyword :foreground ,+solarized-s-base1 :bold t)
 | |
|   `(org-date :foreground ,+solarized-blue :underline t)
 | |
|   `(org-table
 | |
|     :foreground ,+solarized-s-base0  ; used to be green, I think I like this better?
 | |
|     :italic t)
 | |
|   `(org-link :foreground ,+solarized-yellow)
 | |
|   `(org-todo :foreground ,+solarized-cyan)
 | |
|   `(org-code :foreground ,+solarized-s-base1)
 | |
|   `(org-block-begin-line :foreground ,+solarized-s-base1 :italic t)
 | |
|   `(org-block-end-line :foreground ,+solarized-s-base1 :italic t)
 | |
|   `(org-document-info-keyword :foreground ,+solarized-s-base1 :italic t)
 | |
| 
 | |
|   `(org-level-1 :foreground ,+solarized-red)
 | |
|   `(org-level-2 :foreground ,+solarized-green)
 | |
|   `(org-level-3 :foreground ,+solarized-blue)
 | |
|   `(org-level-4 :foreground ,+solarized-yellow)
 | |
|   `(org-level-5 :foreground ,+solarized-cyan)
 | |
|   `(org-level-6 :foreground ,+solarized-violet)
 | |
|   `(org-level-7 :foreground ,+solarized-magenta)
 | |
|   `(org-level-8 :foreground ,+solarized-blue))
 | |
| #+end_src
 | |
| 
 | |
| *** Commands
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun grfn/insert-new-src-block ()
 | |
|   (interactive)
 | |
|   (let* ((current-src-block (org-element-at-point))
 | |
|          (src-block-head (save-excursion
 | |
|                            (goto-char (org-element-property
 | |
|                                        :begin current-src-block))
 | |
|                            (let ((line (thing-at-point 'line t)))
 | |
|                              (if (not (s-starts-with? "#+NAME:" (s-trim line)))
 | |
|                                  line
 | |
|                                (forward-line)
 | |
|                                (thing-at-point 'line t)))))
 | |
|          (point-to-insert
 | |
|           (if-let (results-loc (org-babel-where-is-src-block-result))
 | |
|               (save-excursion
 | |
|                 (goto-char results-loc)
 | |
|                 (org-element-property
 | |
|                  :end
 | |
|                  (org-element-at-point)))
 | |
|             (org-element-property :end (org-element-at-point)))))
 | |
|     (goto-char point-to-insert)
 | |
|     (insert "\n")
 | |
|     (insert src-block-head)
 | |
|     (let ((contents (point-marker)))
 | |
|       (insert "\n#+END_SRC\n")
 | |
|       (goto-char contents))))
 | |
| 
 | |
| (defun grfn/+org-insert-item (orig direction)
 | |
|   (interactive)
 | |
|   (if (and (org-in-src-block-p)
 | |
|            (equal direction 'below))
 | |
|       (grfn/insert-new-src-block)
 | |
|     (funcall orig direction)))
 | |
| 
 | |
| (advice-add #'+org--insert-item :around #'grfn/+org-insert-item)
 | |
| #+end_src
 | |
| *** Bindings
 | |
| #+begin_src elisp :tangle yes
 | |
| (map!
 | |
|  (:after org
 | |
|   :n "C-c C-x C-o" #'org-clock-out
 | |
|   (:leader
 | |
|    "n k" #'org-archive-subtree-default)
 | |
| 
 | |
|   (:map org-capture-mode-map
 | |
|    :n "g RET" #'org-capture-finalize
 | |
|    :n "g \\"  #'org-captue-refile)))
 | |
| #+end_src
 | |
| 
 | |
| ** magit
 | |
| #+begin_src elisp :tangle yes
 | |
| (after! magit
 | |
|   (map! :map magit-mode-map
 | |
|         ;; :n "] ]" #'magit-section-forward
 | |
|         ;; :n "[ [" #'magit-section-backward
 | |
|         )
 | |
| 
 | |
|   (transient-define-suffix magit-commit-wip ()
 | |
|     (interactive)
 | |
|     (magit-commit-create '("-m" "wip")))
 | |
| 
 | |
|   (transient-append-suffix
 | |
|     #'magit-commit
 | |
|     ["c"]
 | |
|     (list "W" "Commit WIP" #'magit-commit-wip))
 | |
| 
 | |
|   (transient-define-suffix magit-reset-head-back ()
 | |
|     (interactive)
 | |
|     (magit-reset-mixed "HEAD~"))
 | |
| 
 | |
|   (transient-define-suffix magit-reset-head-previous ()
 | |
|     (interactive)
 | |
|     (magit-reset-mixed "HEAD@{1}"))
 | |
| 
 | |
|   (transient-append-suffix
 | |
|     #'magit-reset
 | |
|     ["f"]
 | |
|     (list "b" "Reset HEAD~"    #'magit-reset-head-back))
 | |
|   (transient-append-suffix
 | |
|     #'magit-reset
 | |
|     ["f"]
 | |
|     (list "o" "Reset HEAD@{1}" #'magit-reset-head-previous)))
 | |
| #+end_src
 | |
| 
 | |
| ** elisp
 | |
| *** Org config mode
 | |
| The minor-mode for *this file*!
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (after! smartparens
 | |
|   (sp-local-pair 'org-config-mode "'" "'" :actions nil)
 | |
|   (sp-local-pair 'org-config-mode "`" "`" :actions nil))
 | |
| 
 | |
| (define-minor-mode org-config-mode
 | |
|   "Minor-mode for tangled org .el config"
 | |
|   :group 'org
 | |
|   :lighter "Org-config"
 | |
|   :keymap '()
 | |
|   (sp-update-local-pairs 'org-config-mode))
 | |
| #+end_src
 | |
| 
 | |
| *** Bindings
 | |
| #+begin_src elisp :tangle yes
 | |
| (map!
 | |
|  (:map emacs-lisp-mode-map
 | |
|   :n "g SPC" #'eval-buffer
 | |
|   :n "g RET" (λ! () (ert t)) ))
 | |
| #+end_src
 | |
| 
 | |
| ** tuareg
 | |
| *** Config
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| 
 | |
| (defun aspen/tuareg-setup ()
 | |
|   (setq-local sp-max-pair-length (->> '("begin" "sig" "struct")
 | |
|                                       (--map (length it))
 | |
|                                       (-max))
 | |
|               whitespace-line-column 80))
 | |
| 
 | |
| (add-hook 'tuareg-mode-hook #'aspen/tuareg-setup)
 | |
| 
 | |
| (defun sp-tuareg-post-handler (id action context)
 | |
|   (when (equal action 'insert)
 | |
|     (save-excursion
 | |
|       (insert "x")
 | |
|       (newline)
 | |
|       (indent-according-to-mode))
 | |
|     (delete-char 1)))
 | |
| 
 | |
| (after! smartparens-ml
 | |
|   (sp-local-pair 'tuareg-mode "module" "end" :actions nil)
 | |
| 
 | |
|   (dolist (pair-start '("begin" "sig" "struct"))
 | |
|     (sp-local-pair 'tuareg-mode
 | |
|                    pair-start "end"
 | |
|                    :when '(("SPC" "RET" "<evil-ret>"))
 | |
|                    :unless '(sp-in-string-p)
 | |
|                    :actions '(insert navigate)
 | |
|                    :post-handlers '(sp-tuareg-post-handler))))
 | |
| nil
 | |
|     #+end_src
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (after! dune-mode
 | |
|   (add-hook 'dune-mode-hook 'paxedit-mode))
 | |
| #+end_src
 | |
| 
 | |
| *** Bindings
 | |
| #+begin_src elisp :tangle yes
 | |
| (map!
 | |
|  (:map tuareg-mode-map
 | |
|   :n "g RET" (λ! () (compile "dune build @@runtest"))
 | |
|   :n "g SPC" #'dune-promote
 | |
|   :n "g \\" #'utop
 | |
|   :n "g y" #'merlin-locate-type
 | |
|   "C-c C-f" (λ! () (compile "dune fmt"))))
 | |
| #+end_src
 | |
| 
 | |
| *** Theme overrides
 | |
| #+begin_src elisp :tangle yes
 | |
| (custom-set-faces!
 | |
|   `(tuareg-font-lock-governing-face :foreground ,+solarized-s-base01 :bold t)
 | |
|   `(tuareg-font-lock-label-face :foreground ,+solarized-blue)
 | |
|   `(tuareg-font-lock-constructor-face :foreground ,+solarized-yellow)
 | |
|   `(tuareg-font-lock-operator-face :foreground ,+solarized-red)
 | |
|   `(tuareg-font-lock-attribute-face :foreground ,+solarized-red :bold nil)
 | |
|   `(tuareg-font-lock-extension-node-face :background nil :inherit 'font-lock-preprocessor-face)
 | |
|   `(merlin-eldoc-occurrences-face :background ,+solarized-s-base2)
 | |
|   `(merlin-type-face :background ,+solarized-s-base2)
 | |
|   `(utop-prompt :foreground ,+solarized-blue)
 | |
|   `(utop-frozen :foreground ,+solarized-s-base1 :italic t)
 | |
|   `(vertico-group-title :foreground ,+solarized-s-base1)
 | |
|   `(vertico-group-header :foreground ,+solarized-s-base1))
 | |
| #+end_src
 | |
| 
 | |
| ** clojure
 | |
| 
 | |
| *** Setup
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun clojure-thing-at-point-setup ()
 | |
|   (interactive)
 | |
|   ;; Used by cider-find-dwim to parse the symbol at point
 | |
|   (setq-local
 | |
|    thing-at-point-file-name-chars
 | |
|    (concat thing-at-point-file-name-chars
 | |
|            "><!?")))
 | |
| 
 | |
| (defun +grfn/clojure-setup ()
 | |
|   ;; (flycheck-select-checker 'clj-kondo)
 | |
|   (require 'flycheck)
 | |
|   (push 'clojure-cider-kibit flycheck-disabled-checkers)
 | |
|   (push 'clojure-cider-eastwood flycheck-disabled-checkers)
 | |
|   (push 'clojure-cider-typed flycheck-disabled-checkers)
 | |
|   )
 | |
| 
 | |
| (after! clojure-mode
 | |
|   (define-clojure-indent
 | |
|     (PUT 2)
 | |
|     (POST 2)
 | |
|     (GET 2)
 | |
|     (PATCH 2)
 | |
|     (DELETE 2)
 | |
|     (context 2)
 | |
|     (checking 3)
 | |
|     (match 1)
 | |
|     (domonad 0)
 | |
|     (describe 1)
 | |
|     (before 1)
 | |
|     (it 2))
 | |
| 
 | |
|   (add-hook 'clojure-mode-hook #'clojure-thing-at-point-setup)
 | |
|   (add-hook 'clojure-mode-hook #'+grfn/clojure-setup))
 | |
| 
 | |
| (use-package! flycheck-clojure
 | |
|   ;; :disabled t
 | |
|   :after (flycheck cider)
 | |
|   :config
 | |
|   (flycheck-clojure-setup))
 | |
| 
 | |
| (after! clj-refactor
 | |
|   (setq cljr-magic-requires :prompt
 | |
|         cljr-clojure-test-declaration "[clojure.test :refer :all]"
 | |
|         cljr-cljc-clojure-test-declaration"#?(:clj [clojure.test :refer :all]
 | |
| :cljs [cljs.test :refer-macros [deftest is testing]])"
 | |
|         )
 | |
|   (add-to-list
 | |
|    'cljr-magic-require-namespaces
 | |
|    '("s" . "clojure.spec.alpha")))
 | |
| 
 | |
| (set-popup-rule! "^\\*cider-test-report" :size 0.4)
 | |
| nil
 | |
| #+end_src
 | |
| 
 | |
| *** Commands
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun grfn/run-clj-or-cljs-test ()
 | |
|   (interactive)
 | |
|   (message "Running tests...")
 | |
|   (cl-case (cider-repl-type-for-buffer)
 | |
|     (cljs
 | |
|      (cider-interactive-eval
 | |
|       "(with-out-str (cljs.test/run-tests))"
 | |
|       (nrepl-make-response-handler
 | |
|        (current-buffer)
 | |
|        (lambda (_ value)
 | |
|          (with-output-to-temp-buffer "*cljs-test-results*"
 | |
|            (print
 | |
|             (->> value
 | |
|                  (s-replace "\"" "")
 | |
|                  (s-replace "\\n" "\n")))))
 | |
|        nil nil nil)))
 | |
|     (('clj 'multi)
 | |
|      (funcall-interactively
 | |
|       #'cider-test-run-ns-tests
 | |
|       nil))))
 | |
| 
 | |
| (defun cider-copy-last-result ()
 | |
|   (interactive)
 | |
|   (cider-interactive-eval
 | |
|    "*1"
 | |
|    (nrepl-make-response-handler
 | |
|     (current-buffer)
 | |
|     (lambda (_ value)
 | |
|       (kill-new value)
 | |
|       (message "Copied last result (%s) to clipboard"
 | |
|                (if (= (length value) 1) "1 char"
 | |
|                  (format "%d chars" (length value)))))
 | |
|     nil nil nil)))
 | |
| 
 | |
| #+end_src
 | |
| 
 | |
| *** Bindings
 | |
| 
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (map!
 | |
|  (:after
 | |
|   clojure-mode
 | |
|   (:map clojure-mode-map
 | |
|    :n "] f" 'forward-sexp
 | |
|    :n "[ f" 'backward-sexp))
 | |
| 
 | |
|  (:after
 | |
|   cider-mode
 | |
|   (:map cider-mode-map
 | |
|    :n "g SPC" 'cider-eval-buffer
 | |
|    :n "g \\"  'cider-switch-to-repl-buffer
 | |
|    :n "K"     'cider-doc
 | |
|    :n "g K"   'cider-apropos
 | |
|    :n "g d"   'cider-find-dwim
 | |
|    :n "C-w ]" 'cider-find-dwim-other-window
 | |
|    ;; :n "g RET" 'cider-test-run-ns-tests
 | |
|    :n "g RET" 'grfn/run-clj-or-cljs-test
 | |
|    :n "g r" #'cljr-rename-symbol
 | |
| 
 | |
|    "C-c C-r r" 'cljr-add-require-to-ns
 | |
|    "C-c C-r i" 'cljr-add-import-to-ns
 | |
| 
 | |
|    (:localleader
 | |
|     ;; :desc "Inspect last result" :n "i" 'cider-inspect-last-result
 | |
|     ;; :desc "Search for documentation" :n "h s" 'cider-apropos-doc
 | |
|     :desc "Add require to ns" :n "n r" 'cljr-add-require-to-ns
 | |
|     :desc "Add import to ns" :n "n i" 'cljr-add-import-to-ns))
 | |
|   (:map cider-repl-mode-map
 | |
|    :n "g \\" 'cider-switch-to-last-clojure-buffer)))
 | |
|  #+end_src
 | |
| 
 | |
| ** rust
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun aspen/rust-setup ()
 | |
|   (interactive)
 | |
|   (+evil-embrace-angle-bracket-modes-hook-h)
 | |
|   (setq-local whitespace-line-column 100
 | |
|               fill-column 100))
 | |
| 
 | |
| (add-hook 'rust-mode-hook #'aspen/rust-setup)
 | |
| #+end_src
 | |
| 
 | |
| *** Bindings
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (map!
 | |
|  (:map rust-mode-map
 | |
|   :n "g RET" #'lsp-rust-analyzer-run
 | |
|   :n "g R" #'lsp-find-references
 | |
|   :n "g d" #'lsp-find-definition
 | |
|   :n "g Y" #'lsp-goto-type-definition
 | |
|   (:localleader
 | |
|    "m" #'lsp-rust-analyzer-expand-macro)))
 | |
| #+end_src
 | |
| 
 | |
| *** Theme overrides
 | |
| #+begin_src elisp :tangle yes
 | |
| (custom-set-faces!
 | |
|   `(rust-unsafe :foreground ,+solarized-red))
 | |
| #+end_src
 | |
| 
 | |
| ** common-lisp
 | |
| *** Commands
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (defun aspen/sly-panettone ()
 | |
|   (interactive)
 | |
|   (sly
 | |
|    (concat
 | |
|     (s-trim
 | |
|      (shell-command-to-string
 | |
|       "nix-build -o sbcl -E 'with import ~/code/depot {}; nix.buildLisp.sbclWith [web.panettone]'"))
 | |
|     "/bin/sbcl")))
 | |
| 
 | |
| (defun aspen/setup-lisp ()
 | |
|   (interactive)
 | |
|   (rainbow-delimiters-mode)
 | |
|   (paxedit-mode 1)
 | |
|   (flycheck-mode -1))
 | |
| 
 | |
| (add-hook 'common-lisp-mode-hook #'aspen/setup-lisp)
 | |
| 
 | |
| (defun sly-run-tests ()
 | |
|   (interactive)
 | |
|   ;; TODO: handle other test frameworks
 | |
|   (let ((orig-window (get-buffer-window)))
 | |
|     (sly-eval '(fiveam:run!))
 | |
|     (funcall-interactively #'sly-mrepl-sync)
 | |
|     (select-window orig-window)))
 | |
| #+end_src
 | |
| 
 | |
| *** Bindings
 | |
| 
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (map!
 | |
|  (:map sly-mode-map
 | |
|   :n "g \\" #'sly-mrepl-sync
 | |
|   :n "g d" #'sly-edit-definition
 | |
|   :n "K" #'sly-documentation
 | |
|   :n "g SPC" #'sly-compile-and-load-file
 | |
|   :n "g RET" #'sly-run-tests)
 | |
| 
 | |
|  (:map sly-mrepl-mode-map
 | |
|   "C-k" #'sly-mrepl-previous-prompt
 | |
|   "C-r" #'isearch-backward))
 | |
| #+end_src
 | |
| 
 | |
| * Completion
 | |
| ** Corfu
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (setopt +corfu-want-ret-to-confirm nil)
 | |
| 
 | |
| (use-package! corfu
 | |
|   :demand t
 | |
|   :bind (:map corfu-map
 | |
|               ("TAB" . corfu-next)
 | |
|               ([tab] . corfu-next)
 | |
|               ("S-TAB" . corfu-previous)
 | |
|               ([backtab] . corfu-previous))
 | |
|   :init (setopt corfu-on-exact-match 'insert
 | |
|                 corfu-preselect 'prompt
 | |
|                 completion-cycle-threshold 1
 | |
|                 corfu-quit-no-match t
 | |
|                 corfu-quit-at-boundary t)
 | |
|   :config
 | |
|   (map! :map corfu-map
 | |
|         :i "TAB" #'corfu-next
 | |
|         :i [tab] #'corfu-next
 | |
|         :i "S-TAB" #'corfu-previous
 | |
|         :i [backtab] #'corfu-previous))
 | |
| #+end_src
 | |
| 
 | |
| ** Fuzzy search
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (use-package! hotfuzz
 | |
|   :after (orderless corfu)
 | |
|   :config
 | |
|   (setopt completion-styles '(hotfuzz basic)
 | |
|           completion-ignore-case t))
 | |
| #+end_src
 | |
| 
 | |
| * Email
 | |
| #+begin_src elisp :tangle yes
 | |
| (after! notmuch
 | |
|   (setq notmuch-saved-searches
 | |
|         '((:name "inbox" :query "tag:inbox tag:important not tag:trash" :key "i")
 | |
|           (:name "flagged" :query "tag:flagged" :key "f")
 | |
|           (:name "sent" :query "tag:sent" :key "s")
 | |
|           (:name "drafts" :query "tag:draft" :key "d")
 | |
| 
 | |
|           (:name "work" :query "tag:inbox and tag:important and path:work/**"
 | |
|                  :key "w")
 | |
|           (:name "personal" :query "tag:inbox and tag:important and path:personal/**"
 | |
|                  :key "p"))
 | |
|         message-send-mail-function 'message-send-mail-with-sendmail
 | |
|         message-sendmail-f-is-evil 't
 | |
|         message-sendmail-envelope-from 'header
 | |
|         message-sendmail-extra-arguments '("--read-envelope-from")))
 | |
| 
 | |
| (defun aspen/notmuch-sync ()
 | |
|   (interactive)
 | |
|   (let* ((search-buffer (current-buffer))
 | |
|          (proc (start-process-shell-command
 | |
|                 "notmuch-sync"
 | |
|                 "*notmuch-sync*"
 | |
|                 "cd ~/mail/personal/ && gmi sync"))
 | |
|          (buf (process-buffer proc)))
 | |
| 
 | |
|     (set-process-sentinel
 | |
|      proc
 | |
|      (lambda (proc msg)
 | |
|        (internal-default-process-sentinel proc msg)
 | |
|        (when (and (string= msg "finished\n"))
 | |
|          (kill-buffer buf)
 | |
|          (with-current-buffer search-buffer
 | |
|            (when (eq major-mode 'notmuch-search-mode)
 | |
|              (notmuch-refresh-this-buffer))))))
 | |
| 
 | |
|     (with-current-buffer buf
 | |
|       (+popup-buffer-mode))
 | |
|     (display-buffer buf '(display-buffer-at-bottom . ()))))
 | |
| 
 | |
| (set-popup-rule!
 | |
|   "^\\*notmuch-sync\\*$"
 | |
|   :select nil
 | |
|   :quit 'other)
 | |
| 
 | |
| (map! :map notmuch-search-mode-map
 | |
|       :n "g SPC" #'aspen/notmuch-sync)
 | |
| #+end_src
 | |
| 
 | |
| ** Bindings
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (map!
 | |
|  (:leader
 | |
|   :desc "Email" :n "o m" #'notmuch-jump-search
 | |
|   :desc "Search email" "s M" #'consult-notmuch))
 | |
| #+end_src
 | |
| 
 | |
| ** Theme
 | |
| 
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (custom-set-faces!
 | |
|   `(notmuch-message-summary-face
 | |
|     :background ,+solarized-halfway-highlight))
 | |
| #+end_src
 | |
| 
 | |
| * Misc
 | |
| ** TVL
 | |
| #+begin_src emacs-lisp :tangle yes
 | |
| (require 'tvl)
 | |
| #+end_src
 | |
| 
 | |
| ** Matchit
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! evil-matchit)
 | |
| #+end_src
 | |
| ** Direnv
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! direnv
 | |
|   :config (direnv-mode))
 | |
| #+end_src
 | |
| ** IRC
 | |
| *** Connecting to IRC
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (defvar irc-servers
 | |
|   '("hackint"
 | |
|     "libera"))
 | |
| 
 | |
| (defun irc-connect (server)
 | |
|   (interactive
 | |
|    (list (completing-read "Server: " irc-servers)))
 | |
|   (let ((pw (-> (shell-command-to-string
 | |
|                  (format "pass irccloud/%s" server))
 | |
|                 (s-trim)
 | |
|                 (s-lines)
 | |
|                 (-last-item)))
 | |
|         (gnutls-verify-error nil))
 | |
|     (erc-tls :server "bnc.irccloud.com"
 | |
|              :port 6697
 | |
|              :nick "aspen"
 | |
|              :password (concat "bnc@"
 | |
|                                (s-trim (shell-command-to-string "hostname"))
 | |
|                                ":"
 | |
|                                pw))))
 | |
| 
 | |
| (defun aspen/switch-to-erc-buffer-or-connect ()
 | |
|   (interactive)
 | |
|   (if (functionp 'erc-switch-to-buffer)
 | |
|       (call-interactively #'erc-switch-to-buffer)
 | |
|     (call-interactively #'irc-connect)))
 | |
| #+end_src
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (map! :leader "o I" #'irc-connect
 | |
|       :leader "o i" #'aspen/switch-to-erc-buffer-or-connect)
 | |
| #+end_src
 | |
| 
 | |
| *** IRC alerts
 | |
| #+begin_src elisp :tangle yes
 | |
| (use-package! alert)
 | |
| 
 | |
| (defgroup erc-alert nil
 | |
|   "Alert me using alert.el for important ERC messages"
 | |
|   :group 'erc)
 | |
| 
 | |
| (defcustom erc-noise-regexp
 | |
|   "\\(Logging in:\\|Signing off\\|You're now away\\|Welcome back\\)"
 | |
|   "This regexp matches unwanted noise."
 | |
|   :type 'regexp
 | |
|   :group 'erc)
 | |
| 
 | |
| (setq tvl-enabled? t)
 | |
| 
 | |
| (defun disable-tvl-notifications ()
 | |
|   (interactive)
 | |
|   (setq tvl-enabled? nil))
 | |
| 
 | |
| (defun enable-tvl-notifications ()
 | |
|   (interactive)
 | |
|   (setq tvl-enabled? t))
 | |
| 
 | |
| (defun erc-alert-important-p (info)
 | |
|   (let ((message (plist-get info :message))
 | |
|         (erc-message (-> info (plist-get :data) (plist-get :message)))
 | |
|         (erc-channel (-> info (plist-get :data) (plist-get :channel))))
 | |
|     (and erc-message
 | |
|          (not (or (string-match "^\\** *Users on #" message)
 | |
|                   (string-match erc-noise-regexp
 | |
|                                 message)))
 | |
|          (or (and tvl-enabled?
 | |
|                   (string-equal erc-channel "#tvl"))
 | |
|              (string-match "grfn" message)))))
 | |
| 
 | |
| (comment
 | |
|  last-info
 | |
|  erc-noise-regexp
 | |
|  (setq tvl-enabled? nil)
 | |
|  )
 | |
| 
 | |
| (defun my-erc-hook (&optional match-type nick message)
 | |
|   "Shows a notification, when user's nick was mentioned.
 | |
| If the buffer is currently not visible, makes it sticky."
 | |
|   (setq last-message message)
 | |
|   (if (or (null match-type) (not (eq match-type 'fool)))
 | |
|       (let (alert-log-messages)
 | |
|         (alert (or message (buffer-string))
 | |
|                :severity (if (string-match "grfn" (or message ""))
 | |
|                              'high 'low)
 | |
|                :title (or nick (buffer-name))
 | |
|                :data `(:message ,(or message (buffer-string))
 | |
|                                 :channel ,(or nick (buffer-name)))))))
 | |
| 
 | |
| (add-hook 'erc-text-matched-hook 'my-erc-hook)
 | |
| (add-hook 'erc-insert-modify-hook 'my-erc-hook)
 | |
| 
 | |
| (defun my-erc-define-alerts (&rest ignore)
 | |
|   ;; Unless the user has recently typed in the ERC buffer, highlight the fringe
 | |
|   (alert-add-rule
 | |
|    :status   '(buried visible idle)
 | |
|    :severity '(moderate high urgent)
 | |
|    :mode     'erc-mode
 | |
|    :predicate
 | |
|    #'(lambda (info)
 | |
|        (and (not (eq (current-buffer) (plist-get info :buffer)))
 | |
|             (string-match "grfn:" (plist-get info :message))))
 | |
|    :persistent
 | |
|    #'(lambda (info)
 | |
|        ;; If the buffer is buried, or the user has been idle for
 | |
|        ;; `alert-reveal-idle-time' seconds, make this alert
 | |
|        ;; persistent.  Normally, alerts become persistent after
 | |
|        ;; `alert-persist-idle-time' seconds.
 | |
|        (memq (plist-get info :status) '(buried idle)))
 | |
|    :style 'message
 | |
|    :continue t)
 | |
| 
 | |
|   (alert-add-rule
 | |
|    :status 'buried
 | |
|    :mode   'erc-mode
 | |
|    :predicate #'erc-alert-important-p
 | |
|    :style 'libnotify
 | |
|    :append t)
 | |
| 
 | |
|   (alert-add-rule
 | |
|    :status 'buried
 | |
|    :mode   'erc-mode
 | |
|    :predicate #'erc-alert-important-p
 | |
|    :style 'message
 | |
|    :append t)
 | |
| 
 | |
|   (alert-add-rule
 | |
|    :mode 'erc-mode
 | |
|    :predicate #'erc-alert-important-p
 | |
|    :style 'log
 | |
|    :append t)
 | |
| 
 | |
|   (alert-add-rule :mode 'erc-mode :style 'ignore :append t))
 | |
| 
 | |
| (add-hook 'erc-connect-pre-hook 'my-erc-define-alerts)
 | |
| #+end_src
 | |
| 
 | |
| *** Don't send ~:q~, etc, to the server
 | |
| #+begin_src elisp :tangle yes
 | |
| (defun fix-irc-message (msg)
 | |
|   (let ((msg (s-trim msg)))
 | |
|     (if (string-equal msg ":q") "" msg)))
 | |
| (advice-add #'erc-user-input :filter-return #'fix-irc-message)
 | |
| #+end_src
 | |
| 
 | |
| *** Theme overrides
 | |
| #+begin_src elisp :tangle yes
 | |
| (custom-set-faces!
 | |
|   `(erc-button :foreground ,+solarized-blue))
 | |
| #+end_src
 | |
| 
 | |
| *** TODO Nick rainbow colors
 | |
| Stole this from https://github.com/jtdaugherty/emacs-config/blob/master/common/erc-nick-colors.el.
 | |
| 
 | |
| IT doesn't work though :(
 | |
| 
 | |
| #+begin_src elisp :tangle yes
 | |
| (setq nick-face-list '())
 | |
| 
 | |
| ;; Define the list of colors to use when coloring IRC nicks.
 | |
| (setq-default erc-colors-list (list +solarized-yellow
 | |
|                                     +solarized-orange
 | |
|                                     +solarized-red
 | |
|                                     +solarized-magenta
 | |
|                                     +solarized-violet
 | |
|                                     +solarized-blue
 | |
|                                     +solarized-cyan
 | |
|                                     +solarized-green))
 | |
| 
 | |
| (defun build-nick-face-list ()
 | |
|   "build-nick-face-list builds a list of new faces using the
 | |
| foreground colors specified in erc-colors-list.  The nick faces
 | |
| created here will be used to format IRC nicks."
 | |
|   (let ((i -1))
 | |
|     (setq nick-face-list
 | |
|           (mapcar
 | |
|            (lambda (COLOR)
 | |
|              (setq i (1+ i))
 | |
|              (list (custom-declare-face
 | |
|                     (make-symbol (format "erc-nick-face-%d" i))
 | |
|                     (list (list t (list :foreground COLOR)))
 | |
|                     (format "Nick face %d" i))))
 | |
|            erc-colors-list))))
 | |
| 
 | |
| (defun erc-insert-nick-colors ()
 | |
|   "This insert-modify hook looks for nicks in new messages and
 | |
| computes md5(nick) and uses substring(md5_value, 0, 4) mod (length
 | |
| nick-face-list) to index the face list and produce the same face for a
 | |
| given nick each time it is seen.  We get a lot of collisions this way,
 | |
| unfortunately, but it's better than some other methods I tried.
 | |
| Additionally, if you change the order or size of the erc-colors-list,
 | |
| you'll change the colors used for nicks."
 | |
|   (if (null nick-face-list) (build-nick-face-list))
 | |
|   (save-excursion
 | |
|     (goto-char (point-min))
 | |
|     (if (looking-at "<\\([^>]*\\)>")
 | |
|         (let ((nick (match-string 1)))
 | |
|           (put-text-property (match-beginning 1) (match-end 1)
 | |
|                              'face (nth
 | |
|                                     (mod (string-to-number
 | |
|                                           (substring (md5 nick) 0 4) 16)
 | |
|                                          (length nick-face-list))
 | |
|                                     nick-face-list))))))
 | |
| 
 | |
| ;; This adds the ERC message insert hook.
 | |
| (add-hook 'erc-insert-modify-hook 'erc-insert-nick-colors)
 | |
| #+end_src
 | |
| 
 | |
| * Hacks
 | |
| Not having this breaks elisp documentation :(
 | |
| #+begin_src elisp :tangle yes
 | |
| (defvar elisp-demos-user-files nil)
 | |
| #+end_src
 |