25 KiB
Agryphus' Emacs Config
- TABLE OF CONTENTS
- General Keybinds
- Better Defaults
- Evil
- Visual Tweaks
- Fonts
- Coloring
- Languages
- Miscellaneous
General Keybinds
Quick Find Files
(map! :leader
(:prefix ("=" . "open file")
:desc "Edit doom config.org" "c" #'(lambda () (interactive) (find-file "~/.config/doom/config.org"))
:desc "Edit doom init.el" "i" #'(lambda () (interactive) (find-file "~/.config/doom/init.el"))))
(map! "C-/" #'comment-line)
Elisp Evaluation
(map! :leader
(:prefix ("e". "evaluate")
:desc "Evaluate elisp in buffer" "b" #'eval-buffer
:desc "Evaluate defun" "d" #'eval-defun
:desc "Evaluate elisp expression" "e" #'eval-expression
:desc "Evaluate last sexpression" "l" #'eval-last-sexp
:desc "Evaluate elisp in region" "r" #'eval-region))
Unsetting Bindings That Step on Mine
(after! ccls! (unbind-key "M-a" c-mode-base-map))
;; The C package adds a keybind to (ccls-navigate "D"), which not
;; only steps on my binding, but is not even a provided function.
(map! :after ccls
:map (c-mode-map c++-mode-map)
:n "C-h" nil
:n "C-j" nil
:n "C-k" nil
:n "C-l" nil)
Better Defaults
Disable "Really Quit Emacs" Prompt
(setq confirm-kill-emacs nil)
Relative Line Numbers
(setq display-line-numbers-type 'relative)
Scrolloff
(setq ag/scroll-margin 8) ;; Custom var
(setq scroll-margin ag/scroll-margin)
;; Exceptions for modes that need 0 scroll margin
(add-hook 'eat-mode-hook (lambda () (setq-local scroll-margin 0)))
(add-hook 'eat-exit-hook (lambda () (setq-local scroll-margin ag/scroll-margin)))
(add-hook '+doom-dashboard-mode-hook (lambda () (setq-local scroll-margin 0)))
Scratch Buffer Mode
Scratch buffer is, by default, in interactive lisp mode. Default to just plaintext.
(setq initial-major-mode 'text-mode)
Evil
Changing Keybinds
Changing backspace behavior
(define-key evil-insert-state-map (kbd "<backspace>") 'backward-delete-char-untabify)
Leave insert/visual modes with C-C
(define-key evil-insert-state-map (kbd "C-c") 'evil-normal-state)
(define-key evil-visual-state-map (kbd "C-c") 'evil-normal-state)
Remove "jk" escape sequence
By default, evil exits insert mode when "jk" is pressed in sequence. I find this to be confusing behavior.
(setq evil-escape-key-sequence nil)
Clearing highlight with C-L
Mimics the "redraw" signal sent to terminals for vim.
(define-key evil-normal-state-map (kbd "C-l") 'evil-ex-nohighlight)
Swap g[k/j] and k/j
(define-key evil-motion-state-map (kbd "gj") 'evil-next-line)
(define-key evil-motion-state-map (kbd "gk") 'evil-previous-line)
(define-key evil-motion-state-map (kbd "j") 'evil-next-visual-line)
(define-key evil-motion-state-map (kbd "k") 'evil-previous-visual-line)
Resize Font in Insert Mode
These are the same keybinds that are able to work outside of insert mode.
(define-key evil-insert-state-map (kbd "C-M-=") 'doom/increase-font-size)
(define-key evil-insert-state-map (kbd "C-M--") 'doom/decrease-font-size)
(define-key evil-insert-state-map (kbd "C-=") 'text-scale-increase)
(define-key evil-insert-state-map (kbd "C--") 'text-scale-decrease)
Visual Tweaks
Scale Line Number Size with Buffer Text
(add-hook 'text-scale-mode-hook (lambda() (face-remap--remap-face 'line-number)))
(add-hook 'text-scale-mode-hook (lambda() (face-remap--remap-face 'line-number-current-line)))
Block Cursor Not Showing in Terminal Mode
(package! evil-terminal-cursor-changer)
(use-package! evil-terminal-cursor-changer
:hook (tty-setup . evil-terminal-cursor-changer-activate))
Doom Dashboard Spacing
I felt that the spacing between the line items in the graphical doom dashboard was too large. There did not seem to be any variable to set this, so I overrode the entire function and manually decreased the spacing
(defun doom-dashboard-widget-shortmenu ()
(insert "\n")
(dolist (section +doom-dashboard-menu-sections)
(cl-destructuring-bind (label &key icon action when face key) section
(when (and (fboundp action)
(or (null when)
(eval when t)))
(insert
(+doom-dashboard--center
(- +doom-dashboard--width 1)
(let ((icon (if (stringp icon) icon (eval icon t))))
(format (format "%s%%s%%-10s" (if icon "%3s\t" "%3s"))
(or icon "")
(with-temp-buffer
(insert-text-button
label
'action
`(lambda (_)
(call-interactively (or (command-remapping #',action)
#',action)))
'face (or face 'doom-dashboard-menu-title)
'follow-link t
'help-echo
(format "%s (%s)" label
(propertize (symbol-name action) 'face 'doom-dashboard-menu-desc)))
(format "%-37s" (buffer-string)))
;; Lookup command keys dynamically
(propertize
(or key
(when-let*
((keymaps
(delq
nil (list (when (bound-and-true-p evil-local-mode)
(evil-get-auxiliary-keymap +doom-dashboard-mode-map 'normal))
+doom-dashboard-mode-map)))
(key
(or (when keymaps
(where-is-internal action keymaps t))
(where-is-internal action nil t))))
(with-temp-buffer
(save-excursion (insert (key-description key)))
(while (re-search-forward "<\\([^>]+\\)>" nil t)
(let ((str (match-string 1)))
(replace-match
(upcase (if (< (length str) 3)
str
(substring str 0 3))))))
(buffer-string)))
"")
'face 'doom-dashboard-menu-desc))))
;; (if (display-graphic-p)
;; "\n\n"
;; "\n"))))))
"\n"))))) ;; Overwrote above lines so remove the extra newline in graphical mode from the doom dashboard
(remove-hook '+doom-dashboard-functions #'doom-dashboard-widget-footer) ;; No github at bottom
Posframe
Vertico Posframe
(package! vertico-posframe)
(vertico-posframe-mode 1)
(setq vertico-multiform-commands
'((consult-line
posframe
(vertico-posframe-poshandler . posframe-poshandler-frame-top-center)
(vertico-posframe-border-width . 10)
;; NOTE: This is useful when emacs is used in both in X and
;; terminal, for posframe do not work well in terminal, so
;; vertico-buffer-mode will be used as fallback at the
;; moment.
(vertico-posframe-fallback-mode . vertico-buffer-mode))
(t posframe)))
(vertico-multiform-mode 1)
Company Posframe
Company mode, by default, has its suggestions snap to the grid. When using anything other than monospaced font, this creately very glitchy looking behavior. Popping it out in a posframe makes the suggestions exist in their own graphical window.
(package! company-posframe)
(company-posframe-mode 1)
Fonts
Default
(add-to-list 'default-frame-alist '(font . "Symbols Nerd Font Mono 15"))
(add-to-list 'default-frame-alist '(font . "FiraCode 15"))
(set-face-font 'variable-pitch "Inter Display 15")
(set-fontset-font "fontset-default" 'han "Source Han Sans")
Mixed Pitch Mode
(package! mixed-pitch)
Coloring
There are four ways to start emacs with the combinations of GUI/TUI and standalone/daemon. Unfortunately, each of these four methods requires a slightly different way to set window transparency.
Themes
(package! gruber-darker-theme)
(package! no-clown-fiesta-theme)
(add-to-list 'custom-theme-load-path "~/.config/doom/themes/")
(load-theme 'some-clown-fiesta t)
Transparency
;; GUI transparency
(set-frame-parameter nil 'alpha-background 80)
(add-to-list 'default-frame-alist '(alpha-background . 80))
;; Variable sized org headers
(custom-set-faces!
'(default :background "black"))
(defun ag/terminal-faces (frame)
(set-face-attribute 'hl-line frame :background "unspecified-bg")
(set-face-attribute 'org-block frame :background "unspecified-bg")
(set-face-attribute 'default frame :background "unspecified-bg"))
(defun window-transparency ()
(if (display-graphic-p (selected-frame))
(progn ;; $ emacs
;; Transparency for graphical session
)
(progn ;; $ emacs -nw
;; Transparency for terminal session
(ag/terminal-faces (selected-frame)))))
(unless (daemonp)
(add-hook 'window-setup-hook 'window-transparency))
(defun ag/make-client-frame (frame)
;; Called at the creation of each emacsclient frame
(if (display-graphic-p frame)
(progn ;; $ emacsclient -c
;; Transparency for specific graphical frame
)
(progn ;; $ emacsclient -nw
;; Transparency for specific terminal frame
(ag/terminal-faces frame))))
(add-hook 'after-make-frame-functions 'ag/make-client-frame)
Keybinds in order to increase/decrease the transparency of emacs windows in GUI mode. I try to keep these bindings in sync with the terminal that I use, as to make the experiences of GUI and TUI emacs relatively similar.
(defun ag/adjust-alpha-background (delta)
"Increase or decrease the alpha-background by DELTA, not exceeding 1 or going below 0."
(interactive "p")
;; let* macro instead of let, since new-alpha relies on alpha
(let* ((current-alpha (or (frame-parameter (selected-frame) 'alpha-background) 0))
(new-alpha (+ current-alpha delta)))
(when (and (<= new-alpha 100) (>= new-alpha 0))
(set-frame-parameter (selected-frame) 'alpha-background new-alpha))))
(global-set-key (kbd "M-a") (lambda () (interactive) (ag/adjust-alpha-background 5)))
(global-set-key (kbd "M-s") (lambda () (interactive) (ag/adjust-alpha-background -5)))
Languages
Treesitter Config
Treesit-auto
Automatically downloads the relevant treesitter grammar. Includes languages that are not in the main emacs treesitter repository, such as typst (as of the time of writing)
(package! treesit-auto)
(use-package treesit-auto
:config
(global-treesit-auto-mode))
LSP/Completion Config
Company-mode
(setq ag/company-idle-delay 0.0) ;; Give completion suggestions immediately
(setq company-minimum-prefix-length 1)
(setq company-idle-delay ag/company-idle-delay)
(set-company-backend!
'(text-mode
markdown-mode
gfm-mode)
'(:seperate
company-files
company-yasnippet
company-ispell))
;; "lsp-mode overrides my config and prepends company-capf to company-backends, which results in shadowing
;; the other backends. To avoid this issue we can remove the lsp added entry using lsp-after-open-hook"
;; - https://github.com/doomemacs/doomemacs/issues/4477#issuecomment-762882261
(add-hook! lsp-after-open
(setq-local company-backends '(:seperate
company-files
company-capf
company-yasnippet
company-ispell)))
(setq +lsp-company-backends '())
Make lsp-ui sideline suggestions the same size as buffer text
(use-package lsp-ui :commands lsp-ui-mode
:config (progn
;;
;; 2022-03-28 - fix sideline height computation
;;
(defun lsp-ui-sideline--compute-height nil
"Return a fixed size for text in sideline."
(let ((fontHeight (face-attribute 'lsp-ui-sideline-global :height)))
(if (null text-scale-mode-remapping)
'(height
(if (floatp fontHeight) fontHeight
(/ (face-attribute 'lsp-ui-sideline-global :height) 100.0)
)
;; Readjust height when text-scale-mode is used
(list 'height
(/ 1 (or (plist-get (cdr text-scale-mode-remapping) :height)
1)))))))
;;
;; 2022-03-28 - fix sideline alignment
;;
(defun lsp-ui-sideline--align (&rest lengths)
"Align sideline string by LENGTHS from the right of the window."
(list (* (window-font-width nil 'lsp-ui-sideline-global)
(+ (apply '+ lengths) (if (display-graphic-p) 1 2)))))
))
LSP mode in org src blocks
From: https://tecosaur.github.io/emacs-config/config.html
(cl-defmacro lsp-org-babel-enable (lang)
"Support LANG in org source code block."
(setq centaur-lsp 'lsp-mode)
(cl-check-type lang stringp)
(let* ((edit-pre (intern (format "org-babel-edit-prep:%s" lang)))
(intern-pre (intern (format "lsp--%s" (symbol-name edit-pre)))))
`(progn
(defun ,intern-pre (info)
(let ((file-name (->> info caddr (alist-get :file))))
(unless file-name
(setq file-name (make-temp-file "babel-lsp-")))
(setq buffer-file-name file-name)
(lsp-deferred)))
(put ',intern-pre 'function-documentation
(format "Enable lsp-mode in the buffer of org source block (%s)."
(upcase ,lang)))
(if (fboundp ',edit-pre)
(advice-add ',edit-pre :after ',intern-pre)
(progn
(defun ,edit-pre (info)
(,intern-pre info))
(put ',edit-pre 'function-documentation
(format "Prepare local buffer environment for org source block (%s)."
(upcase ,lang))))))))
(defvar org-babel-lang-list
'("go" "python" "ipython" "bash" "sh"))
(dolist (lang org-babel-lang-list)
(eval `(lsp-org-babel-enable ,lang)))
Org
(add-hook 'org-mode-hook 'mixed-pitch-mode)
(setq org-src-fontify-natively t)
Variable Height Headers
(custom-set-faces!
'(org-document-title :height 1.5)
'(org-document-info :height 1.3)
'(org-level-1 :height 1.5)
'(org-level-2 :height 1.4)
'(org-level-3 :height 1.3)
'(org-level-4 :height 1.2)
'(org-level-5 :height 1.1)
'(org-level-6 :height 1.0)
'(org-level-7 :height 1.0)
'(org-level-8 :height 1.0))
Org Modern
(package! org-modern)
Special symbols/characters
(after! org
(setq
org-superstar-headline-bullets-list '("⁖" "◉" "•" "◦" "•" "◦" "•" "◦" "•" "◦")
org-superstar-itembullet-alist '((?+ . ?➤) (?- . ?✦)))) ; changes +/- symbols in item lists
(defun ag/prettify-me ()
(setq prettify-symbols-alist
'(("TODO" . "")
("WAIT" . "")
("NOPE" . "")
("DONE" . "")
("[ ]" . "")
("[X]" . "")
("[-]" . "")
("#+begin_src" . "")
("#+BEGIN_SRC" . "")
("#+end_src" . "")
("#+END_SRC" . "")
(":properties:" . "")
(":PROPERTIES:" . "")
("#+property:" . "")
("#+PROPERTY:" . "")
(":end:" . "―")
(":END:" . "―")
("#+options:" . "")
("#+OPTIONS:" . "")
("#+startup:" . "")
("#+STARTUP:" . "")
("#+title: " . "")
("#+TITLE: " . "")
("#+TOC:" . "")
("#+toc:" . "")
("#+results:" . "")
("#+RESULTS:" . "")
("#+name:" . "")
("#+NAME:" . "")
("#+roam_tags:" . "")
("#+ROAM_TAGS:" . "")
("#+filetags:" . "")
("#+FILETAGS:" . "")
("#+html_head:" . "")
("#+HTML_HEAD:" . "")
("#+subtitle:" . "")
("#+SUBTITLE:" . "")
("#+author:" . "")
("#+AUTHOR:" . "")
(":effort:" . "")
(":EFFORT:" . "")
("scheduled:" . "")
("SCHEDULED:" . "")
("deadline:" . "")
("DEADLINE:" . ""))))
(add-hook 'org-mode-hook 'ag/prettify-me)
;; Can probably remove duplicates with
;; (mapcan (lambda (x) (list x (cons (upcase (car x)) (cdr x))))
Agenda
(setq org-agenda-files
'("~/.local/share/org-agenda"))
(map! :leader :desc "Open org calendar" "o c" #'cfw:open-org-calendar)
(add-hook 'calendar-after-frame-setup-hook 'cfw:refresh-calendar-buffer)
SVG Tags
(package! svg-tag-mode)
(use-package! svg-tag-mode)
(setq svg-tag-tags
'((":TODO:" . ((lambda (tag) (svg-tag-make "TODO"))))
("[X]" . ((lambda (tag) (svg-tag-make "X"))))))
Markdown
Table of Contents
Automatically generate a table of contents for markdown documents
(package! markdown-toc)
;; (add-hook! markdown-toc-mode-hook
;; (setq markdown-toc-header-toc-start "<!-- TOC -->"
;; markdown-toc-header-toc-end "<!-- \\TOC -->"))
(after! markdown-toc
(setq markdown-toc-header-toc-start "<!-- TOC -->"
markdown-toc-header-toc-end "<!-- \\TOC -->"))
Conceal Markup
(add-hook 'markdown-mode-hook '(lambda () (markdown-toggle-markup-hiding)))
Variable Sized Headers
(custom-set-faces!
'(markdown-header-face-1 :height 1.5)
'(markdown-header-face-2 :height 1.4)
'(markdown-header-face-3 :height 1.3)
'(markdown-header-face-4 :height 1.2)
'(markdown-header-face-5 :height 1.1)
'(markdown-header-face-6 :height 1.0)
'(markdown-header-face-7 :height 1.0)
'(markdown-header-face-8 :height 1.0))
List Bullets
(setq markdown-list-item-bullets '("•" "◦"))
Mixed Pitch
(add-hook 'markdown-mode-hook '(lambda () (mixed-pitch-mode)))
Typst
Download the `typst-ts-mode` package, which isn't yet in Melpa.
(package! typst-mode)
(package! typst-ts-mode :recipe (:type git
:host sourcehut
:repo "meow_king/typst-ts-mode"))
Uncomment and run this block of code if the treesitter grammar is not installed.
;; (setq treesit-language-source-alist
;; '(typst "https://github.com/uben0/tree-sitter-typst"))
;; (treesit-install-language-grammar 'typst)
General configuration
(use-package! typst-ts-mode
:config
(setq typst-ts-mode-fontification-precision-level 'max
typst-ts-markup-header-same-height nil
typst-ts-markup-header-scale '(2.0 2.0 2.0 2.0 2.0 2.0)))
Preview
There is no variable to substitute the default preview command, so I overrode it.
(after! typst-ts-mode
(defun typst-ts-mode-preview (file)
(interactive (list (concat (file-name-base buffer-file-name) ".pdf")))
(shell-command (format "setsid -f zathura %s >/dev/null 2>&1" (shell-quote-argument file)))))
Concealing
Making the editor more WYSIWYG-like
(add-hook! typst-ts-mode
(progn
(setq prettify-symbols-alist
'(("= " . "")
("== " . "")
("=== " . "")
("==== " . "")))
(prettify-symbols-mode)))
Shell
(set-company-backend!
'(sh-mode)
'(:seperate
company-files
company-shell
company-yasnippet
company-ispell))
Nix
(add-hook! lsp-nix-nil-after-open
(progn
;; There's a silly goofy little function called doom--setq-company-idle-delay-for-nix-mode-h that, for some reason,
;; has a hook that sets company-idle-delay to nil, which effectively removes auto completion in nix-mode. This was
;; very confusing to me and took me a bit to figure out why company-mode was buggy in nix-mode.
(setq-local company-idle-delay ag/company-idle-delay)
(setq-local company-backends nil)
(setq-local company-backends '(:separate
company-files
company-nixos-options
company-capf
company-yasnippet
company-ispell))))
Miscellaneous
Anki
(package! anki-connect)
(package! anki-editor)
Face Explorer
(package! face-explorer)