.emacs.d/config.org
2024-10-14 17:28:00 -04:00

16 KiB

Emacs Configuration

;; -- lexical-binding: t; --

Helpers

Server

  (require 'bind-key)
  (load "server")
  (unless (server-running-p) (server-start))

Disable Built-In Auto-Save and Backup

  (setq auto-save-default nil
        make-backup-files nil)

No Scratch On Open

  (setq initial-scratch-message nil)
  (setq initial-buffer-choice nil)

  (add-hook 'emacs-startup-hook
      (lambda ()
        (when (and (get-buffer "*scratch*")
       (not (eq (current-buffer) (get-buffer "*scratch*"))))
    (kill-buffer "*scratch*"))))

Dirvish

  (add-hook 'dired-mode-hook 'dired-omit-mode)

  (use-package ethan-wspace
    :ensure t
    :config
    (setq mode-require-final-newline nil)
    (global-ethan-wspace-mode 1))

  (defun my/dirvish-create-file ()
    "Create a new file in the current directory."
    (interactive)
    (let ((new-file (read-file-name "New file name: " (dired-current-directory))))
      (if (file-exists-p new-file)
          (message "File already exists!")
        (write-region "" nil new-file)
        (revert-buffer)  ;; Refresh the directory listing
        (message "File created: %s" new-file))))

  (use-package nerd-icons
    :ensure t)

  (use-package dirvish
    :ensure t
    :init
    (dirvish-override-dired-mode)
    :config
    (dirvish-peek-mode)
    (dirvish-side-follow-mode)
    (setq dired-listing-switches "-al --human-readable --group-directories-first"
          dired-mouse-drag-files t
          dired-omit-files (rx (or (seq bol (? ".") "#")
                                   (seq bol "." eol)
                                   (seq bol ".git" eol)))
          dirvish-attributes '(vc-state subtree-state nerd-icons collapse git-msg file-time file-size)
          dirvish-mode-line-format '(:left (sort symlink) :right (omit yank index))
          dirvish-mode-line-height 25
          dirvish-subtree-state-style 'nerd
          mouse-drag-and-drop-region-cross-program t))

  ;; Addtional syntax highlighting for dired
  (use-package diredfl
    :ensure t
    :hook
    ((dired-mode . diredfl-mode)
     (dirvish-directory-view-mode . diredfl-mode))
    :config
    (set-face-attribute 'diredfl-dir-name nil :bold t))

  (use-package ns-auto-titlebar
    :ensure t
    :config
    (when (eq system-type 'darwin) (ns-auto-titlebar-mode)))

Doom Modeline

  (use-package doom-modeline
    :ensure t
    :config
    (doom-modeline-mode))

VTerm

  (use-package vterm
    :ensure t
    :config
    (setq vterm-timer-delay 0.01))

  (use-package shackle
    :ensure t
    :config
    (setq shackle-rules
          '(("\\*vterm\\*" :regexp t :popup t :align 'below :size 0.4 :select t)))
    (shackle-mode 1))

  (use-package vterm-toggle
    :ensure t)

Nix

  (use-package nix-mode
    :mode "\\.nix\\'")

Indents and Autopairs

  (electric-indent-mode -1)
  (electric-pair-mode 1)

Evil Mode

  (defun indent-tabs-hook ()
    (setq tab-width 2
          indent-tabs-mode nil
          evil-auto-indent t))

  (dolist (hook '(c++-mode-hook c-mode-hook c++-ts-mode-hook c-ts-mode-hook)) (add-hook hook 'indent-tabs-hook))

  (use-package evil
    :ensure t
    :init
    (setq indent-line-function      'evil-indent-line
          evil-shift-width          2
          evil-split-window-below   t
          evil-undo-system          'undo-tree
          evil-vsplit-window-right  t
          evil-want-C-i-jump        nil
          evil-want-C-u-scroll      t
          evil-want-integration     t
          evil-want-keybinding      nil)

    :config
    (evil-mode 1)
    (evil-define-key 'insert prog-mode-map (kbd "TAB") 'tab-to-tab-stop)
    (evil-define-key 'insert 'global
      (kbd "C-c") 'cua-copy-region
      (kbd "C-v") 'cua-paste
      (kbd "C-x") 'cua-cut-region)
    (evil-define-key 'normal 'global
      (kbd "gm")  'magit-status
      (kbd "gp")  'diff-hl-show-hunk
      (kbd "gr")  'diff-hl-revert-hunk
      (kbd "gs")  'diff-hl-stage-current-hunk))

  (use-package evil-surround
    :ensure t
    :config
    (global-evil-surround-mode 1))

  (setq-default whitespace-action
                '(cleanup auto-cleanup))

  (defun my/vterm-toggle-project-root ()
    "Open or toggle vterm at the project root."
    (interactive)
    (let ((default-directory (or (project-root (project-current))
                                default-directory)))
      (vterm-toggle)))

  (use-package general
    :ensure t
    :config
    (general-define-key
      :states '(normal visual emacs)
      :keymaps 'override
      "K" '(eldoc-box-help-at-point :wk "Hover")
      "C-t" '(my/vterm-toggle-project-root :wk "Toggle VTerm")))

  (use-package evil-collection
    :ensure t
    :config
    (evil-collection-init))

  (use-package evil-leader
    :ensure t
    :config
    (global-evil-leader-mode)
    (setq evil-leader/leader "<SPC>")
    (evil-leader/set-key "bb" #'switch-to-buffer)
    (evil-leader/set-key "bj" #'breadcrumb-jump)
    (evil-leader/set-key "e"  #'dirvish-side)
    (evil-leader/set-key "d"  #'flymake-show-diagnostic)
    (evil-leader/set-key "n"  #'flymake-goto-next-error)
    (evil-leader/set-key "N"  #'flymake-goto-prev-error)
    (evil-leader/set-key "n"  #'flymake-goto-next-error)
    (evil-leader/set-key "a"  #'eglot-code-actions))

Catppuccin Theme

  (use-package catppuccin-theme
    :ensure t
    :config
    (load-theme 'catppuccin t))

Disable Autosave and Backup Files

  (setq auto-save-default nil
        make-backup-files nil)

Ligatures

  (use-package ligature
    :config
    (let ((common-ligatures '("<---" "<--"  "<<-" "<-" "->" "-->" "--->" "<->" "<-->" "<--->" "<---->" "<!--"
                              "<==" "<===" "<=" "=>" "=>>" "==>" "===>" ">=" "<=>" "<==>" "<===>" "<====>" "<!---"
                              "<~~" "<~" "~>" "~~>" "::" ":::" "==" "!=" "===" "!=="
                              ":=" ":-" ":+" "<*" "<*>" "*>" "<|" "<|>" "|>" "+:" "-:" "=:" "<******>" "++" "+++")))
      (dolist (mode '(prog-mode org-mode))
        (ligature-set-ligatures mode common-ligatures)))
    (global-ligature-mode t))

LSP

Eglot

  (use-package markdown-mode
    :ensure t
    :mode ("README\\.md\\'" . gfm-mode)
    :init (setq markdown-command "multimarkdown")
    :bind (:map markdown-mode-map
          ("C-c C-e" . markdown-do)))

  (use-package eglot-booster
    :after eglot
    :ensure (eglot-booster :type git :host github :repo "jdtsmith/eglot-booster")
    :config (eglot-booster-mode))

  (use-package eglot
    :ensure nil
    :config
    (defun my-eglot-rename (newname)
      "Rename the current symbol to NEWNAME with initial input a."
      (interactive
       (list (read-from-minibuffer
              (format "Rename `%s' to: " (or (thing-at-point 'symbol t)
                                             (error "no symbol at point")))
              (or (thing-at-point 'symbol t) "") nil nil nil
              (symbol-name (symbol-at-point)))))
      (eglot--server-capable-or-lose :renameProvider)
      (eglot--apply-workspace-edit
       (jsonrpc-request (eglot--current-server-or-lose)
                        :textDocument/rename `(,@(eglot--TextDocumentPositionParams)
                                               :newName ,newname))
       current-prefix-arg))
    (fset #'jsonrpc--log-event #'ignore)
    (setopt eglot-events-buffer-size 0)
    (defun eglot-format-buffer-on-save ()
      (when (not (derived-mode-p 'python-ts-mode))
        (add-hook 'before-save-hook #'eglot-format-buffer -10 t)))
    (add-hook 'eglot-managed-mode-hook #'eglot-format-buffer-on-save)
    (setq eglot-server-programs
      `(,@eglot-server-programs
         '(nix-mode . ("nixd"))
         '(c++-mode . ("clangd" "--clang-tidy" "--completion-style=detailed" "--header-insertion=never"))))
    :hook
    (rust-mode . eglot-ensure)
    (rust-ts-mode . eglot-ensure)
    (sh-script-mode . eglot-ensure)
    (python-mode . eglot-ensure)
    (python-ts-mode . eglot-ensure)
    (json-mode . eglot-ensure)
    (json-ts-mode . eglot-ensure)
    (nix-mode . eglot-ensure)
    (yaml-mode . eglot-ensure)
    (yaml-ts-mode . eglot-ensure)
    (c-mode . eglot-ensure)
    (c-ts-mode . eglot-ensure)
    (c++-mode . eglot-ensure)
    (c++-ts-mode . eglot-ensure)
    (c3-ts-mode . eglot-ensure)
    (rust-mode . eglot-ensure)
    (go-mode . eglot-ensure)
    (go-ts-mode . eglot-ensure))

  (add-hook 'c-mode-hook 'hide-ifdef-mode)
  (add-hook 'c++-mode-hook 'hide-ifdef-mode)
  (setq hide-ifdef-initially t)
  (setq hide-ifdef-shadow 'font-lock-comment-face)

  (use-package rust-mode
    :ensure t)

  (use-package tuareg
    :ensure t
    :mode ("\\.ml\\'" . tuareg-mode)
    :hook (tuareg-mode . eglot-ensure))

  (use-package merlin
    :ensure t
    :hook (tuareg-mode . merlin-mode))

  (use-package glsl-mode
    :ensure t
    :mode ("\\.vert\\'" "\\.frag\\'" "\\.geom\\'"))

  (use-package eldoc-box
    :custom
    (eldoc-box-max-pixel-width 1024)
    :custom-face
    (eldoc-box-body ((t (:family "Iosevka Comfy Motion" :height 140 :background "#181825" :foreground "#cdd6f4"))))
    :config
    (setq eldoc-message-function #'ignore
          eldoc-idle-delay 0))

Apheleia

  (use-package apheleia
    :ensure t
    :config
    (setq apheleia-formatters
      `(,@apheleia-formatters '(alejandra "alejandra" "--quiet" "-") '(clang-format "clang-format")))
    (setq apheleia-mode-alist
      `(,@apheleia-mode-alist '(nix-mode . alejandra) '(c-mode . clang-format) '(c++-mode . clang-format)))
    (apheleia-global-mode +1))

TreeSitter

  (use-package tree-sitter
    :ensure t
    :hook
    (prog-mode . tree-sitter-hl-mode)
    :config
    (global-tree-sitter-mode))

  (use-package tree-sitter-langs
    :ensure t)

GitHub Copilot

  (use-package copilot
    :ensure (:host github :repo "copilot-emacs/copilot.el" :files ("*.el"))
    :hook (prog-mode . copilot-mode)
    :bind (("C-<tab>" . 'copilot-complete)
         :map copilot-completion-map
         ("<tab>" . 'copilot-accept-completion)
         ("C-<tab>" . 'copilot-accept-completion-by-word)
         ("C-<return>" . 'copilot-accept-completion-by-line)))

  (use-package copilot-chat
    :ensure (:host github :repo "chep/copilot-chat.el" :files ("*.el"))
    :after (request))

Corfu

  (use-package corfu
    :ensure t
    :custom
    (corfu-cycle t)
    (corfu-auto t)
    (corfu-auto-prefix 1)
    (corfu-auto-delay 0.0)
    :bind (:map corfu-map ("<escape>" . corfu-quit))
    :init (global-corfu-mode))

  (use-package cape :ensure t)

  ;; get eglot to play nice with corfu
  (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)

  (use-package kind-icon
    :ensure t
    :after corfu
    :custom
    (kind-icon-use-icons t)
    (kind-icon-default-face 'corfu-default)
    (kind-icon-blend-background nil)
    (kind-icon-blend-frac 0.08)
    :config
    (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter))

Rainbow Delimiters

  (use-package rainbow-delimiters
    :ensure t
    :config
    (add-hook 'prog-mode-hook 'rainbow-delimiters-mode))

Line Numbers

  (global-display-line-numbers-mode t)

  (setq display-line-numbers-type 'relative)

  (dolist (mode
           '(term-mode-hook
             vterm-mode-hook
             shell-mode-hook
             org-mode-hook
             dirvish-setup-hook
             eshell-mode-hook))
    (add-hook mode (lambda () (display-line-numbers-mode 0))))

Vim-Style Scrolling

  (setq scroll-step 3
        scroll-conservatively 9999)

Sticky Headers

  (use-package breadcrumb
    :ensure t
    :hook
    (prog-mode . breadcrumb-mode))

System-Specific Settings

  (defun apply-my-fonts (frame)
    (with-selected-frame frame
      (cond
      ((eq system-type 'darwin)
        (set-face-attribute 'default frame :font "Iosevka Comfy Motion-16")
        (set-face-attribute 'fixed-pitch frame :font "Iosevka Comfy Motion-16")
        (set-face-attribute 'variable-pitch frame :font "Iosevka Comfy Motion Duo-16")
        (modify-frame-parameters frame
                                '((font . "Iosevka Comfy Motion-16")
                                  (vertical-scroll-bars . nil))))
      ((eq system-type 'gnu/linux)
        (set-face-attribute 'default frame :font "Iosevka Comfy Motion Medium-12")
        (set-face-attribute 'fixed-pitch frame :font "Iosevka Comfy Motion Medium-12")
        (set-face-attribute 'variable-pitch frame :font "Iosevka Comfy Motion Duo Md-14")
        (modify-frame-parameters frame
                                '((font . "Iosevka Comfy Motion Medium-12")
                                  (undecorated . t)
                                  (vertical-scroll-bars . nil)))))))

  ;; Apply the settings for both regular Emacs and emacsclient frames
  (if (daemonp)
      (add-hook 'after-make-frame-functions 'apply-my-fonts)
    (apply-my-fonts (selected-frame)))

Use Short Answers

  (setq use-short-answers t)

Undo Tree

  (use-package undo-tree
    :ensure t
    :config
    (global-undo-tree-mode)
    (setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))))

Dashboard

  (use-package dashboard
    :ensure t
    :config
    (dashboard-setup-startup-hook)
    (setq dashboard-startup-banner 'logo
          dashboard-center-content t
          dashboard-vertically-center-content t
          dashboard-startup-banner 'logo
          initial-buffer-choice (lambda () (get-buffer-create "*dashboard*"))))

Git Integration

  (use-package transient :ensure t)

  (use-package magit
    :ensure t
    :commands
    magit-status
    magit-blame
    magit-version
    :init
    (defadvice magit-status (around magit-fullscreen activate)
      (window-configuration-to-register :magit-fullscreen) ad-do-it
      (delete-other-windows))
    :config
    (setq magit-branch-arguments nil
          magit-default-tracking-name-function 'magit-default-tracking-name-branch-only
          magit-push-always-verify nil
          magit-restore-window-configuration t))

  (use-package diff-hl
    :ensure t
    :hook ((magit-post-refresh . diff-hl-magit-post-refresh))
    :config
    (global-diff-hl-mode))

  (use-package git-gutter
    :ensure t
    :config
    (global-git-gutter-mode +1))

Direnv

  (use-package envrc
    :ensure t
    :config
    (envrc-global-mode))

Better M-x

Ivy Mode (Completions)

  (setq ivy-ignore-buffers '("\\` " "\\`\\*"))

  (use-package ivy
    :ensure t
    :config
    (ivy-mode)
    (setq ivy-use-virtual-buffers t
          enable-recursive-minibuffers t))

Amx Mode (Better Interface)

  (use-package amx
    :ensure t
    :config
    (amx-mode))

Org Mode Improvements

  (setq-default org-src-tab-acts-natively t
                org-indent-indentation-per-level 2
                org-indent-mode-turns-on-hiding-stars nil)

  (add-hook 'org-mode-hook 'visual-line-mode)

  (require 'org-tempo)
  (add-to-list 'org-modules 'org-tempo t)

  (use-package mixed-pitch
    :hook
    (org-mode . mixed-pitch-mode))

  (use-package org-modern
    :ensure t
    :hook (org-mode . org-modern-mode)
    :config
    (setq org-ellipsis "…")
    (setq org-modern-star 'replace))

  ;; Inhibits autopairs from running for <> in org mode
  (add-hook 'org-mode-hook
      (lambda ()
        (setq-local electric-pair-inhibit-predicate
        `(lambda (c) (if (char-equal c ?<) t (,electric-pair-inhibit-predicate c))))))

  (defun org-babel-edit-prep:emacs-lisp (babel-info)
    (setq-local buffer-file-name (->> babel-info caddr (alist-get :tangle)))
    (lsp))

  (add-hook 'eglot-managed-mode-hook #'flymake-mode)