diff --git a/docs/reference/shell-integration.mdx b/docs/reference/shell-integration.mdx index 89a029ab..ee162243 100644 --- a/docs/reference/shell-integration.mdx +++ b/docs/reference/shell-integration.mdx @@ -23,7 +23,8 @@ removes itself from the equation if you run the same shell elsewhere. | **Remote panes** | The same three POSIX shells, bootstrapped over the SSH connection. Toggle per profile with **Settings → SSH → Session → Shell integration**. | `TTY7_SHELL_INTEGRATION` is set once it is active, and guards against a second -injection when shells nest. +injection when shells nest. It does not put the integration *into* a nested +shell — [shells you start yourself](#shells-you-start-yourself) have none. A shell launched with arguments *you* wrote — `shell.args`, or a @@ -51,10 +52,48 @@ it just falls back to less precise sources: - Ghost suggestions, the completion menu, and ⌃ R's fuzzy history - "Command finished" notifications and the failure marks in history search -- Exact working-directory tracking (tty7 falls back to inspecting the process) +- Exact working-directory tracking Panes, splits, scrollback, search, SSH, and the CLI are unaffected. +The working-directory fallback is worth knowing in detail, because it is not +available everywhere. Where tty7 can see the pane's processes it reads the +foreground one's own working directory instead — a local pane on macOS or +Linux, or a pane in a remote workspace, where the `tty7-server` on that host +does the reading. It is a poll, not a report: it is sampled while the pane is +producing output, at most twice a second, so it can trail a `cd` until the +pane writes something again. A local pane on **Windows** and a pane connected +to an **SSH host** have no fallback at all — on the far end of an `ssh` there +is no process table to read, so a shell that does not report its directory +leaves the pane showing the last directory that did. + +## Shells you start yourself + +The injection happens when the pane's shell is *launched*. Type `zsh` at a +bash prompt — or `bash`, or `sh`, or `docker exec … sh` — and that second +shell is a new process, launched by your shell rather than by tty7. It emits no +prompt marks and no `OSC 7`, and the pane keeps showing the directory the +outer shell last reported until you exit back to it. + +On your own machine this is usually invisible, because prompt frameworks +report the directory themselves: oh-my-zsh does it from +`omz_termsupport_cwd` in `lib/termsupport.zsh`. **Over SSH it is not.** That +file returns early when `SSH_CLIENT` or `SSH_TTY` is set, so on a remote host +a zsh you started by hand reports nothing at all, and neither does tty7. + +To get integration into that shell, make it the shell tty7 starts: + +- **A remote host.** tty7 asks the host for `$SHELL` when it connects and + bootstraps that shell, so `chsh -s /bin/zsh` (then reconnect) is what + switches it. A login script under **Advanced → Session** that runs `zsh` + does *not* — those lines are typed into the session after the shell is + already up, so they nest like anything else. Neither does `exec zsh` from + your `.bashrc`: it replaces the process tty7 set up. +- **A local pane.** Set `shell` in [config](/reference/configuration), and + leave `args` out — arguments you write turn the injection off. + +[If the file panel stopped following a nested shell →](/reference/troubleshooting#the-directory-stopped-following-my-shell) + ## Per-pane history When `per_pane_history` is on, the integration is also what makes it work. It diff --git a/docs/reference/troubleshooting.mdx b/docs/reference/troubleshooting.mdx index e06c3746..3b9d3a99 100644 --- a/docs/reference/troubleshooting.mdx +++ b/docs/reference/troubleshooting.mdx @@ -84,6 +84,75 @@ If they do nothing at all in a particular pane, the shell there probably has no [shell integration](/reference/shell-integration) — nushell, elvish, xonsh and friends run fine but do not get the prompt layer. +## The directory stopped following my shell + +The file panel, new splits, and the sidebar's repo grouping all follow the +directory the pane's shell reports (`OSC 7`). If the pane is frozen on one +directory while you `cd` around, something in the pane is not reporting it. + +The usual cause is a shell you started by hand. tty7 injects its +[shell integration](/reference/shell-integration) into the shell it launches +for the pane, and nothing else: run `zsh` at a bash prompt and that nested +shell has none. Locally you rarely notice, because oh-my-zsh reports the +directory itself — but its `lib/termsupport.zsh` begins with + +```zsh +if [[ -n "$INSIDE_EMACS" || -n "$SSH_CLIENT" || -n "$SSH_TTY" ]]; then + return +fi +``` + +so over SSH, where sshd sets those, oh-my-zsh does not define the reporter at +all. A nested zsh on a remote host therefore reports nothing, from either +side, and the pane keeps showing wherever the outer shell was. + +**Make it the shell tty7 starts.** On the remote host: + +```sh +chsh -s /bin/zsh # then reconnect +``` + +tty7 asks the host for `$SHELL` at connect time and bootstraps *that* shell, +so this is what moves the integration into your zsh — oh-my-zsh keeps working +beside it. Starting `zsh` from a login script, or `exec zsh` from your +`.bashrc`, does not help: both run after (or instead of) the shell tty7 set +up. + +**Or report the directory yourself.** If you cannot change the login shell, +add this to the remote `~/.zshrc` — it restores directory tracking only, not +prompt marks or command status: + +```zsh +# Report the working directory to tty7 (OSC 7). +autoload -Uz add-zsh-hook +__tty7_cwd() { printf '\e]7;file://%s%s\a' "${HOST:-localhost}" "${PWD//\%/%25}" } +add-zsh-hook precmd __tty7_cwd +``` + +It is safe to leave in place afterwards: when tty7 *is* integrating that +shell, the two hooks simply report the same directory twice. The bash +equivalent is `PROMPT_COMMAND`: + +```bash +__tty7_cwd() { printf '\e]7;file://%s%s\a' "${HOSTNAME:-localhost}" "${PWD//%/%25}"; } +PROMPT_COMMAND="__tty7_cwd${PROMPT_COMMAND:+;$PROMPT_COMMAND}" +``` + +Two other reasons a pane never reports its directory: + +- **The shell is one tty7 does not integrate.** Locally: zsh, bash, fish, + PowerShell, nushell. Over SSH: zsh, bash, fish. A remote host whose + `$SHELL` is anything else gets no bootstrap, silently. +- **You gave the shell your own arguments** in `shell` or a `custom_shells` + entry, which turns the injection off by design. + +Where tty7 can see the pane's processes it falls back to reading the +foreground process's working directory, which is why an unintegrated shell in +a **remote workspace** mostly keeps up — that fallback is a poll, though, +sampled while the pane produces output, so it can lag a `cd` until the pane +writes again. There is no such fallback for an **SSH pane** (the processes are +on the far end) or for a local pane on **Windows**. + ## ⌥ B types `∫` instead of moving a word That is macOS's default. Turn on **Settings → Input → Keyboard → Option (⌥) acts