From f9058e1aaab38fd5f31a362382b26d1986933703 Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Fri, 29 Nov 2019 20:58:12 +0530 Subject: [PATCH] Support link creation for hovered file --- LICENSE | Bin 1472 -> 1024 bytes nnn.1 | 12 +++----- src/nnn.c | 81 ++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/LICENSE b/LICENSE index 65bba60715eab0cfe49a854813a7b9e690fab4b1..06d7405020018ddf3cacee90fd4af10487da3d20 100644 GIT binary patch literal 1024 ScmZQz7zLvtFd70QH3R?z00031 literal 1472 zcmb7C-EP}97`@k1eCSm(sBW7L1-1o6X^FPE$&yA=aec{Hj6+Nk14>TOJ^c>V26fP_ zMQunf z!S}8+BVBcVoZ5Gnw?DsH_;7st|FgO4-4xtNwYfLrWP0FSjc)kX?3>8@Yf3Df2C9Sk z+l+VghZziA+2QC0YlFejyJK%$w>bFzZNj>aX6+*dJKFGI+eMN{+qx0#H>b(@fy~fS zbnFHi{V5#mymR9Q6F$0a7x-(!C9^G})H!gMV-> z7So-X@UZ~tI{(29M>_bSb#Z8%hk85xmLxyXQ$-{B+eaw}-&*QV;{*effy9VsZv2A< z)?+b)pU_r{GdCtg9o$8Tb24~*sss@nI^%j9kjU2xz;u?tqXJlKPYCE6BETPI{HTbS zenf5k;ndqSa@DvhMc*JD(zXv<}`0Sa4+Lg@W0WF>SNxmF-! zR5PhX))Y)q-N?F9oM0=-g~|#hwme^e9gM`Ud8tWlSW*0^%c%W{$0dhIwk&uuGr?sp zB+qoT^JSGGIp`}=QZ>&+T=4fC88Ep|KVvHXSA$D9OmenmYp&?|cOpS2StI#2YDNyK zSt>1bqdBdsDvv=Yipy(}arHYDRg8W`jp8ZgOtYC75QqxLFt%)zm_rk#=2AAb7FBtH zes_pPCK<2%|haN>o47k8qeWL}=VSmcW)Nvw$F*T8_}PnXfX S5})4*wp5dC5Jrr9k^Bp_LBu8i diff --git a/nnn.1 b/nnn.1 index 870ae5bc..7e7f3eb2 100644 --- a/nnn.1 +++ b/nnn.1 @@ -154,23 +154,19 @@ auto selects the directory and enters it in this mode. .Sh SELECTION There are 3 groups of shortcuts to add files to selection: .Pp -(1) add an individual file to selection +(1) hovered file selection toggle (indicated by '+' symbol on/off) .br (2) add a range of files to selection .br (3) add all files in the current directory to selection .Pp -Selected files are visually indicated by a \fI+\fR before the entries. -.br The selection can now be listed, copied, moved, removed, archived or linked. -.br +.Pp Absolute paths of the selected files are copied to the temporary file \fB.selection\fR in the config directory. The path is shown in the help and configuration screen. If \fB$NNN_COPIER\fR is set (see ENVIRONMENT section below) the file paths are also copied to the system clipboard. .Pp -Repeat range selection on the same entry to clear selection. It's also possible to edit the current selection. +To flush the selection without running any operation use the _edit, flush selection_ key. The list is flushed even if unchanged. Use this key to remove a file from selection after you navigate away from its directory. .Pp -Deselecting a single file is not implemented because substantial string processing would be required if thousands of files are selected. It would have been trivial if the selection was limited to a single directory (use a flag for each file and select the files with the flag set). However, -.Nm -allows selection across directories making it non-trivial to do that. Also, the buffer used to select is a compact one (no byte wasted) so \fBmemmove\fR() would be required to deselect each intermediate file. Considering these, the alternatives were chosen. +Repeat range selection on the same entry twice to clear selection completely. .Sh FILE SIZE The minimum file size unit is byte (B). The rest are K, M, G, T, P, E, Z, Y (powers of 1024), same as the default units in \fIls\fR. .Sh ENVIRONMENT diff --git a/src/nnn.c b/src/nnn.c index ce63afdb..72ab596d 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -411,10 +411,10 @@ static char * const utils[] = { #define MSG_FAILED 6 #define MSG_SSN_NAME 7 #define MSG_CP_MV_AS 8 -#define MSG_RENAME_SEL 9 +#define MSG_RENAME_OPTS 9 #define MSG_FORCE_RM 10 #define MSG_CREATE_CTX 11 -#define MSG_ARCHIVE_SEL 12 +#define MSG_CUR_SEL_OPTS 12 #define MSG_NEW_OPTS 13 #define MSG_CLI_MODE 14 #define MSG_OVERWRITE 15 @@ -454,10 +454,10 @@ static const char * const messages[] = { "failed!", "session name: ", "'c'p / 'm'v as?", - "rename sel?", + "'c'urrent dir / 's'election?", "forcibly remove %s file%s (unrecoverable)?", - "Create context %d?", - "archive sel?", + "create context %d?", + "'c'urrent / 's'election?", "'f'ile / 'd'ir / 's'ym / 'h'ard?", "cli mode?", "overwrite?", @@ -1516,6 +1516,20 @@ static bool batch_rename(const char *path) char foriginal[TMP_LEN_MAX] = {0}; char buf[sizeof(batchrenamecmd) + (PATH_MAX << 1)]; + if (selbufpos) { + if (ndents) { + i = get_input(messages[MSG_RENAME_OPTS]); + if (i == 'c') { + selbufpos = 0; /* Clear the selection */ + dir = TRUE; + } else if (i != 's') + return ret; + } + } else if (ndents) + dir = TRUE; /* Rename entries in dir */ + else + return ret; + fd1 = create_tmp_file(); if (fd1 == -1) return ret; @@ -1529,18 +1543,6 @@ static bool batch_rename(const char *path) return ret; } - if (selbufpos) { - i = get_input(messages[MSG_RENAME_SEL]); - if (i != 'y' && i != 'Y') { - if (!ndents) - return TRUE; - - selbufpos = 0; /* Clear the selection */ - dir = TRUE; - } - } else - dir = TRUE; /* Rename entries in dir */ - if (dir) for (i = 0; i < ndents; ++i) appendfpath(dents[i].name, NAME_MAX); @@ -2344,24 +2346,43 @@ static size_t mkpath(const char *dir, const char *name, char *out) * Create symbolic/hard link(s) to file(s) in selection list * Returns the number of links created */ -static int xlink(char *suffix, char *path, char *buf, int *presel, int type) +static int xlink(char *suffix, char *path, char *curfname, char *buf, int *presel, int type) { - int count = 0; + int count = 0, choice = 's'; char *pbuf = pselbuf, *fname; size_t pos = 0, len, r; int (*link_fn)(const char *, const char *) = NULL; - /* Check if selection is empty */ - if (!selbufpos) { - printwait(messages[MSG_0_SELECTED], presel); + if (selbufpos) { + if (ndents) { + choice = get_input(messages[MSG_CUR_SEL_OPTS]); + if (choice != 'c' && choice != 's') + return -1; + } + } else if (ndents) + choice = 'c'; + else return -1; - } if (type == 's') /* symbolic link */ link_fn = &symlink; else /* hard link */ link_fn = &link; + if (choice == 'c') { + char lnpath[PATH_MAX]; + + mkpath(path, curfname, buf); + r = mkpath(path, curfname, lnpath); + xstrlcpy(lnpath + r - 1, suffix, PATH_MAX - r - 1); + + if (!link_fn(buf, lnpath)) + return 1; + + printwarn(presel); + return 0; /* One link created */ + } + while (pos < selbufpos) { len = strlen(pbuf); fname = xbasename(pbuf); @@ -4907,20 +4928,19 @@ nochange: switch (sel) { case SEL_ARCHIVE: - r = get_input(messages[MSG_ARCHIVE_SEL]); - if (r == 'y' || r == 'Y') { - endselection(path, newpath); + endselection(path, newpath); + r = get_input(messages[MSG_CUR_SEL_OPTS]); + if (r == 's') { if (!selsafe()) { presel = MSGWAIT; goto nochange; } tmp = NULL; - } else if (!ndents) { - printwait(messages[MSG_0_FILES], &presel); + } else if (!ndents) goto nochange; - } else + else tmp = dents[cur].name; tmp = xreadline(tmp, messages[MSG_ARCHIVE_NAME]); break; @@ -5058,7 +5078,8 @@ nochange: if (tmp[0] == '@' && tmp[1] == '\0') tmp[0] = '\0'; - r = xlink(tmp, path, newpath, &presel, r); + r = xlink(tmp, path, (ndents ? dents[cur].name : NULL), + newpath, &presel, r); close(fd); if (r <= 0)