aboutsummaryrefslogtreecommitdiff
path: root/tw/home/files/emacs-init.el
diff options
context:
space:
mode:
Diffstat (limited to 'tw/home/files/emacs-init.el')
-rw-r--r--tw/home/files/emacs-init.el565
1 files changed, 565 insertions, 0 deletions
diff --git a/tw/home/files/emacs-init.el b/tw/home/files/emacs-init.el
new file mode 100644
index 00000000..daf6f737
--- /dev/null
+++ b/tw/home/files/emacs-init.el
@@ -0,0 +1,565 @@
+;;; init.el --- Emacs configuration. -*- lexical-binding: t -*-
+;;; Commentary:
+;;; Code:
+
+;; Load settings set through Custom.
+;; (setq custom-file (locate-user-emacs-file "custom.el"))
+;; (when (file-readable-p custom-file)
+;; (load custom-file))
+
+(defun tw/xdg-emacs-subdir (type name)
+ "Get the name of a subdirectory called NAME under $XDG_<TYPE>_HOME/emacs."
+ (expand-file-name
+ (concat "emacs/" (string-trim-right name "/") "/")
+ (pcase type
+ ('cache (or (getenv "XDG_CACHE_HOME") "~/.cache/"))
+ ('config (or (getenv "XDG_CONFIG_HOME") "~/.config/"))
+ ('data (or (getenv "XDG_DATA_HOME") "~/.local/share/"))
+ ;; The following two are Guix/GuixSD extensions.
+ ('log (or (getenv "XDG_LOG_HOME") "~/.local/var/log/"))
+ ('state (or (getenv "XDG_STATE_HOME") "~/.local/var/lib/"))
+ (_ (error "Unknown XDG directory type: %S" type)))))
+
+;; Global/built-in Custom settings
+;; Apply these as early as possible so that e.g. the native-comp files go to the right place.
+(mapc (apply-partially #'apply #'customize-set-variable)
+ `((native-comp-async-report-warnings-errors silent "Don't pop up Warnings buffer for native compilation.")
+ (native-compile-target-directory ,(tw/xdg-emacs-subdir 'cache "eln") "Put native-compiled binaries in the cache.")
+ ;; Emacs GUI customization.
+ (inhibit-startup-screen t "Don't show the startup screen with help links.")
+ (menu-bar-mode nil "Hide the menu bar globally.")
+ (tool-bar-mode nil "Hide the tool bar globally.")
+ (tooltip-mode nil "Show tooltips in the echo area instead.")
+ (max-mini-window-height 3 "Let the echo area grow to a maximum of 3 lines, e.g. when using `eldoc-mode'.")
+ (scroll-up-aggressively 0.0 "Don't recenter the window if the point moves off the page.")
+ (scroll-down-aggressively 0.0 "Don't recenter the window if the point moves off the page.")
+ ;; Indentation.
+ (indent-tabs-mode nil "Always use spaces to indent.")
+ ;; Niceties.
+ (global-hl-line-mode t "Highlight the current line in all buffers.")
+ (column-number-mode t "Show the column number in the statusline.")
+ (electric-pair-mode t "Auto-pair suitable characters like parentheses.")
+ (completion-cycle-threshold 6 "Allow cycling through completions if there are 6 or fewer of them.")))
+
+(defalias 'yes-or-no-p #'y-or-n-p
+ "Always use `y-or-n-p' when asking for confirmation.")
+
+;; Custom modes depending on file names.
+(mapc (apply-partially #'add-to-list 'auto-mode-alist)
+ `((,(rx (or bos "/") "PKGBUILD" eos) . sh-mode)
+ (,(rx ".install" eos) . sh-mode)
+ (,(rx bos "/tmp/neomutt-") . mail-mode)
+ (,(rx "." (1+ anything) "rc" eos) . conf-unix-mode)))
+
+(add-to-list 'magic-mode-alist
+ `(,(rx "#!" (* (not space))
+ (? "env" (+ space) (? "-S" (+ space)))
+ (or "guile" "racket"))
+ . scheme-mode))
+
+(add-hook 'mail-mode-hook #'auto-fill-mode)
+
+;; `use-package' requirements.
+(require 'package)
+(package-initialize t)
+(eval-when-compile
+ (require 'use-package))
+(use-package diminish) ; for using :diminish later
+(use-package bind-key) ; for using :bind later
+
+;; Some packages below have `:commands (...) :demand t'.
+;; We need :commands for the byte-compiler, but we want to load the package immediately.
+
+;; Look and feel
+(set-face-attribute 'default nil :family "Hermit" :height 100)
+
+(use-package autothemer
+ ;; The "catppuccin" theme is linked to the appropriate variant by guix home.
+ :config (load-theme 'catppuccin-mocha t))
+
+(defun tw/get-catppuccin-color (name)
+ "Get the hex code of the Catppuccin color named NAME."
+ (cl-loop for color in (autothemer--theme-colors autothemer-current-theme)
+ when (string= (autothemer--color-name color) name)
+ return (autothemer--color-value color)))
+
+(custom-set-faces
+ `(cursor ((default :background ,(tw/get-catppuccin-color "rosewater"))) t
+ "Make the cursor \"rosewater\", as recommended by Catppuccin upstream, overriding catppuccin/emacs."))
+
+(use-package smart-mode-line
+ :commands (sml/setup) :demand t
+ :custom
+ (sml/no-confirm-load-theme t "Stop Emacs from constantly asking for user confirmation.")
+ (sml/mode-width 'right "Move the minor-mode list to the right of the modeline.")
+ (sml/theme 'respectful "Make `smart-mode-line' blend in with the active theme.")
+ :config (sml/setup))
+
+;; Built-in Emacs stuff.
+(use-package package
+ :custom
+ (package-archives nil "Don't fetch packages from the internet; only get them from Guix."))
+
+(use-package recentf
+ :custom
+ (recentf-max-saved-items 1000 "Save lots of recently-opened files.")
+ (recentf-save-file ,(tw/xdg-emacs-subdir 'data "recentf") "Save recently-opened files here.")
+ (recentf-mode t "Save recently-opened files."))
+
+(use-package savehist
+ :custom
+ (savehist-file ,(tw/xdg-emacs-subdir 'data "history") "Save minibuffer history here.")
+ (savehist-mode t "Save minibuffer history on quit."))
+
+(use-package files
+ :custom
+ (backup-directory-alist `(("." . ,(tw/xdg-emacs-subdir 'data "backup")))
+ "Save all backup files in one place to avoid clutter."))
+
+;; General editor behaviour.
+(use-package ivy
+ :commands (ivy-mode) :demand t
+ :custom
+ (ivy-use-selectable-prompt t "Allow selecting the ivy input as-is.")
+ (ivy-use-virtual-buffers t "Show recentf and bookmarks in buffers list.")
+ :config (ivy-mode +1)
+ :diminish ivy-mode)
+
+(use-package counsel ; extra niceties for `ivy-mode'
+ :after (ivy evil) ; evil for :bind-ing to <leader>
+ :bind (("<leader>SPC" . counsel-M-x) ; <leader><leader> doesn't work
+ ("<leader>fr" . counsel-buffer-or-recentf)
+ :map evil-visual-state-map
+ ("<leader>SPC" . counsel-M-x))
+ :commands (counsel-mode) :demand t
+ :config (counsel-mode +1)
+ :diminish counsel-mode)
+
+(defun tw/counsel-dash-is-help ()
+ "Install `counsel-dash-at-point' as `evil-lookup-func'."
+ (setq-local evil-lookup-func #'counsel-dash-at-point))
+
+(use-package counsel-dash
+ :bind (("<leader>K" . counsel-dash-at-point) ; TODO: just install as `evil-lookup-func'?
+ ("<leader>dK" . counsel-dash)
+ ("<leader>di" . counsel-dash-install-docset)
+ ("<leader>da" . counsel-dash-activate-docset)
+ ("<leader>dd" . counsel-dash-deactivate-docset))
+ :hook (python-mode . tw/counsel-dash-is-help)
+ :custom
+ (counsel-dash-docsets-path (tw/xdg-emacs-subdir 'data "dash-docsets") "Store docsets in the XDG data directory.")
+ (counsel-dash-browser-func 'eww "Open documentation pages using `eww' instead of an external browser.")
+ (counsel-dash-enable-debugging nil "Disable popping up useless warnings."))
+
+(use-package rainbow-mode
+ :after (evil)
+ :bind (("<leader>tR" . rainbow-mode)))
+
+(use-package display-line-numbers
+ ;; Included in Emacs >= 26. Better than `linum-mode'.
+ ;; There is also `global-display-line-numbers-mode', but that also
+ ;; enables line numbers in help windows, which I don't want.
+ :hook (prog-mode conf-mode))
+
+(use-package which-key
+ :commands (which-key-mode) :demand t
+ :config (which-key-mode +1)
+ :diminish which-key-mode)
+
+(use-package undo-tree
+ :after (evil) ; for our :bind-ing
+ :bind (("<leader>U" . undo-tree-visualize))
+ :custom
+ (undo-tree-history-directory-alist
+ `(("." . ,(tw/xdg-emacs-subdir 'data "undo-tree-history")))
+ "Store all `undo-tree' history in a single directory, instead of next to the associated file.")
+ :commands (global-undo-tree-mode)
+ :demand t ; this is required so that the :config stanza is actually run asap despite :bind
+ :config (global-undo-tree-mode +1))
+
+;; IDE-like features.
+(use-package vc
+ :after (which-key evil)
+ :init (which-key-add-key-based-replacements
+ "<leader>g" '("vc" . "Version control")
+ "<leader>gM" '("merge" . "Version control merging"))
+ :bind-keymap ("<leader>g" . vc-prefix-map))
+
+(use-package corfu ; https://github.com/minad/corfu
+ :hook (prog-mode ledger-mode shell-mode eshell-mode)
+ :custom
+ (corfu-auto t "Show completion popup after a few seconds automatically.")
+ :diminish corfu-mode)
+
+(use-package corfu-doc
+ :after (corfu)
+ :hook (corfu-mode)
+ :diminish corfu-doc-mode)
+
+(use-package flyspell
+ :hook mail-mode)
+
+(use-package flymake
+ :after (evil which-key)
+ :hook prog-mode
+ :init (which-key-add-key-based-replacements
+ "<leader>e" '("errors" . "Flymake"))
+ :bind (("<leader>eb" . flymake-start)
+ ("<leader>el" . flymake-show-buffer-diagnostics)
+ ("<leader>ep" . flymake-show-project-diagnostics)
+ ("<leader>e." . display-local-help) ; Show the error message at point in the minibuffer.
+ ; `flymake' also shows it using `eldoc', but documentation
+ ; seems to override error messages.
+ ("<leader>en" . flymake-goto-next-error)
+ ("<leader>eN" . flymake-goto-prev-error))
+ :custom
+ (flymake-suppress-zero-counters nil "Show severity counters even when they are zero."))
+
+(use-package flymake-collection
+ :after (flymake)
+ ;; This needs to be called in `after-init-hook' so that all other
+ ;; packages' `:flymake-hook's are processed before f-c-hook-setup is
+ ;; called. See https://github.com/mohkale/flymake-collection.
+ :hook (after-init . flymake-collection-hook-setup))
+
+;; Language Server Protocol.
+(defun tw/help-is-eldoc (&rest _)
+ "Set up `evil-lookup-func' to display the `eldoc' buffer."
+ (setq-local evil-lookup-func #'eldoc-doc-buffer))
+
+(use-package eglot
+ ;; I have clang (for clangd) and python-lsp-server installed.
+ ;; `:hook' adds `-mode' to the package name, but `eglot-mode' doesn't exist.
+ :hook ((python-mode c-mode c++-mode) . eglot)
+ :custom
+ (eglot-autoshutdown t "Shut down language servers after deleting their last associated buffer.")
+ (eglot-sync-connect 0.1 "Wait for the language server in the background if it takes longer than 100ms.")
+ :config
+ ;; TODO: only run `tw/help-is-eldoc' if `eglot-managed-p' is true.
+ (add-hook 'eglot-managed-mode-hook #'tw/help-is-eldoc))
+
+;; Non-LSP language modes.
+(use-package cmake-mode
+ :mode (rx (or (: (or bos "/") "CMakeLists.txt") ".cmake") eos))
+
+(use-package gnuplot
+ :commands (gnuplot-mode gnuplot-make-buffer)
+ :mode ((rx ".gnuplot" eos) . gnuplot-mode))
+
+(use-package graphviz-dot-mode
+ :mode (rx ".dot" eos)
+ :custom (graphviz-dot-view-command "xdot %s" "Use xdot for previewing graphviz files."))
+
+(use-package hcl-mode
+ :mode (rx "." (or "hcl" "nomad") eos))
+
+(use-package mmm-mode
+ :commands (mmm-mode))
+
+(use-package puppet-mode
+ :mode (rx ".pp" eos))
+
+(use-package python
+ :commands (python-mode)
+ :mode (((rx ".py" (? (or ?\i ?\w)) eos) . python-mode)
+ ((rx ".aurora" eos) . python-mode)))
+
+(use-package rec-mode
+ :mode (rx ".rec" eos))
+
+(use-package sh-script ; built-in
+ :custom (sh-basic-offset 2 "Use 2 spaces for `sh-mode' indents."))
+
+(use-package tcl
+ :mode ((rx ".tcl" eos) . tcl-mode)
+ :magic ((rx "#%Module1.0") . tcl-mode))
+
+(use-package web-mode
+ :mode (rx "." (or "htm" "html" "js" "css" "scss") eos))
+
+(use-package yaml-mode
+ :mode (rx ".y" (? "a") "ml" eos))
+
+(use-package ledger-mode
+ :mode (rx ".journal" eos)
+ :custom
+ (ledger-default-date-format ledger-iso-date-format "Use hledger-style dates.")
+ (ledger-reconcile-default-date-format ledger-iso-date-format "Use hledger-style dates.")
+ (ledger-reconcile-default-commodity "€" "Make euros the default currency.")
+ (ledger-post-account-alignment-column 2 "Use 2-space indents.")
+ (ledger-post-amount-alignment-at :decimal "Align amounts at decimal points/commas.")
+ (ledger-post-amount-alignment-column 52 "Align amounts' decimal points to the 52nd column.")
+ (ledger-highlight-xact-under-point nil "Don't highlight the transaction at point."))
+
+(use-package geiser
+ :after (evil)
+ :commands (geiser geiser-eval-buffer geiser-eval-definition geiser-eval-region geiser-eval-last-sexp)
+ :hook (scheme-mode . geiser-autodoc-mode)
+ :config
+ (evil-define-key '(normal visual) scheme-mode-map
+ (kbd "<localleader>i") #'geiser
+ (kbd "<localleader>eb") #'geiser-eval-buffer
+ (kbd "<localleader>ef") #'geiser-eval-definition
+ (kbd "<localleader>er") #'geiser-eval-region
+ (kbd "<localleader>el") #'geiser-eval-last-sexp)
+ :defines scheme-mode-map)
+
+(use-package geiser-racket
+ :after (geiser))
+(use-package geiser-guile
+ :after (geiser))
+
+;; Org-mode
+(use-package org)
+(use-package ob ; org-babel
+ :after (org))
+
+(use-package outline
+ :commands (outline-mode outline-minor-mode)
+ :custom
+ ;; Mirror the default "C-c @" binding for `outline-minor-mode'.
+ (outline-minor-mode-prefix (kbd "<localleader>@") "Use localleader for `outline-minor-mode' keybindings."))
+
+;; My own custom packages, and stuff that isn't on MELPA.
+;; (use-package actionlint ; TODO: port to flymake
+;; :after (flycheck)
+;; :load-path "include/")
+
+(use-package alidist-mode
+ :after (flymake mmm-mode yaml-mode)
+ :mode (rx (or bos "/") "alidist/" (1+ anything) ".sh" eos)
+ :load-path "include/")
+
+(use-package bemscript-mode
+ :load-path "include/"
+ :mode (rx ".bem" eos))
+
+(use-package ifm-mode
+ :load-path "include/"
+ :mode (rx ".ifm" eos))
+
+(use-package pam-env-mode
+ :load-path "include/"
+ :mode (rx (or bos "/") (or "pam_env.conf" ".pam_environment") eos))
+
+(use-package environmentd-mode
+ :load-path "include/"
+ :mode (rx (or bos "/")
+ (or (: (? "etc/") "environment")
+ (: ".environment.d/" (1+ (not ?\/)) ".conf"))
+ eos))
+
+(use-package org-latex-classes
+ :after (ox-latex)
+ :load-path "include/")
+
+(use-package ob-rec
+ ;; `org-babel' hooks for `rec-mode'
+ :after (org ob rec-mode)
+ :load-path "include/")
+
+(use-package vcard-mode
+ :load-path "include/"
+ :mode (rx "." (or "vcf" "vcard") eos))
+
+;; Vim keybindings.
+(defun tw/switch-to-other-buffer ()
+ "Switch to the last-used buffer."
+ (interactive)
+ (switch-to-buffer (other-buffer)))
+
+(defun tw/new-buffer ()
+ "Open a new, empty buffer."
+ (interactive)
+ (switch-to-buffer (generate-new-buffer "untitled")))
+
+(defun tw/delete-current-buffer-file ()
+ "Ask for confirmation, then delete the file associated with the current buffer."
+ (interactive)
+ (let ((buffer (current-buffer)))
+ (when (yes-or-no-p (concat "Delete `" (buffer-file-name buffer) "'?"))
+ (delete-file (buffer-file-name buffer))
+ (kill-buffer buffer))))
+
+(use-package evil
+ :after (which-key)
+ :commands (evil-mode evil-ex-nohighlight)
+ :init (setq evil-want-keybinding nil) ; evil-collection needs this
+ :custom
+ (evil-undo-system 'undo-tree "Use `undo-tree' for evil's undo-redo function.")
+ (evil-want-minibuffer t "Use evil bindings in the minibuffer too.")
+ (evil-want-C-u-scroll t "Scroll on C-u in normal mode, not `universal-argument'.")
+ (evil-want-C-u-delete t "Delete line on C-u in insert mode, not `universal-argument'.")
+ (evil-want-Y-yank-to-eol t "Yank from point to end-of-line on Y.")
+ :config
+ (evil-mode +1)
+ (evil-set-leader '(normal visual) (kbd "SPC")) ; <leader>
+ (evil-set-leader '(normal visual) (kbd "\\") t) ; <localleader>
+ (evil-define-key '(normal insert visual replace) 'global
+ (kbd "C-s") #'save-buffer)
+ ;; Global major-mode-independent keys should be defined here. Major
+ ;; mode-dependent keys (e.g. for launching a REPL) should go under
+ ;; <localleader> instead. Use `use-package' `:bind' for those.
+ (evil-define-key '(normal visual) 'global
+ ;; These keybindings mirror the default Spacemacs ones because I have
+ ;; muscle memory of those.
+ (kbd "<leader>:") #'eval-expression
+ (kbd "<leader>TAB") #'tw/switch-to-other-buffer
+ (kbd "<leader>bb") #'switch-to-buffer
+ (kbd "<leader>bd") #'kill-current-buffer
+ (kbd "<leader>bn") #'tw/new-buffer
+ (kbd "<leader>br") #'revert-buffer-quick
+ (kbd "<leader>bx") #'kill-buffer-and-window
+ (kbd "<leader>fd") #'tw/delete-current-buffer-file
+ (kbd "<leader>ff") #'find-file
+ (kbd "<leader>fs") #'save-buffer
+ (kbd "<leader>h") help-map
+ (kbd "<leader>sc") #'evil-ex-nohighlight
+ (kbd "<leader>tf") #'auto-fill-mode
+ (kbd "<leader>tl") #'toggle-truncate-lines
+ (kbd "<leader>tn") #'display-line-numbers-mode
+ (kbd "<leader>u") #'universal-argument
+ (kbd "<leader>w") evil-window-map
+ (kbd "<leader>wd") #'evil-window-delete ; analogous to "<leader>bd"
+ (kbd "<leader>wx") #'kill-buffer-and-window) ; analogous to "<leader>bx"
+ (which-key-add-key-based-replacements
+ ;; Names are a `cons' of a short name and a long name.
+ ;; E.g. for <leader>b, "buffer" is shown under "b" in the "<leader>" menu,
+ ;; while "Buffers" is shown as the title in the "<leader>b" menu.
+ "<leader>b" '("buffer" . "Buffers")
+ "<leader>f" '("file" . "Files")
+ "<leader>h" '("help" . "General help and documentation")
+ "<leader>q" '("quit" . "Finish editing the current buffer in emacsclient")
+ "<leader>s" '("search" . "Search operations and options")
+ "<leader>t" '("toggle" . "Toggles and quick settings")
+ "<leader>w" '("window" . "Windows"))
+ :functions (evil-define-key evil-set-leader
+ evil-define-key* evil-window-delete evil-delay)
+ :defines (evil-visual-state-map))
+
+(use-package evil-collection
+ :after (evil)
+ :commands (evil-collection-init) :demand t
+ :config (evil-collection-init))
+
+(use-package evil-org
+ :after (evil org)
+ :hook org-mode
+ :config
+ (evil-define-key '(normal visual) org-mode-map
+ (kbd "<localleader>\\") #'org-ctrl-c-ctrl-c
+ (kbd "<localleader>'") #'org-edit-src-code
+ (kbd "<localleader>e") #'org-export-dispatch)
+ (evil-define-key '(normal visual) org-src-mode-map
+ (kbd "<localleader>'") #'org-edit-src-exit
+ (kbd "<localleader>\\") #'org-edit-src-save
+ (kbd "<localleader>a") #'org-edit-src-abort))
+
+(use-package evil-replace-with-register
+ :after (evil)
+ :commands (evil-replace-with-register-install) :demand t
+ ;; :custom (evil-replace-with-register-key "gR" "Use the default key.")
+ :config (evil-replace-with-register-install))
+
+(use-package evil-commentary
+ :after (evil)
+ :commands (evil-commentary-mode) :demand t
+ :config (evil-commentary-mode +1))
+
+(use-package evil-expat ; for :reverse, :remove, :rename, :colo, :g*, ... ex commands
+ :after (evil))
+
+(use-package evil-surround
+ :after (evil)
+ :commands (global-evil-surround-mode) :demand t
+ :config (global-evil-surround-mode +1))
+
+(use-package evil-smartparens
+ :after (evil smartparens)
+ :hook smartparens-enabled-hook)
+
+(use-package evil-multiedit
+ ;; See: https://github.com/hlissner/evil-multiedit#usage
+ :commands (evil-multiedit-default-keybinds) :demand t
+ :config (evil-multiedit-default-keybinds))
+
+(use-package evil-args
+ :after (evil)
+ :config
+ ;; Bind evil-args text objects only.
+ ;; See https://github.com/wcsmith/evil-args for more bindings.
+ (define-key evil-inner-text-objects-map "a" 'evil-inner-arg)
+ (define-key evil-outer-text-objects-map "a" 'evil-outer-arg))
+
+(use-package evil-numbers
+ :after (evil)
+ :bind (("<leader>+" . evil-numbers/inc-at-pt)
+ ("<leader>-" . evil-numbers/dec-at-pt)))
+
+(use-package evil-goggles ; visual previews for edit operations
+ :after (evil)
+ :commands (evil-goggles-mode evil-goggles-use-diff-faces) :demand t
+ :config
+ (evil-goggles-mode +1)
+ (evil-goggles-use-diff-faces)
+ :diminish evil-goggles-mode)
+
+(use-package evil-traces ; visual previews for :ex commands
+ :after (evil)
+ :commands (evil-traces-mode evil-traces-use-diff-faces) :demand t
+ :config
+ (evil-traces-mode +1)
+ (evil-traces-use-diff-faces)
+ :diminish evil-traces-mode)
+
+(use-package evil-markdown
+ :after (evil markdown-mode)
+ :hook markdown-mode)
+
+(use-package evil-tex
+ :after (evil tex)
+ :hook tex-mode)
+
+(use-package evil-text-object-python
+ :after (evil python)
+ :hook (python-mode . evil-text-object-python-add-bindings))
+
+;; Lisp features
+(use-package aggressive-indent
+ :hook (; scheme-mode
+ emacs-lisp-mode common-lisp-mode))
+
+(defun tw/lisp-evil-setup ()
+ "Set up evil in general `lisp-mode' buffers."
+ (setq-local evil-symbol-word-search t
+ ;; https://github.com/wcsmith/evil-args#customization
+ evil-args-delimiters '(" ")))
+
+;; Sadly, not all Lisp modes derive from `lisp-mode'.
+(add-hook 'lisp-mode-hook #'tw/lisp-evil-setup)
+(add-hook 'lisp-data-mode-hook #'tw/lisp-evil-setup) ; for elisp
+(add-hook 'scheme-mode-hook #'tw/lisp-evil-setup)
+
+;; buffer-locally set `evil-lookup-func' (used on K keys) for
+;; languages where something better than man pages is available
+;; (e.g. `describe-symbol' for elisp).
+(defun tw/elisp-lookup-func ()
+ "Show help in `emacs-lisp-mode' buffers."
+ (let ((sym (symbol-at-point)))
+ (if sym (describe-symbol sym)
+ (call-interactively #'describe-symbol))))
+
+(defun tw/emacs-lisp-evil-setup ()
+ "Set up evil in `emacs-lisp-mode' buffers."
+ (setq-local evil-lookup-func #'tw/elisp-lookup-func))
+
+(add-hook 'emacs-lisp-mode-hook #'tw/emacs-lisp-evil-setup)
+
+(evil-define-key '(normal visual) emacs-lisp-mode-map
+ (kbd "<localleader>eb") #'eval-buffer
+ (kbd "<localleader>ef") #'eval-defun
+ (kbd "<localleader>er") #'eval-region
+ (kbd "<localleader>el") #'eval-last-sexp
+ (kbd "<localleader>ep") #'eval-print-last-sexp)
+
+;;; init.el ends here