Emacs-for-Goodness-Sake

Chapter 5: Package Management

Standing on the Shoulders of Giants

Remember when I said Emacs can do everything? I wasn’t exaggerating. There’s a package for everything. Want to control Spotify from Emacs? There’s a package. Want to play Dungeons & Dragons? Package. Want to turn Emacs into a full-featured IDE that makes VS Code jealous? Oh boy, are there packages.

The Emacs package ecosystem is like a candy store where everything is free and the candy makes you more productive. Let’s go shopping.

The Package System: ELPA, MELPA, and Beyond

Emacs has several package repositories:

Add them to your config:

;; Initialize package system
(require 'package)

;; Add package archives
(setq package-archives '(("gnu" . "https://elpa.gnu.org/packages/")
                         ("melpa" . "https://melpa.org/packages/")
                         ("nongnu" . "https://elpa.nongnu.org/nongnu/")))

;; Initialize packages
(package-initialize)

;; Fetch package list if needed
(unless package-archive-contents
  (package-refresh-contents))

🚸 IDE Refugee Note: This is like npm, pip, or cargo, but for your editor. And unlike VS Code extensions, these packages can fundamentally change how Emacs works, not just add features.

Your First Package Installation

Let’s install which-key, a package that shows available keybindings:

M-x package-install RET which-key RET

Now configure it:

(require 'which-key)
(which-key-mode 1)
(setq which-key-idle-delay 0.3)  ; Show hints after 0.3 seconds

Now when you type a prefix key like C-x and wait, you’ll see all available completions. It’s like training wheels for keybindings!

Use-Package: The Game Changer

Managing packages manually gets tedious. Enter use-package, the declarative package configuration tool:

;; Install use-package if not already installed
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(require 'use-package)
(setq use-package-always-ensure t)  ; Auto-install packages

Now you can declare packages beautifully:

(use-package magit
  :ensure t
  :bind ("C-x g" . magit-status)
  :config
  (setq magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))

(use-package company
  :ensure t
  :hook (prog-mode . company-mode)
  :config
  (setq company-idle-delay 0.1
        company-minimum-prefix-length 2))

🤔 Why Though? Use-package makes your config self-documenting, auto-installs missing packages, and lazy-loads them for faster startup. It’s the difference between a config file and a config masterpiece.

Essential Packages Everyone Should Have

1. Completion and Navigation

;; Vertico: Better minibuffer completion
(use-package vertico
  :ensure t
  :init
  (vertico-mode))

;; Orderless: Fuzzy matching
(use-package orderless
  :ensure t
  :custom
  (completion-styles '(orderless basic))
  (completion-category-overrides '((file (styles basic partial-completion)))))

;; Consult: Search and navigation commands
(use-package consult
  :ensure t
  :bind (("C-s" . consult-line)
         ("C-x b" . consult-buffer)
         ("M-y" . consult-yank-pop)))

;; Marginalia: Annotations in minibuffer
(use-package marginalia
  :ensure t
  :init
  (marginalia-mode))

2. Project Management

;; Projectile: Project navigation
(use-package projectile
  :ensure t
  :init
  (projectile-mode +1)
  :bind-keymap
  ("C-c p" . projectile-command-map))

;; Treemacs: File tree sidebar
(use-package treemacs
  :ensure t
  :bind
  (:map global-map
        ("M-0" . treemacs-select-window)
        ("C-x t t" . treemacs)))

3. Git Integration

;; Magit: The best git interface ever created
(use-package magit
  :ensure t
  :bind ("C-x g" . magit-status))

;; Git-gutter: Show changes in fringe
(use-package git-gutter
  :ensure t
  :hook (prog-mode . git-gutter-mode)
  :config
  (setq git-gutter:update-interval 0.02))

4. Better Editing

;; Multiple cursors
(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c" . mc/edit-lines)
         ("C->" . mc/mark-next-like-this)
         ("C-<" . mc/mark-previous-like-this)))

;; Expand region: Semantic selection
(use-package expand-region
  :ensure t
  :bind ("C-=" . er/expand-region))

;; Rainbow delimiters: Colored parentheses
(use-package rainbow-delimiters
  :ensure t
  :hook (prog-mode . rainbow-delimiters-mode))

Language-Specific Packages

Python Development

(use-package python-mode
  :ensure t
  :mode "\\.py\\'"
  :config
  (setq python-indent-offset 4))

(use-package elpy
  :ensure t
  :init
  (elpy-enable))

(use-package blacken  ; Auto-format with black
  :ensure t
  :hook (python-mode . blacken-mode))

JavaScript/TypeScript

(use-package js2-mode
  :ensure t
  :mode "\\.js\\'"
  :config
  (setq js2-basic-offset 2))

(use-package typescript-mode
  :ensure t
  :mode "\\.ts\\'")

(use-package prettier-js
  :ensure t
  :hook ((js2-mode . prettier-js-mode)
         (typescript-mode . prettier-js-mode)))

Web Development

(use-package web-mode
  :ensure t
  :mode (("\\.html?\\'" . web-mode)
         ("\\.css\\'" . web-mode)
         ("\\.jsx\\'" . web-mode))
  :config
  (setq web-mode-markup-indent-offset 2
        web-mode-css-indent-offset 2
        web-mode-code-indent-offset 2))

(use-package emmet-mode
  :ensure t
  :hook (web-mode css-mode))

The Power Packages That Change Everything

LSP Mode: IDE Features

(use-package lsp-mode
  :ensure t
  :commands (lsp lsp-deferred)
  :hook ((python-mode . lsp-deferred)
         (js2-mode . lsp-deferred)
         (typescript-mode . lsp-deferred))
  :config
  (setq lsp-idle-delay 0.6
        lsp-prefer-capf t))

(use-package lsp-ui
  :ensure t
  :hook (lsp-mode . lsp-ui-mode)
  :config
  (setq lsp-ui-doc-enable t
        lsp-ui-doc-delay 0.5))

Company: Autocompletion

(use-package company
  :ensure t
  :hook (after-init . global-company-mode)
  :config
  (setq company-idle-delay 0.1
        company-minimum-prefix-length 2
        company-show-numbers t))

(use-package company-box  ; Better UI
  :ensure t
  :hook (company-mode . company-box-mode))

Flycheck: Syntax Checking

(use-package flycheck
  :ensure t
  :init (global-flycheck-mode)
  :config
  (setq flycheck-display-errors-delay 0.3))

Theme Packages: Make It Beautiful

;; Doom themes: Beautiful modern themes
(use-package doom-themes
  :ensure t
  :config
  (load-theme 'doom-dracula t)
  (doom-themes-visual-bell-config)
  (doom-themes-org-config))

;; Doom modeline: Pretty status bar
(use-package doom-modeline
  :ensure t
  :init (doom-modeline-mode 1)
  :config
  (setq doom-modeline-height 25
        doom-modeline-icon t))

;; All-the-icons: File icons
(use-package all-the-icons
  :ensure t
  :if (display-graphic-p))
;; Run M-x all-the-icons-install-fonts on first install

Life-Changing Utility Packages

;; Undo-tree: Visualize undo history
(use-package undo-tree
  :ensure t
  :init (global-undo-tree-mode)
  :config
  (setq undo-tree-visualizer-timestamps t
        undo-tree-visualizer-diff t))

;; Avy: Jump to any character
(use-package avy
  :ensure t
  :bind ("C-;" . avy-goto-char-timer))

;; Helpful: Better help buffers
(use-package helpful
  :ensure t
  :bind (("C-h f" . helpful-callable)
         ("C-h v" . helpful-variable)
         ("C-h k" . helpful-key)))

;; Which-key: Discover keybindings
(use-package which-key
  :ensure t
  :init (which-key-mode)
  :config
  (setq which-key-idle-delay 0.3))

Managing Package Updates

;; Auto-update packages
(use-package auto-package-update
  :ensure t
  :config
  (setq auto-package-update-delete-old-versions t
        auto-package-update-hide-results t)
  (auto-package-update-maybe))

;; Or manually:
;; M-x package-list-packages
;; Then press 'U' to mark updates, 'x' to install

Creating Your Own Package

Yes, you can create packages too!

;;; my-amazing-package.el --- Does amazing things -*- lexical-binding: t -*-

;; Author: Your Name
;; Version: 1.0
;; Package-Requires: ((emacs "27.1"))

;;; Commentary:
;; This package does amazing things

;;; Code:

(defun my-amazing-function ()
  "Do something amazing."
  (interactive)
  (message "Amazing!"))

(provide 'my-amazing-package)
;;; my-amazing-package.el ends here

Package Debugging

When packages misbehave:

;; Debug package loading
(setq use-package-verbose t)

;; Profile package loading
(use-package benchmark-init
  :ensure t
  :config
  (add-hook 'after-init-hook 'benchmark-init/deactivate))
;; Then M-x benchmark-init/show-durations-tree

;; Isolate package issues
;; Start Emacs with: emacs -Q
;; Then load only the problematic package

The Package Ecosystem Tour

Some packages that showcase Emacs’s versatility:

🎯 Pro Tip: Don’t install everything at once! Add packages as you need them. Your config should grow organically with your needs.

Package Recipes: Complete Configurations

The Writer’s Setup

(use-package olivetti  ; Distraction-free writing
  :ensure t
  :hook (text-mode . olivetti-mode)
  :config
  (setq olivetti-body-width 80))

(use-package writeroom-mode  ; Full-screen writing
  :ensure t
  :bind ("C-c w" . writeroom-mode))

(use-package writegood-mode  ; Writing style hints
  :ensure t
  :hook (text-mode . writegood-mode))

The Developer’s Setup

(use-package format-all  ; Auto-format any language
  :ensure t
  :hook (prog-mode . format-all-mode))

(use-package editorconfig  ; Respect .editorconfig
  :ensure t
  :config
  (editorconfig-mode 1))

(use-package docker
  :ensure t
  :bind ("C-c d" . docker))

🎮 Package Exercises

  1. The Explorer: Install and configure 5 packages you’ve never used
  2. The Curator: Create a themed package collection (all productivity, all git, etc.)
  3. The Speed Demon: Profile your packages and optimize load time
  4. The Creator: Write a simple package that solves a personal problem
  5. The Minimalist: Find the minimum set of packages you actually need

What’s Next?

Chapter 6 introduces Org-mode, which isn’t just a package—it’s a way of life. It’s the reason many people switch to Emacs and never leave. You’re about to understand why.

But remember: packages are tools, not goals. The perfect Emacs setup is the one that helps you work better, not the one with the most packages. Though having a lot of packages is pretty fun too.


“I came for the text editor, I stayed for the packages, I became one with the ecosystem.” —The Emacs Package Enlightenment Process


Chapter 5 Summary