commit 52a61a7a040f97173d222251741b9e9c37c9a801
parent 7e66a5ec08afa16e8a609b2e02a6087a44cf78f6
Author: Arun Prakash Jana <engineerarun@gmail.com>
Date: Wed, 1 Apr 2026 00:54:36 +0530
Support dir syncing with spawned shell
Diffstat:
| M | src/nnn.c | | | 97 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
1 file changed, 96 insertions(+), 1 deletion(-)
diff --git a/src/nnn.c b/src/nnn.c
@@ -6751,8 +6751,103 @@ static bool handle_cmd(enum action sel, char *path, char *newpath, char *lastdir
int r = tmp ? atoi(tmp) : 0;
setenv(env_cfg[NNNLVL], xitoa(r + 1), 1);
- spawn(shell, NULL, NULL, NULL, F_CLI);
+
+ /* Spawn shell and track CWD changes */
+ alignas(max_align_t) char cwdfile[TMP_LEN_MAX];
+ xstrsncpy(cwdfile, g_tmpfpath, tmpfplen);
+ xstrsncpy(cwdfile + tmpfplen - 1, "/.nnnshellcwd", TMP_LEN_MAX - tmpfplen);
+
+ unlink(cwdfile);
+
+ const char *shellbase = xbasename(shell);
+ int rcfd = create_tmp_file();
+
+ if (rcfd >= 0) {
+ alignas(max_align_t) char initscript[PATH_MAX + TMP_LEN_MAX + 128];
+ int len;
+
+ if (strcmp(shellbase, "bash") == 0)
+ len = snprintf(initscript, sizeof(initscript),
+ "[ -f ~/.bashrc ] && . ~/.bashrc\ntrap 'pwd > \"%s\"' EXIT\n", cwdfile);
+ else if (strcmp(shellbase, "zsh") == 0)
+ len = snprintf(initscript, sizeof(initscript),
+ "[ -f \"${ZDOTDIR_ORIG:-$HOME}/.zshrc\" ] && "
+ ". \"${ZDOTDIR_ORIG:-$HOME}/.zshrc\"\n"
+ "trap 'pwd > \"%s\"' EXIT\n", cwdfile);
+ else
+ len = 0;
+
+ if (len > 0) {
+ ssize_t wret = write(rcfd, initscript, len);
+ close(rcfd);
+
+ if (wret <= 0) {
+ spawn(shell, NULL, NULL, NULL, F_CLI);
+ } else if (strcmp(shellbase, "bash") == 0) {
+ spawn(shell, "--rcfile", g_tmpfpath, NULL, F_CLI);
+ } else if (strcmp(shellbase, "zsh") == 0) {
+ /* Create temp ZDOTDIR with .zshrc */
+ alignas(max_align_t) char zdotdir[TMP_LEN_MAX];
+ xstrsncpy(zdotdir, g_tmpfpath, tmpfplen);
+ xstrsncpy(zdotdir + tmpfplen - 1, "/.nnnzsh", TMP_LEN_MAX - tmpfplen);
+ mkdir(zdotdir, 0700);
+
+ /* Move temp rcfile to ZDOTDIR/.zshrc */
+ alignas(max_align_t) char zshrc[TMP_LEN_MAX + 16];
+ snprintf(zshrc, sizeof(zshrc), "%s/.zshrc", zdotdir);
+ rename(g_tmpfpath, zshrc);
+
+ char *oldzdotdir = getenv("ZDOTDIR");
+ char savedzdotdir[PATH_MAX];
+ if (oldzdotdir)
+ xstrsncpy(savedzdotdir, oldzdotdir, PATH_MAX);
+
+ setenv("ZDOTDIR_ORIG", oldzdotdir ? oldzdotdir : home, 1);
+ setenv("ZDOTDIR", zdotdir, 1);
+ spawn(shell, NULL, NULL, NULL, F_CLI);
+
+ /* Restore ZDOTDIR */
+ if (oldzdotdir)
+ setenv("ZDOTDIR", savedzdotdir, 1);
+ else
+ unsetenv("ZDOTDIR");
+ unsetenv("ZDOTDIR_ORIG");
+
+ unlink(zshrc);
+ rmdir(zdotdir);
+ }
+ } else {
+ close(rcfd);
+ spawn(shell, NULL, NULL, NULL, F_CLI);
+ }
+
+ unlink(g_tmpfpath);
+ } else
+ spawn(shell, NULL, NULL, NULL, F_CLI);
+
setenv(env_cfg[NNNLVL], xitoa(r), 1);
+
+ /* Sync nnn directory with shell CWD */
+ int fd = open(cwdfile, O_RDONLY);
+ if (fd >= 0) {
+ ssize_t n = read(fd, newpath, PATH_MAX - 1);
+ close(fd);
+ unlink(cwdfile);
+
+ if (n > 0) {
+ /* Strip trailing newline */
+ if (newpath[n - 1] == '\n')
+ --n;
+ newpath[n] = '\0';
+
+ if (strcmp(path, newpath) != 0 && xdiraccess(newpath)) {
+ xstrsncpy(lastdir, path, PATH_MAX);
+ xstrsncpy(path, newpath, PATH_MAX);
+ clearfilter();
+ }
+ }
+ }
+
return TRUE;
}