This is my emacs, there are many like it, but this one is mine…
I currently use 29.x
on both Linux and Mac systems. YMMV on Windows
or different versions of Emacs.
You will need the following already installed for this configuration to run correctly.
Install the Fira Code Retina font because it’s beautiful and makes for a wonderful font. You will need aspell installed in order to user Flymake mode. Clojure mode requires leiningen.
I strongly suggest you remap your cap locks key to control to help
reduce the onset of Emacs pinky. I even go further and have a new key
binding for M-x
, so you are hitting Ctrl
instead of Alt
.
(require 'use-package)
I like to have my Emacs clean, chrisp, and minimal. Disable the menu bar, tool bar, and scroll Protip: Learn the Emacs navigation key strokes until they are second nature. You can thank me later.
(when window-system
(set-frame-font "Fira Code Retina 20" nil t))
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
;; some breathing room
(set-fringe-mode 10)
(add-to-list 'initial-frame-alist '(fullscreen . maximized))
Set the default GC threshold to be 100MB to increase startup performance. Reset back to default at the end of file.
(setq gc-cons-threshold (* 1024 1024 100))
To improve startup performance, we’ll manually set up the load-path and avoid calling (package-initialize). By setting package–init-file-ensured to t, we prevent package.el from automatically initializing the package system. Additionally, we set package-enable-at-startup to nil, ensuring packages won’t load automatically at startup; use-package will manage package loading instead.
(eval-and-compile
(setq load-prefer-newer t
package-user-dir "~/.emacs.d/elpa"
package--init-file-ensured t
package-enable-at-startup nil)
(unless (file-directory-p package-user-dir)
(make-directory package-user-dir t)))
(setq use-package-always-defer t
use-package-verbose t)
(eval-and-compile
(setq load-path (append load-path (directory-files package-user-dir t "^[^.]" t))))
(use-package timu-spacegrey-theme
:ensure t
:demand t
:config
(load-theme 'timu-spacegrey t))
(use-package mood-line
:ensure t
:config (mood-line-mode))
Experimenting with parens
(use-package rainbow-delimiters
:ensure t
:defer t
:hook ((prog-mode . rainbow-delimiters-mode)))
Dats me.
(setq user-full-name "Trevor Bernard"
user-mail-address "[email protected]")
Ignore minimize functionality when you’re in the GUI because it’s very annoying to accidentally minimize your window.
(when window-system
(keymap-global-set "C-z" 'ignore)
(keymap-global-set "C-x C-z" 'ignore))
M-x is one of the most wildly used key combinations in Emacs but it’s also the most annoying. You have to scrunch your left thumb and fore finger in the most uncomfortable RSI inducing way.
I choose to rebind M-x
to C-x C-m
because of an article Steve
Yegge wrote called: Effective Emacs. This allows you to keep your
fingers on the home row if you have caps lock mapped to control. With
some practice, it will become intuitive.
(keymap-global-set "C-x C-m" 'execute-extended-command)
(keymap-global-set "C-c C-m" 'execute-extended-command)
By default, Emacs creates backup files, auto-save files, and lockfiles, which can clutter your file system. These features are not necessary in modern times. Let’s disable them to keep your directories clean.
(setq
make-backup-files nil
auto-save-default nil
create-lockfiles nil)
;; (add-to-list 'load-path "~/.emacs.d/lisp/")
(setq
;; Don't display the emacs apropos
inhibit-startup-message t
;; Allow short answers 'y' or 'n'
use-short-answers t
;; Make pgup/dn remember current line
scroll-preserve-screen-position t)
; Auto revert buffers
(global-auto-revert-mode t)
;; Show column number
(column-number-mode 1)
;; Allow delete of selection
(delete-selection-mode 1)
;; Syntax Highlighting
(global-font-lock-mode 1)
;; Highlight parenthesis
(show-paren-mode 1)
;; Highlight selected Regions
(transient-mark-mode 1)
(add-hook 'prog-mode-hook 'display-line-numbers-mode)
Use spaces in favour of tabs because they are evil. But when there are tabs show them as 8 spaces.
(setq-default indent-tabs-mode nil)
(setq-default c-basic-offset 4)
(setq-default tab-width 8)
Limit the default fill mode to 80 characters
(setq-default set-fill-column 80)
(setq-default truncate-lines nil)
Ignore the stupid ring bell feature.
(setq ring-bell-function 'ignore)
Allow functions without issuing warnings
(put 'downcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(put 'upcase-region 'disabled nil)
;;;###autoload
(defun my-mac-config ()
;; Mac's ls doesn't support --dired
(setq dired-use-ls-dired nil)
;; Move to trash when deleting stuff
(setq delete-by-moving-to-trash t
trash-directory "~/.Trash/emacs")
;; Don't open files from the workspace in a new frame
(setq ns-pop-up-frames nil)
;; Open up links in Google Chrome
(setq browse-url-browser-function 'browse-url-default-macosx-browser))
(use-package exec-path-from-shell
:ensure t
:if (memq window-system '(mac ns))
:config
(exec-path-from-shell-initialize)
(my-mac-config))
Bind projectile to C-c p
and enable by default.
(use-package projectile
:ensure t
:commands (projectile-mode projectile-command-map)
:init
(setq projectile-project-search-path '("~/p/"))
(setq projectile-keymap-prefix (kbd "C-c p"))
(setq projectile-completion-system 'ivy)
:config
(projectile-mode +1)
:bind-keymap
("C-c p" . projectile-command-map))
C-c
is reserved for the user. Add a more friendly binding for
magit-file-dispatch
(use-package magit
:ensure t
:defer t
:commands (magit-status magit-file-dispatch)
:bind
("C-x g" . magit-status)
("C-c g" . magit-file-dispatch))
Some handy dandy paredit shortcuts
On mac ^-left
and ^-right
are bought to Misson Control. Go to
`System Preferences > Keyboard > Shortcuts > Mission Control` and
change the settings for “Move left a space” and “Move right a space”
or disable them completely.
(use-package paredit
:ensure t
:bind
(:map paredit-mode-map
("C-<right>" . paredit-forward-slurp-sexp)
("C-<left>" . paredit-forward-barf-sexp)
("C-<backspace>" . paredit-backward-kill-word)
("RET" . nil))
:hook ((emacs-lisp-mode lisp-mode lisp-interaction-mode scheme-mode clojure-mode cider-repl-mode inf-clojure-mode-hook) . paredit-mode))
I don’t like my cider to be bleeding edge since it’s caused compatibility problems in the past so pin it to melpa-stable.
(use-package company
:ensure t
:bind
(:map company-active-map
("C-n". company-select-next)
("C-p". company-select-previous)
("M-<". company-select-first)
("M->". company-select-last)))
(use-package clojure-mode
:ensure t
:defer t
:config
(setq show-trailing-whitespace 1)
(setq clojure-align-forms-automatically t)
(eldoc-add-command 'paredit-backward-delete 'paredit-close-round)
(add-hook 'clojure-mode-hook #'subword-mode)
(add-hook 'clojure-mode-hook #'rainbow-delimiters-mode))
(use-package inf-clojure
:ensure t
:defer t
:config
(add-hook 'inf-clojure-mode-hook #'rainbow-delimiters-mode))
(use-package cider
:ensure t
:defer t
:commands cider-jack-in
:custom
(nrepl-log-messages t)
(cider-repl-use-clojure-font-lock t)
(cider-repl-display-help-banner nil)
:config
(add-hook 'cider-mode-hook #'company-mode)
(add-hook 'cider-repl-mode-hook #'company-mode)
(add-hook 'cider-repl-mode-hook #'rainbow-delimiters-mode))
I have long since used this key binding to jack into a repl. My fingers are programmed this way.
(keymap-global-set "C-c C-j" 'cider-jack-in)
When you hit f3
at the end of the sexp in Clojure, it will copy and
evaluate the function into the current repl. I no longer use this
function but it might be useful to someone eventually.
;;;###autoload
(defun my-last-expression ()
"Return the last sexp."
(buffer-substring-no-properties
(save-excursion (backward-sexp) (point))
(point)))
;;;###autoload
(defun cider-execute-in-current-repl (expr)
(if (not (get-buffer (cider-current-connection)))
(message "No active nREPL connection.")
(progn
(set-buffer (cider-current-repl))
(goto-char (point-max))
(insert expr)
(cider-repl-return))))
;;;###autoload
(defun cider-eval-expression-at-point-in-repl ()
(interactive)
(let ((form (my-last-expression)))
;; Eat white
(while (string-match "\\`\s+\\|\n+\\'" form)
(setq form (replace-match "" t t form)))
(cider-execute-in-current-repl form)))
(with-eval-after-load 'cider-repl-mode-hook
(local-set-key '[f3] 'cider-eval-expression-at-point-in-repl))
(add-hook 'emacs-lisp-mode-hook #'eldoc-mode)
I almost exclusively use C-j
in place of hitting the enter key. The
problem is that it’s bound to org-return-indent
function. This is
very annoying in when you are in org-mode
. So instead of trying to
remap my brain, I’ll remap it to newline
.
(use-package ob-rust
:ensure t)
(use-package org
:ensure ob-rust
:bind
(:map
org-mode-map
("C-j" . org-return)
("C-c ]" . org-ref-insert-link)
("C-c l" . org-store-link)
("C-c a" . org-agenda)
("C-c c" . org-capture))
:config
(turn-on-auto-fill)
(org-babel-do-load-languages
'org-babel-load-languages '((rust . t)
(shell . t))))
In order to export to PDF, I choose to use basictex and install packages only when they are missing.
brew reinstall --cask basictex
sudo tlmgr update --self
sudo tlmgr install wrapfig
sudo tlmgr install capt-of
(use-package js
:ensure t
:config
(setq js-indent-level 2))
(use-package css-mode
:ensure t
:config
(setq css-indent-level 2)
(setq css-indent-offset 2))
(use-package flyspell
:ensure t
:config
(setq flyspell-issue-welcome-flag nil)
(setq flyspell-issue-message-flag nil)
(setq flyspell-mark-duplications-flag nil)
(setq ispell-program-name "aspell")
(setq ispell-list-command "list")
(define-key flyspell-mouse-map [down-mouse-3] 'flyspell-correct-word)
(define-key flyspell-mouse-map [mouse-3] 'undefined)
:hook ((text-mode . flyspell-mode)
(org-mode . flyspell-mode)
(prog-mode . flyspell-prog-mode)
(markdown-mode . flyspell-mode)))
(use-package ox-gfm
:ensure t)
(use-package markdown-mode
:ensure t
:mode (("\\.md\\'" . gfm-mode)
("\\.markdown\\'" . gfm-mode))
)
Use diff-mode when editing a git commit message
(add-to-list 'auto-mode-alist '("COMMIT_EDITMSG$" . diff-mode))
Calling M-x ansi-term
will prompt you for which shell you want to
spawn. TODO. Find a keybinding
(defun my/term ()
(interactive)
(term "/bin/zsh"))
Result is my language du jour. It’s slowly becoming my favourite programming language.
(use-package ivy
:ensure t
:config
(ivy-mode 1))
(use-package lsp-ivy
:ensure t
:commands lsp-ivy-workspace-symbol)
(use-package lsp-mode
:ensure t
:config
(add-hook 'lsp-mode-hook #'lsp-ui-mode))
(use-package lsp-ui
:ensure t
:custom
(lsp-ui-doc-enable nil))
(use-package rustic
:defer t
:ensure t
:bind (:map rustic-mode-map
("M-j" . lsp-ui-imenu)
("M-?" . lsp-find-references)
("C-c C-c l" . flycheck-list-errors)
("C-c C-c a" . lsp-execute-code-action)
("C-c C-c r" . lsp-rename)
("C-c C-c q" . lsp-workspace-restart)
("C-c C-c Q" . lsp-workspace-shutdown)
("C-c C-c s" . lsp-rust-analyzer-status))
:custom
(rustic-compile-command "cargo b --release")
(rustic-default-clippy-arguments "--all-targets --all-features -- -D warnings")
(rust-format-on-save t))
An Interactice Emacs Lisp Mode (IELM) gives you an Emacs Lisp shell.
(use-package ielm
:ensure t
:bind
(:map ielm-map
("C-m" . 'ielm-return)
("<return>" . 'ielm-return))
:config
(add-hook 'ielm-mode-hook #'rainbow-delimiters-mode)
(add-hook 'ielm-mode-hook #'paredit-mode))
(use-package tuareg
:ensure t)
(use-package nixpkgs-fmt
:ensure t)
(use-package nix-mode
:mode ("\\.nix\\'" "\\.nix.in\\'")
:ensure t
:bind
(:map nix-mode-map
("C-c C-f" . nixpkgs-fmt))
:config
(nixpkgs-fmt-on-save-mode))
(use-package nix-drv-mode
:ensure nix-mode
:mode "\\.drv\\'")
(use-package nix-shell
:ensure nix-mode
:commands (nix-shell-unpack nix-shell-configure nix-shell-build))
(use-package nix-repl
:ensure nix-mode
:commands (nix-repl))
(use-package terraform-mode
:ensure t)
Reset the GC threshold back to default
(use-package csv-mode
:ensure t)
(use-package just-mode
:ensure t
:config
(setq just-indent-offset 2))
(use-package dockerfile-mode
:ensure t)
(use-package yaml-mode
:ensure t)
(use-package bnf-mode
:ensure t)
(use-package htmlize
:ensure t)
(use-package ag
:ensure t)
(use-package string-inflection
:ensure t)
(use-package hurl-mode
:ensure t
:mode (("\\.hurl\\'" . hurl-mode)))
(use-package yasnippet
:ensure t
:defer 15 ;; takes a while to load so do it async
:config
(yas-reload-all)
:hook
(rust-mode . yas-minor-mode))
(setq gc-cons-threshold 800000)