This is my personal Emacs configuration using basemacs at its core, Meow for editing, and Eglot for coding. It is essentially cobbled together from bits and pieces of other configs I have found online. I have been tweaking it (and will probably continue to tweak it) for several years now. It is a “Literate” config, where prose and code live together in harmony… what this basically means is that configuration code is in this Org file, along with some text that describes what it’s doing.
The primary goal is to (try) to keep things simple. My hope is that this will keep things easy to understand, fast, and bug-free. Some ways I attempt do this are:
- Using
use-package
for almost everything. - Using built in packages where I think it makes sense (e.g.
project.el
overprojectile
). - Keeping things modular.
The code here is tangled using M-x org-babel-tangle
, which creates init.el
and various “modules” in the lisp/
directory.
Let’s get everything setup!
;;; init.el --- -*- lexical-binding: t no-byte-compile: t -*-
Add the lisp/
directory to the load-path
so we can load basemacs-core
, modules, and any other custom lisp code.
(add-to-list 'load-path (expand-file-name "lisp" user-emacs-directory))
Load the base config. This gives us use-package
(along with some other handy packages) and some sane defaults to start with.
(require 'basemacs-core)
Set up the leader keys for general.el
.
(use-package basemacs-core
:custom
(basemacs-leader "C-c")
(basemacs-local-leader "C-c m"))
Here is where the magic happens. Let’s load some modules!
;; emacs
(require 'kpav-defaults)
(require 'kpav-system)
(require 'kpav-meow)
;; (require 'kpav-evil)
(require 'kpav-keys)
(require 'kpav-narrowing)
(require 'kpav-org)
(require 'kpav-ui)
(require 'kpav-windows-and-buffers)
;; prose
(require 'kpav-markdown)
(require 'kpav-org-roam)
;; tools
(require 'kpav-project)
(require 'kpav-git)
(require 'kpav-vterm)
;; (require 'kpav-eshell)
(require 'kpav-docker)
(require 'kpav-irc)
(require 'kpav-guix)
;; code
(require 'kpav-code)
(require 'kpav-php)
(require 'kpav-elisp)
(require 'kpav-clojure)
(require 'kpav-common-lisp)
(require 'kpav-scheme)
(require 'kpav-js)
(require 'kpav-python)
;; (require 'kpav-c)
(require 'kpav-yaml)
;; (require 'kpav-grpc)
(require 'kpav-graphql)
(require 'kpav-nix)
System specific configuration is done in lisp/kpav-local.el
. This loads that file if it exists.
(defconst kpav-local-file (expand-file-name "lisp/kpav-local.el" user-emacs-directory))
(when (file-exists-p kpav-local-file)
(load kpav-local-file))
Things that modify Emacs itself.
Some of my more “opinionated” default settings.
;;; kpav-defaults.el --- -*- lexical-binding: t -*-
Add pixel-scroll-precision
mode. Emacs treats images like a single character
(use-package emacs
:straight (:type built-in)
:custom
(pixel-scroll-mode +1))
Insert matching pairs for things like parens, brackets, quotes, etc. Use it in programming and org modes.
(use-package elec-pair
:straight (:type built-in)
:gfhook
('(prog-mode-hook org-mode-hook) #'electric-pair-mode))
Highlight paren when the cursor is over its matching pair. Also reduce the delay of it to 0
so it will be instant.
(use-package paren
:straight (:type built-in)
:custom
(show-paren-delay 0)
:config
(show-paren-mode +1))
Emacs likes to create lots of extra files for things, these settings prevent that. Also, create a newline at the end of the file on save.
(use-package files
:straight (:type built-in)
:custom
(make-backup-files nil) ;; stop creating backup~ files
(auto-save-default nil) ;; stop creating #autosave# files
(create-lockfiles nil) ;; stop creating .# files
;; (require-final-newline t)
) ;; auto add newline at the end of file
When you visit a file, point goes to the last place where it was when you previously visited the same file.
(use-package saveplace
:straight (:type built-in)
:config
(save-place-mode +1))
See recently opened files.
(use-package recentf
:straight (:type built-in)
:ghook
('after-init-hook #'recentf-mode))
Show whitespace and newlines.
(use-package emacs
:straight (:type built-in)
:gfhook
('(prog-mode-hook org-mode-hook)
(lambda ()
(setq show-trailing-whitespace t
indicate-buffer-boundaries 'left))))
Periods should be followed by a single space, not double spaces
(use-package emacs
:straight (:type built-in)
:config
(setq sentence-end-double-space nil))
Use spaces for indentation, not tabs. Set the width to 4 instead of the default of 8.
(use-package emacs
:straight (:type built-in)
:config
(setq-default indent-tabs-mode nil
tab-width 4))
super-save auto-saves your buffers, when certain events happen - e.g. you switch between buffers, an Emacs frame loses focus, etc.
(use-package super-save
:straight t
:init
:config
(add-to-list 'super-save-triggers 'ace-window)
(super-save-mode +1))
Workaround for compat issue and elpa, see: magit/magit#4841 radian-software/straight.el#1049 radian-software/gnu-elpa-mirror#14
;; (straight-use-package '(compat :host github :repo "emacs-compat/compat"))
(provide 'kpav-defaults)
;;; kpav-defaults.el ends here
Find and replace
;;; kpav-text-editing.el --- -*- lexical-binding: t -*-
(use-package anzu
:straight t
:config
(global-anzu-mode +1))
(provide 'kpav-defaults)
;;; kpav-text-editing.el ends here
;;; kpav-meow.el --- -*- lexical-binding: t -*-
Paren mode
(setq meow-paren-keymap (make-keymap))
(meow-define-state paren
"meow state for interacting with paredit"
:lighter " [P]"
:keymap meow-paren-keymap)
;; meow-define-state creates the variable
(setq meow-cursor-type-paren 'hollow)
(meow-define-keys 'paren
'("<escape>" . meow-normal-mode)
'("l" . paredit-forward)
'("h" . paredit-backward)
'("j" . paredit-forward-down)
'("k" . paredit-forward-up)
'("J" . paredit-forward-slurp-sexp)
'("K" . paredit-forward-barf-sexp)
'("L" . paredit-backward-barf-sexp)
'("H" . paredit-backward-slurp-sexp)
'("u" . meow-undo))
(use-package meow
:straight t
:custom
(meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
;; make "a" act like vim/evil
(meow-use-cursor-position-hack t)
:config
<<paren-mode>>
(setq meow-replace-state-name-list
'((normal . "<N>")
(motion . "MOTION")
(keypad . "KEYPAD")
(insert . "<I>")
(beacon . "BEACON")
(paren . "<λ>")))
(meow-leader-define-key
;; SPC j/k will run the original command in MOTION state.
'("j" . "H-j")
'("k" . "H-k")
;; Use SPC (0-9) for digit arguments.
'("1" . meow-digit-argument)
'("2" . meow-digit-argument)
'("3" . meow-digit-argument)
'("4" . meow-digit-argument)
'("5" . meow-digit-argument)
'("6" . meow-digit-argument)
'("7" . meow-digit-argument)
'("8" . meow-digit-argument)
'("9" . meow-digit-argument)
'("0" . meow-digit-argument)
'("/" . meow-keypad-describe-key)
'("?" . meow-cheatsheet))
(meow-normal-define-key
'(";" . meow-comment)
'("/" . ctrlf-forward-fuzzy)
'("0" . meow-expand-0)
'("9" . meow-expand-9)
'("8" . meow-expand-8)
'("7" . meow-expand-7)
'("6" . meow-expand-6)
'("5" . meow-expand-5)
'("4" . meow-expand-4)
'("3" . meow-expand-3)
'("2" . meow-expand-2)
'("1" . meow-expand-1)
'("-" . negative-argument)
'(")" . meow-reverse)
'("," . meow-inner-of-thing)
'("." . meow-bounds-of-thing)
'("[" . meow-beginning-of-thing)
'("]" . meow-end-of-thing)
'("a" . meow-append)
'("A" . meow-open-below)
'("b" . meow-back-word)
'("B" . meow-back-symbol)
'("c" . meow-change)
'("d" . meow-delete)
'("D" . meow-backward-delete)
'("e" . meow-next-word)
'("E" . meow-next-symbol)
'("f" . meow-find)
'("g" . meow-cancel-selection)
'("G" . meow-grab)
'("h" . meow-left)
'("H" . meow-left-expand)
'("i" . meow-insert)
'("I" . meow-open-above)
'("j" . meow-next)
'("J" . meow-next-expand)
'("k" . meow-prev)
'("K" . meow-prev-expand)
'("l" . meow-right)
'("L" . meow-right-expand)
'("m" . meow-join)
'("n" . meow-search)
'("o" . meow-block)
'("O" . meow-to-block)
'("p" . meow-yank)
'("q" . meow-quit)
'("Q" . meow-goto-line)
'("r" . meow-replace)
'("R" . meow-swap-grab)
'("s" . meow-kill)
'("t" . meow-till)
'("u" . meow-undo)
'("U" . meow-undo-in-selection)
'("v" . meow-visit)
'("w" . meow-mark-word)
'("W" . meow-mark-symbol)
'("x" . meow-line)
'("X" . meow-goto-line)
'("y" . meow-save)
'("Y" . meow-sync-grab)
'("z" . meow-pop-selection)
'("'" . repeat)
'("<escape>" . ignore))
(meow-global-mode 1))
(provide 'kpav-meow)
;;; kpav-meow.el ends here
;;; kpav-evil.el --- -*- lexical-binding: t -*-
Evil mode is vim in Emacs! Using undo-fu
here instead of undo-tree
as I have found that undo-fu
seems to be quicker and less buggy than undo-tree
.
(use-package evil
:straight t
:general
;; make <tab> expand things in org mode for evil
(general-nmap org-mode-map
"<tab>" 'org-cycle)
:init
(use-package undo-fu :straight t)
(setq evil-want-keybinding nil ;; evil-collection assumes this
evil-undo-system 'undo-fu
evil-disable-insert-state-bindings t) ;; emacs keys in insert mode
:config
(general-evil-setup)
(evil-mode +1))
The bit about using Emacs keybinds in evil mode is from https://stackoverflow.com/questions/25542097/emacs-evil-mode-how-to-change-insert-state-to-emacs-state-automatically
Use evil keys in various modes..
(use-package evil-collection
:straight t
:after evil
:config
(evil-collection-init))
surround.vim emulation.
(use-package evil-surround
:straight t
:after evil
:config
(global-evil-surround-mode +1))
vim-commentary emulation
(use-package evil-commentary
:straight t
:config
(evil-commentary-mode +1))
(provide 'kpav-evil)
;;; kpav-evil.el ends here
;;; kpav-keys.el --- -*- lexical-binding: t -*-
Press any two keys for keybinds.
(use-package key-chord
:straight t
:config
(key-chord-mode +1))
(provide 'kpav-keys)
;;; kpav-keys.el ends here
;;; kpav-ui.el --- -*- lexical-binding: t -*-
Set up fonts, This sets up the default
typeface, and the ones to be used in variable-pitch-mode, variable-pitch
and fixed-pitch
.
(use-package faces
:straight (:type built-in)
:init
;; Main typeface
(set-face-attribute 'default nil :family "Recursive Mn Lnr St" :height 130)
;; Proportionately spaced typeface
(set-face-attribute 'variable-pitch nil :family "Recursive Sn Lnr St" :height 1.0)
;; Monospaced typeface
(set-face-attribute 'fixed-pitch nil :family "Recursive Mn Lnr St" :height 1.0))
Increase the line spacing to let the text breathe a bit.
(use-package emacs
:straight (:type built-in)
:init
(setq-default line-spacing 4))
(use-package catppuccin-theme
:straight t
:custom
(catppuccin-flavor 'mocha)
;; (catppuccin-flavor 'latte)
;; (catppuccin-flavor 'latte)
;; (catppuccin-flavor 'latte)
:config
(load-theme 'catppuccin :no-confirm))
Variable Pitch allows us to have multiple fonts in a single buffer. This is useful for Org Mode which can have prose, code, and other things, in the same file.
Turn variable-pitch-mode
on for org-mode
.
(use-package face-remap
:straight (:type built-in)
:after org
:gfhook
('org-mode-hook #'variable-pitch-mode)
:config
;; from https://zzamboni.org/post/beautifying-org-mode-in-emacs/
(custom-theme-set-faces
'user
'(org-block ((t (:inherit fixed-pitch))))
'(org-code ((t (:inherit (shadow fixed-pitch)))))
'(org-document-info-keyword ((t (:inherit (shadow fixed-pitch)))))
'(org-indent ((t (:inherit (org-hide fixed-pitch)))))
'(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-tag ((t (:inherit (shadow fixed-pitch) :weight bold :height 0.8))))
'(org-verbatim ((t (:inherit (shadow fixed-pitch)))))))
Set up for doom-modeline
. Nice looking modeline that plays well with evil and lots of other stuff.
You need to run M-x all-the-icons-install-fonts
to get the fancy fonts in the modeline
(use-package all-the-icons
:straight t
:defer t)
column-number-mode
displays the cursors current line on the modeline
(use-package doom-modeline
:straight t
:demand t
:preface
:init
(column-number-mode +1)
:ghook
'after-init-hook
:custom
(doom-modeline-icon nil)
(doom-modeline-vcs-max-length 50)
(doom-modeline-buffer-file-name-style 'auto)
(doom-modeline-buffer-encoding nil)
(doom-modeline-indent-info nil)
(doom-modeline-major-mode-icon nil)
(doom-modeline-modal-icon nil)
(doom-modeline-persp-name t)
(doom-modeline-workspace-name nil))
(use-package dashboard
:straight t
:custom
;; (dashboard-startup-banner 'logo)
(dashboard-startup-banner (expand-file-name "img/gnu_color.png" user-emacs-directory))
(dashboard-center-content t)
(dashboard-projects-backend 'project-el)
(dashboard-items '((recents . 5)
(bookmarks . 5)
(projects . 5)
(agenda . 5)))
:config
(dashboard-setup-startup-hook))
Add rainbow delimiters in all programming language modes
(use-package rainbow-delimiters
:straight t
:ghook
('prog-mode-hook #'rainbow-delimiters-mode))
Don’t blink the cursor.
(use-package frame
:straight (:type built-in)
:config
(blink-cursor-mode -1))
Highlight the line the cursor is on.
(use-package hl-line
:straight (:type built-in)
:config
(global-hl-line-mode +1))
(provide 'kpav-ui)
;;; kpav-ui.el ends here
;;; kpav-windows-and-buffers.el --- -*- lexical-binding: t -*-
(use-package window
:straight (:type built-in)
;:general
;; (base-leader-def
;; :states 'normal
;; "b" '(:ignore t :wk "buffers")
;; "w" '(:ignore t :wk "windows")
;; ;; "bb" 'switch-to-buffer
;; ;; "bb" 'consult-buffer
;; ;; "bk" 'kill-buffer
;; "wo" 'split-window-horizontally
;; "wu" 'split-window-vertically
;; "wd" 'delete-window)
:config
(meow-leader-define-key
'("wo" . split-window-horizontally)
'("wu" . split-window-vertically)
'("wd" . delete-window)))
Windmove provides a way to move around emacs windows.
Default keybindings are: S-arrowkey
(e.g. S-Left
) to move around
(use-package windmove
:straight (:type built-in)
;:general
;; (base-leader-def
;; :states 'normal
;; "wh" 'windmove-left
;; "wj" 'windmove-down
;; "wk" 'windmove-up
;; "wl" 'windmove-right)
:init
(meow-leader-define-key
'("wh" . windmove-left)
'("wj" . windmove-down)
'("wk" . windmove-up)
'("wl" . windmove-right))
:config
(windmove-default-keybindings))
ace-window lets you jump around windows with a single key
(use-package ace-window
:straight t
:general
("M-o" 'ace-window)
;; (base-leader-def
;; :states 'normal
;; "ww" 'ace-window)
:custom
;; use home row instead of numbers
(aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
:init
(meow-leader-define-key
'("ww" . ace-window)))
Default key is C-x x
. Change it with perp-mode-prefix-key
Each frame gets its own perspective.
Switch buffer command only looks at current perspective
(use-package perspective
:straight t
:custom
(persp-suppress-no-prefix-key-warning t)
;:general
;; (base-leader-def
;; :states 'normal
;; "b`" 'persp-switch-by-number
;; "bb" 'persp-switch-to-buffer
;; "bk" 'persp-remove-buffer
;; "bc" 'persp-kill
;; "br" 'persp-rename
;; "ba" 'persp-add-buffer
;; "bA" 'persp-set-buffer
;; "bi" 'persp-import
;; "bn" 'persp-next
;; "bp" 'persp-prev
;; "bm" 'persp-merge
;; "bu" 'persp-unmerge
;; "bg" 'persp-add-buffer-to-frame-global
;; "b C-s" 'persp-state-save
;; "b C-l" 'persp-state-load
;; "bs" 'persp-switch)
:init
(meow-leader-define-key
;; '("bb" . persp-switch-to-buffer)
'("bk" . persp-remove-buffer)
'("bc" . persp-kill)
'("br" . persp-rename)
'("ba" . persp-add-buffer)
'("bA" . persp-set-buffer)
'("bi" . persp-import)
'("bn" . persp-next)
'("bp" . persp-prev)
'("bm" . persp-merge)
'("bu" . persp-unmerge)
'("bg" . persp-add-buffer-to-frame-global)
'("bS" . persp-state-save)
'("bL" . persp-state-load)
'("bs" . persp-switch))
:config
(persp-mode +1))
(provide 'kpav-windows-and-buffers)
;;; kpav-windows-and-buffers.el ends here
;;; kpav-narrowing.el --- -*- lexical-binding: t -*-
Set up Vertico and various packages that play well with it.
Vertico comes with several extensions in an extensions/
folder. These don’t get automatically loaded with :straight t
, so it needs a custom recipe.
(use-package vertico
:straight (vertico :files (:defaults "extensions/*")
:includes (vertico-buffer
vertico-directory
vertico-flat
vertico-indexed
vertico-mouse
vertico-quick
vertico-repeat
vertico-reverse))
:init
(vertico-mode +1))
A posframe
extension to display it outside of the minibuffer.
(use-package vertico-posframe
:straight t
:custom
(vertico-posframe-parameters
'((left-fringe . 10)
(right-fringe . 10)))
(vertico-posframe-poshandler #'posframe-poshandler-frame-center))
The multiform extension allows configuration per command. Using reverse by default, which I like because what you type does not move positions. Using buffer for ripgrep results as the list could be long.
NOTE - seems that reverse
is unusable with vertico-posframe
!
(use-package vertico-multiform
:custom
;; (vertico-buffer-display-action
;; (const :tag "Bottom of frame"
;; (display-buffer-at-bottom
;; (window-height . ,(+ 3 vertico-count)))))
(vertico-multiform-commands
'((consult-ripgrep buffer)
(t posframe)))
:init
(vertico-multiform-mode +1))
;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
:straight (:type built-in)
:init
(savehist-mode +1))
;; A few more useful configurations...
(use-package emacs
:straight (:type built-in)
:init
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
(setq read-extended-command-predicate
#'command-completion-default-include-p)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t))
(use-package orderless
:straight t
:init
(setq completion-styles '(orderless basic)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion)))))
a from scratch redesigned buffer-search interface
A replacement for the built in I-Search. This replaces the evil search and the built in search. The bit in general
handles evil and ctrlf-mode
automatically redefines C-s
.
C-s
- forward searchC-r
- backward search
(use-package ctrlf
:straight t
;:general
;(evil-normal-state-map "/" 'ctrlf-forward-fuzzy-regexp)
:init
(ctrlf-mode +1))
Marginalia adds information to the completions provided by Vertico (keybinds, info about command, etc.)
(use-package marginalia
:straight t
:general
("M-A" 'marginalia-cycle)
(:keymaps
'minibuffer-local-map
"M-A" 'marginalia-cycle)
:init
(marginalia-mode +1))
Consult provides practical commands based on the Emacs completion function completing-read.
Keys copied from projects README.
(use-package consult
;; :after projectile ;; needed to set `consult-project-root-function'
:straight t
:general
;; 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-flycheck) ;; 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-imenu-multi)
;; M-s bindings (search-map)
("M-s f" 'consult-find)
("M-s F" 'consult-locate)
("M-s g" 'consult-grep)
("M-s G" 'consult-git-grep)
("M-s r" 'consult-ripgrep)
("M-s l" 'consult-line)
("M-s L" 'consult-line-multi)
("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)
(:keymaps
'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
"M-s L" 'consult-line-multi) ;; needed by consult-line to detect isearch
;; (base-leader-def
;; :states 'normal
;; "pg" 'consult-ripgrep
;; "pG" 'consult-git-grep)
:init
(meow-leader-define-key
'("rb" . consult-bookmark)
'("bb" . consult-buffer)
'("pg" . consult-ripgrep)
'("pG" . consult-git-grep))
;; Install ripgrep for consult-ripgrep
(use-package ripgrep :straight t)
;; Optionally configure the register formatting. This improves the register
;; preview for `consult-register', `consult-register-load',
;; `consult-register-store' and the Emacs built-ins.
(setq register-preview-delay 0
register-preview-function #'consult-register-format)
;; Optionally tweak the register preview window.
;; This adds thin lines, sorting and hides the mode line of the window.
;; (advice-add #'register-preview :override #'consult-register-window)
;; Optionally replace `completing-read-multiple' with an enhanced version.
(advice-add #'completing-read-multiple :override #'consult-completing-read-multiple)
;; Use Consult to select xref locations with preview
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:config
;; projectile
;; for this t0 work, either need to autoload it, or use :after projectile
;; (autoload 'projectile-project-root "projectile")
;; (setq consult-project-root-function #'projectile-project-root)
;; project.el
;; (setq consult-project-root-function
;; (lambda ()
;; (when-let (project (project-current))
;; (car (project-roots project)))))
)
(use-package embark
:straight t
:general
;; ("C-'" 'embark-act)
;; ("C-;" 'embark-dwim)
("C-h B" 'embark-bindings)
("C-;" 'embark-act)
("C-h B" 'embark-bindings) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:straight t
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:ghook
('embark-collect-mode #'consult-preview-at-point-mode))
(provide 'kpav-narrowing)
;;; kpav-narrowing.el ends here
;;; kpav-system.el --- -*- lexical-binding: t -*-
Ensure that Emacs uses the correct environment. This is especially useful for OSX, as Emacs may inherit a default set of environment variables, not the ones that you see in a terminal.
(use-package exec-path-from-shell
:if (memq window-system '(mac ns x))
:straight t
:config
(exec-path-from-shell-initialize))
The railwaycat/emacs-mac
port maps the command key to meta, I like it bound to super because it matches my external keyboard better.
(use-package emacs
:straight (:type built-in)
:if (eq system-type 'darwin)
:custom
(mac-option-modifier 'meta)
(mac-command-modifier 'super))
(provide 'kpav-system)
;;; kpav-system.el ends here
Make ESC
close any prompts
(use-package emacs
:straight (:type built-in)
:general
("<escape>" 'keyboard-escape-quit))
Stop warnings buffer from automatically coming up. (Emacs 28)
(use-package emacs
:straight (:type built-in)
:init
(setq native-comp-async-report-warnings-errors nil))
Get list of minor modes in current buffer
(defun kpav/minor-modes ()
(interactive)
(completing-read
"Minor modes: "
local-minor-modes
nil t))
Modes and other things that deal with prose.
;;; kpav-org.el --- -*- lexical-binding: t -*-
- Use evil way of closing and quitting (
:q
:x
) when editing code in org mode - Define some keys
- Disable the checkdock check because most of my elisp code is in snippets in this config
org-use-fast-todo-selection
- Change the status of the todo state by pressing
C-c C-c t <KEY>
- the
<KEY>
is the the letter in the parens after the state (e.g.TODO(t)
)
- Change the status of the todo state by pressing
org-tempo
adds Structure Template completion- e.g.
<s
TAB
turns into#+begin_src
/#end_src
- e.g.
(use-package org
:straight t
;:general
;; (org-src-mode-map
;; [remap evil-save-and-close] 'org-edit-src-exit
;; [remap evil-save-modified-and-close] 'org-edit-src-exit
;; [remap evil-quit] 'org-edit-src-abort)
;; (base-leader-def
;; :states 'normal
;; "a" 'org-agenda)
;; (base-local-leader-def
;; :keymaps 'org-mode-map
;; :states 'normal
;; "b" 'org-babel-tangle)
:preface
(defun my-disable-flycheck-for-elisp ()
(setq flycheck-disabled-checkers '(emacs-lisp-checkdoc)))
:gfhook
('org-src-mode-hook #'my-disable-flycheck-for-elisp)
#'visual-line-mode
:init
(meow-leader-define-key
'("a" . org-agenda))
(setq org-startup-indented t)
:custom
(org-agenda-files (list "~/org/"))
(org-use-fast-todo-selection t)
(org-todo-keywords
'((sequence "TODO(t)" "NEXT(n)" "CURRENT(c)" "|" "DONE(d)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "|" "CANCELLED(a@/!)")))
;; Styling
(org-auto-align-tags nil)
(org-tags-column 0)
(org-hide-emphasis-markers t)
(org-pretty-entities t)
(org-ellipsis "…")
:config
;; structure template completion
(require 'org-tempo))
Install org-contrib
(use-package org-contrib
:straight t)
Prettify headings and lists with org-superstar-mode
(use-package org-superstar
:straight t
:ghook
('org-mode-hook (lambda () (org-superstar-mode +1))))
Capture Templates
agenda.org
is for my tasksslipbox.org
is where I put my “fleeting” notesgrow.org
is for my garden
(use-package org-capture
:straight nil
;:general
;; (base-leader-def
;; :states 'normal
;; "C" 'org-capture)
:custom
(org-capture-templates
'(;; ("t" "Todo" entry (file "~/org/agenda.org")
;; "* TODO %?\n %i\n %^{LINK}p")
("t" "Agenda Todo" entry (file "~/org/agenda.org"))
("s" "Slipbox" entry (file+datetree "~/org/roam/inbox.org")
"* %?\n")
("g" "Grow Log" entry (file+olp+datetree "~/grow/grow.org" "Log")
"* Day Xn\n** Log\n** Notes\n %?\n %i\n"))
:init
(meow-leader-define-key
'("C" . org-capture))))
Org babel languages TODO: figure out a way to put this in language specific configs
(org-babel-do-load-languages
'org-babel-load-languages
'((clojure . t)
(dot . t)
(emacs-lisp . t)
(js . t)
(python . t)
(sql . t)))
(provide 'kpav-org)
;;; kpav-org.el ends here
;;; kpav-org-roam.el --- -*- lexical-binding: t -*-
Trying out Org-roam to handle my note taking instead of my previous attempt at using a single notes.org
and capture templates. I had a hard time keeping things organized, even though I don’t take a large amount of notes. I think this is because the approach of having a single file with headers is too rigid for me, as I feel like I need to be meaningful with my headers or things would get too cluttered, but then things get cluttered anyway as I end up sticking unrelated things in a single header.
Org-roam
promotes the Zettelkasten Method. Basically, you make small notes and link them together. This approach should allow me to take and delete as many (or as few…) notes as I need without abandon, while Org-roam
allows me to easily add, link, and search through them. I can then change things as I need by adding new subfolders or filetags to things. I can even keep using large org files for things if I want (like my blog).
Note structure is:
daily/
- used fororg-roam-dailies
main/
- the default place for notesreference/
- notes about books, articles, videos, etc.work/
- notes for workjira/
- for jira tickets, will most likely link to other notes inwork/
;; (use-package emacsql-sqlite-module
;; :straight t)
(use-package emacsql-sqlite3
:straight t)
;; (use-package emacsql-sqlite-builtin
;; :straight t)
(use-package org-roam
:straight t
:after emacsql-sqlite3
:custom
(org-roam-database-connector 'sqlite3)
;; (org-roam-database-connector 'sqlite-builtin)
(org-roam-directory (file-truename "~/org/roam"))
(org-roam-capture-templates
'(("m" "main" plain "%?"
:if-new (file+head "main/%<%Y%m%d%H%M%S>-${slug}.org"
"#+title: ${title}\n")
:unnarrowed t)
("w" "work" plain "%?"
:if-new (file+head "work/%<%Y%m%d%H%M%S>-${slug}.org"
"#+title: ${title}\n")
:unnarrowed t)
("r" "reference" plain "%?"
:if-new (file+head "reference/%<%Y%m%d%H%M%S>-${slug}.org"
"#+title: ${title}\n")
:unnarrowed t)
("j" "jira" plain "* TODO ${title}\nhttps://reifyhealth.atlassian.net/browse/${title}\n%?"
:if-new (file+head "work/jira/%<%Y%m%d%H%M%S>-${slug}.org"
"#+title: ${title}\n#+filetags: :jira:\n")
:unnarrowed t)))
(org-roam-dailies-directory "daily/")
(org-roam-dailies-capture-templates
'(("d" "default" entry
"* %?"
:target (file+head "%<%Y-%m-%d>.org"
"#+title: %<%Y-%m-%d>\n"))))
:ghook
('after-init-hook #'org-roam-db-autosync-mode)
;:general
;; (base-leader-def
;; :states '(normal visual)
;; "n" '(:ignore :wk "notes")
;; "ni" 'org-roam-node-insert
;; "nf" 'org-roam-node-find
;; "nc" 'org-roam-node-capture
;; "nb" 'org-roam-buffer-toggle
;; "nd" '(:ignore :wk "dailies")
;; "ndt" 'org-roam-dailies-capture-today
;; "ndT" 'org-roam-dailies-goto-today
;; "ndy" 'org-roam-dailies-capture-yesterday
;; "ndY" 'org-roam-dailies-goto-yesterday)
:init
(meow-leader-define-key
'("ni" . org-roam-node-insert)
'("nf" . org-roam-node-find)
'("nc" . org-roam-node-capture)
'("nb" . org-roam-buffer-toggle)
'("ndt" . org-roam-dailies-capture-today)
'("ndT" . org-roam-dailies-goto-today)
'("ndy" . org-roam-dailies-capture-yesterday)
'("ndY" . org-roam-dailies-goto-yesterday))
:config
;; Display the `node' (e.g. main/work/jira) and filetags when searching
;; from https://jethrokuan.github.io/org-roam-guide/
(cl-defmethod org-roam-node-type ((node org-roam-node))
"Return the TYPE of NODE."
(condition-case nil
(file-name-nondirectory
(directory-file-name
(file-name-directory
(file-relative-name (org-roam-node-file node) org-roam-directory))))
(error "")))
(setq org-roam-node-display-template
(concat "${type:15} ${title:*} " (propertize "${tags:10}" 'face 'org-tag))))
(use-package org-roam-ui
:straight
(:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out"))
:after org-roam
:custom
(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)
;:general
;; (base-leader-def
;; :states '(normal visual)
;; "nu" 'org-roam-ui-mode)
:init
(meow-leader-define-key
'("nu" . org-roam-ui-mode)))
(provide 'kpav-org-roam)
;;; kpav-org-roam.el ends here
;;; kpav-markdown.el --- -*- lexical-binding: t -*-
(use-package markdown-mode
:straight t
:defer t)
(provide 'kpav-markdown)
;;; kpav-markdown.el ends here
Add and configure some additional tools.
;;; kpav-git.el --- -*- lexical-binding: t -*-
I only use git
for version control, and I assume most others do as well. This is probably why there are so many great git
packages for Emacs!
Magit may be one of the best front ends for git
ever. It makes using git, both the simple and complex parts of it, easy and intuitive to use, right within Emacs! It also provides some neat stuff like spinoff
, which will create a branch of any unpushed commits. This is handy if you accidentally starting commiting work to the wrong branch, e.g. master
or develop
.
I have a function here which copies the current branch name. This is handy if you need the branch name for something like a CI/CD system.
(use-package magit
:straight t
:defer t
:general
("C-x g" 'magit-status)
;; (base-leader-def
;; :states 'normal
;; "g" '(:ignore t :wk "git")
;; "gs" 'magit-status
;; "gc" 'magit-checkout
;; "gC" 'magit-commit
;; "gb" 'magit-blame
;; "gS" 'magit-stage-file
;; "gU" 'magit-unstage-file
;; "gy" 'kpav/magit-yank-branch-name)
:init
(meow-leader-define-key
'("ss" . magit-status)
'("sc" . magit-checkout)
'("sC" . magit-commit)
'("sb" . magit-blame)
'("sS" . magit-stage-file)
'("sU" . magit-unstage-file)
'("sy" . kpav/magit-yank-branch-name))
:config
(defun kpav/magit-yank-branch-name ()
"Show the current branch in the echo-area and add it to the `kill-ring'."
(interactive)
(let ((branch (magit-get-current-branch)))
(if branch
(progn (kill-new branch)
(message "%s" branch))
(user-error "There is not current branch")))))
Add git change icons in the fringe, e.g. when somethings been added, changed, or removed. Modus themes makes this look decent.
(use-package git-gutter-fringe
:straight t
:config
(global-git-gutter-mode +1)
(setq-default fringes-outside-margins t))
Go through commit history on a file.
(use-package git-timemachine
:straight t
:defer t
;:general
;; (base-leader-def
;; :states 'normal
;; "gt" 'git-timemachine)
:init
(meow-leader-define-key
'("gt" . git-timemachine)))
(use-package git-link
:straight t
;:general
;; (base-leader-def
;; :states '(normal visual)
;; "gl" '(:ignore t :wk "git link")
;; "gll" 'git-link
;; "glc" 'git-link-commit
;; "glh" 'git-link-homepage)
:init
(meow-leader-define-key
'("sll" . git-link)
'("slc" . git-link-commit)
'("slh" . git-link-homepage)))
(provide 'kpav-git)
;;; kpav-git.el ends here
;;; kpav-project.el --- -*- lexical-binding: t -*-
A large part of my workflow is working in projects, which may or may not interact together, so I like to only open and interact with files and buffers on a per project basis. I use persp-mode
to create perspectives for each project, then use the following packages to further interact with them, e.g. opening files or searching for some specific text.
Using the built-in project.el
. It works with marginalia to give extra info about files and buffers
(use-package project
:straight t
;:general
;; (base-leader-def
;; :states 'normal
;; "p" '(:ignore t :wk "projects")
;; "pp" 'project-switch-project
;; "pf" 'project-find-file
;; "pd" 'project-find-dir
;; "pb" 'project-switch-to-buffer)
:init
(meow-leader-define-key
'("pp" . project-switch-project)
'("pf" . project-find-file)
'("pd" . project-find-dir)
'("pb" . consult-project-buffer)))
;; (use-package projectile
;; :straight t
;; :init
;; (use-package ripgrep :straight t)
;; :general
;; (base-leader-def
;; :states 'normal
;; "p" '(:ignore t :wk "projects")
;; "pd" 'projectile-find-dir
;; "pp" 'projectile-switch-project
;; "pP" 'projectile-switch-open-project)
;; :config
;; (projectile-mode +1))
Treemacs provides a nice file explorer for projects.
(use-package treemacs
:straight t
:defer t
:general
([f8] 'treemacs)
;; (base-leader-def
;; :states '(normal)
;; "po" 'treemacs)
:init
(meow-leader-define-key
'("po" . treemacs)))
;; (use-package treemacs-evil
;; :straight t
;; :after (evil treemacs))
(use-package treemacs-magit
:straight t
:after (treemacs magit))
Provide direnv
support for projects with .envrc
files.
(use-package envrc
:straight t
:config
(envrc-global-mode +1))
Use envrc-allow
to explicitly run direnv allow
.
(use-package editorconfig
:straight t
:config
(editorconfig-mode +1))
(provide 'kpav-project)
;;; kpav-project.el ends here
;;; kpav-vterm.el --- -*- lexical-binding: t -*-
This provides a terminal emulator powered by libvterm. It is essentially a full terminal emulator.
(use-package vterm
:straight t)
Open multiple vterms. Evil configuration from it’s README.
(use-package multi-vterm
:straight t
;:general
;; (base-leader-def
;; :states 'normal
;; "t" '(:ignore t :wk "term")
;; "tt" 'multi-vterm
;; "tn" 'multi-vterm-next
;; "tp" 'multi-vterm-prev)
:init
(meow-leader-define-key
'("tt" . multi-vterm)
'("tn" . multi-vterm-next)
'("tp" . multi-vterm-prev))
;;:gfhook #'evil-insert-state
;:config
;(define-key vterm-mode-map [return] #'vterm-send-return)
;(setq vterm-keymap-exceptions nil)
;(evil-define-key 'insert vterm-mode-map (kbd "C-e") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-f") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-a") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-v") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-b") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-w") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-u") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-d") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-n") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-m") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-p") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-j") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-k") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-r") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-t") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-g") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-c") #'vterm--self-insert)
;(evil-define-key 'insert vterm-mode-map (kbd "C-SPC") #'vterm--self-insert)
;(evil-define-key 'normal vterm-mode-map (kbd "C-d") #'vterm--self-insert)
;(evil-define-key 'normal vterm-mode-map (kbd ",c") #'multi-vterm)
;(evil-define-key 'normal vterm-mode-map (kbd ",n") #'multi-vterm-next)
;(evil-define-key 'normal vterm-mode-map (kbd ",p") #'multi-vterm-prev)
;(evil-define-key 'normal vterm-mode-map (kbd "i") #'evil-insert-resume)
;(evil-define-key 'normal vterm-mode-map (kbd "o") #'evil-insert-resume)
;(evil-define-key 'normal vterm-mode-map (kbd "<return>") #'evil-insert-resume)
)
(provide 'kpav-vterm)
;;; kpav-vterm.el ends here
;;; kpav-eshell.el --- -*- lexical-binding: t -*-
(use-package eshell
:straight t)
(use-package multi-eshell
:straight t
:general
(base-leader-def
:states 'normal
"ee" 'multi-eshell
"en" 'multi-eshell-switch-to-next-live-shell
"ep" 'multi-eshell-go-back))
(provide 'kpav-eshell)
;;; kpav-eshell.el ends here
;;; kpav-docker.el --- -*- lexical-binding: t -*-
Get syntax highlighting for Dockerfile
files
(use-package dockerfile-mode
:straight t
:defer t)
Use docker
commands in Emacs
(use-package docker
:straight t
:defer t)
(provide 'kpav-docker)
;;; kpav-docker.el ends here
;;; kpav-irc.el --- -*- lexical-binding: t -*-
Passwords are stored in the ~/.authinfo
file, with the format:
machine irc.libera.chat login kpav password <PASSWORD> port 6697
(use-package erc
:straight (:type built-in)
:defer t
:custom
(erc-server "irc.libera.chat")
(erc-nick "kpav")
(erc-autojoin-channels-alist '(("irc.libera.chat" "#emacs" "#clojure" "#sr.ht" "#archlinux" "#stumpwm"))))
(provide 'kpav-irc)
;;; kpav-irc.el ends here
;;; kpav-guix.el --- -*- lexical-binding: t -*-
(use-package guix
:straight t
:defer t)
(provide 'kpav-guix)
;;; kpav-guix.el ends here
Things that modify coding stuff (mostly programming langs and LSP).
Things that can be used across all languages.
;;; kpav-code.el --- -*- lexical-binding: t -*-
Works with Orderless and LSPs (lsp-mode
and eglot
)
(use-package corfu
:straight t
:custom
(corfu-auto t)
(corfu-quit-no-match 'separator)
:init
(global-corfu-mode))
;; A few more useful configurations...
(use-package emacs
:straight (:type built-in)
:init
;; TAB cycle if there are only few candidates
(setq completion-cycle-threshold 3)
;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
;; Corfu commands are hidden, since they are not supposed to be used via M-x.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; Enable indentation+completion using the TAB key.
;; `completion-at-point' is often bound to M-TAB.
(setq tab-always-indent 'complete))
FlyMake is the built-in syntax checker for Emacs. It works for all (most?) of the languages that I use. Trying this out instead of Flycheck in my move to stick to built-in packages.
(use-package flymake
:straight t
:ghook
('prog-mode-hook #'flymake-mode-on))
YA Snippet is a template system for Emacs.
Set the snippets directory to be in this folder, automatically create it if it does not exist.
(use-package yasnippet
:straight t
:preface
(defconst basemacs-snippets-dir (expand-file-name "snippets/" user-emacs-directory))
(make-directory basemacs-snippets-dir :parents)
:custom
(yas-snippet-dirs (list basemacs-snippets-dir))
:config
(yas-global-mode +1))
Install the official snippet collection, this contains snippets for several programming languages.
(use-package yasnippet-snippets
:straight t
:after yasnippet)
Emacs Polyglot: an Emacs LSP client that stays out of your way:
A simple (compared to lsp-mode
) way to use Language Servers in Emacs. It uses built-in commands (e.g. xref-find-definitions
) and packages (e.g. flymake
).
(use-package eglot
:straight t
:custom
(eglot-connect-timeout 120)
;:general
;; (base-leader-def
;; :states '(normal visual)
;; "l" '(:ignore :wk "lsp")
;; "lg" 'xref-find-definitions
;; "lr" 'xref-find-references
;; "lb" 'xref-go-back
;; "lf" 'eglot-format
;; "lF" 'eglot-format-buffer
;; "la" 'eglot-code-actions
;; "lo" 'eglot-code-action-organize-imports
;; "lR" 'eglot-rename
;; "lh" 'eldoc)
:init
(meow-leader-define-key
'("lg" . xref-find-definitions)
'("lr" . xref-find-references)
'("lb" . xref-go-back)
'("lf" . eglot-format)
'("lF" . eglot-format-buffer)
'("la" . eglot-code-actions)
'("lo" . eglot-code-action-organize-imports)
'("lR" . eglot-rename)
'("lh" . eldoc)))
Although Eglot depends on built-in packages, it needs the newest versions of them. Most of the packages are loaded elsewhere in the config, eldoc
and xref
are all that is left
(use-package eldoc
:straight t)
(use-package xref
:straight t)
Move eldoc
out of the minibuffer when eglot
is enabled.
;; (use-package eldoc-box
;; :straight t
;; :ghook
;; ('eglot-managed-mode-hook #'eldoc-box-hover-at-point-mode t))
(use-package tree-sitter
:defer t
:straight t)
(use-package tree-sitter-langs
:after tree-sitter
:straight t)
(provide 'kpav-code)
;;; kpav-code.el ends here
;;; kpav-lisp-core.el --- -*- lexical-binding: t -*-
Lisps can share a lot of the same config code due to the nature of the syntax.
List of all lisp mode hooks. This is used to enable modes for all of them.
(defconst kpav-lisp-mode-hooks
'(lisp-mode-hook
;; sly-mrepl-mode-hook
emacs-lisp-mode-hook
clojure-mode-hook
scheme-mode-hook
;; cider-repl-mode-hook
))
(use-package paredit
:straight t
:ghook kpav-lisp-mode-hooks)
Lispy provides vim-like commands to navigate and edit Lisp code.
;; (use-package lispy
;; :straight t
;; :ghook kpav-lisp-mode-hooks)
;; (use-package lispyville
;; :straight t
;; :ghook
;; ('lispy-mode-hook #'lispyville-mode))
Symex provides even more vim-like commands (compared t0 lispy) to navigate and edit lisp code. Press C-'
to start.
;; (use-package symex
;; :straight t
;; :custom
;; (symex-modal-backend 'evil)
;; :general
;; ("C-'" 'symex-mode-interface)
;; (:keymaps 'normal
;; (general-chord "jk") 'symex-mode-interface)
;; :config
;; (symex-initialize))
This is a nice guide: https://countvajhula.com/2021/09/25/the-animated-guide-to-symex/
Automatically indent code.
;; (use-package aggressive-indent
;; :straight t
;; :ghook kpav-lisp-mode-hooks)
NOTE: commenting this out for now, useful for me, but not for work projects…too many whitespace changes.
Highlight whats being eval’ed
(use-package eval-sexp-fu
:straight t
:ghook
(kpav-lisp-mode-hooks #'eval-sexp-fu-flash-mode))
(provide 'kpav-lisp-core)
;;; kpav-lisp-core.el ends here
;;; kpav-clojure.el --- -*- lexical-binding: t -*-
(require 'kpav-lisp-core)
Use LSP with all clojure-related modes.
(use-package clojure-mode
:straight t
:defer t
:ghook
;; ('clojure-mode-hook #'lsp)
;; ('clojurec-mode-hook #'lsp)
;; ('clojurescript-mode #'lsp)
('clojure-mode-hook #'eglot-ensure)
('clojurec-mode-hook #'eglot-ensure)
('clojurescript-mode #'eglot-ensure)
;; :custom
;; (lsp-enable-indentation nil)
)
;; is this needed?
;; :config
;; (dolist (m '(clojure-mode
;; clojurec-mode
;; clojurescript-mode
;; clojurex-mode))
;; (add-to-list 'lsp-language-id-configuration `(,m . "clojure")))
CIDER is the Clojure(Script) Interactive Development Environment that Rocks!
(use-package cider
:straight t
:after clojure-mode
:ghook
('cider-repl-mode-hook #'rainbow-delimiters-mode)
;; ('cider-connected-hook #'cider-upgrade-nrepl-connection)
:custom
(cider-inject-dependencies-at-jack-in t)
;; clojure-lsp conflicts
(cider-eldoc-display-for-symbol-at-point nil)
(cider-use-xref nil)
:general
(base-local-leader-def
;:states '(normal visual)
:keymaps 'clojure-mode-map
"r" '(:ignore t :wk "repl")
"rr" 'cider
"rR" 'cider-restart
"rn" 'cider-repl-set-ns
"rb" 'cider-switch-to-repl-buffer
"rc" 'cider-find-and-clear-repl-output
"rl" 'cider-load-buffer
"rq" 'cider-quit
;; eval
"eD" 'cider-insert-defun-in-repl
"eE" 'cider-insert-last-sexp-in-repl
"eR" 'cider-insert-region-in-repl
"eb" 'cider-eval-buffer
"ed" 'cider-eval-defun-at-point
"ee" 'cider-eval-last-sexp
"er" 'cider-eval-region
"eu" 'cider-undef
"em" 'cider-macroexpand-1
"eM" 'cider-macroexpand-all
;; help
"h" '(:ignore t :wk "help")
"ha" 'cider-apropos
"hh" 'cider-doc
"hj" 'cider-javadoc
"hn" 'cider-browse-ns
"hN" 'cider-browse-ns-all
"hs" 'cider-browse-spec
"hS" 'cider-browse-spec-all
;; inspect
"i" '(:ignore t :wk "inspect")
"ii" 'cider-inspect
"ie" 'cider-enlighten-mode
"ir" 'cider-inspect-last-result
;; pprint
"p" '(:ignore t :wk "pprint")
"pd" 'cider-pprint-eval-defun-at-point
"pD" 'cider-pprint-eval-defun-to-comment
"pD" 'cider-pprint-eval-last-sexp-to-repl
;; format
"f" '(:ignore t :wk "format")
"fr" 'cider-format-region
"fb" 'cider-format-buffer
"ff" 'cider-format-defun
;; goto
"g" '(:ignore t :wk "goto")
"gg" 'cider-find-dwim
"gv" 'cider-find-var
"gn" 'cider-find-ns
"gN" 'cider-browse-ns-all
"d" '(:ignore t :wk "debug")
"dr" 'cider-ns-reload
"dR" 'cider-ns-reload-all
"di" 'cider-inspect-defun-at-point)
:init
;; (meow-leader-define-key
;; '("mrr" . cider)
;; '("mrR" . cider-restart)
;; '("mrn" . cider-repl-set-ns)
;; '("mrb" . cider-switch-to-repl-buffer)
;; '("mrc" . cider-find-and-clear-repl-output)
;; '("mrl" . cider-load-buffer)
;; '("mrq" . cider-quit)
;; ;; eval
;; '("meD" . cider-insert-defun-in-repl)
;; '("meE" . cider-insert-last-sexp-in-repl)
;; '("meR" . cider-insert-region-in-repl)
;; '("meb" . cider-eval-buffer)
;; '("med" . cider-eval-defun-at-point)
;; '("mee" . cider-eval-last-sexp)
;; '("mer" . cider-eval-region)
;; '("meu" . cider-undef)
;; '("mem" . cider-macroexpand-1)
;; '("meM" . cider-macroexpand-all)
;; ;; help
;; '("mha" . cider-apropos)
;; '("mhh" . cider-doc)
;; '("mhj" . cider-javadoc)
;; '("mhn" . cider-browse-ns)
;; '("mhN" . cider-browse-ns-all)
;; '("mhs" . cider-browse-spec)
;; '("mhS" . cider-browse-spec-all)
;; ;; inspect
;; '("mii" . cider-inspect)
;; '("mie" . cider-enlighten-mode)
;; '("mir" . cider-inspect-last-result)
;; ;; pprint
;; '("mpd" . cider-pprint-eval-defun-at-point)
;; '("mpD" . cider-pprint-eval-defun-to-comment)
;; '("mpD" . cider-pprint-eval-last-sexp-to-repl)
;; ;; format
;; '("mfr" . cider-format-region)
;; '("mfb" . cider-format-buffer)
;; '("mff" . cider-format-defun)
;; ;; goto
;; '("mgg" . cider-find-dwim)
;; '("mgv" . cider-find-var)
;; '("mgn" . cider-find-ns)
;; '("mgN" . cider-browse-ns-all)
;; ;; debug
;; '("mdr" . cider-ns-reload)
;; '("mdR" . cider-ns-reload-all)
;; '("mdi" . cider-inspect-defun-at-point))
)
Refactoring functionality for Clojure.
(use-package clj-refactor
:straight t
:after cider
:ghook
('clojure-mode-hook (lambda ()
(clj-refactor-mode +1)
(yas-minor-mode +1) ; for adding require/use/import statements
;; Leaves cider-macroexpand-1 unbound
(cljr-add-keybindings-with-prefix "C-c C-m")))
:custom
;; conflicts with clojure-lsp
(cljr-add-ns-to-blank-clj-files nil)
:general
(base-local-leader-def
:states '(normal visual)
:keymaps 'clojure-mode-map
"R" 'hydra-cljr-help-menu/body))
Highlight what’s being eval’ed
(use-package cider-eval-sexp-fu
:straight t)
(provide 'kpav-clojure)
;;; kpav-clojure.el ends here
;;; kpav-common-lisp.el --- -*- lexical-binding: t -*-
(require 'kpav-lisp-core)
Sly provides a Common Lisp REPL for Emacs.
(use-package sly
:straight t
:defer t
:ghook
('sly-mrepl-mode-hook #'rainbow-delimiters-mode)
:general
(base-local-leader-def
:states 'normal
:keymaps 'lisp-mode-map
"eb" 'sly-eval-buffer
"el" 'sly-eval-last-expression
"ed" 'sly-eval-defun
"er" 'sly-eval-region)
:custom
(inferior-lisp-program "/usr/bin/sbcl"))
(use-package sly-quicklisp
:straight t
:after sly)
(use-package sly-asdf
:straight t
:after sly)
(provide 'kpav-common-lisp)
;;; kpav-common-lisp.el ends here
;;; kpav-elisp.el --- -*- lexical-binding: t -*-
(require 'kpav-lisp-core)
Set up keys for evaling elisp.
(use-package emacs
:straight (:type built-in)
:general
(base-local-leader-def
:states '(normal visual)
:keymaps 'emacs-lisp-mode-map
"e" '(:ignore t :wk "eval")
"eb" 'eval-buffer
"el" 'eval-last-sexp
"ed" 'eval-defun
"er" 'eval-region)
(base-local-leader-def
:states 'normal
:keymaps 'lisp-interaction-mode-map
"e" '(:ignore t :wk "eval")
"eb" 'eval-buffer
"el" 'eval-last-sexp
"ed" 'eval-defun
"er" 'eval-region))
(provide 'kpav-elisp)
;;; kpav-elisp.el ends here
;;; kpav-scheme.el --- -*- lexical-binding: t -*-
(require 'kpav-lisp-core)
(use-package geiser
:straight t
:custom
(geiser-activate-implementations '(guile)))
(use-package geiser-guile
:straight t)
(provide 'kpav-scheme)
;;; kpav-scheme.el ends here
;;; kpav-php.el --- -*- lexical-binding: t -*-
I use PHP for my job, so I need to use the WellspringCodingStandard
.
(use-package php-mode
:straight t
:mode "\\.php\\'"
:gfhook #'my-php-setup
:general
(:keymaps 'php-mode-map
"C-c a" 'my/align-php-dbl-arrow)
:custom
;; align -> on successive lines
(php-lineup-cascaded-calls t)
(flycheck-phpcs-standard "WellspringCodingStandard"))
Setup the default coding style and LSP for php. Need to set lsp-enable-file-watchers
to nil because the project has a large amount of files and it causes performance issues.
(defun my-php-setup ()
(php-enable-default-coding-style)
(setq lsp-enable-file-watchers nil)
(lsp))
Align the ==>= in arrays
(defun my/align-php-dbl-arrow ()
"Align the => in arrays."
(interactive)
(align-regexp
(region-beginning) (region-end)
"\\(\\s-*\\) => " 1 0 nil))
Use PHP_CodeSniffer
to format files
(use-package phpcbf
:straight t
:after (php-mode)
:custom
(phpcbf-executable "/usr/local/bin/phpcbf")
(phpcbf-standard "WellspringCodingStandard"))
psysh
is a php repl
(use-package psysh
:straight t
:defer t)
(provide 'kpav-php)
;;; kpav-php.el ends here
;;; kpav-python.el --- -*- lexical-binding: t -*-
Use pyenv
for managing virtual environments
Set python version with:
M-x pyvenv-mode-set
Then
M-x run-python
(use-package pyenv-mode
:straight t
:ghook
('python-mode-hook #'pyenv-mode))
Set up LSP with eglot
(use-package python
:straight t
:mode "\\.py\\'"
:gfhook
#'tree-sitter-mode
#'tree-sitter-hl-mode
#'eglot-ensure
:ghook
('inferior-python-mode-hook #'eglot-ensure))
(provide 'kpav-python)
;;; kpav-python.el ends here
;;; kpav-js.el --- -*- lexical-binding: t -*-
Using the built in js-mode
. This handles both vanilla js and .jsx
.
(use-package js-mode
:straight (:type built-in)
:mode "\\.js\\'"
:interpreter "node"
:gfhook
;;#'lsp
#'tree-sitter-mode
#'tree-sitter-hl-mode
#'eglot-ensure)
Set up for standard TypeScript (.ts
) files.
(use-package typescript-mode
:straight t
:mode "\\.ts\\'"
:commands (typescript-mode)
:gfhook
;;#'lsp
#'eglot-ensure
#'tree-sitter-mode
#'tree-sitter-hl-mode)
typescript-mode
can’t handle .tsx
files, but web-mode
can.
(use-package web-mode
:straight t
:mode "\\.tsx\\'"
:commands (web-mode)
:gfhook
#'eglot-ensure
#'tree-sitter-mode
#'tree-sitter-hl-mode)
Have web-mode
use the TS language server because otherwise eglot
does not know which server to use.
(use-package eglot
:config
(add-to-list 'eglot-server-programs '(web-mode . ("typescript-language-server" "--stdio"))))
(use-package json-mode
:straight t
:mode "\\.json\\'"
:gfhook
#'tree-sitter-mode
#'tree-sitter-hl-mode)
(provide 'kpav-js)
;;; kpav-js.el ends here
;;; kpav-c.el --- -*- lexical-binding: t -*-
Set up the ccls
language server
(use-package ccls
:straight t
:hook ((c-mode c++-mode objc-mode cuda-mode) .
(lambda () (require 'ccls) ;;(lsp)
(eglot)))
:config
(setq ccls-executable "/usr/bin/ccls")
;; use flycheck instead of flymake
;;(setq lsp-prefer-flymake nil)
(setq lsp-prefer-flymake t)
(setq-default flycheck-disabled-checkers '(c/c++-clang c/c++-cppcheck c/c++-gcc)))
(provide 'kpav-c)
;;; kpav-c.el ends here
;;; kpav-yaml.el --- -*- lexical-binding: t -*-
(use-package yaml-mode
:straight t
:defer t)
(provide 'kpav-yaml)
;;; kpav-yaml.el ends here
;;; kpav-grpc.el --- -*- lexical-binding: t -*-
(use-package protobuf-mode
:straight t
:defer t)
(provide 'kpav-grpc)
;;; kpav-grpc.el ends here
;;; kpav-graphql.el --- -*- lexical-binding: t -*-
(use-package graphql-mode
:straight t
:defer t)
(provide 'kpav-graphql)
;;; kpav-graphql.el ends here
Mode for the nix
language.
;;; kpav-nix.el --- -*- lexical-binding: t -*-
(use-package nix-mode
:straight t
:mode "\\.nix\\'")
(provide 'kpav-nix)
;;; kpav-nix.el ends here
(provide 'init)
;;; init.el ends here
jumping and stuff
Should probably be in basemacs-core
e.g. SPC f
See what other settings there are
- State “CANCELLED” from “TODO” [2023-05-21 Sun 21:53]
using corfu
AI completion engine?
conflicts with other org customization
Start projects easier https://github.com/davidmiller/dizzee