Skip to content

evil-bounds-of-not-thing-at-point/evil-forward-end assume forward-thing returns a number, which breaks with Emacs 30.1's forward-thing-provider-alist #2027

Description

@dschrempf

Emacs 30.1 added forward-thing-provider-alist, so a mode can hook in its own forward-thing behavior for a given thing (including Evil's own things, like evil-paragraph).

Problem: on that provider branch, forward-thing returns nil/t (moved / stopped early), not the integer count you get from the old forward-op branch. Evil has a couple of spots that assume it's always a number:

  • evil-bounds-of-not-thing-at-point
  • evil-forward-end

Both do (zerop (forward-thing thing ...)), so once a provider is registered you get:

(zerop nil) => (wrong-type-argument number-or-marker-p nil)

which crashes plain paragraph objects/motions (a p, i p, }, {).

Minimal reproducer: (Emacs 30.2 + Evil 1.15.0, still broken on both master branches as of 2026-07-16):

(setq-local forward-thing-provider-alist
            '((evil-paragraph . (lambda (bw) (forward-paragraph (if bw -1 1))))))
(evil-select-an-object 'evil-paragraph nil nil 'inclusive 1 t)
;; => (wrong-type-argument number-or-marker-p nil)

I ran into this trying to swap some fragile advice-based paragraph-object narrowing (in a Tree-sitter Haskell mode) for a clean buffer-local provider, the one hook Emacs added for exactly this use case immediately crashes Evil.

For context, I also raised the return-value shape upstream with Emacs: https://lists.gnu.org/archive/html/bug-gnu-emacs/2026-07/msg00767.html

The fix is probably just: don't assume forward-thing returns a number, treat nil as "moved" and t as "no progress".

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions