56 KiB
Emacs Config
- Early Init
- Straight.el
- Benchmarking
- Misc Stuff
- Visuals
- Text
- Text Editor
- Buffers
- Windows
- Tabs/Workspaces
- Projects
- VEMCO
- Dirvish/Dired
- Org Mode
- Avy
- Helpful
- Terminals/Shells
- Undo Fu
- Which Key
- IDE Features
- Debugging
- Languages
- Magit
- Restclient
- COMMENT Local variables
Early Init
Garbage Collection
The default Garbage Collector is triggered at 800 KB, way too conservative, let's bump to 512 MB. Garbage collection is a big contributor to startup times. This fends it off, then is reset later by enabling `gcmh-mode'. Not resetting it will cause stuttering/freezes.
;; -*- lexical-binding: t -*-
(defvar default-file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
(setq gc-cons-threshold (expt 2 32))
(add-hook 'emacs-startup-hook
(lambda ()
"Restore defalut values after init."
(setq file-name-handler-alist default-file-name-handler-alist)
(if (boundp 'after-focus-change-function)
(add-function :after after-focus-change-function
(lambda ()
(unless (frame-focus-state)
(garbage-collect))))
(add-hook 'focus-out-hook 'garbage-collect))))
(setq native-comp-async-report-warnings-errors nil)
(setq native-comp-deferred-compilation t)
Disabling these classic visual options during early-init seems to net a 0.04 ms boost in init time
(setq max-specpdl-size 1200)
(setq max-lisp-eval-depth 800)
(scroll-bar-mode -1)
(tool-bar-mode -1)
(menu-bar-mode -1)
(tooltip-mode -1)
Straight.el Prep
Disable package.el, since we will be using straight.el. According to the straight.el documentation;
While it is technically possible to use both package.el and straight.el at the same time, there is no real reason to, and it might result in oddities like packages getting loaded more than once.
Either way, if you need to quickly install a package for testing, you can just run
(straight-use-package)
interactively.
(setq package-enable-at-startup nil)
Enhancements
Prioritize old byte-compiled source files over newer sources. It saves us a little IO time to skip all the mtime checks on each lookup.
(setq load-prefer-newer nil)
(setq safe-local-variable-values
'((org-src-preserve-indentation . t)
(eval add-hook 'after-save-hook
'(lambda nil
(org-babel-tangle))
nil t)))
UTF-8 Support
(setq default-input-method nil)
(setq utf-translate-cjk-mode nil) ; disable CJK coding/encoding (Chinese/Japanese/Korean characters)
(set-language-environment 'utf-8)
(set-keyboard-coding-system 'utf-8-mac) ; For old Carbon emacs on OS X only
(setq locale-coding-system 'utf-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
;;; early-init.el ends here
Straight.el
For now, use straight.el until [[https://github.com/progfolio/elpaca ][elpaca]] is ready for production use.
Then bootstrap
;; -*- lexical-binding: t -*-
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 6))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
Benchmarking
This is commented out since it adds ever so slightly to init time, but keep it around in case we need to benchmark slow init times later.
(straight-use-package 'benchmark-init)
(require 'benchmark-init)
(add-hook 'after-init-hook 'benchmark-init/deactivate)
Misc Stuff
(setq default-directory "/home/joe/")
(setq vc-follow-symlinks t) ; Visit real file when editing a symlink without prompting.
(global-auto-revert-mode t) ; Revert buffer's file when the file changes on disk
;; (setq confirm-kill-emacs 'y-or-n-p)
(require 'recentf)
(recentf-mode t)
(setq recentf-auto-cleanup 10)
(setq recentf-keep '(file-remote-p file-readable-p))
(setq recentf-max-saved-items 1000)
This avoids those annoying #backup# files that get added and eventually slow down loading the file again.
(setq auto-save-default nil)
(setq create-lockfiles nil)
(setq use-dialog-box nil)
(fset 'yes-or-no-p 'y-or-n-p)
(setq large-file-warning-threshold 100000000)
(setq backup-directory-alist `((".*" . ,(expand-file-name "backups" user-emacs-directory))))
(setq backup-by-copying t
delete-old-versions t
kept-new-versions 6
kept-old-versions 2
version-control t)
I don't even know how you resume from GUI mode, we'll find a use for this keybinding later on
(when (display-graphic-p)
(global-unset-key (kbd "C-z")))
Visuals
Dashboard
Use Dashboard.el. First load `all-the-icons` for nicer rendering
;; (straight-use-package 'all-the-icons)
(straight-use-package 'dashboard)
(dashboard-setup-startup-hook)
(setq dashboard-items '((recents . 6)
(projects . 5)
(bookmarks . 5)))
(setq dashboard-startup-banner 'logo)
(setq dashboard-center-content t)
(setq dashboard-set-file-icons t)
(setq dashboard-set-navigator t)
(setq dashboard-set-heading-icons t)
(setq dashboard-projects-backend 'project-el)
(add-hook 'dashboard-mode-hook (lambda ()
(setq-local line-spacing 12)
(dashboard-jump-to-recents)))
(defun joe/launch-dashboard ()
"Jump to the dashboard buffer, if doesn't exists create one."
(interactive)
(switch-to-buffer dashboard-buffer-name)
(dashboard-mode)
(dashboard-insert-startupify-lists))
Olivetti
(straight-use-package 'olivetti)
(require 'olivetti)
(setq olivetti-minimum-body-width 100)
(global-set-key (kbd "C-x x o") 'olivetti-mode)
Themes
;; Small changes to my favorite themes
(straight-use-package
'(doom-themes :type git :host github :repo "doomemacs/themes"
:fork (:host github
:repo "JosephFerano/doom-themes")))
(setq custom-safe-themes t)
(custom-set-faces
'(dashboard-items-face ((t (:inherit widget-button :weight normal)))))
We want to add whatever custom theme we selected to the custom variables since emacs will just
automatically read it on startup but we don't want emacs to add these settings to init.el, which in
our case is worse since we have a literate file. Send all custom variables to custom.el
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file)
Save the chosen theme after picking a new one
(defun joe/save-current-theme (THEME)
(let ((inhibit-message t)
(message-log-max nil))
(customize-save-variable 'custom-enabled-themes custom-enabled-themes)))
;; (add-hook 'kill-emacs-hook #'joe/save-current-theme)
(advice-add 'consult-theme :after #'joe/save-current-theme)
(advice-remove 'load-theme 'joe/save-current-theme)
Other
Setup other stuff
(add-hook 'text-mode-hook (lambda () (setq fill-column 100) (turn-on-auto-fill)))
(setq-default display-line-numbers 'relative)
(make-variable-buffer-local 'global-hl-line-mode)
(dolist (mode '( dashboard-mode-hook org-mode-hook term-mode-hook eww-mode-hook vterm-mode-hook dirvish-directory-view-mode-hook
eshell-mode-hook dired-mode-hook shell-mode-hook magit-mode-hook compilation-mode-hook))
(add-hook mode (lambda () (display-line-numbers-mode 0))))
;; (dolist (mode '(dashboard-mode-hook org-mode-hook term-mode-hook eww-mode-hook vterm-mode-hook
;; eshell-mode-hook shell-mode-hook magit-mode-hook compilation-mode-hook))
;; (add-hook mode (lambda () (display-line-numbers-mode 0))))
(set-window-margins nil 0)
(setq-default right-fringe-width 10)
(setq scroll-margin 0
scroll-conservatively 100000
scroll-preserve-screen-position 1)
(global-hl-line-mode +1)
(column-number-mode +1)
(modify-all-frames-parameters
'((right-divider-width . 5)
(tab-bar-lines . 0)
(internal-border-width . 12)))
(when (>= emacs-major-version 29)
(pixel-scroll-precision-mode t))
(setq inhibit-startup-screen t)
;; Don’t compact font caches during GC, in case doom modeline gets laggy issue
(setq inhibit-compacting-font-caches t)
(straight-use-package 'ligature)
(global-ligature-mode)
(straight-use-package 'highlight-quoted)
(add-hook 'emacs-lisp-mode-hook 'highlight-quoted-mode)
(straight-use-package 'doom-modeline)
(doom-modeline-mode)
(doom-modeline-def-modeline 'main
'(workspace-name bar modals bar window-number matches buffer-info remote-host buffer-position word-count selection-info)
'(parrot objed-state misc-info battery grip irc mu4e gnus github debug repl lsp bar input-method indent-info buffer-encoding bar major-mode process))
;; Set default mode-line
(add-hook 'doom-modeline-mode-hook
(lambda ()
(doom-modeline-set-modeline 'main 'default)))
(dolist (mode '(dired-mode-hook lsp-help-mode-hook fundamental-mode-hook))
(add-hook mode (lambda () (setq truncate-lines t))))
(straight-use-package 'centaur-tabs)
(setq centaur-tabs-set-bar 'under)
(setq x-underline-at-descent-line t)
(setq centaur-tabs-set-close-button nil)
(setq centaur-tabs-set-icons t)
(setq centaur-tabs-show-navigation-buttons nil)
(setq centaur-tabs-set-close-button nil)
(setq centaur-tabs-set-modified-marker nil)
(setq centaur-tabs-show-new-tab-button nil)
(setq centaur-tabs-label-fixed-length 16)
(global-set-key (kbd "C-<tab>") #'centaur-tabs-forward-tab)
(global-set-key (kbd "C-S-<iso-lefttab>") #'centaur-tabs-backward-tab)
(global-set-key (kbd "C-M-<tab>") #'centaur-tabs-forward-group)
(global-set-key (kbd "C-M-S-<iso-lefttab>") #'centaur-tabs-backward-group)
(dolist (mode '(dashboard-mode-hook))
(add-hook mode 'centaur-tabs-local-mode))
(centaur-tabs-mode +1)
Text
(set-face-attribute 'default nil :family "Fira Code Nerd Font Mono" :height 110)
;; (set-face-attribute 'variable-pitch nil :family "Source Code Pro" :height 120)
(setq-default c-basic-offset 4) ;; This is annoying
(setq-default indent-tabs-mode nil)
(setq-default tab-width 4)
(setq-default line-spacing 5)
(setq indent-line-function #'indent-relative)
;; (add-hook 'before-save-hook 'whitespace-cleanup)
Text Editor
Emacs is an great operating system, if only it had a good text editor…
Text editing
;; TODO Find out what to do with this
(defun joe/bookmark-set-and-save ()
"Save the current buffer as a bookmark"
(interactive)
(bookmark-set)
(bookmark-save))
(global-set-key (kbd "M-z") #'zap-up-to-char)
(global-set-key (kbd "M-Z") #'zap-to-char)
(defun joe/duplicate-line-comment ()
(interactive)
(let ((col (current-column)))
(duplicate-line)
(comment-line 1)
(move-to-column col)))
(global-set-key (kbd "C-c d") 'duplicate-line)
(global-set-key (kbd "C-c C-;") 'joe/duplicate-line-comment)
(global-set-key (kbd "M-n") (kbd "C-u 1 C-v"))
(global-set-key (kbd "M-p") (kbd "C-u 1 M-v"))
(defun joe/insert-line-below ()
"Insert an empty line below the current line."
(interactive)
(save-excursion
(end-of-line)
(open-line 1)))
(defun joe/insert-line-above ()
"Insert an empty line above the current line."
(interactive)
(save-excursion
(end-of-line 0)
(open-line 1)))
(global-set-key (kbd "M-o") #'joe/insert-line-below)
(global-set-key (kbd "M-O") #'joe/insert-line-above)
For the longest time I had no idea why the (
and )
vim motions for sentences
weren't working, until I randomly saw this in someone's init.el
(setq sentence-end-double-space nil)
#+end_src
Hydra
(straight-use-package 'hydra)
(defhydra hydra-navigate (global-map "<f2>")
"Window Navigation"
("q" nil "quit")
("d" joe/smooth-scroll-half-page-down "half page down")
("u" joe/smooth-scroll-half-page-up "half page up")
("e" joe/smooth-scroll-short-down "line down")
("y" joe/smooth-scroll-short-up "line up")
("n" next-line "line down")
("p" previous-line "line up")
("M-r" move-to-window-line-top-bottom "Reposition cursor"))
Multiple Cursors
(straight-use-package 'multiple-cursors)
Meow
(straight-use-package 'meow)
(defun meow-setup ()
(setq meow-cheatsheet-layout meow-cheatsheet-layout-qwerty)
(meow-motion-overwrite-define-key
'("j" . meow-next)
'("k" . meow-prev)
'("<escape>" . ignore))
(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
'("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)))
(require 'meow)
(meow-setup)
(meow-global-mode t)
(setq scroll-preserve-screen-position nil)
Boon
(straight-use-package 'boon)
(require 'boon-qwerty)
(boon-mode)
(define-key boon-moves-map "h" 'backward-char)
(define-key boon-moves-map "j" 'next-line)
(define-key boon-moves-map "k" 'previous-line)
(define-key boon-moves-map "l" 'forward-char)
(define-key boon-moves-map "b" 'boon-smarter-backward)
(define-key boon-moves-map "w" 'boon-smarter-forward)
(define-key boon-moves-map "q" '("hop" . avy-goto-char-2))
(define-key boon-command-map (kbd "C-k") #'joe/scroll-down-line)
(define-key boon-command-map (kbd "C-j") #'joe/scroll-up-line)
(define-key boon-command-map (kbd "C-d") #'View-scroll-half-page-forward)
(define-key boon-command-map (kbd "C-u") #'View-scroll-half-page-backward)
(defun joe/scroll-up-line () (interactive) (scroll-up-line 2))
(defun joe/scroll-down-line () (interactive) (scroll-down-line 2))
(define-key boon-moves-map "H" 'backward-paragraph)
(define-key boon-moves-map "L" 'forward-paragraph)
(define-key boon-moves-map "K" 'boon-smarter-upward)
(define-key boon-moves-map "J" 'boon-smarter-downward)
(define-key boon-moves-map "o" 'boon-open-next-line-and-insert)
(define-key boon-moves-map "O" 'boon-open-line-and-insert)
(define-key boon-moves-map "i" 'boon-set-insert-like-state)
(define-key boon-moves-map "r" 'boon-replace-by-character)
(define-key boon-moves-map "y" 'boon-replace-by-character)
(define-key boon-moves-map "p" 'boon-splice)
(define-key boon-moves-map "y" 'boon-treasure-region)
(define-key ctl-x-map "s" 'save-buffer)
Evil
(setq evil-want-keybinding nil)
(setq evil-undo-system 'undo-fu)
(setq evil-want-C-u-scroll t)
(setq evil-want-Y-yank-to-eol t)
(setq evil-disable-insert-state-bindings t)
(setq evil-echo-state nil)
(straight-use-package 'evil)
(straight-use-package 'evil-collection)
(evil-mode t)
(evil-collection-init)
;; TODO: We need 3 bindings; 1.) close buffer 2.) close window 3.) close buffer and window
;; To disable a keybinding just bind it to nil
(evil-set-leader nil (kbd "C-SPC"))
(evil-set-leader 'normal (kbd "SPC"))
(evil-global-set-key 'insert (kbd "C-w") #'evil-delete-backward-word)
(evil-define-key 'normal 'global (kbd "q") 'avy-goto-word-0)
;; vv to expand selection to line
(evil-global-set-key 'visual
(kbd "v")
(lambda ()
(interactive)
(evil-first-non-blank)
(exchange-point-and-mark)
(evil-end-of-line)))
(add-hook 'emacs-startup-hook
(lambda ()
(evil-global-set-key 'normal (kbd "<leader>t") tab-prefix-map)
(evil-define-key 'normal 'global
(kbd "<leader>q") 'kill-buffer-and-window
(kbd "<leader>k") 'kill-this-buffer
(kbd "<leader>h") 'help-command
(kbd "<leader>hf") 'helpful-callable
(kbd "<leader>hv") 'helpful-variable
(kbd "<leader>hk") 'helpful-key
(kbd "<leader>ho") 'helpful-symbol
(kbd "<leader>hg") 'helpful-at-point
(kbd "<leader>fb") 'bookmark-jump
(kbd "<leader>fr") 'consult-recent-file
(kbd "<leader>ff") 'project-find-file
(kbd "<leader>fi") 'joe/edit-init
(kbd "<leader>bl") 'mode-line-other-buffer
(kbd "<leader>ba") 'consult-buffer
(kbd "<leader>bb") 'consult-project-buffer
(kbd "<leader>bi") 'ibuffer
(kbd "<leader>bm") 'joe/toggle-buffer-mode
(kbd "<leader>br") 'joe/revert-buffer-no-confirm
(kbd "<leader>gg") 'magit-status
(kbd "<leader>gc") 'magit-clone
(kbd "<leader>ss") 'joe/vterm-here
(kbd "<leader>sv") 'vterm
(kbd "<leader>Ba") 'joe/bookmark-set-and-save
(kbd "<leader>Bd") 'bookmark-delete
(kbd "<leader>mr") 'joe/compile-run
(kbd "<leader>mc") 'joe/compile-comp
(kbd "<leader>ct") 'consult-theme
(kbd "<leader>cl") 'consult-line
(kbd "<leader>ci") 'consult-imenu
(kbd "<leader>cy") 'consult-yank-from-kill-ring
(kbd "<leader>cg") 'consult-ripgrep
(kbd "<leader>cF") 'consult-find
(kbd "<leader>co") 'consult-outline)))
;; (define-prefix-command 'evil-consult-map)
;; (define-key evil-consult-map "b" 'evil-window-bottom-right)
;; (define-key evil-consult-map "c" 'evil-window-delete)
(defvar global-evil-leader-map (make-sparse-keymap))
(evil-define-key 'normal 'global-evil-leader-map (kbd "SPC") 'evil-send-leader)
(define-minor-mode global-evil-leader-mode
"Minor mode to make evil leader global"
:global t
:keymap global-evil-leader-map)
(global-evil-leader-mode)
;; (evil-define-key 'normal 'global (kbd "M-h") 'tab-line-switch-to-prev-tab)
;; (evil-define-key 'normal 'global (kbd "M-l") 'tab-line-switch-to-next-tab)
(straight-use-package 'evil-surround)
(global-evil-surround-mode t)
(straight-use-package 'evil-snipe)
(evil-snipe-override-mode t)
(straight-use-package 'evil-commentary)
(evil-commentary-mode t)
(straight-use-package 'evil-goggles)
(evil-goggles-mode t)
(setq evil-goggles-duration 0.075)
(setq evil-goggles-pulse t)
(setq evil-goggles-async-duration 0.55)
(define-key evil-window-map "u" #'winner-undo)
(define-key evil-window-map "U" #'winner-redo)
(defun joe/scroll-up-line () (interactive) (scroll-up-line 2))
(defun joe/scroll-down-line () (interactive) (scroll-down-line 2))
(evil-global-set-key 'normal (kbd "C-e") #'joe/scroll-up-line)
(evil-global-set-key 'normal (kbd "C-y") #'joe/scroll-down-line)
(evil-global-set-key 'normal (kbd "<leader>p") project-prefix-map)
Buffers
(defun joe/kill-this-buffer-or-popup ()
(interactive)
"Kill the buffer normally, but if it's a popper popup, call the popper version"
(with-current-buffer (current-buffer)
(if (or (eq popper-popup-status nil)
(eq popper-popup-status 'raised))
(kill-this-buffer)
(popper-kill-latest-popup))))
(global-set-key (kbd "C-x k") #'joe/kill-this-buffer-or-popup)
(global-set-key (kbd "C-x M-k") #'kill-buffer)
(straight-use-package 'all-the-icons-ibuffer)
(add-hook 'ibuffer-mode-hook #'all-the-icons-ibuffer-mode)
(global-set-key [remap list-buffers] 'ibuffer)
(global-set-key (kbd "C-x B") 'ibuffer)
(global-set-key (kbd "C-x b") 'consult-project-buffer)
(global-set-key (kbd "C-x C-b") 'consult-buffer)
(defun joe/switch-other-buffer ()
"Switch to other buffer"
(interactive)
(switch-to-buffer (other-buffer)))
(global-set-key (kbd "C-x l") 'joe/switch-other-buffer)
(save-place-mode t)
(setq save-place-file (expand-file-name "places" user-emacs-directory))
The theme of `C-x 4` bindings is that they operate on other windows, so this function matches that behavior.
(defun joe/kill-other-buffer-and-window ()
"Kill other buffer and window"
(interactive)
(other-window 1)
(kill-buffer-and-window))
(global-set-key (kbd "C-x 4 0") 'joe/kill-other-buffer-and-window)
(global-set-key (kbd "C-x C-0") 'kill-buffer-and-window)
Windows
Window Management
(add-hook 'after-init-hook (lambda () (winner-mode t)))
(straight-use-package 'rotate)
(setq joe/popper-side-toggle 'right)
(defun joe/window-split-vertical () (interactive) (set 'joe/popper-side-toggle 'right) (rotate:main-horizontal))
(defun joe/window-split-horizontal () (interactive) (set 'joe/popper-side-toggle 'below) (rotate:main-vertical))
(define-key ctl-x-4-map (kbd "|") #'joe/window-split-vertical)
(define-key ctl-x-4-map (kbd "-") #'joe/window-split-horizontal)
(define-key ctl-x-4-map (kbd "t") #'rotate-window)
(straight-use-package 'ace-window)
(global-set-key (kbd "C-x o") #'ace-window)
(global-set-key (kbd "C-x C-o") #'ace-swap-window)
(global-set-key (kbd "s-h") #'windmove-left)
(global-set-key (kbd "s-l") #'windmove-right)
(global-set-key (kbd "s-k") #'windmove-up)
(global-set-key (kbd "s-j") #'windmove-down)
Popper
(straight-use-package 'popper)
(require 'popper)
(setq popper-reference-buffers
'("\\*compilation\\*" compilation-mode
"^\\*vterm\\*" vterm-mode
"^\\*Flymake.*" flymake-mode
"^\\*Flycheck.*" flycheck-error-list-mode
"^\\*lsp-help\\*" lsp-help-mode
"^\\*ert\\*" ert-results-mode
"^\\*cargo-test\\*" cargo-test-mode
"^\\*rustic-compilation\\*" rustic-compilation-mode
;; "^\\*ansi-term\\*$" term-mode
("^\\*Warnings\\*$" . hide)
help-mode
helpful-mode))
(global-set-key (kbd "C-`") 'popper-toggle-latest)
(global-set-key (kbd "C-~") 'popper-cycle)
(global-set-key (kbd "C-M-`") 'popper-toggle-type)
(require 'popper-echo)
(popper-echo-mode t)
(defun joe/get-popper-dir ()
(with-current-buffer (current-buffer)
(if (or (> (window-width) 170) (eq olivetti-mode t))
joe/popper-side-toggle
'below)))
;; TODO Consider adding checks for vertical splits and only popup on right if so
(defun joe/popper-display-func (buffer &optional _alist)
(cond
((cl-find-if
(lambda (window)
(with-current-buffer (window-buffer window) popper-popup-status))
(window-list))
(display-buffer-reuse-window
buffer
`((body-function . ,#'select-window))))
((and (not (window-in-direction 'right))
(not (window-in-direction 'left)))
(display-buffer-in-direction
buffer
`((window-height . 0.4)
(window-width . 0.4)
(direction . right)
(body-function . ,#'select-window))))
(t
(display-buffer-in-direction
buffer
`((window-height . 0.4)
(window-width . 0.4)
(direction . below)
(body-function . ,#'select-window))))))
(setq popper-display-function #'joe/popper-display-func)
(popper-mode t)
Scrolling
(require 'pixel-scroll)
(setq pixel-scroll-precision-large-scroll-height 10.0)
(setq pixel-scroll-precision-interpolation-factor 30)
(defun joe/pixel-scroll-lerp (amount direction)
(let ((half-height (* direction (/ (window-height) amount)))
(point-min-or-max (if (> direction 0) (point-min) (point-max))))
(when (or (and (pos-visible-in-window-p (point-min))
(< direction 0)))
(pixel-scroll-precision-interpolate (* 5 half-height)))
(pixel-scroll-precision-interpolate (* 5 half-height))))
(defun joe/smooth-scroll-half-page-down ()
"Smooth scroll down"
(interactive)
(joe/pixel-scroll-lerp 1.5 -1))
;; (pixel-scroll-kbd-up))
(defun joe/smooth-scroll-half-page-up ()
"Smooth scroll up"
(interactive)
(joe/pixel-scroll-lerp 1.5 1))
(defun joe/smooth-scroll-short-down ()
"Smooth scroll down"
(interactive)
(joe/pixel-scroll-lerp 8 -1))
(defun joe/smooth-scroll-short-up ()
"Smooth scroll down"
(interactive)
(joe/pixel-scroll-lerp 8 1))
;; scroll-up-command
(global-set-key (kbd "C-v") #'joe/smooth-scroll-half-page-down)
(global-set-key (kbd "M-v") #'joe/smooth-scroll-half-page-up)
(global-set-key (kbd "C-S-v") #'joe/smooth-scroll-short-down)
(global-set-key (kbd "M-S-v") #'joe/smooth-scroll-short-up)
(straight-use-package 'topspace)
Tabs/Workspaces
(setq tab-bar-mode t)
(setq tab-bar-show nil)
(global-set-key (kbd "M-1") '(lambda () (interactive) (tab-bar-select-tab 1)))
(global-set-key (kbd "M-2") '(lambda () (interactive) (tab-bar-select-tab 2)))
(global-set-key (kbd "M-3") '(lambda () (interactive) (tab-bar-select-tab 3)))
(global-set-key (kbd "M-4") '(lambda () (interactive) (tab-bar-select-tab 4)))
(global-set-key (kbd "M-5") '(lambda () (interactive) (tab-bar-select-tab 5)))
(global-set-key (kbd "M-6") '(lambda () (interactive) (tab-bar-select-tab 6)))
(global-set-key (kbd "M-7") '(lambda () (interactive) (tab-bar-select-tab 7)))
(global-set-key (kbd "M-8") '(lambda () (interactive) (tab-bar-select-tab 8)))
(global-set-key (kbd "M-9") '(lambda () (interactive) (tab-bar-select-tab 9)))
(evil-global-set-key 'insert (kbd "M-1") '(lambda () (interactive) (tab-bar-select-tab 1)))
(evil-global-set-key 'insert (kbd "M-2") '(lambda () (interactive) (tab-bar-select-tab 2)))
(evil-global-set-key 'insert (kbd "M-3") '(lambda () (interactive) (tab-bar-select-tab 3)))
(evil-global-set-key 'insert (kbd "M-4") '(lambda () (interactive) (tab-bar-select-tab 4)))
(evil-global-set-key 'insert (kbd "M-5") '(lambda () (interactive) (tab-bar-select-tab 5)))
(evil-global-set-key 'insert (kbd "M-6") '(lambda () (interactive) (tab-bar-select-tab 6)))
(evil-global-set-key 'insert (kbd "M-7") '(lambda () (interactive) (tab-bar-select-tab 7)))
(evil-global-set-key 'insert (kbd "M-8") '(lambda () (interactive) (tab-bar-select-tab 8)))
(evil-global-set-key 'insert (kbd "M-9") '(lambda () (interactive) (tab-bar-select-tab 9)))
(evil-global-set-key 'normal (kbd "M-1") '(lambda () (interactive) (tab-bar-select-tab 1)))
(evil-global-set-key 'normal (kbd "M-2") '(lambda () (interactive) (tab-bar-select-tab 2)))
(evil-global-set-key 'normal (kbd "M-3") '(lambda () (interactive) (tab-bar-select-tab 3)))
(evil-global-set-key 'normal (kbd "M-4") '(lambda () (interactive) (tab-bar-select-tab 4)))
(evil-global-set-key 'normal (kbd "M-5") '(lambda () (interactive) (tab-bar-select-tab 5)))
(evil-global-set-key 'normal (kbd "M-6") '(lambda () (interactive) (tab-bar-select-tab 6)))
(evil-global-set-key 'normal (kbd "M-7") '(lambda () (interactive) (tab-bar-select-tab 7)))
(evil-global-set-key 'normal (kbd "M-8") '(lambda () (interactive) (tab-bar-select-tab 8)))
(evil-global-set-key 'normal (kbd "M-9") '(lambda () (interactive) (tab-bar-select-tab 9)))
Projects
(defun joe/project-root-override (dir)
(let ((override (locate-dominating-file dir ".project.el")))
(if override
(cons 'transient override)
(project-try-vc dir))))
(add-hook 'project-find-functions #'joe/project-root-override)
VEMCO
Vertico Embark Marginalia Consult Orderless
(straight-use-package 'all-the-icons-completion)
(straight-use-package '(vertico :files (:defaults "extensions/*")
:includes (vertico-indexed
vertico-repeat
vertico-directory)))
(vertico-mode)
;; (straight-use-package 'vertico-posframe)
(define-key vertico-map (kbd "C-w") #'vertico-directory-delete-word)
;; (define-key vertico-map (kbd "C-r") #'vertico-repeat-)
;; (vertico-posframe-mode t)
(vertico-indexed-mode)
;; (setq vertico-posframe-parameters
;; '((left-fringe . 100)
;; (right-fringe . 100)))
;; (setq vertico-posframe-border-width 5)
;; (setq vertico-posframe-min-height 20)
;; (defun posframe-poshandler-slightly-below-top (info)
;; (cons (/ (- (plist-get info :parent-frame-width)
;; (plist-get info :posframe-width))
;; 2)
;; 150))
;; (setq vertico-posframe-poshandler #'posframe-poshandler-slightly-below-top)
(setq vertico-count 17
vertico-resize nil
vertico-cycle t)
(define-key vertico-map (kbd "C-M-n") #'vertico-next-group)
;; #' "C-M-p" #'vertico-previous-group)
(require 'savehist)
(savehist-mode)
(add-hook 'minibuffer-setup-hook #'vertico-repeat-save)
(add-to-list 'savehist-additional-variables 'vertico-repeat-history)
(straight-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))
(straight-use-package 'embark)
(setq embark-quit-after-action '((kill-buffer . nil)))
(defvar joe-mode-map
(let ((map (make-sparse-keymap)))
;; (define-key map (kbd "C-'") #'embark-act)
(define-key map (kbd "M-'") #'embark-dwim)
(define-key map (kbd "C-/") #'comment-line)
map)
"my-keys-minor-mode keymap.")
(define-minor-mode joe-mode
"A minor mode so that my key settings override annoying major modes."
:init-value t
:lighter " joe-keys")
(joe-mode t)
(defun embark-which-key-indicator ()
"An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
(lambda (&optional keymap targets prefix)
(if (null keymap)
(which-key--hide-popup-ignore-command)
(which-key--show-keymap
(if (eq (plist-get (car targets) :type) 'embark-become)
"Become"
(format "Act on %s '%s'%s"
(plist-get (car targets) :type)
(embark--truncate-target (plist-get (car targets) :target))
(if (cdr targets) "…" "")))
(if prefix
(pcase (lookup-key keymap prefix 'accept-default)
((and (pred keymapp) km) km)
(_ (key-binding prefix 'accept-default)))
keymap)
nil nil t (lambda (binding)
(not (string-suffix-p "-argument" (cdr binding))))))))
(setq embark-indicators
'(embark-which-key-indicator
embark-highlight-indicator
embark-isearch-highlight-indicator))
(defun embark-hide-which-key-indicator (fn &rest args)
"Hide the which-key indicator immediately when using the completing-read prompter."
(which-key--hide-popup-ignore-command)
(let ((embark-indicators
(remq #'embark-which-key-indicator embark-indicators)))
(apply fn args)))
(advice-add #'embark-completing-read-prompter
:around #'embark-hide-which-key-indicator)
(global-set-key (kbd "C-'") #'embark-act)
(straight-use-package 'embark-consult)
(straight-use-package 'marginalia)
(setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
(setq marginalia-align 'right)
(setq marginalia-max-relative-age most-positive-fixnum)
(marginalia-mode)
(define-key minibuffer-local-map (kbd "M-A") #'marginalia-cycle)
(require 'all-the-icons-completion)
(all-the-icons-completion-mode)
(all-the-icons-completion-marginalia-setup)
(add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup)
(straight-use-package 'orderless)
(setq completion-styles '(orderless basic)
completion-category-overrides '((file (styles basic partial-completion))))
Consult
(straight-use-package 'consult)
(straight-use-package 'consult-lsp)
;; (defun joe/consult-line ()
;; (interactive)
;; (let ((vertico-posframe-mode -1))
;; (consult-line)))
(global-set-key (kbd "C-. C-l") 'consult-line)
;; (global-set-key (kbd "C-. C-l") 'joe/consult-line)
(global-set-key (kbd "C-. C-i") 'consult-imenu)
(global-set-key (kbd "C-. C-t") 'consult-theme)
(global-set-key (kbd "C-. C-r") 'consult-recent-file)
(global-set-key (kbd "C-. C-y") 'consult-yank-from-kill-ring)
;; (global-set-key (kbd "C-s") 'swiper-thing-at-point)
Dirvish/Dired
(straight-use-package 'dirvish)
(with-eval-after-load 'dirvish
(dirvish-override-dired-mode)
(setq delete-by-moving-to-trash t)
(setq dired-dwim-target t)
(setq dirvish-reuse-session nil)
(dirvish-define-preview exa (file)
"Use `exa' to generate directory preview."
:require ("exa") ; tell Dirvish to check if we have the executable
(when (file-directory-p file) ; we only interest in directories here
`(shell . ("exa" "--icons" "--color=always" "--no-user" "-al" "--group-directories-first" ,file))))
(add-to-list 'dirvish-preview-dispatchers 'exa)
(setq dired-listing-switches "-l --sort=version --almost-all --human-readable --time-style=long-iso --group-directories-first --no-group")
(setq dirvish-preview-dispatchers (cl-substitute 'pdf-preface 'pdf dirvish-preview-dispatchers))
(setq dirvish-attributes '(all-the-icons file-size collapse subtree-state))
(defun joe/dirvish-find-directory (dir)
(interactive "FDirvish Directory:")
(dirvish-dwim dir))
(setq dirvish-quick-access-entries
'(("h" "~/" "Home")
("d" "~/Downloads/" "Downloads")
("D" "~/Documents/" "Documents")
("b" "~/Documents/Books/" "Books")
("p" "~/Development/" "Dev")
("t" "~/TYCS/" "Teachyourselfcs")
("r" "~/Repositories" "Repos")
("B" "~/pCloudDrive/" "pCloud")))
(when (boundp 'evil-mode)
(evil-define-key 'normal dirvish-mode-map
(kbd "C-c f") #'dirvish-fd
(kbd "a") #'dirvish-quick-access
(kbd ".") #'dired-create-empty-file
(kbd "f") #'dirvish-file-info-menu
(kbd "y") #'dirvish-yank-menu
(kbd "h") #'dired-up-directory
(kbd "l") #'dired-find-file
(kbd "s") #'dirvish-quicksort
(kbd "v") #'dirvish-vc-menu
(kbd "q") #'dirvish-quit
(kbd "L") #'dirvish-history-go-forward
(kbd "H") #'dirvish-history-go-backward
(kbd "o") #'dired-open-file
(kbd "TAB") #'dirvish-subtree-toggle
(kbd "M-n") #'dirvish-narrow
(kbd "M-l") #'dirvish-ls-switches-menu
(kbd "M-m") #'dirvish-mark-menu
(kbd "M-t") #'dirvish-layout-toggle
(kbd "M-s") #'dirvish-setup-menu
(kbd "M-e") #'dirvish-emerge-menu
(kbd "M-j") #'dirvish-fd-jump)))
(when (boundp 'evil-mode)
(evil-global-set-key 'normal (kbd "-") #'dirvish-dwim))
(global-set-key (kbd "C-x d") #'dirvish-dwim)
(global-set-key (kbd "C-x C-d") #'joe/dirvish-find-directory)
(defun dired-open-file ()
"In dired, open the file named on this line."
(interactive)
(let* ((file (dired-get-filename nil t)))
(message "Opening %s..." file)
(call-process "xdg-open" nil 0 nil file)
(message "Opening %s done" file)))
Org Mode
(straight-use-package 'org-bullets)
(defun joe/org-init ()
(setq org-todo-keywords '((sequence "TODO" "IN-PROGRESS" "|" "DONE" "BACKLOG")))
(setq org-agenda-files '("~/todo.org"))
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(makefile . t)
(ocaml . t)
(python . t)
(C . t)
(haskell . t)
(rust . t)
(shell . t)))
(require 'org-tempo)
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("ml" . "src ocaml"))
(add-to-list 'org-structure-template-alist '("rs" . "src rust"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("hs" . "src haskell"))
(add-to-list 'org-structure-template-alist '("cc" . "src C :includes stdio.h stdlib.h"))
(setq org-edit-src-content-indentation 0))
(with-eval-after-load 'org (joe/org-init))
(setq org-blank-before-new-entry
'((heading . nil)
(plain-list-item . nil)))
(setq org-cycle-separator-lines 1)
(setq org-hide-emphasis-markers t)
(setq org-src-window-setup 'current-window)
(defun joe/org-hook ()
(local-set-key (kbd "C-. C-i") 'consult-org-heading)
(org-bullets-mode)
(org-indent-mode))
(add-hook 'org-mode-hook 'joe/org-hook)
(straight-use-package 'org-kanban)
Avy
(straight-use-package 'avy)
(setq avy-case-fold-search nil)
(setq avy-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l ?q ?w ?e ?r ?u ?i ?o ?p ?z ?x ?c ?v ?n ?m))
(define-key global-map (kbd "C-;") 'avy-goto-char) ;; I use this most frequently
;; (define-key global-map (kbd "C-'") 'avy-goto-line) ;; Consistent with ivy-avy
(define-key global-map (kbd "M-g c") 'avy-goto-char)
(define-key global-map (kbd "M-g e") 'avy-goto-word-0) ;; lots of candidates
(define-key global-map (kbd "M-g g") 'avy-goto-line) ;; digits behave like goto-line
(define-key global-map (kbd "M-g w") 'avy-goto-word-1) ;; first character of the word
(define-key global-map (kbd "M-g P") 'avy-pop-mark)
Helpful
(straight-use-package 'helpful)
(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)
(global-set-key (kbd "C-h C-d") #'helpful-at-point)
(global-set-key (kbd "C-h F") #'helpful-function)
(global-set-key (kbd "C-h C") #'helpful-command)
Terminals/Shells
(straight-use-package 'vterm)
(setq vterm-shell "/bin/fish")
(setq vterm-timer-delay 0.01)
(setq vterm-buffer-name-string "VTerm - %s")
(setq vterm-max-scrollback 100000)
(setq vterm-kill-buffer-on-exit t)
(defun joe/close-popup-buffer (vterm-buf event-msg)
(unless (or (eq popper-popup-status nil)
(eq popper-popup-status 'raised))
(popper-close-latest)))
(setq vterm-exit-functions '(joe/close-popup-buffer))
(defun joe/vterm-here ()
(interactive)
(let ((vterm-buf (vterm--internal #'switch-to-buffer)))
(with-current-buffer vterm-buf
(setq popper-popup-status 'raised))))
(global-set-key (kbd "C-c t") #'vterm)
(global-set-key (kbd "C-c T") #'joe/vterm-here)
;; (setq explicit-shell-file-name "~/Development/fell/fell")
(add-hook 'shell-mode (lambda () (setq-local global-hl-line-mode nil)))
(setq shell-kill-buffer-on-exit t)
(add-hook 'vterm-mode-hook
(lambda ()
(define-key vterm-mode-map (kbd "C-c C-x") #'vterm-send-C-x)
(when (boundp 'evil-mode)
(evil-define-key 'insert vterm-mode-map (kbd "C-w") #'vterm-send-C-w)
(evil-define-key 'insert vterm-mode-map (kbd "<delete>") #'vterm-send-delete))
(setq-local global-hl-line-mode nil)))
VTerm is loading TRAMP along with it which slows down init time noticeably so call this after startup. Reason we have to call this is so the vterm fucntion can call `vterm–internal`.
(add-hook 'emacs-startup-hook (lambda () (require 'vterm)))
Undo Fu
(straight-use-package 'undo-fu)
(straight-use-package 'undo-fu-session)
(straight-use-package 'vundo)
(global-undo-fu-session-mode)
(setq undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'"))
(setq undo-limit 6710886400) ;; 64mb.
(setq undo-strong-limit 100663296) ;; 96mb.
(setq undo-outer-limit 1006632960) ;; 960mb.
Which Key
(straight-use-package 'which-key)
(setq which-key-idle-delay 0.3)
(add-hook 'after-init-hook (lambda () (which-key-mode)))
(when (boundp 'evil-mode)
(which-key-add-keymap-based-replacements evil-normal-state-map
"<leader>f" '("Files")
"<leader>b" '("Buffers")
"<leader>B" '("Bookmarks")
"<leader>c" '("Consult")
"<leader>d" '("Dired")
"<leader>g" '("Git")
"<leader>m" '("Make")
"<leader>t" '("Tabs")
"<leader>p" '("Packages")
"<leader>s" '("Shell (vterm)")
"<leader>h" '("Help")))
IDE Features
REPLs
(evil-define-key 'insert comint-mode-map (kbd "C-n") 'comint-next-input)
(evil-define-key 'insert comint-mode-map (kbd "C-p") 'comint-previous-input)
Company
println!("Hello world");
;; (global-set-key [remap dabbrev-expand] 'hippie-expand)
;; (global-set-key [remap hippie-expand] 'dabbrev-expand)
;; (global-set-key (kbd "M-/") 'dabbrev-expand)
;; (straight-use-package 'fancy-dabbrev)
;; (global-set-key (kbd "TAB") 'fancy-dabbrev-expand-or-indent)
;; (global-set-key (kbd "<backtab>") 'fancy-dabbrev-backward)
;; (global-set-key (kbd "TAB") 'indent-for-tab-command)
;; (global-set-key (kbd "<backtab>") nil)
;; (straight-use-package 'kind-icon)
;; (require 'kind-icon)
;; (setq completion-in-region-function #'consult-completion-in-region)
;; (setq completion-in-region-function (kind-icon-enhance-completion completion-in-region-function))
;; (setq completion-in-region-function
;; (kind-icon-enhance-completion
;; (lambda (&rest args)
;; (let ((marginalia-classifiers nil))
;; (apply #'consult-completion-in-region args)))))
(setq completion-in-region-function
(lambda (&rest args)
(apply (if vertico-mode
#'consult-completion-in-region
#'completion--in-region)
args)))
(straight-use-package 'company)
(require 'company)
(setq company-minimum-prefix-length 1)
(setq company-tooltip-align-annotations t)
(setq company-minimum-prefix-length 2)
(add-to-list 'completion-at-point-functions #'elisp-completion-at-point)
(with-eval-after-load 'company
(define-key company-active-map (kbd "C-n") nil)
(define-key company-active-map (kbd "C-p") nil)
(define-key company-active-map (kbd "<return>") nil)
(define-key company-active-map (kbd "RET") nil)
(define-key company-active-map (kbd "M-d") #'company-show-doc-buffer)
(define-key company-active-map (kbd "C-f") #'company-complete-selection)
(define-key company-active-map [tab] #'company-complete-common-or-cycle)
(define-key company-active-map (kbd "<backtab>") (lambda () (interactive) (company-complete-common-or-cycle -1)))
(setq company-idle-delay 0.15
company-tooltip-idle-delay 20
company-require-match nil
company-frontends '(company-preview-frontend company-echo-metadata-frontend)
;; company-frontends
;; '(company-pseudo-tooltip-unless-just-one-frontend
;; company-echo-metadata-frontend)
company-backends '((company-capf company-elisp company-files)))
(setq company-transformers '(company-sort-by-occurrence)))
(add-hook 'after-init-hook (lambda () (global-company-mode)))
;; (setq completion-in-region-function #'completion--in-region)
;; (setq completion-in-region-function
;; (lambda (&rest args)
;; (apply (if vertico-mode
;; #'consult-completion-in-region
;; #'completion--in-region)
;; args)))
;; (straight-use-package 'company)
;; (require 'company)
;; (setq company-minimum-prefix-length 1)
;; (setq company-tooltip-align-annotations t)
;; (setq company-minimum-prefix-length 2)
;; (with-eval-after-load 'company
;; (define-key company-active-map (kbd "C-n") nil)
;; (define-key company-active-map (kbd "C-p") nil)
;; (define-key company-active-map (kbd "<return>") nil)
;; (define-key company-active-map (kbd "RET") nil)
;; (define-key company-active-map (kbd "M-d") #'company-show-doc-buffer)
;; (define-key company-active-map (kbd "C-f") #'company-complete-selection)
;; (define-key company-active-map [tab] #'company-complete-common-or-cycle)
;; (define-key company-active-map (kbd "<backtab>") (lambda () (interactive) (company-complete-common-or-cycle -1)))
;; (setq company-idle-delay 0.15
;; company-tooltip-idle-delay 20
;; company-require-match nil
;; company-frontends '(company-preview-frontend company-echo-metadata-frontend)
;; ;; company-frontends
;; ;; '(company-pseudo-tooltip-unless-just-one-frontend
;; ;; company-echo-metadata-frontend)
;; company-backends '((company-capf company-elisp company-files)))
;; (setq company-transformers '(company-sort-by-occurrence)))
;; (add-hook 'after-init-hook (lambda () (global-company-mode)))
;; (dolist (mode '(inferior-python-mode-hook))
;; (add-hook mode (lambda () (company-mode -1))))
;; (straight-use-package 'cape)
;; ;; (setq completion-at-point-functions '(cape-symbol))
;; (add-to-list 'completion-at-point-functions #'cape-dabbrev)
;; (add-to-list 'completion-at-point-functions #'cape-file)
;; (add-to-list 'completion-at-point-functions #'cape-symbol)
;; (setq completion-at-point-functions '(cape-symbol))
;; (straight-use-package 'corfu)
;; (global-corfu-mode 1)
;; (setq corfu-auto t)
;; (setq corfu-auto-delay 0.15)
;; (setq corfu-count 2)
;; ;; (setq corfu-preview-current t)
;; (define-key corfu-map "\C-f" #'corfu-complete)
LSP
(straight-use-package 'lsp-mode)
(straight-use-package 'lsp-ui)
(setq lsp-enable-which-key-integration t)
(setq lsp-keymap-prefix "C-c c")
;; (setq lsp-ui-peek-always-show t)
;; (setq lsp-ui-doc-enable t)
;; TODO: Disable lsp sideline
(setq lsp-headerline-breadcrumb-enable nil)
(setq lsp-eldoc-enable-hover t)
(setq max-mini-window-height 0.25)
(setq lsp-eldoc-enable-hover t)
(setq lsp-ui-doc-enable nil)
(setq eldoc-echo-area-use-multiline-p 'truncate-sym-name-if-fit)
(setq eldoc-idle-delay 0)
(setq lsp-idle-delay 0.2)
;; Signatures
(setq lsp-signature-doc-lines t)
(setq lsp-signature-render-documentation nil)
(setq lsp-eldoc-render-all nil)
(when (boundp 'evil-mode)
(evil-global-set-key 'normal (kbd "M-d") #'lsp-describe-thing-at-point)
(evil-global-set-key 'normal (kbd "<leader>lh") 'lsp-headerline-breadcrumb-mode)
(evil-global-set-key 'normal (kbd "<leader>li") 'lsp-rust-analyzer-inlay-hints-mode)
(evil-global-set-key 'normal (kbd "<leader>cs") 'consult-lsp-symbols)
(evil-global-set-key 'normal (kbd "<leader>cf") 'consult-lsp-file-symbols))
;; This function allows us to extract Rust's true function signature
(cl-defmethod lsp-clients-extract-signature-on-hover (contents (_server-id (eql rust-analyzer)))
(-let* (((&hash "value") contents)
(groups (--partition-by (s-blank? it) (s-lines (s-trim value))))
(sig_group (if (s-equals? "```rust" (car (-third-item groups)))
(-third-item groups)
(car groups)))
(sig (--> sig_group
(--drop-while (s-equals? "```rust" it) it)
(--take-while (not (s-equals? "```" it)) it)
(--map (s-trim it) it)
(s-join " " it))))
(lsp--render-element (concat "```rust\n" sig "\n```"))))
Flycheck
(straight-use-package 'flycheck)
;; TODO Add wrapping to these functions
(when (boundp 'evil-mode)
(evil-global-set-key 'normal (kbd "M-e") #'flycheck-next-error)
(evil-global-set-key 'normal (kbd "M-E") #'flycheck-previous-error)
(evil-global-set-key 'normal (kbd "<leader>ee") 'flycheck-mode)
(evil-global-set-key 'normal (kbd "<leader>el") #'flycheck-list-errors)
(evil-global-set-key 'normal (kbd "<leader>ce") #'consult-lsp-diagnostics))
Compilation
(setq compilation-auto-jump-to-first-error t)
(define-key global-map (kbd "<f9>") #'recompile)
(define-key global-map (kbd "<f10>") #'compile)
Debugging
DAP
(straight-use-package 'dap-mode)
(require 'dap-mode)
;; (setq dap-auto-configure-features '(locals breakpoints expressions tooltip))
(require 'dap-cpptools)
(dap-cpptools-setup)
(add-hook 'dap-stopped-hook
(lambda (arg) (call-interactively #'dap-hydra)))
(setq dap-cpptools-extension-version "1.12.1")
(setq dap-default-terminal-kind "integrated")
(dap-auto-configure-mode +1)
(dap-register-debug-template
"Rust::CppTools Run Configuration"
(list :type "cppdbg"
:request "launch"
:name "Rust::Run"
:MIMode "gdb"
:miDebuggerPath "rust-gdb"
:environment []
:program "${workspaceFolder}/target/debug/kanban-tui"
:cwd "${workspaceFolder}"
:console "external"
:dap-compilation "cargo build"
:dap-compilation-dir "${workspaceFolder}"))
Languages
Python
(straight-use-package 'elpy)
(define-key inferior-python-mode-map (kbd "C-n") #'comint-next-input)
(define-key inferior-python-mode-map (kbd "C-p") #'comint-previous-input)
C
Design some basic functions for compiling. There's also a hook to close the popper window if there are no warnings or errors. It will check if we are still in the compilation buffer as well as whether the point hasn't been moved. This way, if I switched to another popper buffer, like vterm, it doesn't close it.
(straight-use-package 'disaster)
(defun joe/c-mode-hook ()
(local-set-key (kbd "C-x c r") (defun joe/make-run () (interactive) (compile "make run")))
(local-set-key (kbd "C-x c c") (defun joe/make () (interactive) (compile "make")))
(electric-pair-local-mode t)
(c-toggle-comment-style -1))
(add-hook 'c-mode-hook #'joe/c-mode-hook)
(defun joe/close-compilation-if-no-warn-err (buffer string)
"Bury a compilation buffer if succeeded without warnings "
(if (and
(string-match "compilation" (buffer-name buffer))
(string-match "finished" string)
(not
(with-current-buffer (current-buffer)
(search-forward "warning" nil t))))
(run-with-timer 1.5 nil
(lambda ()
(and (eq (point) 1)
(string-match "compilation" (buffer-name (current-buffer)))
(popper-close-latest))))))
(add-hook 'compilation-finish-functions 'joe/close-compilation-if-no-warn-err)
Rust
(straight-use-package 'rustic)
(straight-use-package 'ob-rust) ;; Org-Babel
;; Disabling until we figure out how to get it working
;; (straight-use-package 'parsec) ;; Required by evcxr-mode
;; (straight-use-package
;; '(evcxr
;; :type git
;; :host github
;; :repo "serialdev/evcxr-mode"))
(add-hook 'rust-mode-hook (lambda () (electric-pair-local-mode)))
(add-hook 'rust-mode-hook
(lambda ()
(evcxr-minor-mode)
(electric-pair-local-mode)))
(with-eval-after-load 'rustic
;; Don't autostart
(setq rustic-lsp-setup-p nil)
(setq lsp-rust-analyzer-server-display-inlay-hints t)
(setq lsp-rust-analyzer-display-lifetime-elision-hints-enable "always")
(setq lsp-rust-analyzer-display-chaining-hints t)
(setq lsp-rust-analyzer-display-lifetime-elision-hints-use-parameter-names t)
(setq lsp-rust-analyzer-display-closure-return-type-hints t)
(setq lsp-rust-analyzer-display-parameter-hints t)
(setq lsp-rust-analyzer-display-reborrow-hints t)
(setq lsp-rust-analyzer-cargo-watch-command "clippy"))
Elisp
(global-set-key (kbd "C-x C-r") 'eval-region)
Haskell
(straight-use-package 'haskell-mode)
(setq haskell-interactive-popup-errors nil)
(evil-define-key 'insert haskell-interactive-mode-map (kbd "C-n") #'haskell-interactive-mode-history-next)
(evil-define-key 'insert haskell-interactive-mode-map (kbd "C-p") #'haskell-interactive-mode-history-previous)
OCaml
(straight-use-package 'tuareg)
(straight-use-package 'dune)
(straight-use-package 'utop)
(straight-use-package 'merlin)
(straight-use-package 'merlin-eldoc)
;; Might be worth checking out, depeding on whether we stick with flycheck or not
;; (straight-use-package 'flycheck-ocaml)
;; Also check this out, see if it adds anything
;; (require 'ocp-indent)
(defun opam-env ()
"Load the opam env to get the PATH variables so everything works"
(interactive nil)
(dolist (var
(car (read-from-string
(shell-command-to-string "opam config env --sexp"))))
(setenv (car var) (cadr var))))
(setq opam-share
(substring (shell-command-to-string
"opam config var share 2> /dev/null") 0 -1))
(add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share))
We won't use the LSP server but rather directly talk to Merlin, since I guess LSP just wraps Merlin and there's no need for a middle-man when it's already been implemented.
;; (require 'utop)
;; Use the opam installed utop
(setq utop-command "opam exec -- utop -emacs")
(let ((opam-share (ignore-errors (car (process-lines "opam" "var" "share")))))
(when (and opam-share (file-directory-p opam-share))
;; Register Merlin
(add-to-list 'load-path (expand-file-name "emacs/site-lisp" opam-share))
(autoload 'merlin-mode "merlin" nil t nil)
;; Automatically start it in OCaml buffers
(add-hook 'tuareg-mode-hook 'merlin-mode t)
(add-hook 'caml-mode-hook 'merlin-mode t)
;; Use opam switch to lookup ocamlmerlin binary
(setq merlin-command 'opam)))
Clojure
(straight-use-package 'clojure-mode)
(straight-use-package 'cider)
(setq cider-show-error-buffer 'only-in-repl)
FSharp
(straight-use-package 'fsharp-mode)
;; (straight-use-package 'eglot-fsharp)
Go
(straight-use-package 'go-mode)
;; (straight-use-package 'go-imports)
Other
(straight-use-package 'json)
(straight-use-package 'markdown-mode)
Magit
The best git porcelain/client I've ever used. Also kill stray magit buffers left over as explained here
(straight-use-package 'magit)
(defun joe/magit-kill-buffers (param)
"Restore window configuration and kill all Magit buffers."
(let ((buffers (magit-mode-get-buffers)))
(magit-restore-window-configuration)
(mapc #'kill-buffer buffers)))
(when (boundp 'evil-mode)
(add-hook 'with-editor-mode-hook 'evil-insert-state))
(setq magit-bury-buffer-function #'joe/magit-kill-buffers)
(setq magit-clone-set-remote.pushDefault t)
(setq magit-clone-default-directory "~/Development/")
;; (define-key magit-mode-map "h" 'backward-char)
;; (define-key magit-mode-map "l" 'backward-char)
Restclient
(straight-use-package 'restclient)
COMMENT Local variables
;; Local Variables: ;; eval: (add-hook 'after-save-hook '(lambda () (org-babel-tangle)) nil t) ;; End: