Load the utils file. It contains a collection of elisp functions collected from the internet.
(use-package zach-utils
:load-path "lisp/")
Make sure the theme is available before loading the customize file.
(use-package dracula-theme
:ensure t
:demand
:config (load-theme 'dracula t))
Move the customize config to it’s own file.
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(load custom-file)
Create a group for config settings which can be modifed in customize.
(defgroup my-config nil
"Configuration settings"
:group 'local)
Suppress warnings for functions redefined by defadvice
.
(setq ad-redefinition-action 'accept)
No need to have the startup message, or tool & scroll bars.
(setq inhibit-startup-message t)
(tool-bar-mode -1)
(scroll-bar-mode -1)
Only show the menu bar on OSX.
(when (not (eq system-type `darwin))
(menu-bar-mode -1))
Set the default window size.
(when window-system
(set-frame-size (selected-frame) 150 40))
Show git diffs in the left fringe.
(use-package git-gutter-fringe
:ensure t
:defer 5
:diminish git-gutter-mode
:config (global-git-gutter-mode))
Cleanup the modeline. This should be done after the custom-file is loaded or you will get the safe theme prompt on each startup.
(use-package smart-mode-line
:ensure t
:init (setq sml/theme 'respectful
sml/shorten-directory t
sml/shorten-modes t)
:config (sml/setup))
Make the scrolling smoother by going a line at a time, for both the keyboard and mouse
(setq scroll-margin 1
scroll-step 1
scroll-conservatively 10000
scroll-preserve-screen-position 1
mouse-wheel-follow-mouse 't
mouse-wheel-scroll-amount '(1 ((shift) .1)))
Customize the scratch buffer.
(setq initial-scratch-message
";; scratch buffer -- hack away!")
Set the font based on OS.
(pcase system-type
(`darwin (set-frame-font "Iosevka-13:weight=regular"))
(`gnu/linux (set-frame-font "Meslo LG M 10"))
(`windows-nt (set-frame-font "Cascadia Code 9")))
(setq-default line-spacing 3)
Use 4 spaces for indentation.
(setq-default tab-width 4)
Use font-lock everywhere.
(global-font-lock-mode 1)
Some OSX specific settings.
(use-package exec-path-from-shell
:ensure t
:if (eq system-type 'darwin)
:init
(setq exec-path-from-shell-check-startup-files nil
frame-resize-pixelwise t ;; Prevent's gaps using --with-no-titlebar
mac-option-modifier 'super
mac-command-modifier 'meta) ;; Use cmd as meta.
:config
(exec-path-from-shell-initialize)
;; Make ansi-term play nice with zsh prompt.
(defadvice ansi-term (after advise-ansi-term-coding-system)
(set-buffer-process-coding-system 'utf-8-unix 'utf-8-unix)))
Prevent Magit from showing it’s instructions buffer on each startup.
(use-package magit
:ensure t
:bind ("C-x g" . magit-status)
:init
;; Prevent Magit from showing it's instructions buffer on each startup.
(setq magit-last-seen-setup-instructions "1.4.0")
:config
(use-package magit-popup
:ensure t))
Here we define some global key bindings.
(fill-keymap 'global
"C-x C-b" 'ibuffer
"C-a" 'smart-line-beginning
"<f11>" 'toggle-fullscreen
"C-c e" 'erc-start-or-switch
"C-c t" 'visit-term-buffer
"C-j" 'newline-and-indent)
(use-package whitespace
:init (setq whitespace-style '(face empty lines-tail trailing)
whitespace-line-column 100))
(column-number-mode 1)
(setq-default indent-tabs-mode nil)
Enable the EditorConfig plugin.
(use-package editorconfig
:ensure t
:defer 2
:config (editorconfig-mode))
Use paradox as a replacement to the built-in package menu.
(use-package paradox
:ensure t
:defer 10)
(use-package projectile
:ensure t
:defer 2
:config
(projectile-mode)
(use-package helm-projectile
:ensure t
:bind ("C-c p h")
:config (helm-projectile-on)))
(use-package helm-company
:ensure t
:bind (:map company-mode-map
("C-:" . helm-company)
:map company-active-map
("C-:" . helm-company)))
(use-package helm-flx
:ensure t)
(use-package helm-flycheck
:ensure t
:bind (:map flycheck-mode-map
("C-c ! h" . helm-flycheck)))
(use-package helm
:ensure t
:defer 1
:diminish helm-mode
:bind (("M-x" . helm-M-x)
("M-y" . helm-show-kill-ring)
("C-x C-f" . helm-find-files)
("C-c <SPC>" . helm-all-mark-rings)
("C-x r b" . helm-filtered-bookmarks)
("C-h r" . helm-info-emacs)
("C-," . helm-calcul-expression)
("C-h i" . helm-info-at-point)
("C-x C-d" . helm-browse-project)
("C-h C-f" . helm-apropos)
("C-h a" . helm-apropos)
("C-s" . helm-occur))
:init (setq helm-M-x-fuzzy-match t)
:config
(require 'helm-config)
(helm-mode)
(helm-autoresize-mode)
(helm-flx-mode))
(setq uniquify-buffer-name-style 'post-forward)
(show-paren-mode t)
(setq show-paren-delay 0
show-paren-style 'parenthesis)
(use-package auto-complete
:ensure t
:commands auto-complete-mode
:init
(setq ac-auto-start 0
ac-quick-help-delay 0.5
ac-fuzzy-enable t
ac-use-fuzzy t
ac-auto-show-menu 0.2)
:config
(add-to-list 'ac-dictionary-directories (concat user-emacs-directory "ac-dict"))
(ac-config-default))
(use-package company
:ensure t
:commands company-mode
:init
;; Set company-mode to try and complete instantly
(setq company-idle-delay 0)
:config
(use-package company-irony
:ensure t
:init (add-to-list 'company-backends 'company-irony))
(use-package company-c-headers
:ensure t
:init (add-to-list 'company-backends 'company-c-headers)))
Enable spell checking and syntax highlighting in org-mode
.
(use-package org
:init (setq org-src-fontify-natively t)
:config
(flyspell-mode)
(require 'org-tempo))
Enable toc-org
so this file can have a ToC in Github without any exporting.
(use-package toc-org
:ensure t
:commands toc-org-enable
:init (add-hook 'org-mode-hook 'toc-org-enable))
Enable journal mode, always in indented mode. The journal dir is set based on OS, and all journals added to the org-agenda-files list.
(use-package org-journal
:ensure t
:config
(setq org-startup-indented t)
(let ((j-dir (cond ((eq system-type 'darwin) "~/Dropbox/org-journals")
((eq system-type 'windows-nt) "~/../../Dropbox/org-journals/"))))
(setq org-journal-dir j-dir)
(add-to-list 'org-agenda-files j-dir)))
(use-package paredit
:ensure t
:bind (:map paredit-mode-map
("M-s" . paredit-splice-sexp)
("M-S" . paredit-split-sexp)
("M-j" . paredit-join-sexps)
("M-o" . paredit-forward-down)
("M-O" . paredit-forward-up)
("M-u" . paredit-backward-down)
("M-U" . paredit-backward-up)
("M-l" . paredit-forward)
("M-h" . paredit-backward)
("M-k" . paredit-kill)
("M-(" . backward-barf-sexp)
("M-)" . forward-barf-sexp)
("C-(" . backward-slurp-sexp)
("C-)" . forward-slurp-sexp))
:config
;; Some enhanced fns I found somewhere.
(defun forward-barf-sexp (prefix)
"Calls `paredit-forward-barf-sexp', unless PREFIX is non nil.
With prefix it calls `paredit-barf-all-the-way-forward'"
(interactive "P")
(if prefix
(paredit-barf-all-the-way-forward)
(paredit-forward-barf-sexp)))
(defun forward-slurp-sexp (prefix)
"Calls `paredit-forward-slurp-sexp`, unless PREFIX is non nil.
With prefix it calls `paredit-slurp-all-the-way-forward'"
(interactive "P")
(if prefix
(paredit-slurp-all-the-way-forward)
(paredit-forward-slurp-sexp)))
(defun backward-barf-sexp (prefix)
"Calls `paredit-backward-barf-sexp', unless PREFIX is non nil.
With prefix it calls `paredit-barf-all-the-way-backward'"
(interactive "P")
(if prefix
(paredit-barf-all-the-way-backward)
(paredit-backward-barf-sexp)))
(defun backward-slurp-sexp (prefix)
"Calls `paredit-backward-slurp-sexp', unless PREFIX is non nil.
With prefix it calls `paredit-slurp-all-the-way-backward'"
(interactive "P")
(if prefix
(paredit-slurp-all-the-way-backward)
(paredit-backward-slurp-sexp)))
;; Enable Paredit in the minibuffer.
(defvar paredit-minibuffer-commands '(eval-expression
pp-eval-expression
eval-expression-with-eldoc
ibuffer-do-eval
ibuffer-do-view-and-eval)
"Interactive commands for which paredit should be enabled in the minibuffer.")
(add-hook 'minibuffer-setup-hook
(lambda ()
(if (memq this-command paredit-minibuffer-commands)
(enable-paredit-mode)))))
Use Purcell’s ibuffer-vc for grouping.
(use-package ibuffer-vc
:ensure t
:defer 5
:init
;; Include version control status info in the ibuffer list.
(setq ibuffer-formats
'((mark modified read-only vc-status-mini " "
(name 18 18 :left :elide)
" "
(size 9 -1 :right)
" "
(mode 16 16 :left :elide)
" "
(vc-status 16 16 :left)
" "
filename-and-process)))
:config (add-hook 'ibuffer-hook (lambda()
(ibuffer-vc-set-filter-groups-by-vc-root)
(unless (eq ibuffer-sorting-mode 'alphabetic)
(ibuffer-do-sort-by-alphabetic)))))
Install `markdown-mode`
(use-package markdown-mode
:ensure t
:commands (markdown-mode gfm-mode)
:mode (("README\\.md\\'" . gfm-mode)
("\\.md\\'" . markdown-mode)
("\\.markdown\\'" . markdown-mode)))
(defun neotree-project-dir ()
"Open NeoTree using the git root."
(interactive)
(let ((project-dir (projectile-project-root))
(file-name (buffer-file-name)))
(neotree-toggle)
(if project-dir
(if (neo-global--window-exists-p)
(progn
(neotree-dir project-dir)
(neotree-find file-name)))
(message "Could not find git project root."))))
(use-package neotree
:ensure t
:commands neotree-toggle
:bind ("M-\\" . neotree-project-dir)
:config
(use-package all-the-icons
:ensure t)
(setq neo-theme (if (display-graphic-p)
'icons
'arrow)))
(use-package ledger-mode
:ensure t
:commands ledger-mode)
Some backup settings. These should be cleaned up in the future.
(setq auto-save-file-name-transforms '((".*" "~/.emacs.d/autosaves/\\1" t))
backup-directory-alist '((".*" . "~/.emacs.d/backups/")))
(make-directory (concat user-emacs-directory "autosaves/") t)
(setq vc-make-backup-files t
backup-by-copying t
delete-old-versions t
kept-new-versions 6
kept-old-versions 2
version-control t)
Split the current buffer with a terminal.
(defun visit-term-buffer ()
"Create or visit a terminal buffer."
(interactive)
(if (not (get-buffer "*ansi-term*"))
(progn
(split-window-sensibly (selected-window))
(other-window 1)
(ansi-term (getenv "SHELL")))
(switch-to-buffer-other-window "*ansi-term*")))
Set some keywords to be highlighted.
(use-package fic-mode
:ensure t
:commands (fic-mode)
:init (setq fic-highlighted-words '("FIXME" "FIXME:" "TODO" "TODO:"
"HACK" "HACK:" "NOTE" "NOTE:"
"BUG" "BUG:" "REFACTOR" "REFACTOR:")))
Enable some basic packages for every programming language.
(defcustom programming-language-major-modes
'(prog-mode ; This is the mode perl, makefile, lisp-mode, scheme-mode,
; emacs-lisp-mode, sh-mode, java-mode, c-mode, c++-mode,
; python-mode inherits from.
lua-mode
cmake-mode
tex-mode ; LaTeX inherits
sgml-mode ; HTML inherits
css-mode
nxml-mode
diff-mode
haskell-mode
rst-mode
arduino-mode)
"What to consider as programming languages."
:group 'my-config)
(use-package rainbow-delimiters
:ensure t
:commands (rainbow-delimiters-mode))
(use-package smartparens
:ensure t
:commands (smartparens-mode smartparens-strict-mode)
:config (require 'smartparens-config))
(dolist (mode programming-language-major-modes)
(add-hook
(intern (concat (symbol-name mode) "-hook"))
(lambda ()
(fic-mode)
(rainbow-delimiters-mode)
(whitespace-mode)
(smartparens-mode))))
Don’t ask to save before compilation.
(setq compilation-ask-about-save nil
compilation-window-height 30)
Setup flycheck.
(use-package flycheck
:ensure t
:defer 5
:commands (global-flycheck-mode flycheck-add-mode)
:init
(global-flycheck-mode)
(setq flycheck-completion-system 'ido
flycheck-disabled-checkers '(emacs-lisp-checkdoc))
;; Remove newline checks, since they would trigger an immediate check
;; when we want the idle-change-delay to be in effect while editing.
(setq flycheck-check-syntax-automatically '(save
idle-change
mode-enabled))
:config
(defun magnars/adjust-flycheck-automatic-syntax-eagerness ()
"Adjust how often we check for errors based on if there are any.
This lets us fix any errors as quickly as possible, but in a clean buffer we're an order
of magnitude laxer about checking."
(setq flycheck-idle-change-delay
(if flycheck-current-errors 0.5 5.0)))
(add-hook 'flycheck-after-syntax-check-hook
'magnars/adjust-flycheck-automatic-syntax-eagerness)
;; Each buffer gets its own idle-change-delay because of the
;; buffer-sensitive adjustment above.
(make-variable-buffer-local 'flycheck-idle-change-delay)
(defun flycheck-handle-idle-change ()
"Handle an expired idle time since the last change.
This is an overwritten version of the original flycheck-handle-idle-change, which removes
the forced deferred. Timers should only trigger inbetween commands in a single threaded
system and the forced deferred makes errors never show up before you execute another command."
(flycheck-clear-idle-change-timer)
(flycheck-buffer-automatically 'idle-change))
(use-package flycheck-package
:ensure t
:config (flycheck-package-setup)))
Setup the indentation style for C-based languages (C, C++, Java, etc).
(setq c-default-style "stroustrup")
Support for `*.toml` files.
(use-package toml-mode
:ensure t
:defer 10
:commands toml-mode)
Enable a few packages for elisp-related modes.
(defcustom elisp-programming-major-modes
'(emacs-lisp-mode
lisp-interaction-mode
ielm-mode)
"Modes that are used to do Elisp programming.")
(defun my-elisp-setup ()
"Enable some packages for any elisp related buffer."
(eldoc-mode)
(paredit-mode)
(rainbow-delimiters-mode)
(smartparens-mode -1)
(auto-complete-mode -1)
(company-mode))
(dolist (mode elisp-programming-major-modes)
(add-hook (intern (concat (symbol-name mode) "-hook"))
'my-elisp-setup))
(use-package csharp-mode
:ensure t
:defer t
:config
(use-package omnisharp
:ensure t
:init (add-hook 'csharp-mode-hook 'omnisharp-mode)))
(use-package clojure-mode
:ensure t
:commands (clojure-mode clojurescript-mode)
:config
;; On OSX, each Java process started by Cider or Leiningen will show up on
;; the dock. The following option prevents that.
(setenv "LEIN_JVM_OPTS" "-Dapple.awt.UIElement=true")
(add-hook 'clojure-mode-hook
(lambda ()
;; Disable smartparens in favor of paredit
(smartparens-mode -1)
(paredit-mode)
;; Make sure Eldoc and Company are running
(auto-complete-mode -1)
(company-mode)
(eldoc-mode)))
;; Set up some custom identation rules
(define-clojure-indent
(defroutes 'defun)
(GET 2)
(POST 2)
(PUT 2)
(DELETE 2)
(HEAD 2)
(ANY 2)
(context 2))
;; Use symbols for 'fn', function literals, and sets.
(font-lock-add-keywords
'clojure-mode `(("(\\(fn\\)[\[[:space:]]"
(0 (progn (compose-region (match-beginning 1)
(match-end 1) "λ")
nil)))))
(font-lock-add-keywords
'clojure-mode `(("\\(#\\)("
(0 (progn (compose-region (match-beginning 1)
(match-end 1) "ƒ")
nil)))))
(font-lock-add-keywords
'clojure-mode `(("\\(#\\){"
(0 (progn (compose-region (match-beginning 1)
(match-end 1) "∈")
nil))))))
(use-package cider
:ensure t
:commands (cider-mode cider-repl-mode)
:init
(setq nrepl-hide-special-buffers t
cider-auto-select-error-buffer nil
cider-repl-result-prefix ";; => "
cider-repl-use-pretty-printing t
cider-repl-use-clojure-font-lock t)
(add-hook 'cider-mode-hook (lambda ()
(eldoc-mode)
(company-mode)))
(add-hook 'cider-repl-mode-hook (lambda ()
(eldoc-mode)
(company-mode)
(paredit-mode)))
:config
;; Save buffer before testing or loading.
(defadvice clojure-test-run-tests (before save-first activate)
(save-buffer))
(defadvice cider-load-current-buffer (before save-first activate)
(save-buffer)))
(use-package cljsbuild-mode
:ensure t
:commands (cljsbuild-start)
:init
;; Use "lein trampoline" when building Clojurescript, and hide the buffer when the
;; build was successful.
(setq cljsbuild-hide-buffer-on-success t
cljsbuild-compile-command "lein trampoline cljsbuild auto"))
Use web-mode and js2-mode.
(use-package web-mode
:ensure t
:mode "\\.jsx$"
:commands web-mode
:init
(flycheck-add-mode 'javascript-eslint 'web-mode)
(setq web-mode-markup-indent-offset 2
web-mode-css-indent-offset 2
web-mode-code-indent-offset 2
web-mode-indent-style 2)
:config
(defadvice web-mode-highlight-part (around tweak-jsx-activate)
(if (equal web-mode-content-type "jsx")
(let ((web-mode-enable-part-face nil))
ad-do-it)
ad-do-it)))
(use-package js2-mode
:ensure t
:commands js2-mode
:mode (("\\.js$" . js2-mode)
("\\.es6$" . js2-mode)
("\\.ejs$" . js2-mode))
:interpreter "node"
:init
(setq js-indent-level 2))
Disable jshint in favor of eslint.
(setq-default flycheck-disabled-checkers
(append flycheck-disabled-checkers
'(javascript-jshint)))
Enable NVM support.
(when (file-exists-p "~/.nvm")
(use-package nvm
:ensure t
:defer 5
:config
(nvm-use (caar (last (nvm--installed-versions))))))
Check for a local eslint after switching Projectile projects.
(defun setup-local-eslint ()
"If ESLint found in node_modules directory, use that for flycheck."
(interactive)
(let ((local-eslint (expand-file-name "./node_modules/.bin/eslint")))
(setq flycheck-javascript-eslint-executable
(and (file-exists-p local-eslint) local-eslint))))
(add-hook 'projectile-after-switch-project-hook 'setup-local-eslint)
Setup based on https://robert.kra.hn/posts/2021-02-07_rust-with-emacs/
Use Rustic, a fork of rust-mode.
(use-package rustic
:ensure
: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))
:config
;; uncomment for less flashiness
;; (setq lsp-eldoc-hook nil)
;; (setq lsp-enable-symbol-highlighting nil)
;; (setq lsp-signature-auto-activate nil)
;; comment to disable rustfmt on save
(setq rustic-format-on-save t)
(add-hook 'rustic-mode-hook 'rk/rustic-mode-hook))
(defun rk/rustic-mode-hook ()
;; so that run C-c C-c C-r works without having to confirm
(setq-local buffer-save-without-query t))
Use lsp-mode and lsp-ui-mode.
(use-package lsp-mode
:ensure
:commands lsp
:custom
;; what to use when checking on-save. "check" is default, I prefer clippy
(lsp-rust-analyzer-cargo-watch-command "clippy")
(lsp-eldoc-render-all t)
(lsp-idle-delay 0.6)
(lsp-rust-analyzer-server-display-inlay-hints t)
:config
(add-hook 'lsp-mode-hook 'lsp-ui-mode))
(use-package lsp-ui
:ensure
:commands lsp-ui-mode
:custom
(lsp-ui-peek-always-show t)
(lsp-ui-sideline-show-hover t)
(lsp-ui-doc-enable nil))