Repository navigation
Make OSC 7 directory tracking robust to #, %, and escaped paths - #649
Merged
Merged
Conversation
The shell integrations emitted the raw $PWD inside a file:// URI and the Emacs side took the parsed path verbatim. That round trip was self-consistent but fragile: a `#' in any directory component was split off as a URI fragment (silently stalling tracking locally, committing a wrong TRAMP directory remotely), and percent-encoded reports from foreign emitters (vte.sh, WezTerm, fish's builtin, nushell's control-char encoding) left literal %XX in default-directory. Adopt the kitty/ghostty two-scheme model on both sides: - bash/zsh emit kitty's kitty-shell-cwd:// scheme, which carries the path verbatim, so no shell-side encoder is needed. - fish percent-encodes its file:// report via the string escape builtin, exactly like ghostty's fish integration. - ghostel--update-directory takes kitty-shell-cwd:// paths as-is (substring split, so newlines survive; host downcased to keep the TRAMP connection identity consistent with file:// reports) and percent-decodes file:// paths UTF-8-aware, with %0A/%0D preserved and %00 rejected. When only the raw %XX spelling names a local directory (nushell, stale integration scripts), the raw spelling wins. A URI with an unrecognized scheme is reported instead of being mistaken for a plain OSC 9;9 path. Remote (TRAMP) reports of literal-%XX names still need the updated scripts; an old ghostel receiving the new scheme ignores it until both sides are current.
dakra
force-pushed
the
fix/osc7-path-escaping
branch
3 times, most recently
from
August 24, 2026 16:06
8e071a3 to
245438b
Compare
This branch was previously deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The shell integrations emit the raw $PWD inside a
file://URI and the Emacs side takes the parsed path verbatim. That round trip is self-consistent but fragile:#in any directory component is split off as a URI fragment byurl-generic-parse-url. Locally, tracking silently stalls (thefile-directory-pguard rejects the truncated path); remotely, a wrong TRAMPdefault-directoryis committed without a check.%20etc. indefault-directory.Fix
Adopts the kitty/ghostty two-scheme model on both sides (ghostty's shell integrations are the reference):
kitty-shell-cwd://scheme, which carries the path verbatim — no shell-side encoder needed, and ghostty/kitty parse it too when the remote script runs under them (previously ghostty rejected our raw-spacefile://URIs outright).file://report via thestring escape --style=urlbuiltin, exactly like ghostty's fish integration.ghostel--update-directorytakeskitty-shell-cwd://paths as-is (substring split so newlines survive; host downcased to keep the TRAMP connection identity consistent withfile://reports) and percent-decodesfile://paths UTF-8-aware, with%0A/%0Dpreserved and%00rejected. When only the raw%XXspelling names a local directory (nushell, stale integration scripts), the raw spelling wins. A URI with an unrecognized scheme is reported instead of being mistaken for a plain OSC 9;9 path.Compatibility
file://scripts (unescaped ASCII round-trips unchanged; literal-%XXnames resolve locally via the raw-spelling fallback).%XXnames need the updated scripts; an old ghostel receiving the new scheme ignores it until both sides are current.Verification
make -j8 allgreen (elisp + native + zig tests, checkdoc, package-lint).#/?/literal%20), kitty-scheme remote TRAMP construction,file://decoding (space, UTF-8, escaped%, raw fallback, decoded-wins-when-both-exist), a bash emitter→parser end-to-end round trip for a#/%/space path, and a fish wire-format probe. Windows-incompatible fixtures are taggedposix.a#b?c, literal50%20off, andpäthdirectories correctly, with raw OSC 7 wire captures confirming the emitted forms.