Skip to content

This is my emacs, there are many like it, but this one is mine...

Notifications You must be signed in to change notification settings

trevorbernard/emacs.d

Repository files navigation

Emacs Configuration

Configuration

This is my emacs, there are many like it, but this one is mine…

Getting Started

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 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)

(require 'use-package)

Emacs Initialization

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))

Package Settings

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)))

Personal

Dats me.

(setq user-full-name "Trevor Bernard"
      user-mail-address "[email protected]")

Key Bindings

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))

Invoke M-x without the Alt key

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)

Preferences

Tidy Up: Disabling Unnecessary File Artifacts

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)

Mac specific configuration

;;;###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))

Programming Languages

Bind projectile to C-c p and enable by default.

Projectile Mode

(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))

Magit

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))

Paredit

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))

Clojure

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))

Elisp

(add-hook 'emacs-lisp-mode-hook #'eldoc-mode)

Org 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))))

Exporting to PDF

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

JavaScript

(use-package js
  :ensure t
  :config
  (setq js-indent-level 2))

CSS

(use-package css-mode
  :ensure t
  :config
  (setq css-indent-level 2)
  (setq css-indent-offset 2))

Flyspell

(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)))

Markdown

(use-package ox-gfm
  :ensure t)

(use-package markdown-mode
  :ensure t
  :mode (("\\.md\\'" . gfm-mode)
         ("\\.markdown\\'" . gfm-mode))

  )

Git

Use diff-mode when editing a git commit message

(add-to-list 'auto-mode-alist '("COMMIT_EDITMSG$" . diff-mode))

Terminal Emulation

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"))

Rust

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))

ELISP

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))

OCaml

(use-package tuareg
  :ensure t)

Nix

(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))

Terraform

(use-package terraform-mode
  :ensure t)

Reset the GC threshold back to default

Misc

(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 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)

About

This is my emacs, there are many like it, but this one is mine...

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published