/.emacs.d

Primary LanguageEmacs Lisp

Brendon’s Emacs Config

Early init

(setq package-enable-at-startup nil)
(when (fboundp 'startup-redirect-eln-cache)
  (startup-redirect-eln-cache
   (convert-standard-filename
    (expand-file-name  "var/eln-cache/" user-emacs-directory))))

Init.el Header

;;; -*- lexical-binding: t -*-
;; NOTE: init.el is now generated from Emacs.org.  Please edit that file
;;       in Emacs and init.el will be generated automatically!

Startup

Garbage Collection

(setq gc-cons-threshold 200000000)

Disable Annoying Warnings

(setq native-comp-async-report-warnings-errors nil)
(setq warning-minimum-level :error)

Display Startup Time

(defun me/display-startup-time ()
  (message "Emacs loaded in %s with %d garbage collections."
           (format "%.2f seconds"
                   (float-time
                    (time-subtract after-init-time before-init-time)))
           gcs-done))

(add-hook 'emacs-startup-hook #'me/display-startup-time)

Disable GUI Features

(when (fboundp 'horizontal-scroll-bar-mode)
  (horizontal-scroll-bar-mode -1))
(when (fboundp 'scroll-bar-mode)
  (scroll-bar-mode -1))
(when (fboundp 'tool-bar-mode)
  (tool-bar-mode -1))
(when (fboundp 'tooltip-mode)
  (tooltip-mode -1))
(when (fboundp 'menu-bar-mode)
  (menu-bar-mode -1))
(when (fboundp 'set-fringe-mode)
  (set-fringe-mode 10))

Maximize On Launch

(set-frame-parameter (selected-frame) 'fullscreen 'maximized)
(add-to-list 'default-frame-alist '(fullscreen . maximized))

Platforms

(defconst IS-MAC     (eq system-type 'darwin)
  "If the host is running MacOS return true")
(defconst IS-LINUX   (eq system-type 'gnu/linux)
  "If the host is running Linux return true")
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos))
  "If the host is running Windows return true")
(defconst IS-BSD     (or IS-MAC (eq system-type 'berkeley-unix))
  "If the host is running BSD return true")

Server

Package Management

straight and use-package

(setq straight-use-package-by-default t)
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)

Automatic Package Updates

The auto-package-update package helps us keep our Emacs packages up to date! It will prompt you after a certain number of days either at startup or at a specific time of day to remind you to update your packages.

You can also use M-x auto-package-update-now to update right now!

(use-package auto-package-update
  :custom
  (auto-package-update-interval 7)
  (auto-package-update-prompt-before-update nil)
  (auto-package-update-hide-results t)
  :config
  (auto-package-update-maybe)
  (auto-package-update-at-time "09:00"))

No Littering

(use-package no-littering
  :demand t
  :config
  (setq auto-save-file-name-transforms
        `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
  (setq custom-file (no-littering-expand-etc-file-name "custom.el")))

Keybinding with General

(use-package general
  :demand t
  :config
  (progn
    (general-evil-setup t)
    (general-auto-unbind-keys)

    (general-create-definer leader-map
      :keymaps 'override
      :states '(insert emacs normal hybrid motion visual operator)
      :global-prefix "C-c"
      :non-normal-prefix "M-SPC"
      :prefix "SPC")

    (general-create-definer local-leader-map
      :keymaps 'override
      :states '(insert emacs normal hybrid motion visual operator)
      :global-prefix "C-c m"
      :non-normal-prefix "M-SPC m"
      :prefix "SPC m")))

Emacs Defaults

(use-package emacs
  :demand t
  :straight nil
  :preface
  ;; Fonts and Text ;;
  (defvar me/default-font-size 160)
  (defvar me/default-variable-font-size 160)
  (defun me/reset-text-size ()
    (interactive)
    (text-scale-set 0))

  ;; Transparency ;;
  (defvar me/frame-transparency '(95 . 95))

  ;; Buffers ;;
  (defun me/alternate-buffer ()
    "Go to previous buffer"
    (interactive)
    (switch-to-buffer (other-buffer)))

  (defun me/set-default-line-length-to (line-length)
    "Set the default line length to LINE-LENGTH."
    (setq-default fill-column line-length))

  ;; Saving ;;
  (defun me/save-all-unsaved ()
    "Save all unsaved files. no ask."
    (interactive)
    (save-some-buffers t))

  ;; Utility ;;
  (defun me/create-dir-if-not-exists ()
    "Offer to create directory when it doesn't exist"
    (when buffer-file-name
      (let ((dir (file-name-directory buffer-file-name)))
        (when (and (not (file-exists-p dir))
                   (y-or-n-p (format "Directory %s does not exist. Create it?" dir)))
          (make-directory dir t)))))

  (defun me/open-config ()
    "Open configuration file"
    (interactive)
    (find-file (expand-file-name (concat user-emacs-directory "README.org"))))

  (defun me/reload-emacs-config ()
    (interactive)
    (load-file (expand-file-name (concat user-emacs-directory "init.el"))))

  ;; Scrolling
  (defun me/scroll-half-page (direction)
    "Scrolls half page up if `direction' is non-nil, otherwise will scroll half page down."
    (let ((opos (cdr (nth 6 (posn-at-point)))))
      ;; opos = original position line relative to window
      (move-to-window-line nil)  ;; Move cursor to middle line
      (if direction
          (recenter-top-bottom -1)  ;; Current line becomes last
        (recenter-top-bottom 0))  ;; Current line becomes first
      (move-to-window-line opos)))  ;; Restore cursor/point position

  (defun me/scroll-half-page-down ()
    "Scrolls exactly half page down keeping cursor/point position."
    (interactive)
    (me/scroll-half-page nil))

  (defun me/scroll-half-page-up ()
    "Scrolls exactly half page up keeping cursor/point position."
    (interactive)
    (me/scroll-half-page t))

  (defun me/buffer-to-side-window ()
    "Place the current buffer in the side window at the bottom."
    (interactive)
    (let ((buf (current-buffer)))
      (display-buffer-in-side-window
       buf '((window-height . 0.25)
             (side . bottom)
             (slot . -1)
             (window-parameters . (no-delete-other-windows . t))))
      (delete-window)))

  (defun me/quit-window-force ()
    (interactive)
    (quit-window t))
  :config
  (progn
    ;; Startup ;;
    (setq inhibit-startup-message t)
    (setq initial-scratch-message nil)

    ;; Bells and Ringers ;;
    (setq visible-bell nil)
    (setq ring-bell-function 'ignore)

    ;; History and persistence ;;
    (require 'recentf)
    (add-to-list 'recentf-exclude no-littering-var-directory)
    (add-to-list 'recentf-exclude no-littering-etc-directory)
    (setq recentf-max-menu-items 40)
    (setq recentf-max-saved-items 250)
    (setq save-interprogram-paste-before-kill t)
    (setq initial-buffer-choice nil)
    ;; (require 'desktop)
    ;; (customize-set-variable 'desktop-save 't)
    ;; (desktop-save-mode 1)
    (recentf-mode 1)
    (with-eval-after-load 'no-littering
      (add-to-list 'recentf-exclude no-littering-etc-directory)
      (add-to-list 'recentf-exclude no-littering-var-directory))
    (save-place-mode 1)
    (winner-mode 1)
    (global-auto-revert-mode t)

    ;; Completion ;;
    (setq read-file-name-completion-ignore-case t
          read-buffer-completion-ignore-case t
          completion-ignore-case t
          completion-cycle-threshold 2
          tab-always-indent t
          tab-width 4)
    (setq-default indent-tabs-mode nil)

    (electric-pair-mode t)
    ;; Use `consult-completion-in-region' if Vertico is enabled.
    ;; Otherwise use the default `completion--in-region' function.
    ;; (setq completion-in-region-function
    ;;       (lambda (&rest args)
    ;;         (apply (if vertico-mode
    ;;                    #'consult-completion-in-region
    ;;                  #'completion--in-region)
    ;;                args)))

    ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
    ;; Vertico commands are hidden in normal buffers.
    (setq read-extended-command-predicate
          #'command-completion-default-include-p)

    ;; Minibuffer ;;
    ;; Do not allow the cursor in the minibuffer prompt
    (setq minibuffer-prompt-properties
          '(read-only t cursor-intangible t face minibuffer-prompt))
    (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

    (general-def minibuffer-local-map
      "C-S-p" 'yank)

    ;; Enable recursive minibuffers
    (setq enable-recursive-minibuffers t)

    ;; File Encoding ;;
    (prefer-coding-system 'utf-8)
    (set-default-coding-systems 'utf-8)
    (set-terminal-coding-system 'utf-8)
    (set-keyboard-coding-system 'utf-8)
    (set-selection-coding-system 'utf-8)
    (set-file-name-coding-system 'utf-8)
    (set-clipboard-coding-system 'utf-8)
    (set-buffer-file-coding-system 'utf-8)

    ;; Fonts ;;
    (cond (IS-MAC (setq me/default-font-size 200) (setq me/default-variable-font-size 200))
          (IS-WINDOWS (setq me/default-font-size 90) (setq me/default-variable-font-size 90)))
    (set-face-attribute 'default nil :font "MonoLisa Custom" :height me/default-font-size)
    (set-face-attribute 'fixed-pitch nil :font "MonoLisa Custom" :height me/default-font-size)
    (set-face-attribute 'variable-pitch nil :font "Cantarell" :height me/default-variable-font-size :weight 'regular)
    (global-font-lock-mode t)

    ;; Transparency ;;
    (set-frame-parameter (selected-frame) 'alpha me/frame-transparency)
    (add-to-list 'default-frame-alist `(alpha . ,me/frame-transparency))

    ;; Loading ;;
    (setq load-prefer-newer t)

    ;; Saving ;;
    ;; Auto save
    (setq after-focus-change-function 'me/save-all-unsaved)
    (add-hook 'focus-out-hook 'me/save-all-unsaved)

    ;; Remove whitespace on save
    (add-hook 'before-save-hook 'delete-trailing-whitespace)

    ;; Make file executable if it's a script on save
    (add-hook 'after-save-hook
              'executable-make-buffer-file-executable-if-script-p)

    ;; Create directory if it doesn't exist
    (add-hook 'before-save-hook 'me/create-dir-if-not-exists)

    ;; Version Control ;;
    (setq vc-follow-symlinks t)

    ;; Directories ;;
    (setq default-directory "~/")

    ;; Prog Mode ;;
    (add-hook 'prog-mode-hook 'subword-mode)

    ;; Formatting ;;
    (setq sentence-end-double-space nil)
    ;; (me/set-default-line-length-to 80)

    ;; Behavior ;;
    (setq require-final-newline t)
    (setq show-paren-delay 0.0)
    (global-set-key [remap quit-window] #'me/quit-window-force)

    ;; Confirmations
    (setq confirm-kill-emacs 'y-or-n-p)
    (fset 'yes-or-no-p 'y-or-n-p)

    ;; Modes
    (transient-mark-mode 1)
    (delete-selection-mode 1)
    (show-paren-mode 1)
    (column-number-mode 0)

    ;; Line Numbers

    ;; Disable line numbers for some modes
    (dolist (mode '(org-mode-hook
                    term-mode-hook
                    shell-mode-hook
                    treemacs-mode-hook
                    eshell-mode-hook
                    vterm-mode-hook
                    dired-mode-hook))
      (add-hook mode (lambda () (display-line-numbers-mode 0))))
    (global-display-line-numbers-mode 1)

    ;; Frames
    (setq ns-pop-up-frames nil)

    ;; Windows
    ;; Attempt to always use the same window size and stop resizing stuff weirdly
    (customize-set-variable 'display-buffer-base-action
                            '((display-buffer-reuse-window display-buffer-same-window)
                              (reusable-frames . t)))
    (customize-set-variable 'even-window-sizes nil)
    (setq resize-mini-windows t)

    ;; Mouse
    (setq mouse-yank-at-point t)

    ;; Apropos
    (setq apropos-do-all t)

    ;; Tab bar ;;
    ;; (tab-bar-mode t)
    ;; (customize-set-variable 'tab-bar-new-tab-choice '"*scratch*")
    ;; (customize-set-variable 'tab-bar-show 't)

    ;; Mac OS ;;
    (when IS-MAC
      (setq mac-command-modifier 'control
            mac-option-modifier 'meta
            mac-control-modifier 'super
            mac-right-command-modifier 'control
            mac-right-option-modifier 'meta
            ns-function-modifier 'hyper))

    ;; Keybindings ;;

    ;; Prefixes
    (leader-map
      ""   '(nil :which-key "my lieutenant general prefix")
      "b"  '(:ignore t :wk "buffers")
      "D"  '(:ignore t :wk "debug")
      "e"  '(:ignore t :wk "edit")
      "o"  '(:ignore t :wk "org")
      "f"  '(:ignore t :wk "files")
      "fe" '(:ignore t :wk "emacs")
      "g"  '(:ignore t :wk "git")
      "s"  '(:ignore t :wk "search")
      "x"  '(:ignore t :wk "execute")
      "T"  '(:ignore t :wk "toggles"))

    (local-leader-map
      ""	'(nil :which-key "major mode"))

    ;; Sim Keys
    (leader-map
      "," (general-simulate-key "C-c")
      "C" (general-simulate-key "C-x")
      "M" (general-simulate-key "C-c C-x"))

    ;; Maps
    (leader-map
      "h" '(:keymap help-map :wk "help"))

    ;; Base
    (leader-map
      ";"   'execute-extended-command
      ":"   'eval-expression
      "O"   'other-window-prefix
      "X"   '((lambda () (interactive) (switch-to-buffer "*scratch*")) :wk "scratch")
      "br"  'rename-buffer
      "bd"  'bury-buffer
      "bp"  'me/alternate-buffer
      "bk"  'kill-this-buffer
      "bK"  'kill-some-buffers
      "B"   'ibuffer
      "ea"  'align-regexp
      "eA"  'align
      "er"  'query-replace
      "fB"  'bookmark-set
      "ff"  'find-file
      "fs"  'save-buffer
      "fd"  'dired
      "fS"  'me/save-all-unsaved
      "fee" 'me/open-config
      "fer" 'me/reload-emacs-config
      "feq" 'save-buffers-kill-emacs
      "feQ" 'kill-emacs
      "xp"  'check-parens
      "xe"  'eval-last-sexp
      "xb"  'eval-buffer)

    (leader-map "C-h" '(which-key-C-h-dispatch :wk t))
    (local-leader-map "C-h" '(which-key-C-h-dispatch :wk t))

    (general-def
      "C-v" 'me/scroll-half-page-down
      "M-v" 'me/scroll-half-page-up)

    ;; Remaps
    (general-def with-editor-mode-map
      [remap save-buffer] 'with-editor-finish)


    ))

Builtins

Ediff

(use-package ediff
  :straight nil
  :config
  (progn
    (setq ediff-diff-options "")
    (setq ediff-custom-diff-options "-u")
    (setq ediff-window-setup-function 'ediff-setup-windows-plain)
    (setq ediff-split-window-function 'split-window-vertically)))

Smerge

(use-package smerge-mode
  :straight nil
  :init (setq smerge-command-prefix "")
  :config
  (progn
    (with-eval-after-load 'hydra
      (defhydra hydra/smerge
        (:color pink :hint nil :post (smerge-auto-leave))
        "
^Move^       ^Keep^               ^Diff^                 ^Other^
^^-----------^^-------------------^^---------------------^^-------
_n_ext       _b_ase               _<_: upper/base        _C_ombine
_p_rev       _u_pper              _=_: upper/lower       _r_esolve
^^           _l_ower              _>_: base/lower        _k_ill current
^^           _a_ll                _R_efine
^^           _RET_: current       _E_diff
"
        ("n" smerge-next)
        ("p" smerge-prev)
        ("b" smerge-keep-base)
        ("u" smerge-keep-upper)
        ("l" smerge-keep-lower)
        ("a" smerge-keep-all)
        ("RET" smerge-keep-current)
        ("\C-m" smerge-keep-current)
        ("<" smerge-diff-base-upper)
        ("=" smerge-diff-upper-lower)
        (">" smerge-diff-base-lower)
        ("R" smerge-refine)
        ("E" smerge-ediff)
        ("C" smerge-combine-with-next)
        ("r" smerge-resolve)
        ("k" smerge-kill-current)
        ("q" nil "cancel" :color blue))
      (with-eval-after-load 'general
        (leader-map smerge-mode-map
           "gm" 'hydra/smerge/body)))))

Dired

(use-package dired
  :straight nil
  :commands (dired dired-jump)
  :preface
  :general
  (general-def
    "C-x C-j" 'dired-jump)
  :custom ((dired-listing-switches "-agho --group-directories-first"))
  :hook (dired-mode . dired-hide-details-mode)
  :config
  (general-def '(motion visual normal emacs) dired-mode-map
    "l" 'dired-open-file
    "L" 'dired-view-file
    "h" 'dired-up-directory)

  (setq dired-dwim-target t)
  (setq dired-kill-when-opening-new-dired-buffer t)
  ;; MacOS ;;
  (when IS-MAC
    (setq dired-use-ls-dired t
          insert-directory-program "/opt/homebrew/bin/gls"
          dired-listing-switches "-aBhl --group-directories-first")))

(use-package dired-single
  :commands (dired dired-jump))

(use-package all-the-icons-dired
  :after all-the-icons
  :hook (dired-mode . all-the-icons-dired-mode))

(use-package dired-open
  :commands (dired dired-jump)
  :config
  (setq dired-open-extensions '(("png" . "feh")
                                ("mkv" . "mpv"))))

(use-package dired-hide-dotfiles
  ;;:hook (dired-mode . dired-hide-dotfiles-mode)
  :config
  (with-eval-after-load 'evil-collection
    (evil-collection-define-key 'normal 'dired-mode-map
      "C-S-h" 'dired-hide-dotfiles-mode)))

Packages

doom-themes

(use-package doom-themes
  :init
  (load-theme 'doom-tokyo-night t)
  :config
  (progn
    (setq doom-themes-enable-bold t
          doom-themes-enable-italic t)
    (setq doom-themes-treemacs-theme "doom-tokyo-night")
    (with-eval-after-load 'treemacs
      (doom-themes-treemacs-config))
    (with-eval-after-load 'org
      (doom-themes-org-config))))

solaire-mode

(use-package solaire-mode
  :config
  (solaire-global-mode))

exec-path-from-shell

(use-package exec-path-from-shell
  :if IS-MAC
  :config
  (exec-path-from-shell-initialize))

dash

Modern Elisp List API

(use-package dash
  :commands (global-dash-fontify-mode)
  :init (global-dash-fontify-mode)
  :config (dash-register-info-lookup))

s.el

The long lost Emacs string manipulation library.

(use-package s)

posframe

(use-package posframe
  :demand t)

which-key

(use-package which-key
  :init (which-key-mode)
  :diminish which-key-mode
  :after evil
  :demand t
  :config
  (progn
    (setq which-key-allow-evil-operators t)
    (setq which-key-sort-order 'which-key-key-order-alpha)
    (setq which-key-use-C-h-commands nil)
    (setq which-key-idle-delay 0.5)))

evil

(use-package evil
  :demand t
  :preface
  (defun me/evil-record-macro ()
    (interactive)
    (if buffer-read-only
        (quit-window)
      (call-interactively 'evil-record-macro)))

  (defun me/save-and-kill-this-buffer ()
    (interactive)
    (save-buffer)
    (kill-this-buffer))
  :init
  (progn
    (setq evil-want-integration t
          evil-want-keybinding nil
          evil-want-C-u-scroll t
          evil-want-C-i-jump t
          evil-respect-visual-line-mode t
          evil-undo-system 'undo-tree))
  :config
  (progn
    (evil-mode 1)

    (evil-set-initial-state 'messages-buffer-mode 'normal)
    (evil-set-initial-state 'dashboard-mode 'normal)
    (with-eval-after-load 'general
      (imap "C-n" nil
        "C-p" nil)

      (nmap "R" 'evil-replace-state
        "q" 'me/evil-record-macro
        "g ?" 'nil
        "gu" 'universal-argument
        "gw" 'other-window-prefix)

      (imap "C-g" 'evil-normal-state
        "C-u" 'universal-argument)

      (vmap "gu" 'universal-argument)

      (mmap "j" 'evil-next-visual-line
        "k" 'evil-previous-visual-line
        "L" 'evil-end-of-line-or-visual-line
        "H" 'evil-first-non-blank-of-visual-line
        "gu" 'universal-argument)

      (setq me/window-map (cons 'keymap evil-window-map))

      (general-def me/window-map
        "u" 'winner-undo
        "U" 'winner-redo
        "f" 'other-frame)

      (leader-map "w" '(:keymap me/window-map :wk "windows"))

      (evil-ex-define-cmd "q" #'kill-this-buffer)
      (evil-ex-define-cmd "wq" #'me/save-and-kill-this-buffer)

      (imap "j"
        (general-key-dispatch 'self-insert-command
          :timeout 0.15
          "k" 'evil-normal-state)))))

evil-collection

  (use-package evil-collection
    :after evil
    :diminish evil-collection-unimpaired-mode
    :config
    (evil-collection-init)
(with-eval-after-load 'general
    (nmap
      "go" 'evil-collection-unimpaired-insert-newline-below
      "gO" 'evil-collection-unimpaired-insert-newline-above
      "gp" 'evil-collection-unimpaired-paste-below
      "gP" 'evil-collection-unimpaired-paste-above)))

evil-org

(use-package evil-org
  :after org
  :config
  (progn
    (add-hook 'org-mode-hook 'evil-org-mode)
    (add-hook 'evil-org-mode-hook
              (lambda () (evil-org-set-key-theme)))))

evil-commentary

(use-package evil-commentary
  :after evil
  :config
  (evil-commentary-mode))

evil-nerd-commenter

(use-package evil-nerd-commenter
  :after evil
  :config
  (evilnc-default-hotkeys nil t))

evil-matchit

(use-package evil-matchit
  :after evil
  :config
  (global-evil-matchit-mode 1))

evil-goggles

(use-package evil-goggles
  :after evil
  :config
  (progn
    (setq evil-goggles-pulse t)
    (setq evil-goggles-duration 0.4)
    (setq evil-goggles-blocking-duration 0.1)
    (evil-goggles-mode)
    (evil-goggles-use-diff-faces)))

evil-surround

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

evil-owl

(use-package evil-owl
  :config
  (setq evil-owl-display-method 'posframe
        evil-owl-extra-posframe-args '(:width 50 :height 20)
        evil-owl-max-string-length 50)
  (evil-owl-mode))

evil-mc

(use-package evil-mc
  :after evil
  :config
  (progn
    (evil-define-local-var evil-mc-custom-paused nil
      "Paused functionality when there are multiple cursors active.")

    (defun evil-mc-pause-smartchr-for-mode (mode)
      "Temporarily disables the smartchr keys for MODE."
      (let ((m-mode (if (atom mode) mode (car mode)))
            (s-mode (if (atom mode) mode (cdr mode))))
        (let ((init (intern (concat "smartchr/init-" (symbol-name s-mode))))
              (undo (intern (concat "smartchr/undo-" (symbol-name s-mode)))))
          (when (eq major-mode m-mode)
            (funcall undo)
            (push `(lambda () (,init)) evil-mc-custom-paused)))))

    (defun evil-mc-before-cursors-setup-hook ()
      "Hook to run before any cursor is created.
Can be used to temporarily disable any functionality that doesn't
play well with `evil-mc'."
      (mapc 'evil-mc-pause-smartchr-for-mode
            '(web-mode js2-mode java-mode (enh-ruby-mode . ruby-mode) css-mode))
      (when (boundp 'whitespace-cleanup-disabled)
        (setq whitespace-cleanup-disabled t)
        (push (lambda () (setq whitespace-cleanup-disabled nil)) evil-mc-custom-paused)))

    (defun evil-mc-after-cursors-teardown-hook ()
      "Hook to run after all cursors are deleted."
      (dolist (fn evil-mc-custom-paused) (funcall fn))
      (setq evil-mc-custom-paused nil))

    (add-hook 'evil-mc-before-cursors-created 'evil-mc-before-cursors-setup-hook)
    (add-hook 'evil-mc-after-cursors-deleted 'evil-mc-after-cursors-teardown-hook)

    (defvar evil-mc-mode-line-prefix ""
      "Override of the default mode line string for `evil-mc-mode'.")

    (global-evil-mc-mode 1)))

undo-tree

(use-package undo-tree
  :diminish undo-tree-mode
  :init
  (global-undo-tree-mode)
  :config
  (mmap "U" 'undo-tree-visualize))

projectile

(use-package projectile
  :ensure t
  :init
  (setq projectile-project-search-path '("~/Code/"))
  (projectile-mode +1)
  :config
  (progn
    (leader-map
      "p" '(:keymap projectile-command-map :wk "projects"))
    (with-eval-after-load 'consult
      (general-def projectile-command-map
        "b" 'consult-project-buffer))))

avy

(use-package avy
  :after evil
  :config
  (progn
    (general-def :states '(normal visual motion)
      "gf"	'avy-goto-char-timer
      "gF"	'avy-resume)

    (general-def :states '(normal visual motion insert emacs)
      "C-f" 'avy-goto-char-timer
      "C-S-f" 'avy-resume)

    (setq avy-timeout-seconds 0.2)))

all-the-icons

NOTE: The first time you load your configuration on a new machine, you’ll need to run `M-x all-the-icons-install-fonts` so that mode line icons display correctly.

(use-package all-the-icons)

all-the-icons-completion

(use-package all-the-icons-completion
  :after (all-the-icons marginalia)
  :hook (marginalia-mode . all-the-icons-completion-marginalia-setup)
  :init
  (all-the-icons-completion-mode))

all-the-icons-dired

(use-package all-the-icons-dired
  :after all-the-icons)

vertico

(use-package vertico
  :init (vertico-mode)
  :config
  (progn
    (general-def vertico-map
      "C-d"	'vertico-scroll-up
      "C-u"	'vertico-scroll-down
      "C-v"	'vertico-scroll-up
      "M-v"	'vertico-scroll-down
      "C-j"	'vertico-next
      "C-J"	'vertico-next-group
      "C-k"	'vertico-previous
      "C-K"	'vertico-previous-group
      "M-RET"	'minibuffer-force-complete-and-exit
      "M-TAB"	'minibuffer-complete
      "C-RET" 'vertico-exit-input
      "C-<return>" 'vertico-exit-input)

    (advice-add #'vertico--format-candidate :around
                (lambda (orig cand prefix suffix index _start)
                  (setq cand (funcall orig cand prefix suffix index _start))
                  (concat
                   (if (= vertico--index index)
                       (propertize "» " 'face 'vertico-current)
                     "  ")
                   cand)))))

vertico-directory

(use-package vertico-directory
  :after vertico
  :straight nil
  :load-path "straight/repos/vertico/extensions/"
  :bind
  (:map vertico-map
        ("RET" . vertico-directory-enter)
        ("DEL" . vertico-directory-delete-char)
        ("M-DEL" . vertico-directory-delete-word))
  :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))

vertico-posframe

(use-package vertico-posframe
  :disabled t
  :config
  (setq vertico-posframe-truncate-lines nil)
  (setq vertico-posframe-min-width 80)
  (setq vertico-posframe-poshandler 'posframe-poshandler-window-top-center)
  (vertico-posframe-mode))

savehist

(use-package savehist
  :init
  (savehist-mode))

consult

(use-package consult
  :general
  (leader-map
    "SPC"	'consult-buffer
    "so"	'consult-outline
    "sm"	'consult-mark
    "sl"	'consult-line
    "sL"	'consult-line-multi
    "sM"	'consult-global-map
    "sr"	'consult-ripgrep
    "fF"	'consult-recent-file
    "fb"	'consult-bookmark
    "bb"	'consult-buffer
    "bo"	'consult-buffer-other-window
    "bf"	'consult-buffer-other-frame
    "bm"	'consult-mode-command
    "bh"	'consult-history
    "xc"	'consult-complex-command
    "xk"	'consult-kmacro)

  (general-def
    "C-x b"	'consult-buffer
    "C-x 4 b"	'consult-buffer-other-window
    "C-x 5 b"	'consult-buffer-other-frame
    "C-x M-:"	'consult-complex-command
    "C-x r b"	'consult-bookmark
    "C-x p b"	'consult-project-buffer
    "M-#"	'consult-register-load
    "M-'"	'consult-register-store
    "C-M-#"	'consult-register
    "M-y"	'consult-yank-pop
    "<help> a"	'consult-apropos
    "M-g e"	'consult-compile-error
    "M-g f"	'consult-flymake
    "M-g g"	'consult-goto-line
    "M-g M-g"	'consult-goto-line
    "M-g o"	'consult-outline
    "M-g m"	'consult-mark
    "M-g k"	'consult-global-mark
    "M-g i"	'consult-imenu
    "M-g I"	'consult-imenu-multi
    "M-s d"	'consult-find
    "M-s D"	'consult-locate
    "M-s g"	'consult-grep
    "M-s G"	'consult-git-grep
    "M-s r"	'consult-ripgrep
    "M-s L"	'consult-line-multi
    "M-s m"	'consult-multi-occur
    "M-s k"	'consult-keep-lines
    "M-s u"	'consult-focus-lines
    "M-s e"	'consult-isearch-history)

  (general-def
    "C-s" 'consult-line
    "C-S-s" 'consult-line-multi)

  (general-def isearch-mode-map
    "M-e"	'consult-isearch-history
    "M-s e"	'consult-isearch-history
    "C-s"	'consult-line
    "C-S-s"	'consult-line-multi)

  (general-def minibuffer-local-map
    "M-s"	'consult-history
    "M-r"	'consult-history)

  :init
  ;; Optionally configure the register formatting. This improves the register
  ;; preview for `consult-register', `consult-register-load',
  ;; `consult-register-store' and the Emacs built-ins.
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  ;; This adds thin lines, sorting and hides the mode line of the window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)
  :config
  (progn
    (consult-customize
     consult-theme
     :preview-key '(:debounce 0.2 any)
     consult-ripgrep consult-git-grep consult-grep
     consult-bookmark consult-recent-file consult-xref
     consult--source-bookmark consult--source-recent-file
     consult--source-project-recent-file
     :preview-key (kbd "M-."))

    (defvar-local consult-toggle-preview-orig nil)

    (defun consult-toggle-preview ()
      "Command to enable/disable preview."
      (interactive)
      (if consult-toggle-preview-orig
          (setq consult--preview-function consult-toggle-preview-orig
                consult-toggle-preview-orig nil)
        (setq consult-toggle-preview-orig consult--preview-function
              consult--preview-function #'ignore)))
    (general-def vertico-map
      "M-p" 'consult-toggle-preview)
    (setq consult-narrow-key "<")

    (setq completion-in-region-function
          (lambda (&rest args)
            (apply (if vertico-mode
                       #'consult-completion-in-region
                     #'completion--in-region)
                   args)))))

orderless

(use-package orderless
  :config
  (defvar +orderless-dispatch-alist
    '((?% . char-fold-to-regexp)
      (?! . orderless-without-literal)
      (?`. orderless-initialism)
      (?= . orderless-literal)
      (?~ . orderless-flex)))

  ;; Recognizes the following patterns:
  ;; * ~flex flex~
  ;; * =literal literal=
  ;; * %char-fold char-fold%
  ;; * `initialism initialism`
  ;; * !without-literal without-literal!
  ;; * .ext (file extension)
  ;; * regexp$ (regexp matching at end)
  (defun +orderless-dispatch (pattern index _total)
    (cond
     ;; Ensure that $ works with Consult commands, which add disambiguation suffixes
     ((string-suffix-p "$" pattern)
      `(orderless-regexp . ,(concat (substring pattern 0 -1) "[\x200000-\x300000]*$")))
     ;; File extensions
     ((and
       ;; Completing filename or eshell
       (or minibuffer-completing-file-name
           (derived-mode-p 'eshell-mode))
       ;; File extension
       (string-match-p "\\`\\.." pattern))
      `(orderless-regexp . ,(concat "\\." (substring pattern 1) "[\x200000-\x300000]*$")))
     ;; Ignore single !
     ((string= "!" pattern) `(orderless-literal . ""))
     ;; Prefix and suffix
     ((if-let (x (assq (aref pattern 0) +orderless-dispatch-alist))
          (cons (cdr x) (substring pattern 1))
        (when-let (x (assq (aref pattern (1- (length pattern))) +orderless-dispatch-alist))
          (cons (cdr x) (substring pattern 0 -1)))))))

  ;; Define orderless style with initialism by default
  (orderless-define-completion-style +orderless-with-initialism
    (orderless-matching-styles '(orderless-initialism orderless-literal orderless-regexp)))

  ;; You may want to combine the `orderless` style with `substring` and/or `basic`.
  ;; There are many details to consider, but the following configurations all work well.
  ;; Personally I (@minad) use option 3 currently. Also note that you may want to configure
  ;; special styles for special completion categories, e.g., partial-completion for files.
  ;;
  ;; 1. (setq completion-styles '(orderless))
  ;; This configuration results in a very coherent completion experience,
  ;; since orderless is used always and exclusively. But it may not work
  ;; in all scenarios. Prefix expansion with TAB is not possible.
  ;;
  ;; 2. (setq completion-styles '(substring orderless))
  ;; By trying substring before orderless, TAB expansion is possible.
  ;; The downside is that you can observe the switch from substring to orderless
  ;; during completion, less coherent.
  ;;
  ;; 3. (setq completion-styles '(orderless basic))
  ;; Certain dynamic completion tables (completion-table-dynamic)
  ;; do not work properly with orderless. One can add basic as a fallback.
  ;; Basic will only be used when orderless fails, which happens only for
  ;; these special tables.
  ;;
  ;; 4. (setq completion-styles '(substring orderless basic))
  ;; Combine substring, orderless and basic.
  ;;
  (setq completion-styles '(orderless basic)
        completion-category-defaults nil
          ;;; Enable partial-completion for files.
          ;;; Either give orderless precedence or partial-completion.
          ;;; Note that completion-category-overrides is not really an override,
          ;;; but rather prepended to the default completion-styles.
        ;; completion-category-overrides '((file (styles orderless partial-completion))) ;; orderless is tried first
        completion-category-overrides '((file (styles partial-completion)) ;; partial-completion is tried first
                                        (consult-multi (styles orderless+initialism))
                                        ;; enable initialism by default for symbols
                                        (command (styles +orderless-with-initialism))
                                        (variable (styles +orderless-with-initialism))
                                        (symbol (styles +orderless-with-initialism)))
        orderless-component-separator #'orderless-escapable-split-on-space ;; allow escaping space with backslash!
        orderless-style-dispatchers '(+orderless-dispatch)))

marginalia

(use-package marginalia
  :bind (("M-A" . marginalia-cycle)
         :map minibuffer-local-map
         ("M-A" . marginalia-cycle))

  :custom
  (marginalia-max-relative-age 0)
  (marginalia-align 'left)
  :init
  (marginalia-mode)
  :config
  (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup))

embark

(use-package embark
  :general
  (general-def
    "C-," 'embark-act
    "C-;" 'embark-dwim
    "C-h B" 'embark-bindings)
  :init
  ;; Optionally replace the key help with a completing-read interface
  (setq prefix-help-command #'embark-prefix-help-command)
  :config
  ;; Hide the mode line of the Embark live/completions buffers
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none))))

  (defun +embark-live-vertico ()
    "Shrink Vertico minibuffer when `embark-live' is active."
    (when-let (win (and (string-prefix-p "*Embark Live" (buffer-name))
                        (active-minibuffer-window)))
      (with-selected-window win
        (when (and (bound-and-true-p vertico--input)
                   (fboundp 'vertico-multiform-unobtrusive))
          (vertico-multiform-unobtrusive)))))

  (add-hook 'embark-collect-mode-hook #'+embark-live-vertico))

embark-consult

(use-package embark-consult
  :after (embark consult)
  :demand t ; only necessary if you have the hook below
  ;; if you want to have consult previews as you move around an
  ;; auto-updating embark collect buffer
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

company

(use-package company
  :delight
  :config
  (imap company-active-map
    "TAB" 'company-complete-common-or-cycle
    "C-d" 'company-show-doc-buffer
    "<backtab>" '(lambda () (interactive) (company-complete-common-or-cycle -1)))

  (imap text-mode-map
    "C-." 'company-complete)
  (imap prog-mode-map
    "C-." 'company-complete)

  (setq completion-at-point-functions '(company-complete))

  (with-eval-after-load 'orderless
    (setq orderless-component-separator "[ !]")

    (defun just-one-face (fn &rest args)
      (let ((orderless-match-faces [completions-common-part]))
        (apply fn args)))

    (advice-add 'company-capf--candidates :around #'just-one-face))

  (setq company-require-match nil)
  (setq company-tooltip-limit 5)
  (setq company-show-numbers t)
  (setq company-selection-wrap-around t)
  (setq company-dabbrev-downcase nil)
  (setq company-idle-delay 0.2)
  (setq company-echo-delay 0)
  (setq company-backends '(company-capf
                           company-keywords
                           company-semantic
                           company-elisp
                           company-files
                           company-dabbrev
                           company-etags
                           company-cmake
                           company-ispell
                           company-yasnippet))

  (global-company-mode))

company-posframe

(use-package company-posframe
  :config
  ;; (push '(company-posframe-mode . nil)
  ;;       desktop-minor-mode-table)
  (setq company-tooltip-minimum-width 40)
  (company-posframe-mode 1))

prescient

(use-package prescient)
(use-package company-prescient
  :after (company prescient)
  :config
  (company-prescient-mode))

helpful

(use-package helpful
  :after evil
  :demand t
  :commands (helpful-callable helpful-variable helpful-command helpful-key helpful-at-point)
  :bind
  ("H-d" . helpful-at-point)
  ([remap describe-function] . helpful-function)
  ([remap describe-command] . helpful-command)
  ([remap describe-variable] . helpful-variable)
  ([remap describe-key] . helpful-key)
  (:map evil-motion-state-map
        ("K" . helpful-at-point))
  :config
  (general-def '(normal motion) helpful-mode-map
    "q" 'kill-this-buffer)
  (leader-map
    "bH" 'helpful-kill-buffers))

hydra

(use-package hydra
  :config
  (progn
    (defhydra me/hydra-evil-windows (:hint nil
                                           :pre (winner-mode 1)
                                           :post (redraw-display))
      "
Movement & RESIZE^^^^
^ ^ _k_ ^ ^       _f__d_ file/dired  _o_nly win             ^Move _C-k_
_h_ ^✜^ _l_       _b__B_ buffer/alt  _x_ Delete this win    ^_C-w_ _C-j_
^ ^ _j_ ^ ^       _u_ _r_ undo/redo  _s_plit _v_ertically   ^_C-h_ _C-l_"
      ;; For some reason the evil
      ;; commands behave better than
      ;; the emacs ones
      ("j" evil-window-down)
      ("k" evil-window-up)
      ("l" evil-window-right)
      ("h" evil-window-left)
      ("J" evil-window-increase-height)
      ("K" evil-window-decrease-height)
      ("L" evil-window-increase-width)
      ("H" evil-window-decrease-width)
      ("u" winner-undo)
      ("r" (progn (winner-undo) (setq this-command 'winner-undo)))
      ("d" dired  :color blue)
      ("f" find-file)
      ("b" consult-buffer  :color blue)
      ("B" me/alternate-buffer)
      ("o" delete-other-windows :color blue)
      ("x" delete-window)
      ("s" split-window-horizontally)
      ("v" split-window-vertically)
      ("C-w" evil-window-next :color blue)
      ("C-k" evil-window-move-very-top :color blue)
      ("C-j" evil-window-move-very-bottom :color blue)
      ("C-h" evil-window-move-far-left :color blue)
      ("C-l" evil-window-move-far-right :color blue)
      ("SPC" balance-windows  :color blue))

    (leader-map "W" 'me/hydra-evil-windows/body)))

origami

(use-package origami
  :config
  (global-origami-mode))

org-mode

(use-package org
  :demand t
  :preface
  ;; Functions ;;
  (defun me/org-mode-initial-setup ()
    (setq org-indent-mode-turns-on-hiding-stars t)
    (setq org-tags-column 0)
    (setq org-indent-indentation-per-level 2)
    (org-indent-mode)
    (variable-pitch-mode 1)
    (visual-line-mode 1))

  (defun me/org-babel-tangle-config ()
    (when (string-equal (file-name-directory (buffer-file-name))
                        (expand-file-name user-emacs-directory))
      ;; Dynamic scoping to the rescue
      (let ((org-confirm-babel-evaluate nil))
        (org-babel-tangle))))

  ;; Files ;;
  (defconst me/org-emacs-config-file (concat user-emacs-directory "README.org"))

  :config
  (progn

    ;; Keybinds ;;

    ;; Org Mode Keybinds
    (general-unbind org-mode-map
      "C-c ?" nil)

    (local-leader-map org-mode-map
      "p" 'org-set-property
      "s" '(:ignore t :wk "search")
      "T" '(:ignore t :wk "tables")
      "Ti" 'org-table-field-info
      "i" '(:ignore t :wk "insert")
      "it" 'org-set-tags-command
      "is" 'org-insert-structure-template
      "e" '(:ignore t :wk "edit")
      "es" 'org-sort
      "sm" 'org-match-sparse-tree
      "sM" 'org-tags-sparse-tree
      "st" 'org-sparse-tree)

    (general-def '(motion normal) org-mode-map
      "gt" 'org-toggle-heading
      "gT" 'org-ctrl-c-minus)


    (defun me/org-insert-subheading ()
      (interactive)
      (progn
        (call-interactively #'org-insert-subheading)
        (call-interactively #'evil-insert-state)))

    (general-def '(motion normal) org-mode-map
      "M-RET"      #'me/org-insert-subheading
      "M-<return>" #'me/org-insert-subheading)

    ;; Consult
    (with-eval-after-load 'consult
      (local-leader-map org-mode-map
        "so"	'consult-outline
        "ss" 'consult-org-heading)

      (leader-map org-mode-map
        "ss" 'consult-org-heading))

    ;; Org Src Keybinds
    (general-def org-src-mode-map
      [remap save-buffer] 'org-edit-src-exit)

    (local-leader-map org-src-mode-map
      "s" 'org-edit-src-exit)

    ;; Hooks ;;
    (add-hook 'org-mode-hook 'me/org-mode-initial-setup)
    (add-hook 'org-src-mode-hook 'evil-normalize-keymaps)

    ;; Visuals ;;
    (setq org-ellipsis "")
    (setq org-pretty-entities t)
    (setq org-fontify-todo-headline t)

    ;; Source Editing ;;
    (setq org-edit-src-turn-on-auto-save t)
    (setq org-src-window-setup 'current-window)
    (push '("conf-unix" . conf-unix) org-src-lang-modes)

    ;; Fix coming out of src editing into insert mode
    (defun me/org-edit-special ()
      (interactive)
      (progn
        (call-interactively #'evil-normal-state)
        (call-interactively #'org-edit-special)))

    (general-def org-mode-map
      [remap org-edit-special] #'me/org-edit-special)

    ;; Fonts ;;
    ;; Replace list hyphen with dot
    (font-lock-add-keywords 'org-mode
                            '(("^ *\\([-]\\) "
                               (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) ""))))))

    (dolist (face '((org-level-1 . 1.2)
                    (org-level-2 . 1.1)
                    (org-level-3 . 1.05)
                    (org-level-4 . 1.0)
                    (org-level-5 . 1.0)
                    (org-level-6 . 1.0)
                    (org-level-7 . 1.0)
                    (org-level-8 . 1.0))))

    ;; Ensure that anything that should be fixed-pitch in Org files appears that way
    (set-face-attribute 'org-block nil    :foreground nil :inherit 'fixed-pitch)
    (set-face-attribute 'org-table nil    :inherit 'fixed-pitch)
    (set-face-attribute 'org-formula nil  :inherit 'fixed-pitch)
    (set-face-attribute 'org-code nil     :inherit '(shadow fixed-pitch))
    (set-face-attribute 'org-table nil    :inherit '(shadow fixed-pitch))
    (set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
    (set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
    (set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
    (set-face-attribute 'org-checkbox nil  :inherit 'fixed-pitch)
    (set-face-attribute 'line-number nil :inherit 'fixed-pitch)
    (set-face-attribute 'line-number-current-line nil :inherit 'fixed-pitch)
    (set-face-attribute 'org-hide nil :inherit 'fixed-pitch)

    ;; Open links in current window
    (setf (cdr (assoc 'file org-link-frame-setup)) 'find-file)

    (setq org-cycle-separator-lines 0)

    ;; Babel ;;
    (setq org-confirm-babel-evaluate nil)
    (org-babel-do-load-languages
     'org-babel-load-languages
     '((emacs-lisp . t)))

    ;; Automatically tangle our Emacs.org config file when we save it
    (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'me/org-babel-tangle-config)))))

org-contrib

(use-package org-contrib
  :after org)

org-modern

(use-package org-modern
  :after org
  :init
  (setq org-auto-align-tags nil
        org-tags-column 0
        org-catch-invisible-edits 'show-and-error
        org-insert-heading-respect-content t)
  :config
  (set-face-attribute 'org-modern-symbol nil :family "Fira Code Retina")
  (setq org-modern-checkbox nil)
  (setq org-modern-keyword "")
  (global-org-modern-mode))

visual-fill-column

(use-package visual-fill-column
  :preface
  (defun me/org-mode-visual-fill ()
    (setq visual-fill-column-width 100
          visual-fill-column-center-text t)
    (visual-fill-column-mode 1))

  :hook (org-mode . me/org-mode-visual-fill))

magit

(use-package magit
  :general
  (leader-map
    "gs" 'magit-status
    "gS" 'magit-status-here)
  :custom
  (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
  :config
  (progn
    (defun me/magit-quit ()
      (interactive)
      (magit-mode-bury-buffer t))
    (general-def magit-mode-map
      [remap magit-mode-bury-buffer] #'me/magit-quit)
    (add-hook 'with-editor-mode-hook #'evil-insert-state)))

forge

;; NOTE: Make sure to configure a GitHub token before using this package!
;; - https://magit.vc/manual/forge/Token-Creation.html#Token-Creation
;; - https://magit.vc/manual/ghub/Getting-Started.html#Getting-Started
(use-package forge
  :after magit
  :init
  (setq forge-add-default-bindings t)
  (setq auth-sources '("~/.authinfo")))

rainbow-delimiters

(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))

format-all

(use-package format-all
  :hook (prog-mode . format-all-mode)
  :general (leader-map "=" 'format-all-buffer))

yasnippet

(use-package yasnippet)

treemacs

(use-package treemacs
  :general
  (leader-map
    "Tt" 'treemacs)
  :init
  (setq treemacs-width 20)

  )

(use-package treemacs-evil
  :after (treemacs evil)
  :straight nil
  :load-path "straight/repos/treemacs/src/extra")

(use-package treemacs-all-the-icons
  :after (treemacs magit)
  :straight nil
  :load-path "straight/repos/treemacs/src/extra")

(use-package treemacs-all-the-icons
  :after (treemacs all-the-icons)
  :straight nil
  :load-path "straight/repos/treemacs/src/extra")

(use-package treemacs-perspective
  :after (treemacs perspective)
  :straight nil
  :load-path "straight/repos/treemacs/src/extra")

(use-package treemacs-projectile
  :after (treemacs projectile)
  :straight nil
  :load-path "straight/repos/treemacs/src/extra")

xref

(use-package xref
  :straight nil
  :config
  (with-eval-after-load 'evil
    (mmap xref--xref-buffer-mode-map
      "<backtab" #'xref-prev-group
      "<return" #'xref-goto-xref
      "<tab>" #'xref-next-group)))

lsp-mode

(use-package lsp-mode
  :hook
  ((js-mode         ; ts-ls (tsserver wrapper)
    js-jsx-mode     ; ts-ls (tsserver wrapper)
    typescript-mode ; ts-ls (tsserver wrapper)
    web-mode        ; ts-ls/HTML/CSS
    ) . lsp-deferred)
  ;; (lsp-completion-mode . me/lsp-mode-setup-completion)
  :commands lsp
  ;; only corfu
  ;; :custom (lsp-completion-provider :none)
  :init
  (setq lsp-keymap-prefix "C-l")
  :config
  (lsp-enable-which-key-integration t)

  (local-leader-map prog-mode-map
    "l" (general-simulate-key "C-l"))
  (setq lsp-restart 'auto-restart)
  ;;(setq lsp-enable-symbol-highlighting nil)
  ;;(setq lsp-enable-on-type-formatting nil)
  ;;(setq lsp-signature-auto-activate nil)
  (setq lsp-eldoc-enable-hover nil)
  (setq lsp-signature-render-documentation nil)
  (setq lsp-modeline-code-actions-enable nil)
  (setq lsp-modeline-diagnostics-enable nil)
  (setq lsp-headerline-breadcrumb-enable t)
  (setq lsp-semantic-tokens-enable t)
  (setq lsp-enable-folding t)
  (setq lsp-enable-imenu t)
  (setq lsp-enable-snippet t)
  (setq lsp-enable-indentation nil)
  (setq-default lsp-enable-relative-indentation nil)
  (setq read-process-output-max (* 1024 1024)) ;; 1MB
  (setq lsp-idle-delay 0.5))

lsp-ui

(use-package lsp-ui
  :commands lsp-ui-mode
  :config
  (general-def lsp-ui-doc-mode-map
    "<f5>" 'lsp-ui-doc-focus-frame)
  (general-def lsp-ui-doc-frame-mode-map
    "<f6>" 'lsp-ui-doc-unfocus-frame)
  (setq lsp-ui-doc-position 'at-point)
  (setq lsp-ui-doc-max-height 80)
  (setq lsp-ui-doc-alignment 'window)
  (setq lsp-ui-doc-enable t)
  (setq lsp-ui-doc-header t)
  (set-face-attribute 'lsp-ui-doc-header nil :foreground (face-foreground 'default) :background (face-background 'default))
  (setq lsp-ui-doc-max-width 50)
  (setq lsp-ui-doc-include-signature t)
  (setq lsp-ui-doc-show-with-cursor t)
  (setq lsp-ui-doc-delay 0.5)
  (setq lsp-ui-doc-border (face-foreground 'default))
  (setq lsp-ui-sideline-mode nil)
  (setq lsp-ui-sideline-show-code-actions nil)
  (setq lsp-ui-sideline-delay 0.05))

lsp-treemacs

(use-package lsp-treemacs
  :after (perspective lsp treemacs)
  :config
  (lsp-treemacs-sync-mode 1))

flymake

(use-package flymake
  :straight nil
  :custom
  (flymake-fringe-indicator-position nil))

tree-sitter

(use-package tree-sitter
  :config
  (global-tree-sitter-mode)
  (add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode))

(use-package tree-sitter-langs)
(use-package tree-sitter-indent)

dap-mode

(use-package dap-mode
  :after lsp
  :config
  (progn
    (dap-auto-configure-mode)
    (require 'dap-node)
    (dap-node-setup)))

yaml-mode

(use-package yaml-mode)

json-mode

(use-package json-mode)

markdown-mode

(use-package markdown-mode
  :mode ("\\.md\\'" . markdown-mode)
  :custom (markdown-wiki-link-search-type '(sub-directories parent-directories))
  :init
  (setq markdown-link-space-sub-char " ")
  (setq markdown-wiki-link-alias-first nil)
  (setq markdown-fontify-code-blocks-natively t)
  (setq markdown-enable-wiki-links t)
  (setq markdown-wiki-link-fontify-missing t))

obsidian

(use-package obsidian
  :ensure t
  :demand t
  :config
  (progn
    (leader-map
      "c" 'obsidian-capture
      "os" 'obsidian-search
      "oj" 'obsidian-jump
      "ot" 'obsidian-tag-find)

    (leader-map obsidian-mode-map
      "ol" 'obsidian-insert-wikilink
      "oL" 'obsidian-insert-link
      "oo" 'obsidian-follow-link-at-point)

    (general-def obsidian-mode-map
      "C-c C-o" 'obsidian-follow-link-at-point
      "C-c C-l" 'obsidian-insert-wikilink)

    (obsidian-specify-path "~/Documents/BrendOS")
    (global-obsidian-mode t))
  :custom
  ;; This directory will be used for `obsidian-capture' if set.
  (obsidian-inbox-directory "• Encounters/• Unsorted"))

vterm

(use-package vterm
  :commands vterm
  :general (leader-map "`" 'vterm)
  :config
  (progn
    (setq vterm-buffer-name-string "vterm %s")
    (setq vterm-shell "fish")
    (setq vterm-max-scrollback 10000)))

perspective

(use-package perspective
  :defer nil
  :demand t
  :init
  (setq persp-initial-frame-name "config")
  (setq persp-show-modestring nil)
  (setq persp-state-default-file (no-littering-expand-var-file-name "persp/auto-save"))
  (setq persp-suppress-no-prefix-key-warning t)
  (persp-mode)
  (when (file-exists-p persp-state-default-file)
    (persp-state-load persp-state-default-file))
  :custom
  (persp-sort 'access)
  :config
  (progn
    (defun me/persp-state-save ()
      (let ((dir-name (no-littering-expand-var-file-name "persp/")))
        (when (not (file-exists-p dir-name))
          (make-directory dir-name t)))
      (persp-state-save))

    (add-hook 'kill-emacs-hook 'me/persp-state-save)

    (general-def perspective-map
      "t" 'persp-switch
      "b" 'persp-ibuffer)

    (leader-map
      "P" '(:keymap perspective-map :wk "perspectives")
      "C-TAB" 'persp-last
      "TAB" 'persp-switch)

    (with-eval-after-load 'consult
      (consult-customize consult--source-buffer :hidden t :default nil)
      (add-to-list 'consult-buffer-sources persp-consult-source))))

doom-modeline

(use-package doom-modeline
  :init
  (doom-modeline-mode 1)
  (setq doom-modeline-bar-width 1
        doom-modeline-minor-modes nil
        doom-modeline-buffer-file-name-style 'auto
        doom-modeline-minor-modes nil
        doom-modeline-modal-icon t
        doom-modeline-persp-name t
        doom-modeline-display-default-persp-name t
        doom-modeline-persp-icon nil
        doom-modeline-buffer-encoding nil)
  :config
  ;; This configuration to is fix a bug where certain windows would not display
  ;; their full content due to the overlapping modeline
  (advice-add #'fit-window-to-buffer :before (lambda (&rest _) (redisplay t))))

Override Doom Modeline Perspective Names

For some reason they only support persp-mode and not perspective

(with-eval-after-load 'perspective
  (progn
    ;; First remove the advice and hooks
    (general-remove-hook (list 'persp-renamed-functions 'persp-activated-functions 'find-file-hook 'buffer-list-update-hook) #'doom-modeline-update-persp-name)
    (advice-remove #'lv-message #'doom-modeline-update-persp-name)

    ;; New function for updating persp name
    (defun me/doom-modeline-update-persp-name (&rest _)
      "Update perspective name in mode-line."
      (setq doom-modeline--persp-name
            (when (and doom-modeline-persp-name)
              (let* ((persp (persp-current-name))
                     (face (if (and persp)
                               'doom-modeline-persp-buffer-not-in-persp
                             'doom-modeline-persp-name))
                     (icon (doom-modeline-icon 'material "folder" "🖿" "#"
                                               :face `(:inherit ,face :slant normal)
                                               :height 1.1
                                               :v-adjust -0.225)))
                (when (or doom-modeline-display-default-persp-name)
                  (concat doom-modeline-spc
                          (propertize (concat (and doom-modeline-persp-icon
                                                   (concat icon doom-modeline-vspc))
                                              (propertize persp 'face face))
                                      'mouse-face 'doom-modeline-highlight)
                          doom-modeline-spc))))))
    ;; Initialize
    (me/doom-modeline-update-persp-name)

    ;; Add hooks
    (general-add-hook (list 'persp-switch-hook 'persp-activated-hook 'persp-after-rename-hook 'persp-state-after-save-hook 'find-file-hook 'buffer-list-update-hook) #'me/doom-modeline-update-persp-name)
    (advice-add #'lv-message :after #'doom-modeline-update-persp-name)))

Templates

((nil . ((eval git-auto-commit-mode 1))))