Skip to content

Serve whole soft-wrapped targets to thing-at-point and ffap - #584

Merged
dakra merged 2 commits into
mainfrom
worktree-thingatpt-providers
Jul 29, 2026
Merged

dakra merged 2 commits into
mainfrom
worktree-thingatpt-providers

Conversation

@dakra

@dakra dakra commented Jul 29, 2026

Copy link
Copy Markdown
Owner

The renderer commits one buffer line per terminal row, so a path or URL longer than the terminal is split by a real newline. Link detection already attaches the whole target to every row, but commands that extract their string from buffer text — thing-at-point, ffap, the find-file M-n default — still stopped at the row break: ffap on a wrapped path resolved to the directory prefix that exists and visited that instead of the file (#582).

Commit 1 — the feature:

  • Buffer-local thing-at-point providers for filename, existing-filename, and url. On a detected link the answer comes from the link's target (filename drops the :LINE tail, so stock existing-filename works and returns the absolute path detection already validated); elsewhere the logical line is joined before extraction, which also covers the active prompt line detection skips and URLs with detection switched off. On Emacs 30, bounds providers make bounds-of-thing-at-point span the wrap on detected links. The forward-thing provider alist is left alone — an entry there replaces the default motion instead of falling through.
  • A file-name-at-point-functions member returning the detected file, feeding M-n in find-file prompts.
  • New ghostel-find-file-at-point, bound via <remap> <find-file-at-point>: opens the link at point at its recorded line and column; falls back to find-file-at-point off a link or when the detected file no longer exists. ffap itself offers no early-enough extension point: ffap-alist is consulted only after the existence checks that let the directory-prefix fragment win. Known residual: a literal M-x ffap bypasses the remap; that is only fixable upstream.

Commit 2 — extraction: the self-contained hyperlink subsystem (link keymap, open/navigation commands, URL/file detection with the soft-wrap join machinery, detection timer, the new integrations) moves to lisp/ghostel-links.el (~800 lines; ghostel.el drops from 6097 to 5367 lines), eagerly required like ghostel-prompt.el. Kept as a separate commit so the feature diff stays reviewable. Only deviations from a verbatim move: :group 'ghostel on the moved defcustoms, the repeat-map relocated next to its commands, and the mode-body registrations collapsed into ghostel-links-setup.

Testing: 10 new ERT tests (wrapped/unwrapped links, both fragments, property and joined-line fallbacks, OSC 8 target, bounds span, hook, command fallbacks); make -j8 all and make checkdoc green on both commits; verified end-to-end against the reporter's exact scenario in a native terminal buffer.

dakra added 2 commits July 29, 2026 08:36
The renderer commits one buffer line per terminal row, so a path or
URL longer than the terminal is split by a real newline.  Link
detection already attaches the whole target to every row, but
commands that extract their string from buffer text — thing-at-point,
ffap, the find-file M-n default — still stopped at the row break:
ffap on a wrapped path resolved to the directory prefix that exists
and visited that instead of the file.

ghostel-mode now registers buffer-local thing-at-point providers for
filename, existing-filename, and url.  On a detected link the answer
comes from the link's target, so filename drops the :LINE tail and
existing-filename is the absolute path detection already validated;
elsewhere the logical line is joined before extraction, which also
covers the active prompt line detection skips and URLs with detection
switched off.  On Emacs 30, bounds providers make
bounds-of-thing-at-point span the wrap on detected links.  The
forward-thing provider alist is left alone: an entry there replaces
the default motion instead of falling through.

file-name-at-point-functions gains a buffer-local member returning
the detected file, which feeds the M-n default in find-file prompts.

find-file-at-point is remapped to the new ghostel-find-file-at-point,
which opens the link at point at its recorded line and column and
falls back to find-file-at-point off a link or when the detected file
no longer exists.  ffap itself offers no early-enough extension
point: ffap-alist is consulted only after the existence checks that
let the directory-prefix fragment win.
ghostel.el had grown past six thousand lines.  The link cluster is
self-contained — no other file used its internals — and moves
wholesale: the link keymap and open/navigation commands, plain-text
URL and file detection with the soft-wrap join machinery, the
deferred-detection timer and its state, and the thing-at-point/ffap
integration.

ghostel.el requires the file eagerly, like ghostel-prompt.el: the
renderer attaches ghostel-link-map to OSC 8 spans as it renders, so
the map must be bound before any redraw.  The mode body's link
registrations collapse into the new ghostel-links-setup.  The moved
defcustoms name :group ghostel explicitly, since the defgroup stays
in core, and ghostel-hyperlink-repeat-map now sits next to the
navigation commands it repeats.  The code is otherwise moved
verbatim.
@dakra
dakra force-pushed the worktree-thingatpt-providers branch from c75140e to f0a9cf0 Compare July 29, 2026 11:51
@dakra
dakra merged commit f0a9cf0 into main Jul 29, 2026
29 checks passed
@dakra
dakra deleted the worktree-thingatpt-providers branch July 29, 2026 14:23
@dakra
dakra temporarily deployed to github-pages July 29, 2026 14:24 — with GitHub Actions Inactive

This branch was previously deployed

1 inactive deployment
github-pages — f0a9cf01 Deployed Jul 29, 2026 by dakra via deploy #135
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant