Posts
-
Soft Wrapping Done Right with visual-wrap-prefix-mode
Emacs has always offered two camps when it comes to long lines: hard wrapping (inserting actual newlines at
fill-columnwithM-qorauto-fill-mode) and soft wrapping (displaying long lines across multiple visual lines withvisual-line-mode).1Hard wrapping modifies the buffer text, which isn’t always desirable. Soft wrapping preserves the text but has always had one glaring problem: continuation lines start at column 0, completely ignoring the indentation context. This makes wrapped code and structured text look terrible.
Emacs 30 finally solves this with
visual-wrap-prefix-mode.What it does
When enabled alongside
visual-line-mode,visual-wrap-prefix-modeautomatically computes awrap-prefixfor each line based on its surrounding context. Continuation lines are displayed with proper indentation — as if the text had been filled withM-q— but without modifying the buffer at all.The effect is purely visual. Your file stays untouched.
Basic setup
As usual, you can enable the mode for a single buffer:
(visual-wrap-prefix-mode 1)Or globally:
(global-visual-wrap-prefix-mode 1)You’ll likely want to pair it with
visual-line-mode:(global-visual-line-mode 1) (global-visual-wrap-prefix-mode 1)Note that with
visual-line-modesoft wrapping happens at the window edge. If you’d like to control the extra indentation applied to continuation lines, you can tweakvisual-wrap-extra-indent(default0):;; Add 2 extra spaces of indentation to wrapped lines (setq visual-wrap-extra-indent 2)Before and after
Without
visual-wrap-prefix-mode(standardvisual-line-mode):Some deeply indented text that is quite long and wraps to the next line without any indentation, which looks terrible and breaks the visual structure.With
visual-wrap-prefix-mode:Some deeply indented text that is quite long and wraps to the next line with proper indentation, preserving the visual structure nicely.A bit of history
If this sounds familiar, that’s because it’s essentially the
adaptive-wrappackage from ELPA — renamed and integrated into core Emacs. If you’ve been usingadaptive-wrap-prefix-mode, you can now switch to the built-in version and drop the external dependency.Closing Thoughts
As mentioned earlier, I’m not into soft wrapping myself - I hate long lines and I prefer code to look exactly the same in every editor. Still, sometimes you’ll be dealing with some code you can’t change, and I guess many people don’t feel as strongly about cross-editor consistency as me. In those cases
visual-wrap-prefix-modewill be quite handy!I have to admit I had forgotten about
auto-fill-modebefore doing the research for this article - now I’m wondering why I’m not using it, as pressingM-qall the time can get annoying.That’s all I have for you today. Keep hacking!
-
I’ve always been in the
M-qcamp. ↩
-
-
Preview Regex Replacements as Diffs
If you’ve ever hesitated before running
query-replace-regexpacross a large file (or worse, across many files), you’re not alone. Even experienced Emacs users get a bit nervous about large-scale regex replacements. What if the regex matches something unexpected? What if the replacement is subtly wrong?Emacs 30 has a brilliant answer to this anxiety:
replace-regexp-as-diff.How it works
Run
M-x replace-regexp-as-diff, enter your search regexp and replacement string, and instead of immediately applying changes, Emacs shows you a diff buffer with all proposed replacements. You can review every single change in familiar unified diff format before committing to anything.If you’re happy with the changes, you can apply them as a patch. If something looks off, just close the diff buffer and nothing has changed.
Multi-file support
It gets even better. There are two companion commands for working across files:
multi-file-replace-regexp-as-diff— prompts you for a list of files and shows all replacements across them as a single diff.dired-do-replace-regexp-as-diff— works on marked files in Dired. Mark the files you want to transform, run the command, and review the combined diff.
The Dired integration is particularly nice — mark files with
m, run the command from the Dired buffer, and you get a comprehensive preview of all changes.Note to self - explore how to hook this into Projectile.
A practical example
Say you want to rename a function across your project. In Dired:
- Mark all relevant files with
m(or% mto mark by regexp) - Run
dired-do-replace-regexp-as-diff - Enter the search pattern:
\bold_function_name\b - Enter the replacement:
new_function_name - Review the diff, apply if it looks good
No more sweaty palms during large refactorings.1
Closing Thoughts
I have a feeling that in the age of LLMs probably few people will get excited about doing changes via patches, but it’s a pretty cool workflow overall. I love reviewing changes as diffs and I’ll try to incorporate some of the commands mentioned in this article in my Emacs workflow.
That’s all I have for you today. Keep hacking!
-
Assuming you’re still doing any large-scale refactorings “old-school”, that is. And that you actually read the diffs carefully! ↩
-
So Many Ways to Work with Comments
I’ve been using Emacs for over 20 years and I still keep discovering (and rediscovering) comment-related commands and variables. You’d think that after two decades I’d have comments figured out, but it turns out there’s a surprising amount of depth hiding behind a few keybindings.
What prompted this article was my recent work on neocaml, a tree-sitter based major mode for OCaml. OCaml uses
Read More(* ... *)block comments – no line comments at all – and that unusual syntax forced me to dig deeper into how Emacs handles comments internally. I learned more about comment variables in the past few months than in the previous 20 years combined. -
Hide Minor Modes in the Modeline in Emacs 31
Most Emacs users run a tone of minor modes and many of them contribute something (usually useless) to the modeline. The problem is that the modeline is not infinite and can quickly get quite cluttered. That’s why for the longest time I’ve been using the third-party
diminishpackage and I have something like this in my config:(use-package diminish :config (diminish 'abbrev-mode) (diminish 'flyspell-mode) (diminish 'flyspell-prog-mode) (diminish 'eldoc-mode))diminishgets the job done, but it’s a bit annoying that you need a third-party package for something so basic. Fortunately that’s about to change…I just learned that in Emacs 31 it’s finally possible to hide minor modes in the modeline using built-in functionality! Here’s how you can do the above:
(setq mode-line-collapse-minor-modes '(abbrev-mode flyspell-mode flyspell-prog-mode eldoc-mode))And here’s how you can hide all minor modes (probably a bad idea, though, as some add useful info to the modeline):
(setq mode-line-collapse-minor-modes '(not))For more info on what you can do with this new functionality see
C-h v mode-line-collapse-minor-modes. After all, they don’t call Emacs the “self-documenting editor” for no reason.From the docs you’ll learn that hidden mode “lighters” (Emacs lingo for a mode’s modeline indicator) get compressed into one. It’s
...by default, but it can be customized via the variablemode-line-collapse-minor-modes-to.Apart from
diminish, there are also the newerdelightandminionspackages that tackle more or less the same problem. As explained here forminions, they might still be useful, depending on your use-cases. One of the great aspects of Emacs is having options and when it comes to dealing with the minor mode lighters we have plenty of options!That’s all I have for you today. Happy Christmas holidays! Keep hacking!
-
Tree-sitter powered code completion
Tree-sitter has taken the world of programming by a storm. Together with LSP, it’s probably the technology that has influenced the most programming editors and IDEs in the past several years. And now that Emacs 29+ comes with built-in Tree-sitter support I’ve been spending a lot of quality time with it, working on clojure-ts-mode and neocaml-mode.
There’s a lot I’d like to share with you about using Tree-sitter effectively, but today I’ll focus on a different topic. When most people hear about Tree-sitter they think of font-locking (syntax highlighting) and indentation powered by the abstract syntax tree (AST), generated by a Tree-sitter grammar. For a while I’ve also been thinking that the AST data can also be used for simple, yet reasonably accurate, code completion. (within the context of a single code buffer, that is) That’s definitely not nearly as powerful of what you’d normally get from a dedicated tool (e.g. an LSP server), as those usually have project-wide completion capabilities, but it’s pretty sweet given that it’s trivial to implement and doesn’t require any external dependencies.
Below, you’ll find a simple proof of concept for such a completion, in the context of
clojure-ts-mode:1(defvar clojure-ts--completion-query-globals (treesit-query-compile 'clojure `((source (list_lit ((sym_lit) @sym (:match ,clojure-ts--variable-definition-symbol-regexp @sym)) :anchor [(comment) (meta_lit) (old_meta_lit)] :* :anchor ((sym_lit) @var-candidate))) (source (list_lit ((sym_lit) @sym (:match ,clojure-ts--function-type-regexp @sym)) :anchor [(comment) (meta_lit) (old_meta_lit)] :* :anchor ((sym_lit) @fn-candidate)))))) (defconst clojure-ts--completion-annotations (list 'var-candidate " Global variable" 'fn-candidate " Function")) (defun clojure-ts--completion-annotation-function (candidate) (thread-last minibuffer-completion-table (alist-get candidate) (plist-get clojure-ts--completion-annotations))) (defun clojure-ts-completion-at-point-function () (when-let* ((bounds (bounds-of-thing-at-point 'symbol)) (source (treesit-buffer-root-node 'clojure)) (nodes (treesit-query-capture source clojure-ts--completion-query-globals))) (list (car bounds) (cdr bounds) (thread-last nodes (seq-filter (lambda (item) (not (equal (car item) 'sym)))) (seq-map (lambda (item) (cons (treesit-node-text (cdr item) t) (car item))))) :exclusive 'no :annotation-function #'clojure-ts--completion-annotation-function)))I hope you’ll agree that the code is both simple and easy to follow (especially if you know a bit about Tree-sitter queries and Emacs’s completion APIs). The meat of the example is
clojure-ts--completion-annotation-function, the rest is just completion scaffolding.And the result looks like this:
Not too shabby for 30 lines of code, right? With a bit more efforts this can be made smarter (e.g. to include local bindings as well), and potentially we can even be consulting all open buffers running
clojure-ts-modeto fetch completion data from the as well. (although that’s probably an overkill)Still, I think that’s an interesting use of Tree-sitter that some of you might find useful. It seems that Nic Ferrier has been playing with this idea recently as well - check out his recent video on the subject here.
In time Tree-sitter will redefine how we’re building Emacs major modes and what they can do.2 It’s still early days and sky is the limit. Exciting times ahead!
That’s all I have for you today. Keep hacking!
P.S. I plan to write more on the topic of Tree-sitter and how to use it in Emacs major modes, but in the mean time you might find some of my development notes useful:
Subscribe via RSS | View Older Posts
