Skip to content

ptdel/.emacs.d

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 

Repository files navigation

Emacs Configuration

I try to stay out of my configs as much as possible, and to help me do that I keep a few things in mind:

  • only configure what I need.
  • keep everything declarative.
  • use tools with sane defaults.

Sometimes I don’t adhere to these, it is what it is.

Package Setup

Declaring upstream package archives: ELPA and MELPA.

(require 'package)
(setq package-archives '(("gnu" . "http://elpa.gnu.org/packages/")
      	                ("melpa" . "https://melpa.org/packages/")))
(package-initialize)

use-package lets me declare and configure packages inside of a single macro. This keeps everything relatively declarative and isolated.

(unless (package-installed-p 'use-package)
  (package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t)

Global Configuration

exec-path-from-shell ensures that Emacs will inherit my environment. I connect to Emacs from a client, so this configurations runs conditionally if Emacs is a daemon.

(use-package exec-path-from-shell
  :ensure t
  :if (daemonp)
  :config
  (setq exec-path-from-shell-variables '("PATH"))
  (exec-path-from-shell-initialize))

Customization

Customizations that emacs tries to add are stored in a separate file. I don’t want to declare things like font size or color themes so they reside here.

(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)

Scatch Buffer

By default, scratch is an empty org-mode buffer. This makes it easy for me to write random things down.

(setq default-directory "~/")
(setq initial-major-mode 'org-mode)
(setq inhibit-startup-message t)
(setq initial-scratch-message nil)

Regions

When operating on regions, this will remove a highlighted region before text insertion, giving the behavior of replacing text.

(delete-selection-mode)

OS interoperability

When using the clipboard, setting select-enable-clipboard to t I can copy and paste between Emacs and the system.

(setq select-enable-clipboard t)

Many languages, linters, and operating systems require the presence of an empty line at the bottom of a file.

(setq require-final-newline t)

Enables the mouse wheel, which I prefer over the typical scrolling keychords.

(mouse-wheel-mode t)
(setq mouse-drag-copy-region nil)

Saving

I keep all backups and auto-save files in the temporary directory to avoid littering.

(setq backup-directory-alist
      `((".*" . ,temporary-file-directory)))

(setq auto-save-file-name-transforms
      `((".*" ,temporary-file-directory t)))

(setq tramp-backup-directory-alist backup-directory-alist)

(setq auto-save-list-file-prefix temporary-file-directory)

Secrets & Auth Sources

the authinfo file keeps sensitive information out of my configuration. It’s not checked into git, and needs my gpg key to be accessed.

(setq auth-source-debug t)
(setq auth-sources '((:source "~/.emacs.d/.authinfo.gpg")))

UI and Appearance

I’m ensuring that I use ligature-friendly fonts. This is just for aesthetics it doesn’t help with anything.

(add-to-list 'default-frame-alist '(font . "Fira Code"))
(set-face-attribute 'default t :font "Fira Code")

Interface

diminish keeps minor modes from cluttering up the modeline. I don’t need an indication that most things are running.

(use-package diminish :ensure t)

displaying certain words in their greek letter makes me feel smart and superior

(global-prettify-symbols-mode 1)

Prevents the operating system’s dialog boxes from popping up with messages from Emacs. They’re annoying and get in the way.

(setq use-dialog-box nil)

I recover a little surface area by removing the various bars from the editor. When I was learning Emacs having those menus visible was helpful.

(tool-bar-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)

Highlights the current line the cursor is on. Very helpful for not getting lost.

(global-hl-line-mode t)

Lets me see what line and column number I’m on. I obsess about this.

(column-number-mode)

Parens

show-paren-mode highlights matching pairs of parentheses or brackets. By setting show-paren-style to mixed the enclosed expression will be highlighted instead if there is no matching parentheses.

(show-paren-mode)
(setq show-paren-style 'mixed)

electric-pair-mode will automatically insert a matching delimiter after one is inserted, with the cursor moved between them.

(electric-pair-mode 1)
(electric-indent-mode -1)

rainbow-delimiters highlights delimiters according to their depth. This makes it really easy to see how deeply nested in a loop you are, or where you are in a lisp form.

(use-package rainbow-delimiters
  :ensure t
  :hook (prog-mode . rainbow-delimiters-mode))

Ligatures

A full ligature configuration for Cascadia and FiraCode fonts. Just try not to look at this section if you don’t have to.

(use-package ligature
  :ensure t
  :config
  (ligature-set-ligatures 't '("www"))
  (ligature-set-ligatures 'eww-mode '("ff" "fi" "ffi"))
  (ligature-set-ligatures 'prog-mode
                        '(("=" (rx (+ (or ">" "<" "|" "/" "~" ":" "!" "="))))
                          (";" (rx (+ ";")))
                          ("&" (rx (+ "&")))
                          ("!" (rx (+ (or "=" "!" "\." ":" "~"))))
                          ("?" (rx (or ":" "=" "\." (+ "?"))))
                          ("%" (rx (+ "%")))
                          ("|" (rx (+ (or ">" "<" "|" "/" ":" "!" "}" "\]"
                                          "-" "=" ))))
                          ("\\" (rx (or "/" (+ "\\"))))
                          ("+" (rx (or ">" (+ "+"))))
                          (":" (rx (or ">" "<" "=" "//" ":=" (+ ":"))))
                          ("/" (rx (+ (or ">"  "<" "|" "/" "\\" "\*" "!"
                                          "="))))
                          ("\." (rx (or "=" "-" "\?" "\.=" "\.<" (+ "\."))))
                          ("-" (rx (+ (or ">" "<" "|" "~" "-"))))
                          ("*" (rx (or ">" "/" ")" (+ "*"))))
                          ("w" (rx (+ "w")))
                          ("<" (rx (+ (or "\+" "\*" "\$" "<" ">" ":" "~"  "!"
                                          "-"  "/" "|" "="))))
                          (">" (rx (+ (or ">" "<" "|" "/" ":" "=" "-"))))
                          ("#" (rx (or ":" "=" "!" "(" "\?" "\[" "{" "_(" "_"
                                       (+ "#"))))
                          ("~" (rx (or ">" "=" "-" "@" "~>" (+ "~"))))
                          ("_" (rx (+ (or "_" "|"))))
                          ("0" (rx (and "x" (+ (in "A-F" "a-f" "0-9")))))
                          "Fl"  "Tl"  "fi"  "fj"  "fl"  "ft"
                          "{|"  "[|"  "]#"  "(*"  "}#"  "$>"  "^="))
  (global-ligature-mode t))

Navigation

History

save-place-mode moves the cursor to it’s last location in the previously visited file.

(save-place-mode 1)

Enable auto-revert-mode to automatically update files that change externally to Emacs (such as external formatters or git checkouts):

(global-auto-revert-mode)

Completion

vertico ecosystem

vertico is a minimalistic vertical completion interface similar to the built-in. I moved from helm after realizing I didn’t use most of what it provided. I load it with savehist-mode so that my minibuffer history is preserved.

(use-package vertico
  :ensure t
  :init
  (vertico-mode)
  (savehist-mode)
  :config
  (setq vertico-cycle t))

orderless is a completion style that divides a pattern into parts and matches those parts in any order.

(use-package orderless
  :ensure t
  :config
  (setq completion-styles '(orderless basic partial-completion)
	completion-category-overrides '((eglot (styles . (basic))))))

marginalia enriches minibuffer completions with additional information.

(use-package marginalia
  :ensure t
  :after vertico
  :init
  (marginalia-mode))

consult provides various commands that can be invoked based on completion candidates. The consult-get-project-root function constrains consult to the root directory of a git project when in a git directory.

(defun consult-get-project-root ()
  (when (fboundp 'projectile-project-root)
    (projectile-project-root)))

(use-package consult
  :ensure t
  :bind
  (("C-s" . consult-line)
   ("C-r" . consult-history)
   ("C-c i" . consult-imenu)
   ("C-c g" . consult-ripgrep))
  :custom
  (consult-project-root-function #'consult-get-project-root))

embark lets you take actions on items under cursor in the minibuffer. For example: renaming a file, moving a file, etc. embark-consult provides additional functionality for use with consult.

(use-package embark
  :ensure t
  :bind
  (("C-." . embark-act)
   ("C-;" . embark-dwim)
   ("C-h B" . embark-bindings))
  :init
  (setq prefix-help-command #'embark-prefix-help-command))

(use-package embark-consult
  :ensure t
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

corfu is a minimalisting completion-at-point framework that works well with vertico.

(use-package corfu
  :ensure t
  :custom
  (corfu-auto t)
  (corfu-quit-no-match t)
  :init
  (global-corfu-mode))

  ;; (use-package cape
  ;;   :ensure t
  ;;   :init
  ;;   (add-to-list 'completion-at-point-functions #'cape-file)
  ;;   (add-to-list 'completion-at-point-functions #'cape-line))

which-key

which-key will, after a brief delay, popup a list of options for an incomplete command.

(use-package which-key
  :ensure t
  :diminish which-key-mode
  :custom
  (setq which-key-popup-type 'side-window)
  :init (which-key-mode)) 

Project Management

perspective helps me keep the minibuffer clean, and allows me to create groups of buffers that make moving between projects and programming languages easier.

(use-package perspective
  :ensure t
  :bind (("C-c b" . persp-switch))
  :config
  (persp-mode))

I use projectile to quickly switch between the different projects I have. I keep personal and work projects all in their own folders under one directory so projectile can easily find everything.

(use-package projectile
  :ensure t
  :diminish projectile-mode
  :config (projectile-mode)
  :custom ((projectile-completion-system 'vertico))
  :init
  (setq projectile-project-search-path '("~/Code/")))

(use-package consult-projectile
  :ensure t
  :bind
  (("C-c p" . consult-projectile)))

Programming Environment

Version Control

I use Magit for interacting with Git through emacs. It’s a much nicer interface than most hosted VCS/SCM tools.

(use-package magit
  :ensure t
  :custom
  (magit-git-executable "/usr/bin/git")
  (vc-follow-symlinks t)
  :bind (("C-x v" . magit-status)))

I also enable git-commit-mode for better editing of commit messages:

(use-package git-commit
  :ensure t
  :config
  (global-git-commit-mode))

Language Parsing

tree-sitter is an incremental parsing library that provides an intelligent form of syntax highlighting. It’s now included with Emacs.

(require 'treesit)
(add-to-list 'major-mode-remap-alist
  '((python-mode . python-ts-mode)
    (typescript-mode . typescript-ts-mode)
    (clojure-mode . clojure-ts-mode)))

apheleia is a formatter that works for multiple languages.

(use-package apheleia
  :ensure t
  :config
  (apheleia-global-mode +1))

Language Server

eglot is an unintrusive LSP that works well with tree-sitter. eldoc-box makes documentation pop up in a childframe under the cursor.

(use-package eglot
  :ensure t
  :defer t
  :bind (("C-c e" . eglot-code-actions))
  :hook
  ((clojure-mode . eglot-ensure)
   (typescript-mode . eglot-ensure)
   (python-mode . eglot-ensure)
   (python-mode . (lambda () (set-fill-column 88)))))

(setq eldoc-echo-area-use-multiline-p nil)

Snippets

yasnippet is a template system that helps save a lot of time when writing code. I also load a package that provides a large library of existing snippets.

(use-package yasnippet
  :ensure t
  :diminish yas-minor-mode
  :config
  (add-to-list 'yas-snippet-dirs "~/.emacs.d/snippets")
  :bind (("C-c y i" . yas-insert-snippet)
         ("C-c y v" . yas-visit-snippet-file)))
(add-hook 'prog-mode-hook #'yas-minor-mode)

(use-package yasnippet-snippets
  :ensure t)

Structural Editing

paredit provides structural editing capabilties when working with lisp dialects.

(use-package paredit
  :ensure t
  :diminish paredit-mode
  :hook
  ((cider-repl-mode-hook . paredit-mode)
   (cider-mode-hook . paredit-mode)
   (clojure-ts-mode . paredit-mode)))

ChatGPT

ChatGPT provides a conversational interface that replaces the google search bar.

(use-package chatgpt-shell
  :ensure t
  :defer t
  :config
  (setq chatgpt-shell-openai-key
    (auth-source-pick-first-password :host "api.openai.com")))

Scheduling & Organization

org-mode

I use org-mode to manage my notes, documentation, todos, calendar items, etc.

(use-package org
  :ensure t
  :config
  (progn
    (setq org-agenda-files '("/mnt/media/org/todo.org" "/mnt/media/org/calendar.org")
	  org-agenda-span 'day
	  org-log-done t
	  org-directory "/mnt/media/org/"
	  org-todo-keywords '((sequence "TODO" "PROGRESS" "|" "DONE"))
	  org-capture-templates
	  '(("t" "todo" entry (file "/mnt/media/org/todo.org")
	     "* TODO %?\n%u\n%a\n" :clock-in t :clock-resume t))
	  org-refile-targets (quote ((nil :maxlevel . 9)
			       (org-agenda-files :maxlevel . 9)))))
  :bind (("C-c a" . org-agenda)
	 ("C-c c" . org-capture)))

org-pomodoro lets me employ the pomodoro technique while working on org todo’s.

(use-package org-pomodoro
  :ensure t
  :commands (org-pomodoro)
  :config
  (setq alert-user-configuration '((((:category . "org-pomodoro")) libnotify nil))))

org-modern provides a modern style to org. that’s it.

(use-package org-modern
  :ensure t
  :init
  (global-org-modern-mode))

Roam

org-roam implements much of the same functionality provided by Roam or Obsidian in org-mode. It is a powerful way to build a knowledgebase. org-roam-ui provides a clean interface for traversing roam nodes.

(use-package org-roam
  :ensure t
  :custom
  (org-roam-directory (file-truename "/mnt/media/org/roam"))
  :bind (("C-c r l" . org-roam-buffer-toggle)
	 ("C-c r f" . org-roam-node-find)
	 ("C-c r g" . org-roam-graph)
	 ("C-c r i" . org-roam-node-insert)
	 ("C-c r c" . org-roam-capture)
	 ;; Dailies
	 ("C-c r j" . org-roam-dailies-capture-today))
  :config
  (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
  (org-roam-db-autosync-mode))

(use-package org-roam-ui
  :after org-roam
  :config
  (setq org-roam-ui-sync-theme t
	org-roam-ui-follow t
	org-roam-ui-update-on-save t
	org-roam-ui-open-on-start t))

khalel

khalel allows me to see my calendar events in the org-agenda which is very nice. Under the hood it is using vdirsyncer and khal to manage multiple calendars.

(use-package khalel
  :ensure t
  :commands (khalel-export-org-subtree-to-calendar
	     khalel-import-events
	     khalel-edit-calendar-event
	     khalel-add-capture-template)
  :config
  (progn
    (setq khalel-khal-command "khal"
	  khalel-vdirsyncer-command "vdirsyncer"
	  khalel-import-org-file (concat org-directory "calendar.org")
	  khalel-import-org-file-confirm-overwrite nil
	  khalel-import-end-date- "+7d")))

Mail and Communication

mu4e

managing mail with mu4e. I keep this in a separate file because it contains a lot of mail-specific information that I don’t want to share in git, so the mail.el file isn’t checked into the repository.

(load "~/.emacs.d/mail")

RSS

elfeed is a feed reader for RSS and Atom. Works well enough with Eww.

(use-package elfeed
  :ensure t
  :bind ("C-x w" . 'elfeed)
  :config
  (setq browse-url-browser-function 'eww-browse-url))

Languages

I am gradually replacing the typical language modes with the new modes supplied by tree-sitter. This area remains for language-specific tools.

Clojure

(use-package clojure-mode
  :ensure t)

 (use-package clj-deps-new
  :ensure t)

(use-package cider
  :ensure t
  :config
  (setq cider-clojure-cli-global-options "-A:portal"))

(defun portal.api/open ()
  (interactive)
  (cider-nrepl-sync-request:eval
    "(do (ns dev) (def portal ((requiring-resolve 'portal.api/open))) (add-tap (requiring-resolve 'portal.api/submit)))"))

(defun portal.api/clear ()
  (interactive)
  (cider-nrepl-sync-request:eval "(portal.api/clear)"))

(defun portal.api/close ()
  (interactive)
  (cider-nrepl-sync-request:eval "(portal.api/close)"))

Python

(use-package python
  :ensure t
  :config
  (setq python-indent-guess-indent-offset-verbose nil))

(use-package poetry
  :ensure t
  :defer t
  :config
  (setq poetry-tracking-strategy 'switch-buffer)
  :hook ((python-mode . poetry-tracking-mode)))

TypeScript

(use-package typescript-mode
  :ensure t)

(use-package vue-mode
  :ensure t
  :config
  (setq mmm-submode-decoration-level 0))

Miscellaneous

Garbage Collection

We set the GC threshold lower for interactive use (this undoes a setting from early-init.el). This needs to be the last thing in the file to get the benefits of faster startup.

(setq gc-cons-threshold (* 2 1000 1000))

About

Emacs configuration

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published