~thecatster/.emacs.d

0549384fef4f86d51955a5c0b8f9e862fcfc0860 — Daniil Rose 4 months ago 2c969f2 master
Update vanilla config
M .gitignore => .gitignore +6 -0
@@ 7,4 7,10 @@ elpa/
parinfer-rust/
projectile-bookmarks.eld
straight/
elpaca/
backup/
var/

.DS_Store
.local/
tree-sitter/

M README.md => README.md +1 -2
@@ 1,4 1,3 @@
# `.emacs.d`
A single place to keep my Emacs configuration instead of being spread
across multiple repositories. A config for EXWM, mu4e, Ivy, and more
are included.
across multiple repositories.

M early-init.el => early-init.el +3 -5
@@ 1,10 1,8 @@
;;; early-init.el -*- lexical-binding: t; -*-
;; Do not edit this file! Generated by Emacs.org in .files

;; Got to disable package.el, we're using straight.el!
;; This fixes a weird libgccjit error in macOS 13.2.1
(setenv "LIBRARY_PATH" "/opt/homebrew/opt/gcc/lib/gcc/12:/opt/homebrew/opt/libgccjit/lib/gcc/12:/opt/homebrew/opt/gcc/lib/gcc/12/gcc/aarch64-apple-darwin21/12")

;; Got to disable package.el, we're using straight!
(setq package-enable-at-startup nil)

;; Again, /inspired/ from Doom, ensure Engineered is running in this directory.
(setq user-emacs-directory (expand-file-name "~/.local/emacs/")
      url-history-file (expand-file-name "url/history" user-emacs-directory))

A history => history +4 -0
@@ 0,0 1,4 @@
;; -*- mode: emacs-lisp; coding: utf-8-unix -*-
;; Minibuffer history file, automatically generated by ‘savehist’.

(setq savehist-minibuffer-history-variables '(extended-command-history))

M init.el => init.el +25 -1572
@@ 1,1572 1,25 @@
(defconst IS-WINDOWS (memq system-type '(cygwin windows-nt ms-dos)))
(defconst IS-MAC     (eq system-type 'darwin))
(defconst IS-LINUX   (eq system-type 'gnu/linux))

(defconst engineered-version "2.4.0"
  "Current version of Engineered Emacs.")

;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are
;; compiled ahead-of-time when they are installed and site files are compiled
;; when gccemacs is installed.
(setq comp-deferred-compilation nil)
(setq comp-async-report-warnings-errors nil)

;; Getting strange messages with Guix that do not affect performance
(setq warning-minimum-level :error)

;;; Shut up, startup
;; Legacy system advice, who cares
(setq ad-redefinition-action 'accept)

;; "For information about GNU Emacs..." I'll read the docs or go to the website, moving on
(unless (daemonp)
  (advice-add #'display-startup-echo-area-message :override #'ignore))

;; Shut up, *Message*
(setq inhibit-startup-message t
      large-file-warning-threshold nil
      vc-follow-symlinks t
      ad-redefinition-action 'accept
      inhibit-startup-echo-area-message user-login-name
      inhibit-default-init t
      byte-compile-warnings '(not cl-functions))

;;; Optimizations!
;; Don't rely on case insensitivity.
(setq auto-mode-case-fold nil)

;; Disabling bidirectional text rendering gives a performance boost.
(setq-default bidi-display-reordering 'left-to-right
              bidi-paragraph-direction nil)
(setq bidi-inhibit-bpa t)

;; Don't render in non-focused, why would you?
(setq-default cursor-in-non-selected-windows nil)
(setq highlight-nonselected-windows nil)

;; *Zoom* scrolling
(setq fast-but-imprecise-scrolling t)

;; Can't figure out what for, but this is needed.
(require 'ido)

;; Why are you pinging domain names?
(setq ffap-machine-p-known 'reject)

;; Don't waste time on resizing the frame with font size.
(setq frame-inhibit-implied-resize t)

;; Here's where we handle the GC
(setq gcmh-idle-delay 5
      gc-cons-threshold (* 2000 1024 1024) ;; 2000mb
      gcmh-high-cons-threshold (* 4000 1024 1024))  ;; 4000mb

;; This increases from the default of 4k, helps LSP
(setq read-process-output-max (* 16 1024 1024)) ;; 16mb

;; Slow the UI updates
(setq idle-update-delay 1.0)

;; Increase memory usage, but increase performance. No thank you, font compacting!
(setq inhibit-compacting-font-caches t)

;; I said, **Zoom** scrolling!
(setq redisplay-skip-fontification-on-input t)

;; Remove unnecessary CLI options
(unless IS-MAC   (setq command-line-ns-option-alist nil))
(unless IS-LINUX (setq command-line-x-option-alist nil))

;; A hack from Doom again, this helps with terminal Emacs startup
(unless (daemonp)
  (advice-add #'tty-run-terminal-initialization :override #'ignore))

;; I know this is from Doom again, but again, Henrik knows what he's doing!
;;; Security

;; Emacs is essentially one huge security vulnerability, what with all the
;; dependencies it pulls in from all corners of the globe. Let's try to be at
;; least a little more discerning.
(setq gnutls-verify-error (not (getenv-internal "INSECURE"))
      gnutls-algorithm-priority
      (when (boundp 'libgnutls-version)
        (concat "SECURE128:+SECURE192:-VERS-ALL"
                (if (and (not IS-WINDOWS)
                         (not (version< emacs-version "26.3"))
                         (>= libgnutls-version 30605))
                    ":+VERS-TLS1.3")
                ":+VERS-TLS1.2"))
      ;; `gnutls-min-prime-bits' is set based on recommendations from
      ;; https://www.keylength.com/en/4/
      gnutls-min-prime-bits 3072
      tls-checktrust gnutls-verify-error
      tls-program '("gnutls-cli -p %p %h"))

;; Emacs stores `authinfo' in $HOME and in plain-text. WHY!?
(setq auth-sources (list (concat user-emacs-directory "authinfo.gpg")
                         "~/.authinfo"
                         "~/.authinfo.gpg"))

;; UTF-8!
(when (fboundp 'set-charset-priority)
  (set-charset-priority 'unicode))
(set-default-coding-systems 'utf-8)
(prefer-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)

;; MELPA!
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("org" . "https://orgmode.org/elpa/") t)
(add-to-list 'package-archives '("gnu" . "https://elpa.gnu.org/packages/") t)
(package-initialize)

(setq load-prefer-newer t)

(defvar bootstrap-version)
(defvar native-comp-deferred-compilation-deny-list ())
(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)
(setq straight-use-package-by-default t)

(setq user-full-name "Daniil Rose"
      user-mail-address "daniil.rose@member.fsf.org")

(use-package diminish)

(scroll-bar-mode -1)
(tool-bar-mode   -1)
(tooltip-mode    -1)
(menu-bar-mode   -1)

(use-package so-long
  :config
  (global-so-long-mode 1))

(when IS-MAC
  ;; Switch keys around, since it's easier to hit Command
  (setq mac-option-key-is-meta nil
        mac-command-key-is-meta t
        mac-command-modifier 'meta
        mac-option-modifier 'super)

  ;; Use spotlight as search
  (setq locate-command "mdfind")

  ;; Curse Lion and its sudden but inevitable fullscreen mode!
  ;; NOTE Meaningless to railwaycat's emacs-mac build
  (setq ns-use-native-fullscreen nil)

  ;; Visit files opened outside of Emacs in existing frame, not a new one
  (setq ns-pop-up-frames nil)

  ;; sane trackpad/mouse scroll settings
  (setq mac-redisplay-dont-reset-vscroll t
        mac-mouse-wheel-smooth-scroll nil)

  ;; Sets `ns-transparent-titlebar' and `ns-appearance' frame parameters so window
  ;; borders will match the enabled theme.
  (and (or (daemonp)
           (display-graphic-p))
       (require 'ns-auto-titlebar nil t)
       (ns-auto-titlebar-mode +1))

  ;; Integrate with Keychain
  (add-to-list 'auth-sources 'macos-keychain-internet)
  (add-to-list 'auth-sources 'macos-keychain-generic)

  ;; Delete files to trash
  (use-package osx-trash
    :init
    (setq delete-by-moving-to-trash t)
    (and IS-MAC
         (not (fboundp 'system-move-file-to-trash))
         (defalias #'system-move-file-to-trash #'osx-trash-move-file-to-trash))))

(when IS-MAC
  (use-package exec-path-from-shell
    :init
    (exec-path-from-shell-initialize)))

(use-package volatile-highlights
  :hook (after-init . volatile-highlights-mode))

(setq tramp-default-method "ssh")

(use-package auto-sudoedit
  :diminish auto-sudoedit-mode
  :config
  (auto-sudoedit-mode 1))

(remove-hook 'find-file-hooks 'vc-find-file-hook)
(setq vc-follow-symlinks t)

(setq initial-scratch-message "Welcome to Engineered Emacs!")
(setq initial-major-mode 'fundamental-mode)

(setq ring-bell-function 'ignore)

(setq-default indent-tabs-mode nil)
(setq-default tab-width 2)

(setq-default
 window-combination-resize t
 delete-by-moving-to-trash t
 x-stretch-cursor t)

(setq undo-limit 80000000
      auto-save-default nil
      truncate-string-ellipsis "…"
      scroll-margin 20)

(with-eval-after-load 'subword
  (diminish 'subword-mode))
(global-subword-mode 1)

(setq set-mark-command-repeat-pop t)

(setq global-auto-revert-non-file-buffers t)
(global-auto-revert-mode 1)

(line-number-mode nil)

(add-to-list 'load-path "~/.emacs.d/lisp/")

(setq scroll-step 1)

(defalias 'yes-or-no-p 'y-or-n-p)

(setq backup-directory-alist '(("." . "~/.emacs.d/backup"))
      backup-by-copying t    ; Don't delink hardlinks
      version-control t      ; Use version numbers on backups
      delete-old-versions t  ; Automatically delete excess backups
      kept-new-versions 20   ; how many of the newest versions to keep
      kept-old-versions 5)

(add-hook 'before-save-hook 'delete-trailing-whitespace)

(add-to-list 'default-frame-alist '(font . "JetBrainsMono Nerd Font"))
(use-package emojify
  :hook (after-init . global-emojify-mode)
  :custom
  (emojify-set-emoji-style 'unicode)
  :commands emojify-mode)

(use-package default-text-scale
  :defer 1
  :config
  (default-text-scale-mode))

(use-package super-save
  :defer 1
  :diminish super-save-mode
  :config
  (super-save-mode +1)
  (setq super-save-auto-save-when-idle t))

(setq display-buffer-base-action
      '(display-buffer-reuse-mode-window
        display-buffer-reuse-window
        display-buffer-same-window))

;; If a popup does happen, don't resize windows to be equal-sized
(setq even-window-sizes nil)

(use-package all-the-icons-dired)
(use-package peep-dired)

(add-hook 'dired-mode-hook 'all-the-icons-dired-mode)

(use-package dired-subtree
  :bind (:map dired-mode-map
              ("i" . dired-subtree-insert)
              (";" . dired-subtree-remove)))

(use-package dired-ranger
  :bind (:map dired-mode-map
              ("W" . dired-ranger-copy)
              ("X" . dired-ranger-move)
              ("Y" . dired-ranger-paste)))

(add-hook 'dired-mode-hook 'auto-revert-mode)

(setq dired-open-extensions '(("gif" . "sxiv")
                              ("jpg" . "sxiv")
                              ("png" . "sxiv")
                              ("mkv" . "mpv")
                              ("mp4" . "mpv")))

(setq catster/use-evil nil)

(when catster/use-evil
   (require 'catsters-evil))

(use-package atom-one-dark-theme
  :config
  (load-theme 'atom-one-dark t))
(use-package all-the-icons)

(setq catster/use-doom-ml t)

(when catster/use-doom-ml
  (use-package doom-modeline
    :custom
    (doom-modeline-major-mode-icon t)
    (doom-modeline-minor-modes nil)
    :hook (after-init . doom-modeline-mode)))

(unless catster/use-doom-ml
  (use-package smart-mode-line-atom-one-dark-theme)
  (use-package smart-mode-line
    :after smart-mode-line-atom-one-dark-theme
    :init
    (setq sml/theme 'atom-one-dark)
    (setq sml/no-confirm-load-theme t)
    :config
    (sml/setup)))

(use-package anzu
  :init
  (global-anzu-mode))

;; Don't bring up key recipient dialogue.
(require 'epa-file)
(setq epa-file-select-keys 1)
(setq epa-file-encrypt-to '("<daniil.rose@member.fsf.org>"))

;; Increase the password cache expiry time, technically doesn't do anything for GPG2
(setq password-cache-expiry (* 60 15))

;; Fix EasyPG error.
;; From https://colinxy.github.io/software-installation/2016/09/24/emacs25-easypg-issue.html.
(defvar epa-pinentry-mode)
(setq epa-pinentry-mode 'loopback)

(use-package pinentry)
(setf epg-pinentry-mode 'loopback)
(defun pinentry-emacs (desc prompt ok error)
   (let ((str (read-passwd
               (concat (replace-regexp-in-string "%22" "\""
                                                 (replace-regexp-in-string "%0A" "\n" desc)) prompt ": "))))
     str))

(straight-use-package '(vertico :files (:defaults "extensions/*")
                                :includes (vertico-buffer
                                           vertico-directory
                                           vertico-flat
                                           vertico-indexed
                                           vertico-mouse
                                           vertico-quick
                                           vertico-repeat
                                           vertico-reverse)))
(vertico-mode)
(setq vertico-cycle t)

(defun basic-remote-try-completion (string table pred point)
  (and (vertico--remote-p string)
       (completion-basic-try-completion string table pred point)))
(defun basic-remote-all-completions (string table pred point)
  (and (vertico--remote-p string)
       (completion-basic-all-completions string table pred point)))
(add-to-list
 'completion-styles-alist
 '(basic-remote basic-remote-try-completion basic-remote-all-completions nil))
(setq completion-styles '(orderless)
      completion-category-overrides '((file (styles basic-remote partial-completion)))
      completion-category-defaults nil)

(use-package vertico-directory
  :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))

(use-package orderless
  :init
  (setq completion-styles '(orderless)
        completion-category-overrides '((file (styles partial-completion)))))

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

(use-package emacs
  :init
  (defun crm-indicator (args)
    (cons (concat "[CRM] " (car args)) (cdr args)))
  (advice-add #'completing-read-multiple :filter-args #'crm-indicator)

  (setq minibuffer-prompt-properties
        '(read-only t cursor-intangible t face minibuffer-prompt))
  (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)

  (setq read-extended-command-predicate
        #'command-completion-default-include-p)

  (setq enable-recursive-minibuffers t))

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

  :init
  (marginalia-mode))

(use-package all-the-icons-completion
  :init
  (all-the-icons-completion-mode))

(use-package consult
  :bind (;; C-c bindings (mode-specific-map)
         ("C-c h" . consult-history)
         ("C-c m" . consult-mode-command)
         ("C-c b" . consult-bookmark)
         ("C-c k" . consult-kmacro)
         ;; C-x bindings (ctl-x-map)
         ("C-x M-:" . consult-complex-command)     ;; orig. repeat-complex-command
         ("C-x b" . consult-buffer)                ;; orig. switch-to-buffer
         ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
         ("C-x 5 b" . consult-buffer-other-frame)  ;; orig. switch-to-buffer-other-frame
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)          ;; orig. abbrev-prefix-mark (unrelated)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)                ;; orig. yank-pop
         ("<help> a" . consult-apropos)            ;; orig. apropos-command
         ;; M-g bindings (goto-map)
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)               ;; Alternative: consult-flycheck
         ("M-g g" . consult-goto-line)             ;; orig. goto-line
         ("M-g M-g" . consult-goto-line)           ;; orig. goto-line
         ("M-g o" . consult-outline)               ;; Alternative: consult-org-heading
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("M-g i" . consult-imenu)
         ("M-g I" . consult-project-imenu)
         ;; M-s bindings (search-map)
         ("M-s f" . consult-find)
         ("M-s L" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ;; Replace isearch with consult-line
         ("C-s" . consult-line)
         ("M-s m" . consult-multi-occur)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch)
         :map isearch-mode-map
         ("M-e" . consult-isearch)                 ;; orig. isearch-edit-string
         ("M-s e" . consult-isearch)               ;; orig. isearch-edit-string
         ("M-s l" . consult-line))                 ;; needed by consult-line to detect isearch

  :hook (completion-list-mode . consult-preview-at-point-mode)

  :init
  (setq register-preview-delay 0
        register-preview-function #'consult-register-format)

 (add-hook 'vertico-mode-hook (lambda ()
                                (setq completion-in-region-function
                                      (if vertico-mode
                                          #'consult-completion-in-region
                                        #'completion--in-region))))

 (advice-add #'register-preview :override #'consult-register-window)

 (advice-add #'completing-read-multiple :override #'consult-completing-read-multiple)

 (setq xref-show-xrefs-function #'consult-xref
       xref-show-definitions-function #'consult-xref)

 :config
 (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-file consult--source-project-file consult--source-bookmark
  :preview-key (kbd "M-."))

 (setq consult-narrow-key "<") ;; (kbd "C-+")
 (setq consult-project-root-function
       (lambda ()
         (when-let (project (project-current))
           (car (project-roots project))))))

(use-package embark
  :bind
  (("C-." . embark-act)         ;; pick some comfortable binding
   ("C-;" . embark-dwim)        ;; good alternative: M-.
   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'

  :init
  (setq prefix-help-command #'embark-prefix-help-command)

  :config
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none)))))

(use-package embark-consult
  :after (embark consult)
  :demand t
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

(use-package corfu
  :hook ((prog-mode hy-mode) . corfu-mode)
  :custom
  (corfu-cycle t)            ;; Enable cycling for `corfu-next/previous'
  (corfu-auto t)             ;; Enable auto completion
  (corfu-quit-at-boundary t) ;; Automatically quit at word boundary
  (corfu-quit-no-match t)    ;; Automatically quit if there is no match
  (corfu-auto-delay 0)
  (corfu-auto-prefix 2)
  :bind (:map corfu-map
          ("TAB" . corfu-next)
          ([tab] . corfu-next)
          ("S-TAB" . corfu-previous)
          ([backtab] . corfu-previous)))

(use-package orderless
  :init
  (setq completion-styles '(orderless)
        completion-category-defaults nil
        completion-category-overrides '((file (styles . (partial-completion))))))

(use-package dabbrev
  :bind (("M-/" . dabbrev-completion)
         ("C-M-/" . dabbrev-expand)))

(use-package emacs
  :init

  (setq completion-cycle-threshold 3)
  (setq read-extended-command-predicate
         #'command-completion-default-include-p)
  (setq tab-always-indent 'complete))

(use-package affe
  :after orderless
  :config
  ;; Configure Orderless
  (setq affe-regexp-function #'orderless-pattern-compiler
        affe-highlight-function #'orderless--highlight)

  ;; Manual preview key for `affe-grep'
  (consult-customize affe-grep :preview-key (kbd "M-.")))

(use-package which-key
  :init
  (which-key-mode 1)
  :diminish which-key-mode
  :config
  (setq which-key-idle-delay 0.3)
  (setq which-key-separator " ")
  (setq which-key-prefix-prefix "+"))

(use-package projectile
  :diminish projectile-mode
  :config
  (setq projectile-require-project-root nil)
  (setq projectile-mode-line "")
  (projectile-mode)
  :demand t
  :bind-keymap ("C-c p" . projectile-command-map)
  :init
  (when (file-directory-p "~/Projects/Programming")
    (setq projectile-project-search-path '("~/Projects/Programming"))))

(use-package crux
  :config
  ;; Replace default commands with CRUX
  (global-set-key [remap move-beginning-of-line] #'crux-move-beginning-of-line)
  (global-set-key (kbd "C-c o") #'crux-open-with)
  (global-set-key [(shift return)] #'crux-smart-open-line)
  (global-set-key (kbd "C-<backspace>") #'crux-kill-line-backwards)
  (global-set-key [remap kill-whole-line] #'crux-kill-whole-line))

(use-package no-littering
  :config
  (require 'recentf)
  (add-to-list 'recentf-exclude no-littering-var-directory)
  (add-to-list 'recentf-exclude no-littering-etc-directory)
  (setq auto-save-file-name-transforms
        `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
  (setq custom-file (expand-file-name "custom.el" user-emacs-directory)))

(defun rk/open-compilation-buffer (&optional buffer-or-name shackle-alist shackle-plist)
  "Helper for selecting window for opening *compilation* buffers."
  ;; find existing compilation window left of the current window or left-most window
  (let ((win (or (loop for win = (if win (window-left win) (get-buffer-window))
                       when (or (not (window-left win))
                                (string-prefix-p "*compilation" (buffer-name (window-buffer win))))
                       return win)
                 (get-buffer-window))))
    ;; if the window is dedicated to a non-compilation buffer, use the current one instead
    (when (window-dedicated-p win)
      (let ((buf-name (buffer-name (window-buffer win))))
        (unless (string-prefix-p "*compilation" buf-name)
          (setq win (get-buffer-window)))))
    (set-window-buffer win (get-buffer buffer-or-name))
    (set-frame-selected-window (window-frame win) win)))


(use-package shackle
  :diminish
  :custom
  (shackle-rules '((compilation-mode :custom rk/open-compilation-buffer :select t)
                   ("\\*Apropos\\|Help\\|Occur\\|tide-references\\*" :regexp t :same t :select t :inhibit-window-quit t)
                   ("\\*magit" :regexp t :same t :select t)
                   ("\\*shell.*" :regexp t :same t :select t)
                   ("\\*PowerShell.*" :regexp t :same t :select t)
                   ("\\*Cargo.*" :regexp t :other t :select nil)
                   ("*Messages*" :select nil :other t)
                   ("*go-guru-output*" :select t :same t)
                   ("*Proced*" :select t :same t)
                   ("*Buffer List*" :select t :same t)
                   ("\\*Pp Eval" :regexp t :same nil :select t :other t)
                   ("*Messages*" :same nil :other t :select t :inhibit-window-quit t)

                   ;; slime
                   ("*slime-source*" :select nil :same nil :other t)
                   ("*slime-description*" :select nil :other t :inhibit-window-quit t)
                   ("\\*slime-repl" :regexp t :same nil :select nil :other t)
                   ;; ("\\*sldb" :regexp t :other t :inhibit-window-quit t :select t)
                   ("\\*slime-compilation" :regexp t :same nil :select nil :other t)
                   ("*slime-scratch*" :same nil :select t :other t)

                   ;; ert
                   ("*ert*" :select nil :same nil :other t)

                   ;; clojure
                   ("*sesman CIDER browser*" :inhibit-window-quit t :select t :same t)
                   ("\\*cider-repl" :regexp t :same nil :other t)))
  (shackle-default-rule nil))

(shackle-mode)

(use-package undo-fu
  :config
  (global-unset-key (kbd "C-/"))
  (global-set-key (kbd "C-/")   'undo-fu-only-undo)
  (global-set-key (kbd "C-S-/") 'undo-fu-only-redo))

(use-package helpful
  :config
  ;; Note that the built-in `describe-function' includes both functions
  ;; and macros. `helpful-function' is functions only, so we provide
  ;; `helpful-callable' as a drop-in replacement.
  (global-set-key (kbd "C-h f") #'helpful-callable)

  (global-set-key (kbd "C-h v") #'helpful-variable)
  (global-set-key (kbd "C-h k") #'helpful-key)
  ;; Lookup the current symbol at point. C-c C-d is a common keybinding
  ;; for this in lisp modes.
  (global-set-key (kbd "C-c C-d") #'helpful-at-point)

  ;; Look up *F*unctions (excludes macros).
  ;;
  ;; By default, C-h F is bound to `Info-goto-emacs-command-node'. Helpful
  ;; already links to the manual, if a function is referenced there.
  (global-set-key (kbd "C-h F") #'helpful-function)

  ;; Look up *C*ommands.
  ;;
  ;; By default, C-h C is bound to describe `describe-coding-system'. I
  ;; don't find this very useful, but it's frequently useful to only
  ;; look at interactive functions.
  (global-set-key (kbd "C-h C") #'helpful-command))

(use-package latex
  :straight nil
  :defer t
  :ensure auctex
  :hook ((LaTeX-mode . prettify-symbols-mode))
  :bind (:map LaTeX-mode-map
         ("C-S-e" . latex-math-from-calc))
  :config
  ;; Format math as a Latex string with Calc
  (defun latex-math-from-calc ()
    "Evaluate `calc' on the contents of line at point."
    (interactive)
    (cond ((region-active-p)
           (let* ((beg (region-beginning))
                  (end (region-end))
                  (string (buffer-substring-no-properties beg end)))
             (kill-region beg end)
             (insert (calc-eval `(,string calc-language latex
                                          calc-prefer-frac t
                                          calc-angle-mode rad)))))
          (t (let ((l (thing-at-point 'line)))
               (end-of-line 1) (kill-line 0)
               (insert (calc-eval `(,l
                                    calc-language latex
                                    calc-prefer-frac t
                                    calc-angle-mode rad))))))))

(use-package preview
  :straight nil
  :after latex
  :hook ((LaTeX-mode . preview-larger-previews))
  :config
  (defun preview-larger-previews ()
    (setq preview-scale-function
          (lambda () (* 1.25
                   (funcall (preview-scale-from-face)))))))

(use-package cdlatex
  :ensure t
  :hook (LaTeX-mode . turn-on-cdlatex)
  :bind (:map cdlatex-mode-map
              ("<tab>" . cdlatex-tab)))

(use-package yasnippet-snippets)

(use-package yasnippet
  :hook ((LaTeX-mode . yas-minor-mode)
         (post-self-insert . my/yas-try-expanding-auto-snippets))
  :after yasnippet-snippets
  :diminish yas-minor-mode
  :hook ((prog-mode text-mode) . yas-minor-mode)
  :config
  (add-to-list 'yas-snippet-dirs "~/.emacs.d/snippets")
  (yas-reload-all)
  (use-package warnings
    :config
    (cl-pushnew '(yasnippet backquote-change)
                warning-suppress-types
                :test 'equal))
  (setq yas-triggers-in-field t)
  ;; Function that tries to autoexpand YaSnippets
  ;; The double quoting is NOT a typo!
  (defun my/yas-try-expanding-auto-snippets ()
    (when (and (boundp 'yas-minor-mode) yas-minor-mode)
      (let ((yas-buffer-local-condition ''(require-snippet-condition . auto)))
        (yas-expand)))))

(use-package cdlatex
  :hook ((cdlatex-tab . yas-expand)
         (cdlatex-tab . cdlatex-in-yas-field))
  :config
  (use-package yasnippet
    :bind (:map yas-keymap
           ("<tab>" . yas-next-field-or-cdlatex)
           ("TAB" . yas-next-field-or-cdlatex))
    :config
    (defun cdlatex-in-yas-field ()
      ;; Check if we're at the end of the Yas field
      (when-let* ((_ (overlayp yas--active-field-overlay))
                  (end (overlay-end yas--active-field-overlay)))
        (if (>= (point) end)
            ;; Call yas-next-field if cdlatex can't expand here
            (let ((s (thing-at-point 'sexp)))
              (unless (and s (assoc (substring-no-properties s)
                                    cdlatex-command-alist-comb))
                (yas-next-field-or-maybe-expand)
                t))
          ;; otherwise expand and jump to the correct location
          (let (cdlatex-tab-hook minp)
            (setq minp
                  (min (save-excursion (cdlatex-tab)
                                       (point))
                       (overlay-end yas--active-field-overlay)))
            (goto-char minp) t))))

    (defun yas-next-field-or-cdlatex ()
      (interactive)
      "Jump to the next Yas field correctly with cdlatex active."
      (if (bound-and-true-p cdlatex-mode)
          (cdlatex-tab)
        (yas-next-field-or-maybe-expand)))))

(use-package magit
  :commands (magit-status magit-get-current-branch)
  :custom
  (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
  :bind ("C-x g" . magit-status))

;; well yeah I want git gutter
(use-package git-gutter
  :diminish
  :hook ((prog-mode) . git-gutter-mode)
  :config
  (setq git-gutter:update-interval 2))

(use-package ediff)
;; don't start another frame
;; this is done by default in prelude
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; put windows side by side
(setq ediff-split-window-function (quote split-window-horizontally))
;;revert windows on exit - needs winner mode
(winner-mode)
(add-hook 'ediff-after-quit-hook-internal 'winner-undo)

(setq catster/use-pdf-view t)

(when catster/use-pdf-view
  ;; wrapper for save-buffer ignoring arguments
  (defun bjm/save-buffer-no-args ()
    "Save buffer ignoring arguments"
    (save-buffer))

  (use-package pdf-tools
    :config
    ;; initialise
    (pdf-tools-install :no-query)
    (setq-default pdf-view-display-size 'fit-page)
    ;; automatically annotate highlights
    (setq pdf-annot-activate-created-annotations t)
    ;; use isearch instead of swiper
    (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)
    ;; turn off cua so copy works
    (add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))
    ;; more fine-grained zooming
    (setq pdf-view-resize-factor 1.1)
    ;; keyboard shortcuts
    (define-key pdf-view-mode-map (kbd "h") 'pdf-annot-add-highlight-markup-annotation)
    (define-key pdf-view-mode-map (kbd "t") 'pdf-annot-add-text-annotation)
    (define-key pdf-view-mode-map (kbd "D") 'pdf-annot-delete)
    ;; wait until map is available
    (with-eval-after-load "pdf-annot"
      (define-key pdf-annot-edit-contents-minor-mode-map (kbd "<return>") 'pdf-annot-edit-contents-commit)
      (define-key pdf-annot-edit-contents-minor-mode-map (kbd "<S-return>") 'newline)
      ;; save after adding comment
      (advice-add 'pdf-annot-edit-contents-commit :after 'bjm/save-buffer-no-args))))

(use-package dashboard
  :preface
  (defun my/dashboard-banner ()
    "Set a dashboard banner including information on package initialization
  time and garbage collections."""
    (setq dashboard-banner-logo-title
          (format "Emacs ready in %.2f seconds with %d garbage collections."
                  (float-time (time-subtract after-init-time before-init-time)) gcs-done)))
  :custom
  (dashboard-set-heading-icons t)
  (dashboard-set-file-icons t)
  (dashboard-center-content t)
  :config
  (setq dashboard-startup-banner 'logo)
  (dashboard-setup-startup-hook)
  :hook ((after-init     . dashboard-refresh-buffer)
         (dashboard-mode . my/dashboard-banner)))

(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))

(use-package dockerfile-mode
  :mode "Dockerfile\\'")

(use-package docker
  :bind ("C-c d" . docker))

(use-package docker-compose-mode)

(use-package docker-tramp)

(use-package hydra)

(setq lv-use-separator t)

(use-package caddyfile-mode)

(use-package erc-hl-nicks
  :after erc)

(use-package erc-image
  :after erc)

(use-package erc
  :straight nil
  :preface
  (defun connect-irc-or-switch ()
    "Connects to ERC, or switch to last active buffer."
    (interactive)
    (if (get-buffer "bnc.irccloud.com:6697")
        (erc-track-switch-buffer 1)
      (when (y-or-n-p "Start ERC? ")
        (erc-tls :server "bnc.irccloud.com" :port 6697 :nick "thecatster"))))

  (defun my/erc-notify (nickname message)
    "Displays a notification message for ERC."
    (let* ((channel (buffer-name))
           (nick (erc-hl-nicks-trim-irc-nick nickname))
           (title (if (string-match-p (concat "^" nickname) channel)
                      nick
                    (concat nick " (" channel ")")))
           (msg (s-trim (s-collapse-whitespace message))))
      (alert (concat nick ": " msg) :title title)))

  (defun my/erc-count-users ()
    "Displays the number of users connected on the current channel."
    (interactive)
    (if (get-buffer "bnc.irccloud.com:6697")
        (let ((channel (erc-default-target)))
          (if (and channel (erc-channel-p channel))
              (message "%d users are online on %s"
                       (hash-table-count erc-channel-users)
                       channel)
            (user-error "The current buffer is not a channel")))
      (user-error "You must first start ERC")))

  (defun my/erc-preprocess (string)
    "Avoids channel flooding."
    (setq str
          (string-trim
           (replace-regexp-in-string "\n+" " " str))))

  :hook ((ercn-notify . my/erc-notify)
         (erc-send-pre . my/erc-preprocess))
  :commands erc
  :init
  (require 'erc-desktop-notifications)
  :custom
  (erc-autojoin-timing 'ident)
  (erc-fill-function 'erc-fill-static)
  (erc-fill-static-center 22)
  (erc-hide-list '("JOIN" "PART" "QUIT"))
  (erc-lurker-hide-list '("JOIN" "PART" "QUIT"))
  (erc-lurker-threshold-time 43200)
  (erc-prompt-for-nickserv-password nil)
  (erc-prompt-for-password nil)
  (erc-auto-query 'bury)
  (erc-join-buffer 'bury)
  (erc-rename-buffers t)
  (erc-kill-buffer-on-part t)
  (erc-fill-column 120)
  (erc-autojoin-channels-alist '(("bnc.irccloud.com" "#systemcrafters" "#emacs" "#guix" "#emacs-conf" "#archlinux" "#org-mode")))
  (erc-quit-reason (lambda (s) (or s "Exiting hyperspace... prepare for jump by jump")))
  (erc-server-reconnect-attempts 3)
  (erc-server-reconnect-timeout 3)
  (erc-track-exclude-types '("JOIN" "MODE" "NICK" "PART" "AWAY"
                             "324" "329" "332" "333" "353" "477"))
  (erc-modules '(
                 autojoin
                 button
                 completion
                 fill
                 hl-nicks
                 image
                 irccontrols
                 keep-place
                 list
                 log
                 match
                 menu
                 move-to-prompt
                 netsplit
                 networks
                 noncommands
                 notify
                 notifications
                 readonly
                 ring
                 stamp
                 track))
  :config
  (erc-services-mode 1)
  (erc-update-modules))

(use-package flycheck
  :hook ((lsp-mode ledger-mode org-mode) . flycheck-mode)
  :config
  (setq-default flycheck-temp-prefix ".flycheck"))

(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'org-mode-hook 'flyspell-mode)

(flycheck-define-checker proselint
  "A linter for prose."
  :command ("proselint" source-inplace)
  :error-patterns
  ((warning line-start (file-name) ":" line ":" column ": "
	    (id (one-or-more (not (any " "))))
	    (message) line-end))
  :modes (text-mode markdown-mode gfm-mode org-mode))

(add-to-list 'flycheck-checkers 'proselint)

(use-package treemacs
  :defer t
  :config
  (treemacs-follow-mode t)
  (treemacs-filewatch-mode t)
  (treemacs-fringe-indicator-mode 'always)
  (treemacs-git-mode 'deferred))

(use-package lsp-treemacs
  :after treemacs)

(use-package treemacs-projectile
  :after (treemacs projectile))

(use-package treemacs-magit
  :after (treemacs magit))

(use-package screenshot
  :config
  (load-file (locate-library "screenshot.el")))

(use-package editorconfig
  :config
  (editorconfig-mode 1))

(use-package quickrun)

(use-package scad-mode)
(use-package scad-preview)

(setq catster/use-mail nil)

(when catster/use-mail
  (add-to-list 'load-path "~/.emacs.d/mu4e/")
  (require 'catsters-mail))

(use-package format-all
  :hook (prog-mode . format-all-mode))

(show-paren-mode 1)
  (use-package smartparens
    :hook (prog-mode . smartparens-mode)
    :config
    (setq sp-highlight-pair-overlay t)
    (setq sp-autoskip-closing-pair 'always)
    (setq sp-cancel-autoskip-on-backward-movement nil))

(use-package compile
  :custom
  (compilation-scroll-output t))

(use-package rainbow-delimiters
  :diminish rainbow-delimiters-mode
  :hook ((hy-mode python-mode rustic-mode c-mode js-mode rjsx-mode web-mode css-mode html-mode) . rainbow-delimiters-mode))

(use-package rainbow-mode
  :diminish rainbow-mode
  :hook ((org-mode emacs-lisp-mode web-mode typescript-mode rjsx-mode) . rainbow-mode)
  :config
  (setq rainbow-x-colors nil))

(use-package kurecolor)

(use-package fzf)

(use-package deadgrep)

(use-package hl-todo
  :hook (prog-mode . hl-todo-mode)
  :hook (yaml-mode . hl-todo-mode)
  :custom
  (hl-todo-highlight-punctuation ":")
  (hl-todo-keyword-faces
        `(;; For things that need to be done, just not today.
          ("TODO" warning bold)
          ;; For problems that will become bigger problems later if not
          ;; fixed ASAP.
          ("FIXME" error bold)
          ;; For tidbits that are unconventional and not intended uses of the
          ;; constituent parts, and may break in a future update.
          ("HACK" font-lock-constant-face bold)
          ;; For things that were done hastily and/or hasn't been thoroughly
          ;; tested. It may not even be necessary!
          ("REVIEW" font-lock-keyword-face bold)
          ;; For especially important gotchas with a given implementation,
          ;; directed at another user other than the author.
          ("NOTE" success bold)
          ;; For things that just gotta go and will soon be gone.
          ("DEPRECATED" font-lock-doc-face bold)
          ;; For a known bug that needs a workaround
          ("BUG" error bold)
          ;; For warning about a problematic or misguiding code
          ("XXX" font-lock-constant-face bold))))

(use-package lsp-mode
  :defer t
  :hook (((rustic-mode
     python-mode
     rjsx-mode
     web-mode
     typescript-mode
     clojure-mode) . lsp)
   (lsp-mode . lsp-enable-which-key-integration))
  :commands (lsp)
  :init
  (setq  lsp-keymap-prefix "C-c l"
   lsp-eslint-run "onSave"
   lsp-completion-provider :capf
   lsp-log-io nil
   lsp-idle-delay 1
   lsp-headerline-breadcrumb-enable nil))

(use-package lsp-ui
  :hook (lsp-mode . lsp-ui-mode)
  :commands lsp-ui-mode
  :init
  (setq lsp-ui-sideline-show-hover nil
  lsp-ui-sideline-enable t
  lsp-ui-doc-enable nil
  lsp-signature-auto-activate nil
  lsp-signature-render-document nil
  ;; This is SO annoying. Believe it or not, I know what a `fn` does
  ;; in Rust!
  lsp-eldoc-render-all nil))

;; (use-package dap-mode
;;   :after lsp-mode
;;   :custom
;;   (lsp-enable-dap-auto-configure nil)
;;   :config
;;   (dap-ui-mode 1)
;;   (dap-tooltip-mode 1)
;;   (require 'dap-python)
;;   (require 'dap-lldb)
;;   (require 'dap-gdb-lldb)
;;   (dap-register-debug-template "Rust::GDB Run Configuration"
;;                                (list :type "gdb"
;;                                      :request "launch"
;;                                      :name "GDB::Run"
;;                                      :gdbpath "rust-gdb"
;;                                      :target nil
;;                                      :cwd nil))
;;   (require 'dap-node)
;;   (dap-node-setup))

;; (add-hook 'dap-stopped-hook
;;           (lambda (arg) (call-interactively #'dap-hydra)))

;;; Source: Configuring Emacs for Rust development - https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/
(use-package ron-mode)

(use-package rustic
  :after lsp-mode
  :bind (:map rustic-mode-map
              ("C-c C-c l" . flycheck-list-errors)
              ("M-?" . lsp-find-references)
              ("C-c C-c a" . lsp-execute-code-action)
              ("C-c C-c r" . lsp-rename)
              ("C-c C-c q" . lsp-workspace-restart)
              ("C-c C-c Q" . lsp-workspace-shutdown)
              ("C-c C-c s" . lsp-rust-analyzer-status)
              ("C-c C-c d" . dap-hydra))
  :config
  (setq lsp-rust-analyzer-cargo-watch-command "clippy")
  (setq lsp-rust-analyzer-server-display-inlay-hints t)
  (setq rustic-format-on-save nil)
  (add-hook 'rustic-mode-hook 'rk/rustic-mode-hook))

(defun rk/rustic-mode-hook ()
  (setq-local buffer-save-without-query t))

(use-package cargo-mode
  :config
  (add-hook 'rustic-mode-hook 'cargo-minor-mode))

(use-package lsp-python-ms
  :after lsp-mode
  :defer 0.3
  :custom (lsp-python-ms-auto-install-server t))

(use-package python
  :after lsp-mode
  :delight "π "
  :bind (("M-[" . python-nav-backward-block)
         ("M-]" . python-nav-forward-block))
  :preface
  (defun python-remove-unused-imports()
    "Removes unused imports and unused variables with autoflake."
    (interactive)
    (if (executable-find "autoflake")
        (progn
          (shell-command (format "autoflake --remove-all-unused-imports -i %s"
                                 (shell-quote-argument (buffer-file-name))))
          (revert-buffer t t t))
      (warn "python-mode: Cannot find autoflake executable."))))

(use-package blacken
  :delight
  :hook (python-mode . blacken-mode)
  :custom (blacken-line-length 79))

(use-package py-isort
  :after python
  :hook ((python-mode . pyvenv-mode)
         (before-save . py-isort-before-save)))

(use-package pyenv-mode
  :after python
  :hook ((python-mode . pyenv-mode)
         (projectile-switch-project . projectile-pyenv-mode-set))
  :custom (pyenv-mode-set "3.8.5")
  :preface
  (defun projectile-pyenv-mode-set ()
    "Set pyenv version matching project name."
    (let ((project (projectile-project-name)))
      (if (member project (pyenv-mode-versions))
          (pyenv-mode-set project)
        (pyenv-mode-unset)))))

(use-package pyvenv
  :after python
  :hook (python-mode . pyvenv-mode)
  :custom
  (pyvenv-default-virtual-env-name "env")
  (pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[venv:"
                                                         pyvenv-virtual-env-name "]"))))

(use-package pipenv
  :hook (python-mode . pipenv-mode)
  :init
  (setq
   pipenv-projectile-after-switch-function
   #'pipenv-projectile-after-switch-extended))

;; BUG: Currently, you have to manually activate Hy mode again due to a bug in the package.
;; A PR has been open since February 2021, but not yet merged.
(use-package hy-mode)

(use-package ccls
  :after projectile
  :custom
  (ccls-args nil)
  (ccls-executable (executable-find "ccls"))
  (projectile-project-root-files-top-down-recurring
   (append '("compile_commands.json" ".ccls")
           projectile-project-root-files-top-down-recurring))
  :config (push ".ccls-cache" projectile-globally-ignored-directories))

(use-package cmake-mode
  :mode ("CMakeLists\\.txt\\'" "\\.cmake\\'"))

(use-package cmake-font-lock
  :after (cmake-mode)
  :hook (cmake-mode . cmake-font-lock-activate))

(use-package google-c-style
  :hook ((c-mode c++-mode) . google-set-c-style)
  (c-mode-common . google-make-newline-indent))

(use-package arduino-mode)

(use-package typescript-mode
  :hook (typescript-mode . (lambda () (electric-indent-local-mode -1) (setq-local create-lockfiles nil)))
  :init
  (define-derived-mode typescript-tsx-mode typescript-mode "tsx")
  :config
  (setq typescript-indent-level 2)
  (add-to-list 'auto-mode-alist '("\\.tsx?\\'" . typescript-tsx-mode)))

(use-package tree-sitter
  :hook ((typescript-mode . tree-sitter-hl-mode)
         (typescript-tsx-mode . tree-sitter-hl-mode)))

(use-package tree-sitter-langs
  :after tree-sitter
  :config
  (tree-sitter-require 'tsx)
  (add-to-list 'tree-sitter-major-mode-language-alist '(typescript-tsx-mode . tsx)))

(use-package rjsx-mode
  :hook (rjsx-mode . (lambda () (electric-indent-local-mode -1) (setq-local create-lockfiles nil)))
  :mode "\\.js.*$")

(use-package json-mode
  :mode "\\.json$")

(use-package prettier-js
  :hook ((typescript-mode typescript-tsx-mode rjsx-mode json-mode css-mode html-mode) . prettier-js-mode)
  :config
  (setq prettier-js-show-errors nil))

(use-package geiser-mit)

(use-package macrostep-geiser
  :after geiser-mode
  :config (add-hook 'geiser-mode-hook #'macrostep-geiser-setup))

(use-package macrostep-geiser
  :after geiser-repl
  :config (add-hook 'geiser-repl-mode-hook #'macrostep-geiser-setup))

(defun +org|setup-ui ()
  "Configures the UI for `org-mode'."
  (auto-fill-mode 0)
  (visual-line-mode 1)
  (setq-default org-adapt-indentation nil
                org-cycle-include-plain-lists t
                org-eldoc-breadcrumb-separator " → "
                org-entities-user '(("flat" "\\flat" nil "" "" "266D" "♭") ("sharp" "\\sharp" nil "" "" "266F" "♯"))
                org-fontify-done-headline t
                org-fontify-quote-and-verse-blocks t
                org-fontify-whole-heading-line t
                org-footnote-auto-label 'plain
                org-hidden-keywords nil
                org-hide-emphasis-markers t
                org-hide-leading-stars t
                org-hide-leading-stars-before-indent-mode t
                org-image-actual-width nil
                org-indent-indentation-per-level 2
                org-indent-mode-turns-on-hiding-stars t
                org-list-description-max-indent 4
                org-pretty-entities nil
                org-pretty-entities-include-sub-superscripts t
                org-priority-faces '((?a . error) (?b . warning) (?c . success))
                org-refile-targets '((nil :maxlevel . 3) (org-agenda-files :maxlevel . 3))
                org-startup-folded t
                org-startup-indented t
                org-startup-with-inline-images nil
                org-tags-column 0
                org-todo-keywords '((sequence "TODO(t)" "|" "DONE(d)") (sequence "[ ](T)" "[-](p)" "[?](m)" "|" "[X](D)") (sequence "NEXT(n)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)"))
                org-todo-keyword-faces '(("[-]" :inherit (font-lock-constant-face bold)) ("[?]" :inherit (warning bold)) ("WAITING" :inherit bold) ("LATER" :inherit (warning bold)))
                org-use-sub-superscripts '{}))

(add-hook 'org-mode-hook #'+org|setup-ui)

(setq org-src-preserve-indentation nil
      org-edit-src-content-indentation 0)

(font-lock-add-keywords 'org-mode
                        '(("^ *\\([-]\\) "
                           (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))

(custom-theme-set-faces
 'user
 '(org-block ((t (:inherit fixed-pitch))))
 '(org-code ((t (:inherit (shadow fixed-pitch)))))
 '(org-document-info ((t (:foreground "dark orange"))))
 '(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
 '(org-indent ((t (:inherit (org-hide fixed-pitch)))))
 '(org-link ((t (:foreground "royal blue" :underline t))))
 '(org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 '(org-property-value ((t (:inherit fixed-pitch))) t)
 '(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
 '(org-table ((t (:inherit fixed-pitch :foreground "#83a598"))))
 '(org-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.8))))
 '(org-verbatim ((t (:inherit (shadow fixed-pitch))))))

(defun ck/org-confirm-babel-evaluate (lang body)
  (not (or (string= lang "latex") (string= lang "emacs-lisp") (string= lang "ledger"))))
(setq org-confirm-babel-evaluate 'ck/org-confirm-babel-evaluate)

;; Change colours for headings
(custom-set-faces
 '(default     ((t (:foreground "#BBC2CF"))))
 '(org-level-1 ((t (:foreground "#BF9D7A"))))
 '(org-level-2 ((t (:foreground "#E4E9CD"))))
 '(org-level-3 ((t (:foreground "#EBF2EA"))))
 '(org-level-4 ((t (:foreground "#0ABDA0"))))
 '(org-level-5 ((t (:foreground "#80ADD7")))))

(use-package org-superstar
  :diminish org-superstar-mode
  :hook (org-mode . org-superstar-mode))

(use-package org-appear
  :diminish org-appear-mode
  :hook (org-mode . org-appear-mode))

(setq org-directory "~/Nextcloud/org/" ; This way, all org mode files are synced across devices
      org-agenda-files '("~/Nextcloud/org/")
      org-default-notes-file (expand-file-name "notes.org" org-directory)
      org-ellipsis " ▼ "
      org-capture-templates
      '(("t" "todo" entry (file+headline "~/Nextcloud/org/todo.org" "Tasks")
         "* TODO [#A] %?\nSCHEDULED: %(org-insert-time-stamp (org-read-date nil t \"+0d\"))\n%a\n")
        ("j" "Journal Entry" entry (file+olp+datetree "~/Nextcloud/org/journal.org.gpg")
         "* %? %i %a Added: %U")
        ("K" "Cliplink capture task" entry (file "")
         "* TODO %(org-cliplink-capture) \n  SCHEDULED: %t\n" :empty-lines 1))
      org-log-done 'time
      org-journal-date-format "%B %d, %Y (%A) "
      org-hide-emphasis-markers t
      org-link-abbrev-alist    ; This overwrites the default Doom org-link-abbrev-list
      '(("google" . "http://www.google.com/search?q=")
        ("arch-wiki" . "https://wiki.archlinux.org/index.php/")
        ("ddg" . "https://duckduckgo.com/?q=")
        ("wiki" . "https://en.wikipedia.org/wiki/"))
      org-todo-keywords        ; This overwrites the default Doom org-todo-keywords
      '((sequence
         "TODO(t)"           ; A task that is ready to be tackled
         "BLOG(b)"           ; Blog writing assignments
         "GYM(g)"            ; Things to accomplish at the gym
         "PROJ(p)"           ; A project that contains other tasks
         "VIDEO(v)"          ; Video assignments
         "WAIT(w)"           ; Something is holding up this task
         "|"                 ; The pipe necessary to separate "active" states and "inactive" states
         "DONE(d)"           ; Task has been completed
         "CANCELLED(c)"))) ; Task has been cancelled

(setq calc-angle-mode 'rad  ; radians are rad, screw degrees
      calc-symbolic-mode t) ; keeps expressions like \sqrt{2} irrational for as long as possible

(with-eval-after-load 'org-indent
  (add-hook 'org-mode-hook 'org-indent-mode))

;; Word choice and such
(use-package writegood-mode
  :bind ("C-c g" . writegood-mode)
  :config
  (add-to-list 'writegood-weasel-words "actionable"))

;; Various good settings
(setq org-agenda-window-setup (quote current-window)) ;; open agenda in current window
(setq org-deadline-warning-days 7) ;; warn me of any deadlines in next 7 days
(setq org-agenda-span (quote fortnight)) ;; show me tasks scheduled or due in next fortnight
(setq org-agenda-skip-scheduled-if-deadline-is-shown t) ;; don't show tasks as scheduled if they are already shown as a deadline
(setq org-agenda-skip-deadline-prewarning-if-scheduled (quote pre-scheduled))
(setq org-agenda-todo-ignore-deadlines (quote all))
(setq org-agenda-todo-ignore-scheduled (quote all))
(setq org-agenda-sorting-strategy
      (quote
       ((agenda deadline-up priority-down)
        (todo priority-down category-keep)
        (tags priority-down category-keep)
        (search category-keep))))

(use-package org-journal
  :init
  (setq org-journal-prefix-key "C-x j")
  :config
  (setq org-journal-dir "~/Nextcloud/org/journal/"
        org-journal-date-format "%A, %d %B %Y"))

(use-package ob-hy)
(use-package ob-rust)

(org-babel-do-load-languages
 'org-babel-load-languages
 '((arduino . t)
   (C . t)
   (emacs-lisp . t)
   (gnuplot . t)
   (hy . t)
   (js . t)
   (latex . t)
   (lisp . t)
   (python . t)
   (rust . t)
   (shell . t)))

(setq org-roam-v2-ack t)

(use-package org-roam
      :custom
      (org-roam-v2-ack t)
      (org-roam-db-gc-threshold most-positive-fixnum)
      (org-roam-directory (file-truename "~/Nextcloud/org/org-roam"))
      :config
      (org-roam-setup)
      (require 'org-roam-protocol))

(use-package org-roam-ui
    :after org-roam
    :hook (after-init . org-roam-ui-mode)
    :config
    (setq org-roam-ui-sync-theme t
          org-roam-ui-follow t
          org-roam-ui-update-on-save t
          org-roam-ui-open-on-start t))

(use-package org-cliplink
  :config
  (global-set-key (kbd "C-x p i") 'org-cliplink))

(use-package org-web-tools
  :custom
  (org-web-tools-pandoc-sleep-time 0.5))

(defun dw/org-present-prepare-slide ()
  (org-overview)
  (org-show-entry)
  (org-show-children))

(defun dw/org-present-hook ()
  (setq-local face-remapping-alist '((default (:height 1.5) variable-pitch)
                                     (header-line (:height 4.5) variable-pitch)
                                     (org-code (:height 1.55) org-code)
                                     (org-verbatim (:height 1.55) org-verbatim)
                                     (org-block (:height 1.25) org-block)
                                     (org-block-begin-line (:height 0.7) org-block)))
  (setq header-line-format " ")
  (org-display-inline-images)
  (dw/org-present-prepare-slide))

(defun dw/org-present-quit-hook ()
  (setq-local face-remapping-alist '((default variable-pitch default)))
  (setq header-line-format nil)
  (org-present-small)
  (org-remove-inline-images))

(defun dw/org-present-prev ()
  (interactive)
  (org-present-prev)
  (dw/org-present-prepare-slide))

(defun dw/org-present-next ()
  (interactive)
  (org-present-next)
  (dw/org-present-prepare-slide))

(use-package org-present
  :bind (:map org-present-mode-keymap
              ("C-c C-j" . dw/org-present-next)
              ("C-c C-k" . dw/org-present-prev))
  :hook ((org-present-mode . dw/org-present-hook)
         (org-present-mode-quit . dw/org-present-quit-hook)))

(use-package org-make-toc
  :hook (org-mode . org-make-toc-mode))

;; NO spell check for embedded snippets
(defadvice org-mode-flyspell-verify (after org-mode-flyspell-verify-hack activate)
  (let* ((rlt ad-return-value)
         (begin-regexp "^[ \t]*#\\+begin_\\(src\\|html\\|latex\\|example\\|quote\\)")
         (end-regexp "^[ \t]*#\\+end_\\(src\\|html\\|latex\\|example\\|quote\\)")
         (case-fold-search t)
         b e)
    (when ad-return-value
      (save-excursion
        (setq b (re-search-backward begin-regexp nil t))
        (if b (setq e (re-search-forward end-regexp nil t))))
      (if (and b e (< (point) e)) (setq rlt nil)))
    (setq ad-return-value rlt)))

(use-package general
  :init
  ;; My Caps Lock is bound to escape, so this is always close.
  (defconst my-leader "<escape>")
  (general-create-definer my-leader-def :prefix my-leader)
  (general-auto-unbind-keys)
  :config
  (my-leader-def
    "" '(:ignore t :wk "personal keybindings"))
  ;; Org Agenda
  (my-leader-def
    "a" '(:ignore t :wk "org")
    "aa" '(org-agenda :wk "agenda"))
  ;; Org Roam
  (my-leader-def
    "n" '(:ignore t :wk "org roam")
    "nl" '(org-roam-buffer-toggle :wk "buffer toggle")
    "nf" '(org-roam-node-find :wk "find node")
    "ng" '(org-roam-graph :wk "graph")
    "ni" '(org-roam-node-insert :wk "insert node")
    "nc" '(org-roam-capture :wk "capture")
    "nj" '(org-roam-dailies-capture-today :wk "daily capture")
    "nu" '(org-roam-ui-open :wk "ui")))
;;; init.el -*- lexical-binding: t; -*-

;; Load my modules
(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory))

(require 'catsters-straight)
(require 'catsters-keymap)
(require 'catsters-options)
(require 'catsters-utilities)
(require 'catsters-minibuffer)

;; Language configs
(require 'catsters-py)
(require 'catsters-rs)
(require 'catsters-cc)
(require 'catsters-jl)
(require 'catsters-web)
(require 'catsters-org)
(require 'catsters-text)

;; Use tree sitter
(require 'catsters-treesitter)

;; LSP and other related utilities (wait until other language modes are installed)
(require 'catsters-programming)

A modules/catsters-cc.el => modules/catsters-cc.el +15 -0
@@ 0,0 1,15 @@
;;; catsters-cc.el --- C/C++ lang -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package cmake-font-lock
  :after (cmake-mode)
  :hook (cmake-mode . cmake-font-lock-activate))

(use-package google-c-style
  :hook ((c-mode c++-mode c-ts-mode c++-ts-mode) . google-set-c-style))

(use-package arduino-mode)

(provide 'catsters-cc)
;;; catsters-cc.el ends here

A modules/catsters-jl.el => modules/catsters-jl.el +14 -0
@@ 0,0 1,14 @@
;;; catsters-jl.el --- Julia lang -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package julia-ts-mode
  :mode "\\.jl$"
  :custom
  (setq julia-ts-mode-hook julia-mode-hook))

(use-package julia-vterm
  :hook (julia-mode . julia-vterm-mode))

(provide 'catsters-jl)
;;; catsters-jl.el ends here

A modules/catsters-keymap.el => modules/catsters-keymap.el +17 -0
@@ 0,0 1,17 @@
;;; catsters-keymap.el --- Custom keybindings -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package general
  :demand t
  :init
  ;; My Caps Lock is bound to escape, so this is always close.
  (defconst my-leader "<escape>")
  (general-create-definer my-leader-def :prefix my-leader)
  (general-auto-unbind-keys)
  :config
  (my-leader-def
    "" '(:ignore t :wk "personal keybindings")))

(provide 'catsters-keymap)
;;; catsters-keymap.el ends here

A modules/catsters-minibuffer.el => modules/catsters-minibuffer.el +204 -0
@@ 0,0 1,204 @@
;;; catsters-minibuffer.el --- Config for minibuffer completion       -*- lexical-binding: t; -*-
;;; Commentary:
;;; Code:

(use-package marginalia
  :general
  (:keymaps 'minibuffer-local-map
            "M-A" 'marginalia-cycle)
  :custom
  (marginalia-align-offset 5)
  (marginalia-max-relative-age 0)
  :init
  (marginalia-mode))

(use-package consult-dir
  :bind (("C-x C-d" . consult-dir)
         :map vertico-map
         ("C-x C-d" . consult-dir)
         ("C-x C-j" . consult-dir-jump-file))
  :custom
  (consult-dir-project-list-function #'consult-dir-projectile-dirs)
  :config
  (add-to-list 'consult-dir-sources 'consult-dir--source-tramp-ssh t))

(use-package vertico :straight  (vertico :files (:defaults "extensions/*") ; Special recipe to load extensions conveniently
                                       :includes (vertico-indexed
                                                  vertico-flat
                                                  vertico-grid
                                                  vertico-mouse
                                                  vertico-quick
                                                  vertico-buffer
                                                  vertico-repeat
                                                  vertico-reverse
                                                  vertico-directory
                                                  vertico-multiform
                                                  vertico-unobtrusive
                                                  ))
  :demand t
  :general
  (:keymaps 'vertico-map
            "<tab>" #'vertico-insert ; Set manually otherwise setting `vertico-quick-insert' overrides this
            "<escape>" #'minibuffer-keyboard-quit
            "?" #'minibuffer-completion-help
            "C-M-n" #'vertico-next-group
            "C-M-p" #'vertico-previous-group
            ;; Multiform toggles
            "<backspace>" #'vertico-directory-delete-char
            "C-w" #'vertico-directory-delete-word
            "C-<backspace>" #'vertico-directory-delete-word
            "RET" #'vertico-directory-enter
            "C-i" #'vertico-quick-insert
            "C-o" #'vertico-quick-exit
            "M-o" #'kb/vertico-quick-embark
            "M-G" #'vertico-multiform-grid
            "M-F" #'vertico-multiform-flat
            "M-R" #'vertico-multiform-reverse
            "M-U" #'vertico-multiform-unobtrusive
            )
  :hook (
         (minibuffer-setup . vertico-repeat-save) ; Make sure vertico state is saved
         )
  :custom
  (vertico-count 13)
  (vertico-resize t)
  (vertico-cycle nil)
  ;; Extensions
  (vertico-grid-separator "       ")
  (vertico-grid-lookahead 50)
  (vertico-buffer-display-action '(display-buffer-reuse-window))
  (vertico-multiform-categories
   '((file reverse)
     (consult-grep buffer)
     (consult-location)
     (imenu buffer)
     (library reverse indexed)
     (t reverse)
     ))
  (vertico-multiform-commands
   '(("flyspell-correct-*" grid reverse)
     (org-refile grid reverse indexed)
     (consult-yank-pop indexed)
     (consult-flycheck)
     (consult-lsp-diagnostics)
     ))
  :init
  (defun kb/vertico-multiform-flat-toggle ()
    "Toggle between flat and reverse."
    (interactive)
    (vertico-multiform--display-toggle 'vertico-flat-mode)
    (if vertico-flat-mode
        (vertico-multiform--temporary-mode 'vertico-reverse-mode -1)
      (vertico-multiform--temporary-mode 'vertico-reverse-mode 1)))
  (defun kb/vertico-quick-embark (&optional arg)
    "Embark on candidate using quick keys."
    (interactive)
    (when (vertico-quick-jump)
      (embark-act arg)))

  ;; Workaround for problem with `tramp' hostname completions. This overrides
  ;; the completion style specifically for remote files! See
  ;; https://github.com/minad/vertico#tramp-hostname-completion
  (defun kb/basic-remote-try-completion (string table pred point)
    (and (vertico--remote-p string)
         (completion-basic-try-completion string table pred point)))
  (defun kb/basic-remote-all-completions (string table pred point)
    (and (vertico--remote-p string)
         (completion-basic-all-completions string table pred point)))
  (add-to-list 'completion-styles-alist
               '(basic-remote           ; Name of `completion-style'
                 kb/basic-remote-try-completion kb/basic-remote-all-completions nil))
  :config
  (vertico-mode)
  ;; Extensions
  (vertico-multiform-mode)

  ;; Prefix the current candidate with “» ”. From
  ;; https://github.com/minad/vertico/wiki#prefix-current-candidate-with-arrow
  (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)))
  )

(use-package orderless
  :custom
  (completion-styles '(orderless))
  (completion-category-defaults nil)    ; I want to be in control!
  (completion-category-overrides
   '((file (styles basic-remote ; For `tramp' hostname completion with `vertico'
                   orderless
                   ))
     ))

  (orderless-component-separator 'orderless-escapable-split-on-space)
  (orderless-matching-styles
   '(orderless-literal
     orderless-prefixes
     orderless-initialism
     orderless-regexp
     ;; orderless-flex
     ;; orderless-strict-leading-initialism
     ;; orderless-strict-initialism
     ;; orderless-strict-full-initialism
     ;; orderless-without-literal          ; Recommended for dispatches instead
     ))
  (orderless-style-dispatchers
   '(prot-orderless-literal-dispatcher
     prot-orderless-strict-initialism-dispatcher
     prot-orderless-flex-dispatcher
     ))
  :init
  (defun orderless--strict-*-initialism (component &optional anchored)
    "Match a COMPONENT as a strict initialism, optionally ANCHORED.
The characters in COMPONENT must occur in the candidate in that
order at the beginning of subsequent words comprised of letters.
Only non-letters can be in between the words that start with the
initials.

If ANCHORED is `start' require that the first initial appear in
the first word of the candidate.  If ANCHORED is `both' require
that the first and last initials appear in the first and last
words of the candidate, respectively."
    (orderless--separated-by
        '(seq (zero-or-more alpha) word-end (zero-or-more (not alpha)))
      (cl-loop for char across component collect `(seq word-start ,char))
      (when anchored '(seq (group buffer-start) (zero-or-more (not alpha))))
      (when (eq anchored 'both)
        '(seq (zero-or-more alpha) word-end (zero-or-more (not alpha)) eol))))

  (defun orderless-strict-initialism (component)
    "Match a COMPONENT as a strict initialism.
This means the characters in COMPONENT must occur in the
candidate in that order at the beginning of subsequent words
comprised of letters.  Only non-letters can be in between the
words that start with the initials."
    (orderless--strict-*-initialism component))

  (defun prot-orderless-literal-dispatcher (pattern _index _total)
    "Literal style dispatcher using the equals sign as a suffix.
It matches PATTERN _INDEX and _TOTAL according to how Orderless
parses its input."
    (when (string-suffix-p "=" pattern)
      `(orderless-literal . ,(substring pattern 0 -1))))

  (defun prot-orderless-strict-initialism-dispatcher (pattern _index _total)
    "Leading initialism  dispatcher using the comma suffix.
It matches PATTERN _INDEX and _TOTAL according to how Orderless
parses its input."
    (when (string-suffix-p "," pattern)
      `(orderless-strict-initialism . ,(substring pattern 0 -1))))

  (defun prot-orderless-flex-dispatcher (pattern _index _total)
    "Flex  dispatcher using the tilde suffix.
It matches PATTERN _INDEX and _TOTAL according to how Orderless
parses its input."
    (when (string-suffix-p "." pattern)
      `(orderless-flex . ,(substring pattern 0 -1)))))

(provide 'catsters-minibuffer)
;;; catsters-minibuffer.el ends here

A modules/catsters-options.el => modules/catsters-options.el +327 -0
@@ 0,0 1,327 @@
;;; catsters-options.el --- General options for Emacs -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(defconst IS-MAC     (eq system-type 'darwin))
(defconst IS-LINUX   (eq system-type 'gnu/linux))

;; Welcome Message!
(setq initial-scratch-message "Welcome to the Catster's Emacs Configuration!")
(setq initial-major-mode 'fundamental-mode)

;; Prevent unwanted runtime builds in gccemacs (native-comp); packages are
;; compiled ahead-of-time when they are installed and site files are compiled
;; when gccemacs is installed.
(setq comp-deferred-compilation nil)
(setq comp-async-report-warnings-errors nil)

;;; Shut up, startup
(setq ad-redefinition-action 'accept)
(setq warning-minimum-level :error)

(unless (daemonp)
  (advice-add #'display-startup-echo-area-message :override #'ignore))

(setq inhibit-startup-message t)
(setq large-file-warning-threshold nil)
(setq ad-redefinition-action 'accept)
(setq inhibit-startup-echo-area-message user-login-name)
(setq inhibit-default-init t)
(setq byte-compile-warnings '(not cl-functions))

;;; Optimizations!
;; Don't rely on case insensitivity.
(setq auto-mode-case-fold nil)

;; Disabling bidirectional text rendering gives a performance boost.
(setq-default bidi-display-reordering 'left-to-right
              bidi-paragraph-direction nil)
(setq bidi-inhibit-bpa t)

;; Don't render in non-focused, why would you?
(setq-default cursor-in-non-selected-windows nil)
(setq highlight-nonselected-windows nil)

;; *Zoom* scrolling
(setq fast-but-imprecise-scrolling t)

;; Can't figure out what for, but this is needed.
(require 'ido)

;; Why are you pinging domain names?
(setq ffap-machine-p-known 'reject)

;; Here's where we handle the GC
(setq gcmh-idle-delay 5
      gc-cons-threshold (* 2000 1024 1024) ;; 2000mb
      gcmh-high-cons-threshold (* 4000 1024 1024))  ;; 4000mb

;; This increases from the default of 4k, helps LSP
(setq read-process-output-max (* 16 1024 1024)) ;; 16mb

;; Slow the UI updates
(setq idle-update-delay 1.0)

;; Increase memory usage, but increase performance. No thank you, font compacting!
(setq inhibit-compacting-font-caches t)

;; I said, **Zoom** scrolling!
(setq redisplay-skip-fontification-on-input t)

;; Remove unnecessary CLI options
(unless IS-MAC   (setq command-line-ns-option-alist nil))
(unless IS-LINUX (setq command-line-x-option-alist nil))

;; A hack from Doom, this helps with terminal Emacs startup
(unless (daemonp)
  (advice-add #'tty-run-terminal-initialization :override #'ignore))

;; Emacs stores `authinfo' in $HOME and in plain-text. WHY!?
(setq auth-sources (list (concat user-emacs-directory "authinfo.gpg")
                         "~/.authinfo"
                         "~/.authinfo.gpg"))

;; UTF-8!
(when (fboundp 'set-charset-priority)
  (set-charset-priority 'unicode))
(set-default-coding-systems 'utf-8)
(prefer-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)

;;; Personal Info
(setq user-full-name "Daniil Rose"
      user-mail-address "daniil.rose@posteo.org")

;;; Settings specifically when I am using my MacBook Pro
(when IS-MAC
  ;; Switch keys around, since it's easier to hit Command
  (setq mac-option-key-is-meta nil
        mac-command-key-is-meta t
        mac-command-modifier 'meta
        mac-option-modifier 'super)

  (setq ns-use-native-fullscreen nil)

  (setq ns-pop-up-frames nil)

  (setq mac-redisplay-dont-reset-vscroll t
        mac-mouse-wheel-smooth-scroll nil)

  ;; Sets `ns-transparent-titlebar' and `ns-appearance' frame parameters so window
  ;; borders will match the enabled theme.
  (and (or (daemonp)
           (display-graphic-p))
       (require 'ns-auto-titlebar nil t)
       (ns-auto-titlebar-mode +1))

  ;; Integrate with Keychain
  (add-to-list 'auth-sources 'macos-keychain-internet)
  (add-to-list 'auth-sources 'macos-keychain-generic)

  ;; Delete files to trash
  (use-package osx-trash
    :init
    (setq delete-by-moving-to-trash t)
    (and IS-MAC
         (not (fboundp 'system-move-file-to-trash))
         (defalias #'system-move-file-to-trash #'osx-trash-move-file-to-trash)))

  (use-package exec-path-from-shell
    :init
    (setq exec-path-from-shell-arguments nil)
    (exec-path-from-shell-initialize)))

;; Usually I'm doing something in SSH
(setq tramp-default-method "ssh")

;; Help with slowdowns related to version control
(remove-hook 'find-file-hooks 'vc-find-file-hook)
(setq vc-follow-symlinks t)

;; Please don't ring the bell
(setq ring-bell-function 'ignore)

;; Set to reasonable tab width
(setq-default tab-width 4)

;; Allow for different resizing
(setq-default window-combination-resize t)

;; Don't accidentally delete a file
(setq-default delete-by-moving-to-trash t)

;; If using unicode, stretch over the symbol
(setq-default x-stretch-cursor t)

;; Set a high undo limit
(setq undo-limit 80000000)

;; Don't auto save by default: we address this with super save
(setq auto-save-default nil)

;; Use ellipsis to truncate info
(setq truncate-string-ellipsis "…")

;; Scroll every 20 lines
(setq scroll-margin 20)

;; Camel case and what not is a word
(global-subword-mode 1)

;; Move the mark after a command
(setq set-mark-command-repeat-pop t)

;; Use radians over degrees, and keep irrational numbers
(setq calc-angle-mode 'rad)
(setq calc-symbolic-mode t)

;; Revert: keep the buffers up to date
(setq global-auto-revert-non-file-buffers t)
(global-auto-revert-mode 1)

;; We don't need line numbers
(line-number-mode nil)

;; Scroll one line at a time
(setq scroll-step 1)

;; Shorten yes or no questions
(defalias 'yes-or-no-p 'y-or-n-p)

;; Backup files
(setq backup-directory-alist '(("." . (expand-file-name "backup" user-emacs-directory)))
      backup-by-copying t    ; Don't delink hardlinks
      version-control t      ; Use version numbers on backups
      delete-old-versions t  ; Automatically delete excess backups
      kept-new-versions 20   ; how many of the newest versions to keep
      kept-old-versions 5)

;; Delete trailing whitespace when saving
(add-hook 'before-save-hook 'delete-trailing-whitespace)

;; Make the default font JetBrains Mono!
(add-to-list 'default-frame-alist '(font . "JetBrainsMono Nerd Font"))

;; Move misc files to a separate directory
(use-package no-littering
  :config
  (require 'recentf)
  (add-to-list 'recentf-exclude no-littering-var-directory)
  (add-to-list 'recentf-exclude no-littering-etc-directory)
  (setq auto-save-file-name-transforms
        `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
  (setq custom-file (expand-file-name "custom.el" user-emacs-directory))
  (recentf-mode))

;; Change the colour theme to tomorrow eighties!
(use-package color-theme-sanityinc-tomorrow
  :init
  (load-theme 'sanityinc-tomorrow-eighties t))

;; Better Defaults!
(unless (memq window-system '(mac ns))
  (menu-bar-mode -1))
(when (fboundp 'tool-bar-mode)
  (tool-bar-mode -1))
(when (fboundp 'scroll-bar-mode)
  (scroll-bar-mode -1))
(when (fboundp 'horizontal-scroll-bar-mode)
  (horizontal-scroll-bar-mode -1))

(autoload 'zap-up-to-char "misc"
  "Kill up to, but not including ARGth occurrence of CHAR." t)

(require 'uniquify)
(setq uniquify-buffer-name-style 'forward)

;; https://www.emacswiki.org/emacs/SavePlace
(save-place-mode 1)

(global-set-key (kbd "M-/") 'hippie-expand)
(global-set-key (kbd "C-x C-b") 'ibuffer)
(global-set-key (kbd "M-z") 'zap-up-to-char)

(global-set-key (kbd "C-s") 'isearch-forward-regexp)
(global-set-key (kbd "C-r") 'isearch-backward-regexp)
(global-set-key (kbd "C-M-s") 'isearch-forward)
(global-set-key (kbd "C-M-r") 'isearch-backward)

(show-paren-mode 1)
(setq-default indent-tabs-mode nil)
(savehist-mode 1)
(setq save-interprogram-paste-before-kill t
      apropos-do-all t
      mouse-yank-at-point t
      require-final-newline t
      load-prefer-newer t
      backup-by-copying t
      frame-inhibit-implied-resize t
      ediff-window-setup-function 'ediff-setup-windows-plain)

;; A better modeline
(use-package doom-modeline
  :demand t
  :custom
  (doom-modeline-height 20)
  (doom-modeline-enable-word-count 1)
  :init
  (doom-modeline-mode 1))

(use-package hide-mode-line
  :demand t
  :hook (completion-list-mode . hide-mode-line-mode))

;; Allow popup frames
(use-package posframe
  :demand t)

;; Icons in Emacs
(use-package all-the-icons
  :demand t
  :custom
  (all-the-icons-scale-factor 1.1)
  :if (display-graphic-p))

;; A superior undo system
(use-package undo-fu
  :demand t
  :general ("C-/" 'undo-fu-only-undo
            "C-S-/" 'undo-fu-only-redo))

(use-package undo-fu-session
  :demand t
  :after undo-fu
  :config
  (setq undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'"))
  (undo-fu-session-global-mode))

;; Better reimplementations of built-in functions
(use-package crux
  :hook (emacs-startup . crux-reopen-as-root-mode)
  :general (;; Consult replacements
            "C-s" 'consult-line
            "C-x b" 'consult-buffer
            ;; Crux replacements
            "C-a" 'crux-move-beginning-of-line
            "C-c o" 'crux-open-with
            "S-RET" 'crux-smart-open-line
            "C-S-RET" 'crux-smart-open-line-above
            "C-c D" 'crux-delete-file-and-buffer
            "C-c r" 'crux-rename-file-and-buffer
            "C-<backspace>" 'crux-kill-line-backwards
            "C-S-<backspace>" 'crux-kill-whole-line
            "C-k" 'crux-smart-kill-line))

(use-package expand-region
  :bind ("C-=" . er/expand-region))

(use-package default-text-scale)

(use-package super-save
  :config
  (super-save-mode +1)
  (setq super-save-auto-save-when-idle t)
  (setq auto-save-default nil))

(provide 'catsters-options)
;;; catsters-options.el ends here

A modules/catsters-org.el => modules/catsters-org.el +114 -0
@@ 0,0 1,114 @@
;;; catsters-org.el --- Org mode settings -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package org
  :straight (:type built-in)
  :hook (org-mode . +org|setup-ui)
  :config
  (defun +org|setup-ui ()
    "Configures the UI for `org-mode'."
    (auto-fill-mode 0)
    (visual-line-mode 1)
    (setq-default org-adapt-indentation nil
                  org-cycle-include-plain-lists t
                  org-eldoc-breadcrumb-separator " → "
                  org-entities-user '(("flat" "\\flat" nil "" "" "266D" "♭") ("sharp" "\\sharp" nil "" "" "266F" "♯"))
                  org-fontify-done-headline t
                  org-fontify-quote-and-verse-blocks t
                  org-fontify-whole-heading-line t
                  org-footnote-auto-label 'plain
                  org-hidden-keywords nil
                  org-hide-emphasis-markers t
                  org-hide-leading-stars t
                  org-hide-leading-stars-before-indent-mode t
                  org-image-actual-width nil
                  org-indent-indentation-per-level 2
                  org-indent-mode-turns-on-hiding-stars t
                  org-list-description-max-indent 4
                  org-pretty-entities nil
                  org-pretty-entities-include-sub-superscripts t
                  org-priority-faces '((?a . error) (?b . warning) (?c . success))
                  org-refile-targets '((nil :maxlevel . 3) (org-agenda-files :maxlevel . 3))
                  org-startup-folded t
                  org-startup-indented t
                  org-startup-with-inline-images nil
                  org-tags-column 0
                  org-todo-keywords '((sequence "TODO(t)" "|" "DONE(d)") (sequence "[ ](T)" "[-](p)" "[?](m)" "|" "[X](D)") (sequence "NEXT(n)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)"))
                  org-todo-keyword-faces '(("[-]" :inherit (font-lock-constant-face bold)) ("[?]" :inherit (warning bold)) ("WAITING" :inherit bold) ("LATER" :inherit (warning bold)))
                  org-use-sub-superscripts '{}))

  (add-hook 'org-mode-hook #'+org|setup-ui)

  (font-lock-add-keywords 'org-mode
                          '(("^ *\\([-]\\) "
                             (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))

  (custom-theme-set-faces
   'user
   '(org-block ((t (:inherit fixed-pitch))))
   '(org-code ((t (:inherit (shadow fixed-pitch)))))
   '(org-document-info ((t (:foreground "dark orange"))))
   '(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
   '(org-indent ((t (:inherit (org-hide fixed-pitch)))))
   '(org-link ((t (:foreground "royal blue" :underline t))))
   '(org-meta-line ((t (:inherit (font-lock-comment-face fixed-pitch)))))
   '(org-property-value ((t (:inherit fixed-pitch))) t)
   '(org-special-keyword ((t (:inherit (font-lock-comment-face fixed-pitch)))))
   '(org-table ((t (:inherit fixed-pitch :foreground "#83a598"))))
   '(org-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.8))))
   '(org-verbatim ((t (:inherit (shadow fixed-pitch))))))

  (defun ck/org-confirm-babel-evaluate (lang body)
    (not (or (string= lang "latex") (string= lang "emacs-lisp") (string= lang "ledger"))))
  (setq org-confirm-babel-evaluate 'ck/org-confirm-babel-evaluate)

  ;; Change colours for headings
  (custom-set-faces
   '(default     ((t (:foreground "#BBC2CF"))))
   '(org-level-1 ((t (:foreground "#BF9D7A"))))
   '(org-level-2 ((t (:foreground "#E4E9CD"))))
   '(org-level-3 ((t (:foreground "#EBF2EA"))))
   '(org-level-4 ((t (:foreground "#0ABDA0"))))
   '(org-level-5 ((t (:foreground "#80ADD7")))))

  (with-eval-after-load 'org-indent
    (add-hook 'org-mode-hook 'org-indent-mode))
  )

(use-package org-superstar
  :diminish org-superstar-mode
  :hook (org-mode . org-superstar-mode))

(use-package org-appear
  :diminish org-appear-mode
  :hook (org-mode . org-appear-mode))

(use-package org-journal
  :init
  (setq org-journal-prefix-key "C-x j")
  :config
  (setq org-journal-dir "~/Documents/org/journal/"
        org-journal-date-format "%A, %d %B %Y"))

(use-package org-make-toc
  :hook (org-mode . org-make-toc-mode))

;; NO spell check for embedded snippets
(defadvice org-mode-flyspell-verify (after org-mode-flyspell-verify-hack activate)
  (let* ((rlt ad-return-value)
         (begin-regexp "^[ \t]*#\\+begin_\\(src\\|html\\|latex\\|example\\|quote\\)")
         (end-regexp "^[ \t]*#\\+end_\\(src\\|html\\|latex\\|example\\|quote\\)")
         (case-fold-search t)
         b e)
    (when ad-return-value
      (save-excursion
        (setq b (re-search-backward begin-regexp nil t))
        (if b (setq e (re-search-forward end-regexp nil t))))
      (if (and b e (< (point) e)) (setq rlt nil)))
    (setq ad-return-value rlt)))



(provide 'catsters-org)
;;; catsters-org.el ends here

A modules/catsters-programming.el => modules/catsters-programming.el +144 -0
@@ 0,0 1,144 @@
;;; catsters-programming.el --- Packages that help with programming -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

;; Hook the tree sitter modes into normal ones
(add-hook 'python-ts-mode-hook 'python-mode-hook)
(add-hook 'yaml-ts-mode-hook 'yaml-mode-hook)
(add-hook 'markdown-ts-mode-hook 'markdown-mode-hook)
(add-hook 'rust-ts-mode-hook 'rustic-mode-hook)

(use-package yasnippet)

;; Inline errors
(use-package flycheck)

;; LSP
(use-package lsp-bridge :straight (lsp-bridge :host github
                                            :repo "manateelazycat/lsp-bridge"
                                            :files ("*.el" "*.py" "acm" "core" "langserver"
                                                    "multiserver" "resources"))
  :demand t
  :hook (after-init . global-lsp-bridge-mode)
  :general (:prefix "C-c l"
                    "l" 'flycheck-list-errors
                    "a" 'lsp-bridge-code-action
                    "r" 'lsp-bridge-rename
                    "f" 'lsp-bridge-code-format
                    "p" 'lsp-bridge-popup-documentation
                    "d" 'lsp-bridge-find-def
                    "?" 'lsp-bridge-find-references)
  :custom
  (acm-enable-quick-access t)
  (acm-backend-yas-match-by-trigger-keyword t)
  (lsp-bridge-enable-hover-diagnostic t)
  (lsp-bridge-enable-auto-format-code nil)
  (lsp-bridge-enable-org-babel t)
  (lsp-bridge-python-lsp-server "pyright")
  (lsp-bridge-python-multi-lsp-server "pyright_ruff")
  (lsp-bridge-tex-lsp-server "digestif")
  (lsp-bridge-c-lsp-server "clangd"))

;; Project Management
(use-package projectile
  :demand t
  :general (:keymaps 'projectile-command-map
                     "p" 'consult-projectile-switch-project
                     "b" 'consult-projectile-switch-to-buffer
                     "f" 'consult-projectile-find-file
                     "d" 'consult-projectile-find-dir
                     "e" 'consult-projectile-recentf)
  :init
  ;; On macOS, I keep all of my programming projects in the Developer folder
  (when IS-MAC
    (when (file-directory-p "~/Developer")
      (setq projectile-project-search-path '("~/Developer"))))
  :config
  (projectile-mode)
  :bind-keymap ("C-c p" . projectile-command-map))

(use-package consult-projectile
  :straight (consult-projectile :type git :host gitlab :repo "OlMon/consult-projectile" :branch "master"))

;; File tree for projects
(use-package treemacs
  :demand t
  :config
  (treemacs-follow-mode t)
  (treemacs-filewatch-mode t)
  (treemacs-fringe-indicator-mode 'always)
  (treemacs-git-mode 'deferred))

(use-package treemacs-projectile
  :demand t)

(use-package treemacs-magit
  :demand t)

;; The BEST Git Client
(use-package magit
  :commands (magit-status magit-get-current-branch)
  :custom
  (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
  :bind ("C-x g" . magit-status))

;; See git status on the side
(use-package git-gutter
  :hook (prog-mode . git-gutter-mode)
  :custom
  (git-gutter:update-interval 2))

;; Easier to distinguish brackets
(use-package rainbow-delimiters
  :hook (prog-mode . rainbow-delimiters-mode))

;; Useful for working with pairs and sexps
(use-package smartparens
  :hook (prog-mode . smartparens-mode)
  :custom
  (sp-highlight-pair-overlay t)
  (sp-autoskip-closing-pair 'always)
  (sp-cancel-autoskip-on-backward-movement nil))

;; Improve grep and search
(use-package fzf)
(use-package deadgrep)
(use-package rg
  :init
  (rg-enable-default-bindings))

;; Highlight various keywords in comments
(use-package hl-todo
  :hook (prog-mode . hl-todo-mode)
  :custom
  (hl-todo-highlight-punctuation ":")
  (hl-todo-keyword-faces
   `(;; For things that need to be done, just not today.
     ("TODO" warning bold)
     ;; For problems that will become bigger problems later if not
     ;; fixed ASAP.
     ("FIXME" error bold)
     ;; For tidbits that are unconventional and not intended uses of the
     ;; constituent parts, and may break in a future update.
     ("HACK" font-lock-constant-face bold)
     ;; For things that were done hastily and/or hasn't been thoroughly
     ;; tested. It may not even be necessary!
     ("REVIEW" font-lock-keyword-face bold)
     ;; For especially important gotchas with a given implementation,
     ;; directed at another user other than the author.
     ("NOTE" success bold)
     ;; For things that just gotta go and will soon be gone.
     ("DEPRECATED" font-lock-doc-face bold)
     ;; For a known bug that needs a workaround
     ("BUG" error bold)
     ;; For warning about a problematic or misguiding code
     ("XXX" font-lock-constant-face bold))))

;; Scrolling output in compilation buffers
(use-package compile
  :straight (:type built-in)
  :custom
  (compilation-scroll-output t))

(provide 'catsters-programming)
;;; catsters-programming.el ends here

A modules/catsters-py.el => modules/catsters-py.el +60 -0
@@ 0,0 1,60 @@
;;; catsters-py.el --- Python lang -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package python
  :bind (("M-[" . python-nav-backward-block)
         ("M-]" . python-nav-forward-block))
  :preface
  (defun python-remove-unused-imports()
    "Removes unused imports and unused variables with autoflake."
    (interactive)
    (if (executable-find "autoflake")
        (progn
          (shell-command (format "autoflake --remove-all-unused-imports -i %s"
                                 (shell-quote-argument (buffer-file-name))))
          (revert-buffer t t t))
      (warn "python-mode: Cannot find autoflake executable."))))

(use-package python-black
  :demand t
  :after python
  :hook (python-mode . python-black-on-save-mode-enable-dwim))

(use-package py-isort
  :after python
  :hook ((python-mode . pyvenv-mode)
         (before-save . py-isort-before-save)))

(use-package pyenv-mode
  :after python
  :hook ((python-mode . pyenv-mode)
         (projectile-switch-project . projectile-pyenv-mode-set))
  :custom (pyenv-mode-set "3.8.5")
  :preface
  (defun projectile-pyenv-mode-set ()
    "Set pyenv version matching project name."
    (let ((project (projectile-project-name)))
      (if (member project (pyenv-mode-versions))
          (pyenv-mode-set project)
        (pyenv-mode-unset)))))

(use-package pyvenv
  :after python
  :hook (python-mode . pyvenv-mode)
  :custom
  (pyvenv-default-virtual-env-name "env")
  (pyvenv-mode-line-indicator '(pyvenv-virtual-env-name ("[venv:"
                                                         pyvenv-virtual-env-name "]"))))

(use-package pipenv
  :hook (python-mode . pipenv-mode)
  :init
  (setq
   pipenv-projectile-after-switch-function
   #'pipenv-projectile-after-switch-extended))

(use-package live-py-mode)

(provide 'catsters-py)
;;; catsters-py.el ends here

A modules/catsters-rs.el => modules/catsters-rs.el +59 -0
@@ 0,0 1,59 @@
;;; catsters-rs.el --- Rust lang -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;; rustic = basic rust-mode + additions

(use-package rustic
  :demand t
  :custom
  (rustic-lsp-setup-p nil))

;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;; for rust-analyzer integration

;; (setq lsp-rust-analyzer-cargo-watch-command "clippy")
;; (setq rustic-lsp-server "rust-analyzer")
;; (setq lsp-rust-server "rust-analyzer")
;; ;; This controls the overlays that display type and other hints inline. Enable
;; ;; / disable as you prefer. Well require a `lsp-workspace-restart' to have an
;; ;; effect on open projects.
;; (setq lsp-rust-analyzer-server-display-inlay-hints t)
;; (setq lsp-rust-analyzer-display-lifetime-elision-hints-enable "skip_trivial")
;; (setq lsp-rust-analyzer-display-chaining-hints t)
;; (setq lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names nil)
;; (setq lsp-rust-analyzer-display-closure-return-type-hints t)
;; (setq lsp-rust-analyzer-display-parameter-hints nil)
;; (setq lsp-rust-analyzer-display-reborrow-hints nil)

;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;; for Cargo.toml and other config files

(use-package toml-mode)

;; -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
;; setting up debugging support with dap-mode

(when (executable-find "lldb-mi")
  (use-package dap-mode
    :config
    (dap-ui-mode)
    (dap-ui-controls-mode 1)

    (require 'dap-lldb)
    (require 'dap-gdb-lldb)
    ;; installs .extension/vscode
    (dap-gdb-lldb-setup)
    (dap-register-debug-template
     "Rust::LLDB Run Configuration"
     (list :type "lldb"
           :request "launch"
           :name "LLDB::Run"
	         :gdbpath "rust-lldb"
           ;; uncomment if lldb-mi is not in PATH
           ;; :lldbmipath "path/to/lldb-mi"
           ))))

(provide 'catsters-rs)
;;; catsters-rs.el ends here

A modules/catsters-straight.el => modules/catsters-straight.el +24 -0
@@ 0,0 1,24 @@
;;; catsters-straight.el --- Package management -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(setq straight-repository-branch "develop")

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/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)
(setq straight-use-package-by-default t)

(provide 'catsters-straight)
;;; catsters-straight.el ends here

A modules/catsters-straight.el~ => modules/catsters-straight.el~ +22 -0
@@ 0,0 1,22 @@
;;; catsters-straight.el --- Package management -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 6))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/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)
(setq straight-use-package-by-default t)

(provide 'catsters-straight)
;;; catsters-straight.el ends here

A modules/catsters-text.el => modules/catsters-text.el +65 -0
@@ 0,0 1,65 @@
;;; catsters-text.el --- Text format support -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(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 latex
  :straight (:type built-in)
  :hook (LaTeX-mode . prettify-symbols-mode)
  :bind (:map LaTeX-mode-map
         ("C-S-e" . latex-math-from-calc))
  :config
  ;; Format math as a Latex string with Calc
  (defun latex-math-from-calc ()
    "Evaluate `calc' on the contents of line at point."
    (interactive)
    (cond ((region-active-p)
           (let* ((beg (region-beginning))
                  (end (region-end))
                  (string (buffer-substring-no-properties beg end)))
             (kill-region beg end)
             (insert (calc-eval `(,string calc-language latex
                                          calc-prefer-frac t
                                          calc-angle-mode rad)))))
          (t (let ((l (thing-at-point 'line)))
               (end-of-line 1) (kill-line 0)
               (insert (calc-eval `(,l
                                    calc-language latex
                                    calc-prefer-frac t
                                    calc-angle-mode rad))))))))

(use-package preview
  :straight (:type built-in)
  :after latex
  :hook (LaTeX-mode . preview-larger-previews)
  :config
  (defun preview-larger-previews ()
    (setq preview-scale-function
          (lambda () (* 1.25
                        (funcall (preview-scale-from-face)))))))

(use-package cdlatex
  :hook (LaTeX-mode . turn-on-cdlatex)
  :bind (:map cdlatex-mode-map
              ("<tab>" . cdlatex-tab)))

(use-package dockerfile-mode
  :mode "Dockerfile\\'")

(use-package docker-compose-mode)

(use-package caddyfile-mode)

(use-package json-mode
  :mode "\\.json$")

(use-package yaml-mode)

(provide 'catsters-text)
;;; catsters-text.el ends here

A modules/catsters-treesitter.el => modules/catsters-treesitter.el +10 -0
@@ 0,0 1,10 @@
;;; catsters-treesitter.el --- Treesitter config -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package treesit-auto
  :config
  (global-treesit-auto-mode))

(provide 'catsters-treesitter)
;;; catsters-treesitter.el ends here

A modules/catsters-utilities.el => modules/catsters-utilities.el +176 -0
@@ 0,0 1,176 @@
;;; catsters-utilities.el --- Nice things to have -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(use-package which-key
  :init
  (which-key-mode))

(defun rk/open-compilation-buffer (&optional buffer-or-name shackle-alist shackle-plist)
  "Helper for selecting window for opening *compilation* buffers."
  ;; find existing compilation window left of the current window or left-most window
  (let ((win (or (loop for win = (if win (window-left win) (get-buffer-window))
                       when (or (not (window-left win))
                                (string-prefix-p "*compilation" (buffer-name (window-buffer win))))
                       return win)
                 (get-buffer-window))))
    ;; if the window is dedicated to a non-compilation buffer, use the current one instead
    (when (window-dedicated-p win)
      (let ((buf-name (buffer-name (window-buffer win))))
        (unless (string-prefix-p "*compilation" buf-name)
          (setq win (get-buffer-window)))))
    (set-window-buffer win (get-buffer buffer-or-name))
    (set-frame-selected-window (window-frame win) win)))


(use-package shackle
  :hook (emacs-startup . shackle-mode)
  :custom
  (shackle-rules '((compilation-mode :custom rk/open-compilation-buffer :select t)
                   ("\\*Apropos\\|Help\\|Occur\\|tide-references\\*" :regexp t :same t :select t :inhibit-window-quit t)
                   ("\\*magit" :regexp t :same t :select t)
                   ("\\*shell.*" :regexp t :same t :select t)
                   ("\\*PowerShell.*" :regexp t :same t :select t)
                   ("\\*Cargo.*" :regexp t :other t :select nil)
                   ("*Messages*" :select nil :other t)
                   ("*go-guru-output*" :select t :same t)
                   ("*Proced*" :select t :same t)
                   ("*Buffer List*" :select t :same t)
                   ("\\*Pp Eval" :regexp t :same nil :select t :other t)
                   ("*Messages*" :same nil :other t :select t :inhibit-window-quit t)

                   ;; slime
                   ("*slime-source*" :select nil :same nil :other t)
                   ("*slime-description*" :select nil :other t :inhibit-window-quit t)
                   ("\\*slime-repl" :regexp t :same nil :select nil :other t)
                   ;; ("\\*sldb" :regexp t :other t :inhibit-window-quit t :select t)
                   ("\\*slime-compilation" :regexp t :same nil :select nil :other t)
                   ("*slime-scratch*" :same nil :select t :other t)

                   ;; ert
                   ("*ert*" :select nil :same nil :other t)

                   ;; vterm
                   ("^\\*vterm" :size 0.25 :select t)

                   ;; clojure
                   ("*sesman CIDER browser*" :inhibit-window-quit t :select t :same t)
                   ("\\*cider-repl" :regexp t :same nil :other t)))
  (shackle-default-rule nil))

;; Killer terminal emulation in Emacs
(use-package vterm
  :demand t
  :hook (vterm-mode . hide-mode-line-mode) ; modeline serves no purpose in vterm
  :preface
  ;; HACK Because vterm clusmily forces vterm-module.so's compilation on us when
  ;;      the package is loaded, this is necessary to prevent it when
  ;;      byte-compiling this file (`use-package' blocks eagerly loads packages
  ;;      when compiled).
  (when noninteractive
    (advice-add #'vterm-module-compile :override #'ignore)
    (provide 'vterm-module))
  :general ("C-c t" 'vterm-other-window)
  :custom
  (vterm-kill-buffer-on-exit t)
  (vterm-max-scrollback 5000))

(use-package helpful
  :config
  ;; Note that the built-in `describe-function' includes both functions
  ;; and macros. `helpful-function' is functions only, so we provide
  ;; `helpful-callable' as a drop-in replacement.
  (global-set-key (kbd "C-h f") #'helpful-callable)

  (global-set-key (kbd "C-h v") #'helpful-variable)
  (global-set-key (kbd "C-h k") #'helpful-key)
  ;; Lookup the current symbol at point. C-c C-d is a common keybinding
  ;; for this in lisp modes.
  (global-set-key (kbd "C-c C-d") #'helpful-at-point)

  ;; Look up *F*unctions (excludes macros).
  ;;
  ;; By default, C-h F is bound to `Info-goto-emacs-command-node'. Helpful
  ;; already links to the manual, if a function is referenced there.
  (global-set-key (kbd "C-h F") #'helpful-function)

  ;; Look up *C*ommands.
  ;;
  ;; By default, C-h C is bound to describe `describe-coding-system'. I
  ;; don't find this very useful, but it's frequently useful to only
  ;; look at interactive functions.
  (global-set-key (kbd "C-h C") #'helpful-command))

  ;; wrapper for save-buffer ignoring arguments
  (defun bjm/save-buffer-no-args ()
    "Save buffer ignoring arguments"
    (save-buffer))

  (use-package pdf-tools
    :config
    ;; initialise
    (pdf-tools-install :no-query)
    (setq-default pdf-view-display-size 'fit-page)
    ;; automatically annotate highlights
    (setq pdf-annot-activate-created-annotations t)
    ;; use isearch instead of swiper
    (define-key pdf-view-mode-map (kbd "C-s") 'isearch-forward)
    ;; turn off cua so copy works
    (add-hook 'pdf-view-mode-hook (lambda () (cua-mode 0)))
    ;; more fine-grained zooming
    (setq pdf-view-resize-factor 1.1)
    ;; keyboard shortcuts
    (define-key pdf-view-mode-map (kbd "h") 'pdf-annot-add-highlight-markup-annotation)
    (define-key pdf-view-mode-map (kbd "t") 'pdf-annot-add-text-annotation)
    (define-key pdf-view-mode-map (kbd "D") 'pdf-annot-delete)
    ;; wait until map is available
    (with-eval-after-load "pdf-annot"
      (define-key pdf-annot-edit-contents-minor-mode-map (kbd "<return>") 'pdf-annot-edit-contents-commit)
      (define-key pdf-annot-edit-contents-minor-mode-map (kbd "<S-return>") 'newline)
      ;; save after adding comment
      (advice-add 'pdf-annot-edit-contents-commit :after 'bjm/save-buffer-no-args)))

;; Fun dashboard for Emacs
(use-package dashboard
  :preface
  (defun my/dashboard-banner ()
    "Set a dashboard banner including information on package initialization
  time and garbage collections."""
    (setq dashboard-banner-logo-title
          (format "Emacs ready in %.2f seconds with %d garbage collections."
                  (float-time (time-subtract after-init-time before-init-time)) gcs-done)))
  :custom
  (dashboard-set-heading-icons t)
  (dashboard-set-file-icons t)
  (dashboard-center-content t)
  :config
  (setq dashboard-startup-banner 'logo)
  (dashboard-setup-startup-hook)
  :hook ((after-init     . dashboard-refresh-buffer)
         (dashboard-mode . my/dashboard-banner)))

(setq initial-buffer-choice (lambda () (get-buffer "*dashboard*")))

;; Docker support built-in
(use-package docker
  :bind ("C-c d" . docker))

;; Enables editorconfig support for cross-IDE settings
(use-package editorconfig
  :config
  (editorconfig-mode 1))

;; See previews of colours in Emacs
(use-package rainbow-mode
  :diminish rainbow-mode
  :hook (prog-mode . rainbow-mode)
  :config
  (setq rainbow-x-colors nil))

(use-package hackernews)

(provide 'catsters-utilities)
;;; catsters-utilities.el ends here




A modules/catsters-web.el => modules/catsters-web.el +6 -0
@@ 0,0 1,6 @@
;;; catsters-web.el --- Web langs -*- lexical-binding: t -*-
;;; Commentary:
;;; Code:

(provide 'catsters-web)
;;; catsters-web.el ends here