Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

### New features

- Add `prelude-swift` module: Swift support via the tree-sitter powered `swift-ts-mode` and `sourcekit-lsp` (registered with Eglot, since Eglot has no built-in entry for Swift). Starts an LSP session through the usual `prelude-lsp-enable` abstraction.
- Add `prelude-mistty` module: a terminal based on [MisTTY](https://github.com/szermatt/mistty), a pure-elisp shell/comint hybrid on top of `term.el` (no native module to compile). Rebinds Prelude's terminal key `C-c t` to `mistty`.
- Add a `prelude-spell-checker` option to choose between `flyspell` (the default) and [jinx](https://github.com/minad/jinx), a faster libenchant-based spell checker that only checks the visible part of the buffer. Jinx is installed on demand and enabled as a single global mode; set `(setq prelude-spell-checker 'jinx)` in your personal config to opt in (requires libenchant and a C compiler).
- Add a `prelude-whitespace-cleanup-style` option to choose how whitespace is cleaned on save: `whitespace-cleanup` (the default, tidies the whole file) or [ws-butler](https://github.com/lewang/ws-butler), which trims only the lines you actually edited so saving a file in someone else's project no longer produces noisy whitespace-only diffs. ws-butler is installed on demand.
- Add `prelude-ai` module: a thin wrapper around [gptel](https://github.com/karthink/gptel) for LLM-backed chat (Claude, GPT, Gemini, Ollama, etc.). Binds `gptel-menu` to `C-c q`. Backends and API keys are configured in personal config -- see the module documentation for examples.
- Add `prelude-forge` module: enables [Forge](https://github.com/magit/forge) on top of Magit so you can read and reply to GitHub/GitLab/Gitea pull requests and issues without leaving Emacs.
- Add `prelude-eglot-booster` module: speeds up Eglot via the [emacs-lsp-booster](https://github.com/blahgeek/emacs-lsp-booster) wrapper. The Emacs side ([eglot-booster](https://github.com/jdtsmith/eglot-booster)) is auto-installed via `package-vc-install` when the booster binary is on `PATH`; otherwise the module no-ops.
Expand All @@ -14,6 +18,14 @@

### Changes

- Add an `early-init.el` that tunes startup: it raises the GC threshold while Emacs loads (restoring a modest value once startup is over), disables the tool bar via frame parameters so the initial frame is never drawn with one, sets `frame-inhibit-implied-resize`, native-compiles packages at install time (`package-native-compile`), and sets a sane `LANG` for GUI Emacs on macOS (which otherwise starts in the `C` locale and breaks spell-checker dictionaries and subprocess sorting).
- Populate `treesit-language-source-alist` with recipes for the languages Prelude's modules use, so a missing grammar can be installed with `M-x treesit-install-language-grammar` without hunting down repository URLs.
- Modernize the Eglot event-log setting to prefer `eglot-events-buffer-config` on newer Eglot, falling back to the obsolete `eglot-events-buffer-size` on older versions.
- Bridge Eglot diagnostics into Flycheck via [flycheck-eglot](https://github.com/flycheck/flycheck-eglot) when `prelude-lsp-client` is `eglot`, so LSP diagnostics show up in Prelude's Flycheck UI instead of only through Flymake. Installed on demand; lsp-mode users are unaffected (lsp-mode has its own Flycheck integration).
- Add [Embark](https://github.com/oantolin/embark) (and `embark-consult`) to `prelude-vertico`: a keyboard-driven context menu bound to `C-.` (`embark-act`), `C-;` (`embark-dwim`) and `C-h B` (`embark-bindings`), with `embark-export` into editable grep/occur buffers. In Flyspell buffers those keys keep their Flyspell auto-correct meaning; Embark still works in the minibuffer and elsewhere.
- Enable the `vertico-directory` extension in `prelude-vertico`: `RET` descends into the selected directory, `DEL` deletes a whole path component, and `M-DEL` deletes a word of it.
- Enable `corfu-history-mode` in `prelude-corfu` so recently chosen completion candidates sort first (persisted across sessions via savehist).
- Set `consult-narrow-key` to `<` in `prelude-vertico`, so you can narrow consult candidates to a single group (e.g. `< b` for buffers in `consult-buffer`).
- Tidy up `prelude-common-lisp`: drop stale `slime-autodoc-use-multiline-p` setting (the variable was removed from upstream SLIME; modern autodoc honors `eldoc-echo-area-use-multiline-p`), set `inferior-lisp-program` to `sbcl` so `M-x run-lisp` works without SLIME, and add `slime-quicklisp` to `slime-contribs` for Quicklisp integration.

### Bugs fixed
Expand Down
30 changes: 29 additions & 1 deletion core/prelude-core.el
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,30 @@ Does nothing if Emacs was compiled without tree-sitter support."
(treesit-ready-p grammar t))
(add-to-list 'major-mode-remap-alist (cons old-mode new-mode))))

;; Grammar recipes for the languages Prelude's modules know about, so a
;; missing grammar can be installed with `M-x treesit-install-language-grammar'
;; (or `treesit-install-language-grammar' for the whole set) instead of
;; hunting down repository URLs. Add your own recipes from personal config.
(when (require 'treesit nil t)
(dolist (recipe
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(c "https://github.com/tree-sitter/tree-sitter-c")
(cpp "https://github.com/tree-sitter/tree-sitter-cpp")
(css "https://github.com/tree-sitter/tree-sitter-css")
(elixir "https://github.com/elixir-lang/tree-sitter-elixir")
(go "https://github.com/tree-sitter/tree-sitter-go")
(gomod "https://github.com/camdencheek/tree-sitter-go-mod")
(heex "https://github.com/phoenixframework/tree-sitter-heex")
(javascript "https://github.com/tree-sitter/tree-sitter-javascript")
(json "https://github.com/tree-sitter/tree-sitter-json")
(python "https://github.com/tree-sitter/tree-sitter-python")
(ruby "https://github.com/tree-sitter/tree-sitter-ruby")
(rust "https://github.com/tree-sitter/tree-sitter-rust")
(tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src")
(typescript "https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src")
(yaml "https://github.com/ikatyang/tree-sitter-yaml")))
(add-to-list 'treesit-language-source-alist recipe)))

(defun prelude-lsp-enable ()
"Enable the LSP client configured via `prelude-lsp-client'."
(pcase prelude-lsp-client
Expand All @@ -162,7 +186,11 @@ Does nothing if Emacs was compiled without tree-sitter support."
;; Eglot configuration
(with-eval-after-load 'eglot
(setq eglot-autoshutdown t)
(setq eglot-events-buffer-size 0)
;; don't log every LSP event - the logging adds overhead with chatty
;; servers (set these back when you need to debug an LSP session)
(if (boundp 'eglot-events-buffer-config)
(setq eglot-events-buffer-config '(:size 0 :format full)) ; newer Eglot
(setq eglot-events-buffer-size 0)) ; older Eglot
(setq eglot-extend-to-xref t)

(define-key eglot-mode-map (kbd "C-c C-l r") #'eglot-rename)
Expand Down
22 changes: 21 additions & 1 deletion core/prelude-custom.el
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,31 @@ Will only occur if `prelude-whitespace' is also enabled."
:type 'boolean
:group 'prelude)

(defcustom prelude-whitespace-cleanup-style 'whitespace-cleanup
"How whitespace is cleaned up on save when enabled.
`whitespace-cleanup' (the default) tidies the whole file, which can
produce noisy whitespace-only diffs in projects that aren't already
clean. `ws-butler' instead trims only the lines you actually edited,
leaving the rest of the file untouched (installed on demand)."
:type '(choice (const :tag "whitespace-cleanup (whole file)" whitespace-cleanup)
(const :tag "ws-butler (edited lines only)" ws-butler))
:group 'prelude)

(defcustom prelude-flyspell t
"Non-nil values enable Prelude's flyspell support."
"Non-nil values enable Prelude's spell checking support."
:type 'boolean
:group 'prelude)

(defcustom prelude-spell-checker 'flyspell
"The spell checker to use when `prelude-flyspell' is enabled.
`flyspell' is the classic built-in checker (it needs an external
aspell/hunspell binary). `jinx' is a faster, libenchant-based
checker that only checks the visible portion of the buffer, but it
requires libenchant and a C compiler to build its native module."
:type '(choice (const :tag "Flyspell (built-in)" flyspell)
(const :tag "Jinx (libenchant)" jinx))
:group 'prelude)

(defcustom prelude-user-init-file (expand-file-name "personal/"
user-emacs-directory)
"Path to your personal customization file.
Expand Down
32 changes: 29 additions & 3 deletions core/prelude-editor.el
Original file line number Diff line number Diff line change
Expand Up @@ -206,20 +206,46 @@
ispell-extra-args '("--sug-mode=ultra")))

(defun prelude-enable-flyspell ()
"Enable command `flyspell-mode' if `prelude-flyspell' is not nil."
(when (and prelude-flyspell (executable-find ispell-program-name))
"Enable command `flyspell-mode' when Prelude's spell checker is Flyspell.
Does nothing when `prelude-spell-checker' is set to something else
\(e.g. `jinx', which is a single global mode enabled below)."
(when (and prelude-flyspell
(eq prelude-spell-checker 'flyspell)
(executable-find ispell-program-name))
(flyspell-mode +1)))

;; jinx is an enchant-based spell checker; unlike flyspell it's a
;; single global mode that checks only the visible part of the buffer,
;; so it's enabled once here rather than per-buffer. The enable is
;; guarded so a missing libenchant only warns instead of aborting startup.
(when (and prelude-flyspell (eq prelude-spell-checker 'jinx))
(prelude-require-package 'jinx)
(with-demoted-errors "Prelude: could not enable jinx: %S"
(global-jinx-mode +1)))

(defun prelude-cleanup-maybe ()
"Invoke `whitespace-cleanup' if `prelude-clean-whitespace-on-save' is not nil."
(when prelude-clean-whitespace-on-save
(whitespace-cleanup)))

;; ws-butler trims trailing whitespace on save, but only on the lines
;; you actually edited, so saving a file in someone else's project
;; doesn't produce noisy whitespace-only diffs. Only pull it in when
;; it's the chosen cleanup style.
(when (and prelude-whitespace
prelude-clean-whitespace-on-save
(eq prelude-whitespace-cleanup-style 'ws-butler))
(prelude-require-package 'ws-butler)
(require 'ws-butler nil t))

(defun prelude-enable-whitespace ()
"Enable `whitespace-mode' if `prelude-whitespace' is not nil."
(when prelude-whitespace
;; keep the whitespace decent all the time (in this buffer)
(add-hook 'before-save-hook 'prelude-cleanup-maybe nil t)
(when prelude-clean-whitespace-on-save
(if (eq prelude-whitespace-cleanup-style 'ws-butler)
(ws-butler-mode +1)
(add-hook 'before-save-hook 'prelude-cleanup-maybe nil t)))
(whitespace-mode +1)))

(add-hook 'text-mode-hook 'prelude-enable-flyspell)
Expand Down
6 changes: 2 additions & 4 deletions core/prelude-ui.el
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@

;;; Code:

;; the toolbar is just a waste of valuable screen estate
;; in a tty tool-bar-mode does not properly auto-load, and is
;; already disabled anyway
(tool-bar-mode -1)
;; the toolbar is disabled via `default-frame-alist' in early-init.el,
;; so the initial frame is never drawn with one

(when prelude-minimalistic-ui
(menu-bar-mode -1))
Expand Down
2 changes: 2 additions & 0 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,15 @@ modules visit the [docs](modules/index.md).
;; (require 'prelude-scheme)
(require 'prelude-shell)
;; (require 'prelude-scss)
;; (require 'prelude-swift)
;; (require 'prelude-ts)
(require 'prelude-web) ;; Emacs mode for web templates
(require 'prelude-xml)
(require 'prelude-yaml)

;;; Misc
(require 'prelude-erc) ;; A popular Emacs IRC client
;; (require 'prelude-mistty) ;; MisTTY terminal (pure elisp, no native module)
```

You'll need to adjust your `prelude-modules.el` file once the
Expand Down
17 changes: 17 additions & 0 deletions docs/modules/mistty.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Prelude MisTTY

[MisTTY](https://github.com/szermatt/mistty) is a shell/comint hybrid
built on top of `term.el`. It gives you full terminal emulation for TUI
programs while keeping ordinary Emacs editing and motion on the command
line. Unlike `vterm` it's pure Emacs Lisp, so there's no native module
to compile.

## Key bindings

Enabling this module rebinds Prelude's terminal key, <kbd>C-c t</kbd>,
from `crux-visit-term-buffer` to `mistty`, on the assumption that if
you've turned it on you'd rather that key opened MisTTY. You can pick a
different binding in your personal config if you prefer.

Inside a MisTTY buffer, <kbd>C-c C-j</kbd> and <kbd>C-c C-q</kbd> toggle
between the terminal and the Emacs editing modes.
31 changes: 31 additions & 0 deletions docs/modules/swift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Prelude Swift

!!! Note

This module builds on top of the shared [Programming](programming.md) module.

## Package Prerequisites

For the proper functioning of this module, you'll need the following on
your system:

- a Swift toolchain (`swift`, `swiftc`)
- `sourcekit-lsp` (bundled with the Xcode command line tools or a Swift toolchain)

## Swift Mode

The module uses the tree-sitter powered `swift-ts-mode` for editing
Swift code, so you'll need the `swift` tree-sitter grammar installed.
Prelude ships a recipe for it, so `M-x treesit-install-language-grammar
RET swift` will fetch and build it for you.

Whenever you are editing Swift code run <kbd>C-h m</kbd> to look at the
Swift mode key bindings.

## LSP support

The module starts an LSP session automatically via Prelude's
`prelude-lsp-enable`, using whichever client `prelude-lsp-client`
selects (Eglot by default). Eglot has no built-in entry for Swift, so
the module registers `sourcekit-lsp` for it. lsp-mode users get Swift
support through the `lsp-sourcekit` package.
32 changes: 32 additions & 0 deletions docs/modules/vertico.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ packages for a modern and lightweight completion experience.
- [vertico](https://github.com/minad/vertico) - the vertical completion UI
- [orderless](https://github.com/oantolin/orderless) - flexible
completion style (space-separated patterns)
- [marginalia](https://github.com/minad/marginalia) - rich annotations
in the minibuffer (docstrings, file sizes, etc.)
- [consult](https://github.com/minad/consult) - enhanced versions
of built-in commands
- [embark](https://github.com/oantolin/embark) - a keyboard-driven
context menu for candidates and things at point
- [embark-consult](https://github.com/oantolin/embark) - integration
between Embark and Consult

## Consult Key Bindings

Expand Down Expand Up @@ -74,3 +80,29 @@ Prelude:
The module configures the `orderless` completion style, which allows you to
type space-separated patterns that can match in any order. For example, typing
`buf swi` would match `switch-to-buffer`.

## Acting on Candidates with Embark

[Embark](https://github.com/oantolin/embark) is a keyboard-driven context
menu. Point it at a minibuffer candidate or a thing at point (a file, a URL, a
symbol, ...) and it offers the actions that make sense for it.

| Key | Command | Description |
| --- | ------- | ----------- |
| <kbd>C-.</kbd> | `embark-act` | Act on the thing at point or candidate |
| <kbd>C-;</kbd> | `embark-dwim` | Run the default action directly |
| <kbd>C-h B</kbd> | `embark-bindings` | Browse the bindings at point |

A particularly handy trick is `embark-export`: from a `consult-ripgrep` (or
`consult-line`, etc.) session you can export the whole candidate set into a
proper `grep`/`occur` buffer, which you can then edit in place with
[wgrep](https://github.com/mhayashi1120/Emacs-wgrep).

!!! Note

<kbd>C-.</kbd> and <kbd>C-;</kbd> are also bound by `flyspell-mode`
(auto-correct), so in buffers where Prelude enables Flyspell those keys
keep their Flyspell meaning. Embark still works everywhere else, including
the minibuffer, which is where you'll use it most with Vertico and Consult.
Switch to the `jinx` spell checker (see `prelude-spell-checker`), or rebind
the keys, if you'd rather have Embark at point in prose buffers too.
68 changes: 68 additions & 0 deletions early-init.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
;;; early-init.el --- Prelude's early configuration.
;;
;; Copyright (c) 2011-2026 Bozhidar Batsov
;;
;; Author: Bozhidar Batsov <bozhidar@batsov.com>
;; URL: https://github.com/bbatsov/prelude
;; Version: 1.1.0
;; Keywords: convenience

;; This file is not part of GNU Emacs.

;;; Commentary:

;; This file is loaded before the package system and the UI are
;; initialized, which makes it the right place for a few settings that
;; have to be applied very early during startup.

;;; License:

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 3
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Code:

;; Raise the garbage collection threshold as high as possible for the
;; duration of startup, so we don't pay for repeated collections while
;; a lot of code is being loaded. A modest threshold is restored once
;; startup is over (a permanently huge threshold trades frequent short
;; pauses for rare, long freezes).
(setq gc-cons-threshold most-positive-fixnum)

(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold (* 50 1000 1000) ; 50MB
gc-cons-percentage 0.2)))

;; Disable the tool bar via frame parameters, so the initial frame is
;; never created with one in the first place. Toggling `tool-bar-mode'
;; later forces an expensive frame resize.
(push '(tool-bar-lines . 0) default-frame-alist)

;; Don't resize the frame in response to font or UI changes during
;; startup - it's needless work before the frame is even visible.
(setq frame-inhibit-implied-resize t)

;; Native-compile packages when they are installed rather than lazily
;; on first load, so you don't hit compilation pauses while working.
(setq package-native-compile t)

;; GUI Emacs on macOS doesn't inherit the environment from the shell,
;; so without LANG it ends up in the "C" locale, which breaks things
;; like spell-checker dictionaries and subprocess sorting.
(when (and (eq system-type 'darwin) (not (getenv "LANG")))
(setenv "LANG" "en_US.UTF-8"))

;;; early-init.el ends here
5 changes: 2 additions & 3 deletions init.el
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,8 @@ by Prelude.")
(add-to-list 'load-path prelude-vendor-dir)
(prelude-add-subfolders-to-load-path prelude-vendor-dir)

;; reduce the frequency of garbage collection by making it happen on
;; each 50MB of allocated data (the default is on every 0.76MB)
(setq gc-cons-threshold 50000000)
;; the garbage collection threshold is tuned in early-init.el (raised
;; during startup, restored to a modest value once startup is over)

;; warn when opening files bigger than 100MB
(setq large-file-warning-threshold 100000000)
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ nav:
- Scheme: modules/scheme.md
- SCSS: modules/scss.md
- Shell: modules/shell.md
- Swift: modules/swift.md
- TypeScript: modules/ts.md
- Web/HTML: modules/web.md
- XML: modules/xml.md
Expand All @@ -58,6 +59,7 @@ nav:
- Forge (PRs/Issues): modules/forge.md
- Key Chord: modules/key_chord.md
- Literate Programming: modules/literate-programming.md
- MisTTY (Terminal): modules/mistty.md
- Org Mode: modules/orgmode.md
- FAQ: faq.md
- Troubleshooting: troubleshooting.md
Expand Down
6 changes: 5 additions & 1 deletion modules/prelude-corfu.el
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@
:init
(global-corfu-mode)
:config
(corfu-popupinfo-mode))
(corfu-popupinfo-mode)
;; sort candidates by recency of selection, so the ones you pick
;; often bubble to the top; the history persists across sessions
;; when savehist-mode is on (which Prelude enables in core)
(corfu-history-mode))

(use-package cape
:ensure t
Expand Down
Loading
Loading