fix(wrapper): follow the shell working directory in the wrapper process (#129)
Fixes #124. Since #78 the shell reports `IRIS_CWD` on `chpwd`, but the wrapper only passes it to `spec.SetCWD` for suggestions. Its own working directory never moves, so tools that read the pane's foreground process to locate the shell resolve the wrong path after a `cd`. I hit this with herdr, which stopped detecting the git repository of a pane once IRIS was in it. tmux uses the same lookup for `pane_current_path`. The absolute path check matches what `spec.SetCWD` already does, so both treat a malformed value the same way. The `os.Chdir` error is dropped because the path comes from the shell integration, the user cannot act on the failure, and keeping the last known directory is better than stopping the loop. `go test ./...` passes. I tested this end to end on macOS only: the wrapper followed the `cd`, and herdr picked the repository back up. One limitation: the outer launcher process keeps its start directory, only the wrapper running `runWrapper` follows. That was enough for herdr, which reads the wrapper.
This commit is contained in:
@@ -117,6 +117,13 @@ func restoreTerminal() {
|
||||
}
|
||||
}
|
||||
|
||||
func syncProcessCWD(cwd string) {
|
||||
if !filepath.IsAbs(cwd) {
|
||||
return
|
||||
}
|
||||
_ = os.Chdir(cwd)
|
||||
}
|
||||
|
||||
// runWrapper sets up the pty environment, launches the shell,
|
||||
// and manages the main input loop to provide real-time suggestions
|
||||
// it handles raw terminal mode to intercept keystrokes and
|
||||
@@ -494,6 +501,7 @@ func runWrapper() {
|
||||
|
||||
if cwd, ok := strings.CutPrefix(query, "IRIS_CWD:"); ok {
|
||||
spec.SetCWD(cwd)
|
||||
syncProcessCWD(cwd)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package root
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func wantDir(t *testing.T, path string) string {
|
||||
t.Helper()
|
||||
resolved, err := filepath.EvalSymlinks(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return resolved
|
||||
}
|
||||
|
||||
func currentDir(t *testing.T) string {
|
||||
t.Helper()
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return wantDir(t, cwd)
|
||||
}
|
||||
|
||||
func TestSyncProcessCWDFollowsShell(t *testing.T) {
|
||||
shellDir := t.TempDir()
|
||||
t.Chdir(t.TempDir())
|
||||
|
||||
syncProcessCWD(shellDir)
|
||||
|
||||
if got := currentDir(t); got != wantDir(t, shellDir) {
|
||||
t.Fatalf("os.Getwd() = %q, want %q", got, wantDir(t, shellDir))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncProcessCWDKeepsDirectoryOnBadPath(t *testing.T) {
|
||||
launcherDir := t.TempDir()
|
||||
t.Chdir(launcherDir)
|
||||
|
||||
for _, cwd := range []string{"", "relative/path", filepath.Join(launcherDir, "does-not-exist")} {
|
||||
syncProcessCWD(cwd)
|
||||
|
||||
if got := currentDir(t); got != wantDir(t, launcherDir) {
|
||||
t.Fatalf("syncProcessCWD(%q) moved the process to %q, want %q", cwd, got, wantDir(t, launcherDir))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user