nnn

mirror of https://github.com/jarun/nnn
Log | Files | Refs | README | LICENSE

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:
Msrc/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; }