(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)
;; Of course Windows does it's own thing D:
(when IS-WINDOWS
(setq w32-get-true-file-attributes nil
w32-pipe-read-delay 0
w32-pipe-buffer-size (* 64 1024)))
;; 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"))
;; Of course Windows does it's own thing.
(when (and IS-WINDOWS (null (getenv-internal "HOME")))
(setenv "HOME" (getenv "USERPROFILE"))
(setq abbreviated-home-dir nil))
;; 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)
;; Of course Windows does it's own thing.
(unless IS-WINDOWS
(setq selection-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
;;(auth-sources 'macos-keychain-internet '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)))
(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 12"))
(use-package emojify
:hook (erc-mode . emojify-mode)
: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)
(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))
;; 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 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 yasnippet-snippets)
(use-package yasnippet
: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 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 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 nil)
(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 dockerfile-mode
:mode "Dockerfile\\'")
(use-package docker-compose-mode)
(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 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
;; :straight (:host github :repo "tecosaur/screenshot"))
(use-package ledger-mode)
(use-package flycheck-ledger
:after ledger-mode)
(use-package elfeed
:config
(setq elfeed-use-curl t))
(use-package elfeed-protocol
:after elfeed
:config
(setq elfeed-protocol-fever-maxsize 50)
(setq elfeed-feeds
(list (list "fever+https://thecatster@rss.danielr.xyz/"
:api-url "https://rss.danielr.xyz/fever/"
:use-authinfo t
:autotags '(("www.cnx-software.com" embedded)))))
(elfeed-protocol-enable))
(use-package elfeed-goodies
:after elfeed
:config
(setq elfeed-goodies/entry-pane-position 'bottom)
(elfeed-goodies/setup))
(use-package elfeed-dashboard
:config
(setq elfeed-dashboard-file "~/.emacs.d/elfeed-dashboard.org")
(advice-add 'elfeed-search-quit-window :after #'elfeed-dashboard-update-links))
(use-package elfeed-autotag
:config
(setq elfeed-autotag-files '("~/Nextcloud/org/elfeed.org"))
(elfeed-autotag))
(use-package scad-mode)
(use-package scad-preview)
(use-package simple-httpd)
(setq catster/use-mail nil)
(when catster/use-mail
(add-to-list 'load-path "~/.emacs.d/mu4e/")
(require 'catsters-mail))
(show-paren-mode 1)
(use-package smartparens
:hook (prog-mode . smartparens-mode)
:config
(setq sp-highlight-pair-overlay nil)
(setq sp-autoskip-closing-pair 'always)
(setq sp-cancel-autoskip-on-backward-movement nil))
(use-package compile
:custom
(compilation-scroll-output t))
(use-package parinfer-rust-mode
:hook ((emacs-lisp-mode clojure-mode lisp-mode hy-mode racket-mode). parinfer-rust-mode)
:init
(setq parinfer-rust-auto-download t)
(setq parinfer-rust-preferred-mode 'paren))
(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 fzf)
(use-package deadgrep)
(use-package flycheck
:hook ((lsp-mode ledger-mode) . flycheck-mode)
:config
(setq-default flycheck-temp-prefix ".flycheck"))
(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'."
(org-indent-mode)
(auto-fill-mode 0)
(visual-line-mode 1)
(diminish org-indent-mode)
(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
(org-indent-mode 1)
;; 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"))
:bind (("C-c n l" . org-roam-buffer-toggle)
("C-c n f" . org-roam-node-find)
("C-c n g" . org-roam-graph)
("C-c n i" . org-roam-node-insert)
("C-c n c" . org-roam-capture)
;; Dailies
("C-c n j" . org-roam-dailies-capture-today))
: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)))