mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
Merge pull request #825 from l0ng-ai/docs/nested-shell-cwd-698
docs: why a nested shell stops reporting its cwd (#698)
This commit is contained in:
@@ -19,11 +19,13 @@ removes itself from the equation if you run the same shell elsewhere.
|
||||
| **bash** | An rcfile that sources your own first. |
|
||||
| **fish** | A `-C` init command. |
|
||||
| **PowerShell** | An encoded init command that wraps your existing `prompt` function and PSReadLine's line reader. |
|
||||
| **nushell** | A `--config` wrapper whose `config.nu` sources yours first, then adds tty7's hooks. Local panes only. |
|
||||
| **WSL** *(Windows)* | The distro's shell is bootstrapped with the same scripts. |
|
||||
| **Remote panes** | The same three POSIX shells, bootstrapped over the SSH connection. Toggle per profile with **Settings → SSH → Session → Shell integration**. |
|
||||
| **Remote panes** | The same three POSIX shells, bootstrapped over the SSH connection. Toggle per profile with **Settings → SSH →** a profile **→ Advanced → 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.
|
||||
|
||||
<Note>
|
||||
A shell launched with arguments *you* wrote — `shell.args`, or a
|
||||
@@ -51,10 +53,49 @@ it just falls back to less precise sources:
|
||||
|
||||
- Ghost suggestions, the completion menu, and <kbd>⌃ R</kbd>'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 **Settings → Terminal → Shell → Program** (or `shell`
|
||||
in [config](/reference/configuration)), and leave **Arguments** empty —
|
||||
arguments you write turn the injection off.
|
||||
|
||||
[If the Files 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
|
||||
|
||||
@@ -81,8 +81,79 @@ shell:
|
||||
- **Settings → Input → Prompt → History search**
|
||||
|
||||
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.
|
||||
[shell integration](/reference/shell-integration) — elvish, xonsh and friends
|
||||
run fine but do not get the prompt layer.
|
||||
|
||||
## The directory stopped following my shell
|
||||
|
||||
The Files 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 the cwd reporter sits at the end of its
|
||||
`lib/termsupport.zsh`, behind
|
||||
|
||||
```zsh
|
||||
if [[ -n "$INSIDE_EMACS" || -n "$SSH_CLIENT" || -n "$SSH_TTY" ]]; then
|
||||
return
|
||||
fi
|
||||
```
|
||||
|
||||
so over SSH, where sshd sets those, sourcing stops there and the reporter is
|
||||
never defined — only the title hooks above that line still run. 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 not one tty7 integrates.** It injects into zsh, bash, fish,
|
||||
PowerShell and nushell locally, and into zsh, bash and fish over SSH — 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**.
|
||||
|
||||
## <kbd>⌥ B</kbd> types `∫` instead of moving a word
|
||||
|
||||
|
||||
Reference in New Issue
Block a user