Posts

  • expreg: Expand Region, Reborn

    expand-region is one of my all time favorite Emacs packages. I’ve been using it since forever – press a key, the selection grows to the next semantic unit, press again, it grows further. Simple, useful, and satisfying. I’ve mentioned it quite a few times over the years, and it’s been a permanent fixture in my config for as long as I can remember.

    But lately I’ve been wondering if there’s a better way. I’ve been playing with Neovim and Helix from time to time (heresy, I know), and both have structural selection baked in via tree-sitter – select a node, expand to its parent, and so on. Meanwhile, I’ve been building and using more tree-sitter major modes in Emacs (e.g. clojure-ts-mode and neocaml), and the contrast started to bother me. We have this rich AST sitting right there in the buffer, but expand-region doesn’t know about it.

    The fundamental limitation is that expand-region relies on hand-written, mode-specific expansion functions for each language. Someone has to write and maintain er/mark-ruby-block, er/mark-python-statement, er/mark-html-tag, and so on. Some languages have great support, others get generic fallbacks. And when a new language comes along, you’re on your own until someone writes the expansion functions for it.

    Read More
  • 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-column with M-q or auto-fill-mode) and soft wrapping (displaying long lines across multiple visual lines with visual-line-mode).1

    Hard 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-mode automatically computes a wrap-prefix for each line based on its surrounding context. Continuation lines are displayed with proper indentation — as if the text had been filled with M-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-mode soft wrapping happens at the window edge. If you’d like to control the extra indentation applied to continuation lines, you can tweak visual-wrap-extra-indent (default 0):

    ;; Add 2 extra spaces of indentation to wrapped lines
    (setq visual-wrap-extra-indent 2)
    

    Before and after

    Without visual-wrap-prefix-mode (standard visual-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-wrap package from ELPA — renamed and integrated into core Emacs. If you’ve been using adaptive-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-mode will be quite handy!

    I have to admit I had forgotten about auto-fill-mode before doing the research for this article - now I’m wondering why I’m not using it, as pressing M-q all the time can get annoying.

    That’s all I have for you today. Keep hacking!

    1. I’ve always been in the M-q camp. 

  • Preview Regex Replacements as Diffs

    If you’ve ever hesitated before running query-replace-regexp across 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:

    1. Mark all relevant files with m (or % m to mark by regexp)
    2. Run dired-do-replace-regexp-as-diff
    3. Enter the search pattern: \bold_function_name\b
    4. Enter the replacement: new_function_name
    5. 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!

    1. 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 (* ... *) 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.

    Read More
  • 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 diminish package 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))
    

    diminish gets 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 variable mode-line-collapse-minor-modes-to.

    Apart from diminish, there are also the newer delight and minions packages that tackle more or less the same problem. As explained here for minions, 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!

Subscribe via RSS | View Older Posts