nixrice/misc/.config/doom/config.org
2024-12-11 15:06:50 -05:00

26 KiB

Agryphus' Emacs Config

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)

Style

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.

Fonts

Default

  (defun ag/load-fonts ()
    (set-face-font 'variable-pitch "Liberation Serif 15") ;; Serif
    (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") ;; Sans serif
    (set-fontset-font "fontset-default" 'han "Source Han Sans"))
  (ag/load-fonts)

Mixed Pitch Mode

  (package! mixed-pitch)

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
             (set-face-font 'variable-pitch "Liberation Serif 15") ;; Serif
             ;; (ag/load-fonts)
             ;; 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)))

  (defun ag/prettify-me ()
    (setq prettify-symbols-alist
      '(("[ ]"          . "")
        ("```"          . "")
        ("```\n"        . "")
        ("[x]"          . "󰄵"))))
  (add-hook 'markdown-mode-hook '(lambda () (progn (ag/prettify-me)
                                              (global-prettify-symbols-mode))))

  (setq markdown-max-image-size '(700 . 700))

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)))
  (add-hook 'typst-ts-mode-hook '(lambda () (mixed-pitch-mode)))
  (add-hook 'typst-ts-mode-hook '(lambda () (electric-indent-mode -1)))

Install Tree-Sitter Grammar

Uncomment and run the below code once to install the tree sitter grammar for typst-ts-mode

;; (add-to-list 'treesit-language-source-alist
;;              '(typst "https://github.com/uben0/tree-sitter-typst"))
;; (treesit-install-language-grammar 'typst)

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)