This file documents the configuration used by "Emacs for the rest of us".
See the quick start guide for instructions on installing and using Emacs with this configuration.
It is difficult to support multiple versions of emacs, so we will pick an arbitrary cutoff and throw an error if the version of emacs is "too old".
when (< emacs-major-version 26)
(error "Your version of emacs is old and must be upgraded before you can use these packages! Version >= 26 is required."))
(
;; start maximized
setq frame-resize-pixelwise t
(t)
x-frame-normalize-before-maximize
(add-to-list 'initial-frame-alist '(fullscreen . fullheight))
;; set coding system so emacs doesn't choke on melpa file listings
-8)
(set-language-environment 'utfsetq locale-coding-system 'utf-8)
(-8)
(set-default-coding-systems 'utf-8)
(set-terminal-coding-system 'utfunless (eq system-type 'windows-nt)
(-8))
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utfsetq buffer-file-coding-system 'utf-8)
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(
;; set things that need to be set before packages load
setq outline-minor-mode-prefix "\C-c\C-o")
(
(add-hook 'outline-minor-mode-hooklambda () (local-set-key "\C-c\C-o"
(
outline-mode-prefix-map)))setq save-abbrevs 'silently)
(setq max-specpdl-size 10000
(5000) max-lisp-eval-depth
The main purpose of these emacs configuration files is to install and configure useful emacs packages. Here we carry out the installation.
Note that we use a heuristic to decide whether to install language support (e.g., for R
or Scala
etc.). If the corresponding program is in your PATH
Emacs support will be installed. For example, if R
is in your PATH
the ESS package will be installed.
If a program is not in your PATH
but you wish to install an Emacs package anyway you can add it to the list of required packages following the instructions in the custom.el
file. For example, putting (add-to-list 'package-slected-packages 'ess)
in your custom.el
file will ensure that the ESS package is installed even if the R
program is not in your PATH
.
;; load the package manager
require 'package)
(when (< emacs-major-version 27)
(
(package-initialize))
require 'cl-lib)
(
;; Add additional package sources
"melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '(
;; Fix gnu package archive verification in Emacs 26.2 by disabling broken TLS 1.3 support
;; per https://www.reddit.com/r/emacs/comments/cdei4p/failed_to_download_gnu_archive_bad_request/
if (and (= emacs-major-version 26) (= emacs-minor-version 2))
(setq gnutls-algorithm-priority "NORMAL:-VERS-TLS1.3"))
(
;; Assume yes to the package installation prompts if EMACS_AUTOINSTALL_PACKAGES=yes
if (string-equal (getenv "EMACS_AUTOINSTALL_PACKAGES") "yes")
(compile activate)
(defadvice package-install-selected-packages (around auto-confirm symbol-function 'yes-or-no-p) (lambda (&rest args) t))
(letf (((symbol-function 'y-or-n-p) (lambda (&rest args) t)))
((
ad-do-it)))
;; A list of the packages we always want
setq package-selected-packages
(;; gnu packages
'(
windresize
diff-hl
adaptive-wrap
pdf-tools
yasnippet
yasnippet-snippets
multiple-cursors
visual-regexp
command-log-mode
undo-tree
better-defaults
minions
ace-window
rotate
howdoi
multi-term
with-editor
anzu
counsel
flx-ido
smex
hydra
ivy-hydra
wgrep
which-key
outline-magic
smooth-scroll
unfill
company
company-math
web-mode
markdown-mode
polymode
poly-markdown
poly-org
poly-noweb
eval-in-repl
exec-path-from-shell
dumb-jump
flycheck
htmlize
dictionary
untitled-new-buffer))
;; hide compilation buffer when complete
;; from http://emacs.stackexchange.com/questions/62/hide-compilation-window
(add-hook 'compilation-finish-functionslambda (buf str)
(if (null (string-match ".*exited abnormally.*" str))
(;;no errors, make the compilation window go away in a few seconds
progn
(
(run-at-time"2 sec" nil 'delete-windows-on
"*compilation*"))
(get-buffer-create
(run-at-time"2 sec" nil 'delete-windows-on
"*Compile-Log*"))
(get-buffer-create "No Compilation Errors!")))))
(message
;; install packages if needed
unless (cl-every 'package-installed-p package-selected-packages)
("Missing packages detected, please wait...")
(message
(package-refresh-contents)
(package-install-selected-packages))
(package-initialize)
We try to install most things using the package manager, but a few things need to be included in a custom lisp directory. Add it to the path so we can load from it easily.
;; add custom lisp directory to path
unless
("lisp"))
(file-exists-p (concat user-emacs-directory "lisp")))
(make-directory (concat user-emacs-directory
;; add custom lisp directory to path
let ((default-directory (concat user-emacs-directory "lisp/")))
(setq load-path
(append
(let ((load-path (copy-sequence load-path))) ;; Shadow
(append
(".")))
(copy-sequence (normal-top-level-add-to-load-path '(
(normal-top-level-add-subdirs-to-load-path)))
load-path)))
;; on OSX Emacs needs help setting up the system paths
when (memq window-system '(mac ns))
(require 'exec-path-from-shell)
(;; From https://github.com/aculich/.emacs.d/blob/master/init.el
;; Import additional environment variables beyond just $PATH
dolist (var '("PYTHONPATH" ; Python modules
("INFOPATH" ; Info directories
"JAVA_OPTS" ; Options for java processes
"SBT_OPTS" ; Options for SBT
"RUST_SRC_PATH" ; Rust sources, for racer
"CARGO_HOME" ; Cargo home, for racer
"EMAIL" ; My personal email
"GPG_TTY"
"GPG_AGENT_INFO"
"SSH_AUTH_SOCK"
"SSH_AGENT_PID"
))
(add-to-list 'exec-path-from-shell-variables var))
(exec-path-from-shell-initialize))
;; Add to the list of the packages we want
when (executable-find "R")
(
(add-to-list 'package-selected-packages 'ess)
(add-to-list 'package-selected-packages 'poly-R))when (executable-find "python")
(
(add-to-list 'package-selected-packages 'poetry)
(add-to-list 'package-selected-packages 'conda))when (executable-find "pdflatex")
(
(add-to-list 'package-selected-packages 'auctex)
(add-to-list 'package-selected-packages 'ivy-bibtex))when (executable-find "git")
(
(add-to-list 'package-selected-packages 'git-commit)
(add-to-list 'package-selected-packages 'magit))when (executable-find "julia")
(
(add-to-list 'package-selected-packages 'julia-mode)
(add-to-list 'package-selected-packages 'julia-repl))when (or (executable-find "ghc")
("stack"))
(executable-find
(add-to-list 'package-selected-packages 'haskell-mode)
(add-to-list 'package-selected-packages 'company-ghci))when (executable-find "jupyter")
(
(add-to-list 'package-selected-packages 'ein))when (executable-find "pandoc")
(
(add-to-list 'package-selected-packages 'pandoc-mode)
(add-to-list 'package-selected-packages 'ox-pandoc))when (executable-find "scala")
(
(add-to-list 'package-selected-packages 'scala-mode)
(add-to-list 'package-selected-packages 'sbt-mode))
;; install packages if needed
unless (cl-every 'package-installed-p package-selected-packages)
("Missing packages detected, please wait...")
(message
(package-refresh-contents) (package-install-selected-packages))
This section sets up various utilities and conveniences. Many of these are low priority, so we set them first in order to allow any conflicting settings to be overridden later.
;; ;; clean up the mode line
setq minions-mode-line-lighter "☰")
(1)
(minions-mode
;; No, we do not need the splash screen
setq inhibit-startup-screen t)
(
require 'better-defaults)
(;; better defaults are well, better... but we don't always agree
"menu-bar"
(with-eval-after-load 1))
(menu-bar-mode "scroll-bar"
(with-eval-after-load 1))
(scroll-bar-mode
setq select-active-regions 'only)
(
;; from https://github.com/bbatsov/prelude/
;; store all backup and autosave files in the tmp dir
setq backup-directory-alist
(".*" . ,temporary-file-directory)))
`((setq auto-save-file-name-transforms
(".*" ,temporary-file-directory t)))
`((;; autosave the undo-tree history
setq undo-tree-history-directory-alist
(".*" . ,temporary-file-directory)))
`((
;; scrolling behavior
setq mouse-wheel-scroll-amount '(1 ((shift) . 1))) ; one line at a time
(setq mouse-wheel-progressive-speed nil) ; don't accelerate scrolling
(setq mouse-wheel-follow-mouse 't) ; scroll window under mouse
(setq scroll-preserve-screen-position t)
(setq scroll-conservatively 100000)
(setq scroll-error-top-bottom t)
(setq scroll-preserve-screen-position t)
(;; scroll without moving point
require 'smooth-scroll)
(-1)
(global-set-key [(control down)] 'scroll-up-1)
(global-set-key [(control up)] 'scroll-down-1)
(global-set-key [(control left)] 'scroll-right-1)
(global-set-key [(control right)] 'scroll-left
;; Use y/n instead of yes/no
(fset 'yes-or-no-p 'y-or-n-p)
1) ; makes the region visible
(transient-mark-mode 1) ; makes the line number show up
(line-number-mode 1) ; makes the column number show up
(column-number-mode
;; make home and end behave
"<home>") 'move-beginning-of-line)
(global-set-key (kbd "<end>") 'move-end-of-line)
(global-set-key (kbd
;; enable toggling paragraph un-fill
"\M-Q" 'unfill-paragraph)
(define-key global-map
;;; line wrapping
;; neck beards be damned, we don't need to hard wrap. The editor can soft wrap for us.
(remove-hook 'text-mode-hook 'turn-on-auto-fill);; (add-hook 'visual-line-mode-hook 'adaptive-wrap-prefix-mode)
;;
t)
(setq-default truncate-lines 1)
(global-visual-line-mode
(add-hook 'prog-mode-hooklambda()
(setq truncate-lines t)
(t)))
(outline-minor-mode
;; indicate visual-line-mode wrap
setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))
(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))
(;; but be gentle
when (fboundp 'set-fringe-bitmap-face)
(
(defface visual-line-wrap-facet (:foreground "gray")))
'(("Face for visual line indicators.")
(set-fringe-bitmap-face 'left-curly-arrow 'visual-line-wrap-face)
(set-fringe-bitmap-face 'right-curly-arrow 'visual-line-wrap-face))
;; don't require two spaces for sentence end.
setq sentence-end-double-space nil)
(
;; The beeping can be annoying--turn it off
setq visible-bell t
(
ring-bell-function #'ignore)
;; save place -- move to the place I was last time I visited this file
t)
(save-place-mode
;; regular cursor
;(setq-default cursor-type '(bar . 5))
0)
(setq-default blink-cursor-blinks
(add-hook 'after-init-hooklambda()
(setq blink-cursor-blinks 0)))
(
;; easy navigation in read-only buffers
setq view-read-only t)
("view-mode"
(with-eval-after-load "s") 'isearch-forward-regexp))
(define-key view-mode-map (kbd
;; set up read-only buffers
(add-hook 'read-only-mode-hook lambda()
(cond
(and (not buffer-read-only)
((not (eq (get major-mode 'mode-class) 'special)))
(-1)
(hl-line-mode 0)
(setq-local blink-cursor-blinks 3))
(setq-local cursor-type '(bar . t))
(company-mode and buffer-read-only
((not (eq (get major-mode 'mode-class) 'special)))
(t)
(hl-line-mode 1)
(setq-local blink-cursor-blinks
(setq-local cursor-type 'hollow)-1)))))
(company-mode
;; show parentheses
1)
(show-paren-mode setq show-paren-delay 0) (
Emacs will never to as simple as Notepad, but perhaps it can be made more consistent with the way most other programs behave. In addition to more consistent copy/paste, undo/redo, we also implement multiple cursors. Use C-c C-m
to add or remove cursors.
;; Use CUA mode to make life easier. We do _not__ use standard copy/paste etc. (see below).
t)
(cua-mode
t) ;; cua goodness without copy/paste etc.
(cua-selection-mode
;; load windows-style keys using windows key instead of control.
require 'win-win)
(
;; ;; Make control-z undo
let ((map (make-sparse-keymap)))
(;; remap `undo' and `undo-only' to `undo-tree-undo'
;; (define-key map [remap undo] 'undo-tree-undo)
;; (define-key map [remap undo-only] 'undo-tree-undo)
;; bind standard undo bindings (since these match redo counterparts)
;; (define-key map (kbd "C-/") 'undo-tree-undo)
;; (define-key map "\C-_" 'undo-tree-undo)
;; redo doesn't exist normally, so define our own keybindings
map (kbd "C-?") 'undo-tree-redo)
(define-key map (kbd "M-_") 'undo-tree-redo)
(define-key map (kbd "C-S-z") 'undo-tree-redo)
(define-key ;; just in case something has defined `redo'...
map [remap redo] 'undo-tree-redo)
(define-key ;; we use "C-x U" for the undo-tree visualizer
map (kbd "\C-x U") 'undo-tree-visualize)
(define-key ;; bind register commands
map (kbd "C-x r u") 'undo-tree-save-state-to-register)
(define-key map (kbd "C-x r U") 'undo-tree-restore-state-from-register)
(define-key ;; set keymap
setq undo-tree-map map))
(
t)
(global-undo-tree-mode
;; Make C-g quit undo tree
"C-g") 'undo-tree-visualizer-quit)
(define-key undo-tree-visualizer-mode-map (kbd "<escape> <escape> <escape>") 'undo-tree-visualizer-quit)
(define-key undo-tree-visualizer-mode-map (kbd
;;
;; Make right-click do something close to what people expect
require 'mouse3)
("<mouse-3>") 'mouse3-popup-menu)
(global-set-key (kbd ;; (global-set-key (kbd "C-f") 'isearch-forward)
;; (global-set-key (kbd "C-s") 'save-buffer)
;; (global-set-key (kbd "C-o") 'counsel-find-file)
"<C-S-SPC>") nil)
(define-key cua-global-keymap (kbd "<C-return>") nil)
(define-key cua-global-keymap (kbd setq cua-rectangle-mark-key (kbd "<C-S-SPC>"))
("<C-S-SPC>") 'cua-rectangle-mark-mode)
(define-key cua-global-keymap (kbd
;; zoom in/out like we do everywhere else.
"C-+") 'text-scale-increase)
(global-set-key (kbd "C--") 'text-scale-decrease)
(global-set-key (kbd "<C-mouse-5>") 'text-scale-decrease)
(global-set-key (kbd "<C-mouse-4>") 'text-scale-increase)
(global-set-key (kbd ;; page up/down
"<C-prior>") 'beginning-of-buffer)
(global-set-key (kbd "<C-next>") 'end-of-buffer)
(global-set-key (kbd
;; allow multiple cursors, as in Sublime and VScode
require 'multiple-cursors)
(nil)
(defhydra multiple-cursors-hydra (:hint "
^Up^ ^Down^ ^Other^