diff --git a/misc/auto-completion/bash/nnn-completion.bash b/misc/auto-completion/bash/nnn-completion.bash index 22da4af3..11b8ef26 100644 --- a/misc/auto-completion/bash/nnn-completion.bash +++ b/misc/auto-completion/bash/nnn-completion.bash @@ -16,6 +16,7 @@ _nnn () -b -c -d + -e -E -g -H @@ -27,7 +28,6 @@ _nnn () -Q -r -R - -s -S -t -v @@ -39,7 +39,7 @@ _nnn () COMPREPLY=( $(compgen -W "$bookmarks" -- "$cur") ) elif [[ $prev == -p ]]; then COMPREPLY=( $(compgen -f -d -- "$cur") ) - elif [[ $prev == -s ]]; then + elif [[ $prev == -e ]]; then local sessions_dir=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/sessions COMPREPLY=( $(cd "$sessions_dir" && compgen -f -d -- "$cur") ) elif [[ $cur == -* ]]; then diff --git a/misc/auto-completion/fish/nnn.fish b/misc/auto-completion/fish/nnn.fish index c71d33cc..0c10f93c 100644 --- a/misc/auto-completion/fish/nnn.fish +++ b/misc/auto-completion/fish/nnn.fish @@ -15,6 +15,7 @@ complete -c nnn -s a -d 'use access time' complete -c nnn -s b -r -d 'bookmark key to open' -x -a '(echo $NNN_BMS | awk -F: -v RS=\; \'{print $1"\t"$2}\')' complete -c nnn -s c -d 'cli-only opener' complete -c nnn -s d -d 'start in detail mode' +complete -c nnn -s e -r -d 'load session by name' -x -a '@\t"last session" (ls $sessions_dir)' complete -c nnn -s E -d 'use EDITOR for undetached edits' complete -c nnn -s g -d 'regex filters' complete -c nnn -s H -d 'show hidden files' @@ -26,7 +27,6 @@ complete -c nnn -s p -r -d 'copy selection to file' -a '-\tstdout' complete -c nnn -s Q -d 'disable quit confirmation' complete -c nnn -s r -d 'show cp, mv progress (Linux-only)' complete -c nnn -s R -d 'disable rollover at edges' -complete -c nnn -s s -r -d 'load session by name' -x -a '@\t"last session" (ls $sessions_dir)' complete -c nnn -s S -d 'start in disk usage analyzer mode' complete -c nnn -s t -d 'disable dir auto-select' complete -c nnn -s v -d 'show program version and exit' diff --git a/misc/auto-completion/zsh/_nnn b/misc/auto-completion/zsh/_nnn index c37012c8..6e94a0ee 100644 --- a/misc/auto-completion/zsh/_nnn +++ b/misc/auto-completion/zsh/_nnn @@ -13,6 +13,7 @@ args=( '(-b)-b[bookmark key to open]:key char' '(-c)-c[cli-only opener]' '(-d)-d[start in detail mode]' + '(-e)-e[load session]:session name' '(-E)-E[use EDITOR for undetached edits]' '(-g)-g[regex filters]' '(-H)-H[show hidden files]' @@ -24,7 +25,6 @@ args=( '(-Q)-Q[disable quit confirmation]' '(-r)-r[show cp, mv progress (Linux-only)]' '(-R)-R[disable rollover at edges]' - '(-s)-s[load session]:session name' '(-S)-S[start in disk usage analyzer mode]' '(-t)-t[disable dir auto-select]' '(-v)-v[show program version and exit]' diff --git a/nnn.1 b/nnn.1 index 9b8a806c..89daf5d3 100644 --- a/nnn.1 +++ b/nnn.1 @@ -10,6 +10,7 @@ .Op Ar -b key .Op Ar -c .Op Ar -d +.Op Ar -e name .Op Ar -E .Op Ar -g .Op Ar -H @@ -20,7 +21,6 @@ .Op Ar -Q .Op Ar -r .Op Ar -R -.Op Ar -s name .Op Ar -S .Op Ar -v .Op Ar -x @@ -56,6 +56,9 @@ supports the following options: .Fl d detail mode .Pp +.Fl "e name" + load a session by name +.Pp .Fl E use $EDITOR for internal undetached edits .Pp @@ -89,9 +92,6 @@ supports the following options: .Fl R disable rollover at edges .Pp -.Fl "s name" - load a session by name -.Pp .Fl S start in disk usage analyzer mode .Pp diff --git a/src/nnn.c b/src/nnn.c index a2608edb..e7ae5027 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -321,6 +321,7 @@ static char *initpath; static char *cfgdir; static char *g_selpath; static char *plugindir; +static char *sessiondir; static char *pnamebuf, *pselbuf; static struct entry *dents; static blkcnt_t ent_blocks; @@ -330,6 +331,8 @@ static kv bookmark[BM_MAX]; static kv plug[PLUGIN_MAX]; static uchar g_tmpfplen; static uchar blk_shift = BLK_SHIFT_512; +static bool interrupted = FALSE; +static bool rangesel = FALSE; /* Retain old signal handlers */ #ifdef __linux__ @@ -350,14 +353,8 @@ static char g_tmpfpath[TMP_LEN_MAX] __attribute__ ((aligned)); /* Buffer to store plugins control pipe location */ static char g_pipepath[TMP_LEN_MAX] __attribute__ ((aligned)); -/* MISC NON-PERSISTENT INTERNAL BINARY STATES */ - /* Plugin control initialization status */ -#define STATE_PLUGIN_INIT 0x1 -#define STATE_INTERRUPTED 0x2 -#define STATE_RANGESEL 0x4 - -static uchar g_states; +static bool g_plinit = FALSE; /* Options to identify file mime */ #if defined(__APPLE__) @@ -534,7 +531,6 @@ static const char * const env_cfg[] = { #define ENV_EDITOR 2 #define ENV_PAGER 3 #define ENV_NCUR 4 -#define DIR_SESSIONS 5 static const char * const envs[] = { "SHELL", @@ -542,7 +538,6 @@ static const char * const envs[] = { "EDITOR", "PAGER", "nnn", - "/sessions", }; #ifdef __linux__ @@ -609,7 +604,7 @@ static void sigint_handler(int sig) { (void) sig; - g_states |= STATE_INTERRUPTED; + interrupted = TRUE; } static uint xatoi(const char *str) @@ -2829,17 +2824,9 @@ static void savecurctx(settings *curcfg, char *path, char *curname, int r /* nex *curcfg = cfg; } -static void makesessionpath(char *spath, const char *sname) -{ - size_t r = mkpath(cfgdir, envs[DIR_SESSIONS] + 1 /* begins with '/' */, spath); - - spath[r - 1] = '/'; - xstrlcpy(spath + r, sname, PATH_MAX - r); - -} - -static void save_session(bool last_session, int *presel, char *spath) +static void save_session(bool last_session, int *presel) { + char spath[PATH_MAX]; int i; session_header_t header; FILE *fsession; @@ -2863,8 +2850,7 @@ static void save_session(bool last_session, int *presel, char *spath) sname = !last_session ? xreadline(NULL, messages[MSG_SSN_NAME]) : "@"; if (!sname[0]) return; - - makesessionpath(spath, sname); + mkpath(sessiondir, sname, spath); fsession = fopen(spath, "wb"); if (!fsession) { @@ -2898,8 +2884,9 @@ END: printwait(messages[MSG_FAILED], presel); } -static bool load_session(const char *sname, char **path, char **lastdir, char **lastname, char *spath, bool restore) +static bool load_session(const char *sname, char **path, char **lastdir, char **lastname, bool restore) { + char spath[PATH_MAX]; int i = 0; session_header_t header; FILE *fsession; @@ -2910,13 +2897,13 @@ static bool load_session(const char *sname, char **path, char **lastdir, char ** sname = sname ? sname : xreadline(NULL, messages[MSG_SSN_NAME]); if (!sname[0]) return FALSE; - } - /* Save current session */ + mkpath(sessiondir, sname, spath); + } else + mkpath(sessiondir, "@", spath); + if (has_loaded_dynamically) - save_session(TRUE, NULL, spath); - - makesessionpath(spath, (!restore ? sname : "@")); + save_session(TRUE, NULL); fsession = fopen(spath, "rb"); if (!fsession) { @@ -2958,8 +2945,7 @@ END: if (!status) { printmsg(messages[MSG_FAILED]); xdelay(XDELAY_INTERVAL_MS); - } else if (restore) - unlink(spath); + } return status; } @@ -3488,7 +3474,7 @@ static void show_help(const char *path) "6(Sh)Tab Cycle context%-11cd Detail view toggle\n" "c/ Filter%-13cIns ^N Nav-as-you-type toggle\n" "aEsc Exit prompt%-9c^L F5 Redraw/clear prompt\n" - "c. Toggle hidden%-11c? Help, conf\n" + "c. Hidden toggle%-11c? Help, conf\n" "9Q ^Q Quit%-20cq Quit context\n" "b^G QuitCD%-1c\n" "1FILES\n" @@ -3620,9 +3606,9 @@ static bool run_selected_plugin(char **path, const char *file, char *newpath, ch if (*file == '_') return run_cmd_as_plugin(*path, file, newpath, runfile); - if (!(g_states & STATE_PLUGIN_INIT)) { + if (!g_plinit) { plctrl_init(); - g_states |= STATE_PLUGIN_INIT; + g_plinit = TRUE; } fd = open(g_pipepath, O_RDONLY | O_NONBLOCK); @@ -3809,7 +3795,7 @@ static int dentfill(char *path, struct entry **dents) dir_blocks += dirwalk(buf, &sb); - if (g_states & STATE_INTERRUPTED) { + if (interrupted) { closedir(dirp); return n; } @@ -3906,7 +3892,7 @@ static int dentfill(char *path, struct entry **dents) else num_files = num_saved; - if (g_states & STATE_INTERRUPTED) { + if (interrupted) { closedir(dirp); return n; } @@ -4202,7 +4188,7 @@ static void redraw(char *path) mvprintw(lastln, 0, "%d/%d [%d:%s] %cu:%s free:%s files:%lu %lldB %s", cur + 1, ndents, cfg.selmode, - ((g_states & STATE_RANGESEL) ? "*" : (nselected ? xitoa(nselected) : "")), + (rangesel ? "*" : (nselected ? xitoa(nselected) : "")), c, buf, coolsize(get_fs_info(path, FREE)), num_files, (ll)pent->blocks << blk_shift, ptr); } else { /* light or detail mode */ @@ -4216,7 +4202,7 @@ static void redraw(char *path) mvprintw(lastln, 0, "%d/%d [%d:%s] %s%s %s %s %s [%s]", cur + 1, ndents, cfg.selmode, - ((g_states & STATE_RANGESEL) ? "*" : (nselected ? xitoa(nselected) : "")), + (rangesel ? "*" : (nselected ? xitoa(nselected) : "")), sort, buf, get_lsperms(pent->mode), coolsize(pent->size), ptr, base); } } else @@ -4245,7 +4231,7 @@ static void browse(char *ipath, const char *session) xcols = COLS; /* setup first context */ - if (!session || !load_session(session, &path, &lastdir, &lastname, newpath, FALSE)) { + if (!session || !load_session(session, &path, &lastdir, &lastname, FALSE)) { xstrlcpy(g_ctx[0].c_path, ipath, PATH_MAX); /* current directory */ path = g_ctx[0].c_path; g_ctx[0].c_last[0] = g_ctx[0].c_name[0] = '\0'; @@ -4293,8 +4279,8 @@ begin: printwarn(&presel); populate(path, lastname); - if (g_states & STATE_INTERRUPTED) { - g_states &= ~STATE_INTERRUPTED; + if (interrupted) { + interrupted = FALSE; cfg.apparentsz = 0; cfg.blkorder = 0; blk_shift = BLK_SHIFT_512; @@ -4883,8 +4869,8 @@ nochange: goto nochange; startselection(); - if (g_states & STATE_RANGESEL) - g_states &= ~STATE_RANGESEL; + if (rangesel) + rangesel = FALSE; /* Toggle selection status */ dents[cur].flags ^= FILE_SELECTED; @@ -4917,14 +4903,14 @@ nochange: goto nochange; startselection(); - g_states ^= STATE_RANGESEL; + rangesel ^= TRUE; if (stat(path, &sb) == -1) { printwarn(&presel); goto nochange; } - if (g_states & STATE_RANGESEL) { /* Range selection started */ + if (rangesel) { /* Range selection started */ inode = sb.st_ino; selstartid = cur; continue; @@ -4954,8 +4940,8 @@ nochange: goto nochange; startselection(); - if (g_states & STATE_RANGESEL) - g_states &= ~STATE_RANGESEL; + if (rangesel) + rangesel = FALSE; selstartid = 0; selendid = ndents - 1; @@ -5381,13 +5367,12 @@ nochange: r = get_input(messages[MSG_SSN_OPTS]); if (r == 's') { - save_session(FALSE, &presel, newpath); + save_session(FALSE, &presel); goto nochange; } if (r == 'l' || r == 'r') { - if (load_session(NULL, &path, &lastdir, - &lastname, newpath, r == 'r')) { + if (load_session(NULL, &path, &lastdir, &lastname, r == 'r')) { setdirwatch(); goto begin; } @@ -5503,6 +5488,7 @@ static void usage(void) " -b key open bookmark key\n" " -c cli-only opener\n" " -d detail mode\n" + " -e name load session by name\n" " -E use EDITOR for undetached edits\n" " -g regex filters [default: string]\n" " -H show hidden files\n" @@ -5514,7 +5500,6 @@ static void usage(void) " -Q no quit confirmation\n" " -r use advcpmv patched cp, mv\n" " -R no rollover at edges\n" - " -s name load session by name\n" " -S du mode\n" " -t no dir auto-select\n" " -v show version\n" @@ -5553,7 +5538,8 @@ static bool setup_config(void) cfgdir = (char *)malloc(len); plugindir = (char *)malloc(len); - if (!cfgdir || !plugindir) { + sessiondir = (char *)malloc(len); + if (!cfgdir || !plugindir || !sessiondir) { xerror(); return FALSE; } @@ -5587,9 +5573,12 @@ static bool setup_config(void) } /* Create ~/.config/nnn/sessions */ - xstrlcpy(cfgdir + r + 4 - 1, envs[DIR_SESSIONS], 10); /* subtract length of "/nnn" (4) */ + xstrlcpy(cfgdir + r + 4 - 1, "/sessions", 10); /* subtract length of "/nnn" (4) */ DPRINTF_S(cfgdir); + xstrlcpy(sessiondir, cfgdir, len); + DPRINTF_S(sessiondir); + if (!xmktree(cfgdir, TRUE)) { xerror(); return FALSE; @@ -5634,6 +5623,7 @@ static void cleanup(void) { free(g_selpath); free(plugindir); + free(sessiondir); free(cfgdir); free(initpath); free(bmstr); @@ -5656,7 +5646,7 @@ int main(int argc, char *argv[]) bool progress = FALSE; #endif - while ((opt = getopt(argc, argv, "HSKiab:cdEgnop:QrRs:tvxh")) != -1) { + while ((opt = getopt(argc, argv, "HSKiab:cde:Egnop:QrRtvxh")) != -1) { switch (opt) { case 'S': cfg.blkorder = 1; @@ -5678,6 +5668,9 @@ int main(int argc, char *argv[]) case 'c': cfg.cliopener = 1; break; + case 'e': + session = optarg; + break; case 'E': cfg.waitedit = 1; break; @@ -5722,9 +5715,6 @@ int main(int argc, char *argv[]) case 'R': cfg.rollover = 0; break; - case 's': - session = optarg; - break; case 't': cfg.autoselect = 0; break;