From 28f69e59faa0f067ee404cc85b7d2e36a6432d90 Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Sun, 10 Sep 2017 13:05:25 +0530 Subject: [PATCH] Support file and dir create --- README.md | 19 +++++++------ nnn.1 | 4 ++- nnn.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++--------- nnn.h | 7 +++-- 4 files changed, 87 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index ef92c324..c055ca3f 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Have fun with it! PRs are welcome. Check out [#1](https://github.com/jarun/nnn/i - Numeric order (1, 2, ... 10, 11, ...) for numeric names - Sort by modification time, size - Convenience - - Rename files + - Create, rename files and directories - Spawn SHELL (fallback sh) in the current directory - Invoke file path copier (*easy* shell integration) - Change directory at exit (*easy* shell integration) @@ -209,17 +209,18 @@ Search keyword and option completion scripts for Bash, Fish and Zsh can be found - | Go to last visited dir / | Filter dir contents ^/ | Open desktop search tool - . | Toggle hide .dot files - b | Show bookmark prompt + . | Toggle hide . files + b | Bookmark prompt ^B | Pin current dir ^V | Go to pinned dir - c | Show change dir prompt + c | Change dir prompt d | Toggle detail view - D | Show current file details - m | Show concise media info - M | Show full media info + D | File details + m | Brief media info + M | Full media info + n | Create new ^R | Rename selected entry - s | Toggle sort by file size + s | Toggle sort by size S | Toggle disk usage mode t | Toggle sort by mtime ! | Spawn SHELL in dir @@ -228,7 +229,7 @@ Search keyword and option completion scripts for Bash, Fish and Zsh can be found p | Open entry in PAGER ^K | Invoke file path copier ^L | Redraw, clear prompt - ? | Show help, settings + ? | Help, settings Q | Quit and change dir q, ^Q | Quit ``` diff --git a/nnn.1 b/nnn.1 index cd1446ad..9ad5c824 100644 --- a/nnn.1 +++ b/nnn.1 @@ -72,9 +72,11 @@ Toggle detail view .It Ic D Show current file details screen .It Ic m -Show concise media info +Show brief media info .It Ic M Show full media info +.It Ic n +Create a new file or directory .It Ic ^R Rename selected entry .It Ic s diff --git a/nnn.c b/nnn.c index 547c471f..0709f53e 100644 --- a/nnn.c +++ b/nnn.c @@ -254,6 +254,7 @@ static char * const utils[] = { static char *STR_NFTWFAIL = "nftw(3) failed"; static char *STR_ATROOT = "You are at /"; static char *STR_NOHOME = "HOME not set"; +static char *STR_INPUT = "No traversal delimiter allowed"; /* For use in functions which are isolated and don't return the buffer */ static char g_buf[MAX_CMD_LEN]; @@ -1016,8 +1017,12 @@ xreadline(char *fname) wchar_t *buf = (wchar_t *)g_buf; size_t buflen = NAME_MAX - 1; - DPRINTF_S(fname) - len = pos = mbstowcs(buf, fname, NAME_MAX); + if (fname) { + DPRINTF_S(fname); + len = pos = mbstowcs(buf, fname, NAME_MAX); + } else + len = (size_t)-1; + /* For future: handle NULL, say for a new name */ if (len == (size_t)-1) { buf[0] = '\0'; @@ -1083,7 +1088,7 @@ xreadline(char *fname) if (old_curs != ERR) curs_set(old_curs); settimeout(); - DPRINTF_S(buf) + DPRINTF_S(buf); wcstombs(g_buf, buf, NAME_MAX); return g_buf; } @@ -1647,17 +1652,18 @@ show_help(char *path) "e- | Go to last visited dir\n" "e/ | Filter dir contents\n" "d^/ | Open desktop search tool\n" - "e. | Toggle hide .dot files\n" - "eb | Show bookmark prompt\n" + "e. | Toggle hide . files\n" + "eb | Bookmark prompt\n" "d^B | Pin current dir\n" "d^V | Go to pinned dir\n" - "ec | Show change dir prompt\n" + "ec | Change dir prompt\n" "ed | Toggle detail view\n" - "eD | Show current file details\n" - "em | Show concise media info\n" - "eM | Show full media info\n" + "eD | File details\n" + "em | Brief media info\n" + "eM | Full media info\n" + "en | Create new\n" "d^R | Rename selected entry\n" - "es | Toggle sort by file size\n" + "es | Toggle sort by size\n" "eS | Toggle disk usage mode\n" "et | Toggle sort by mtime\n" "e! | Spawn SHELL in dir\n" @@ -1666,7 +1672,7 @@ show_help(char *path) "ep | Open entry in PAGER\n" "d^K | Invoke file path copier\n" "d^L | Redraw, clear prompt\n" - "e? | Show help, settings\n" + "e? | Help, settings\n" "eQ | Quit and change dir\n" "aq, ^Q | Quit\n\n"); @@ -2607,6 +2613,56 @@ nochange: } else if (!copier) printmsg("NNN_COPIER is not set"); goto nochange; + case SEL_NEW: + printprompt("name: "); + tmp = xreadline(NULL); + clearprompt(); + if (tmp == NULL || tmp[0] == '\0') + break; + + /* Allow only relative, same dir paths */ + if (tmp[0] == '/' || basename(tmp) != tmp) { + printmsg(STR_INPUT); + goto nochange; + } + + /* Open the descriptor to currently open directory */ + fd = open(path, O_RDONLY | O_DIRECTORY); + if (fd == -1) { + printwarn(); + goto nochange; + } + + /* Check if another file with same name exists */ + if (faccessat(fd, tmp, F_OK, AT_SYMLINK_NOFOLLOW) != -1) { + printmsg("Entry exists"); + goto nochange; + } + + /* Check if it's a dir or file */ + printprompt("Press 'f' for file or 'd' for dir"); + cleartimeout(); + r = getch(); + settimeout(); + if (r == 'f') { + r = openat(fd, tmp, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); + close(r); + } else if (r == 'd') + r = mkdirat(fd, tmp, S_IRWXU | S_IRWXG | S_IRWXO); + else { + close(fd); + break; + } + + if (r == -1) { + printwarn(); + close(fd); + goto nochange; + } + + close(fd); + mkpath(path, tmp, oldpath, PATH_MAX); + goto begin; case SEL_RENAME: if (ndents <= 0) break; @@ -2617,9 +2673,9 @@ nochange: if (tmp == NULL || tmp[0] == '\0') break; - /* Allow only relative paths */ + /* Allow only relative, same dir paths */ if (tmp[0] == '/' || basename(tmp) != tmp) { - printmsg("relative paths only"); + printmsg(STR_INPUT); goto nochange; } diff --git a/nnn.h b/nnn.h index f6bb4a7d..2de943d4 100644 --- a/nnn.h +++ b/nnn.h @@ -34,6 +34,7 @@ enum action { SEL_MTIME, SEL_REDRAW, SEL_COPY, + SEL_NEW, SEL_RENAME, SEL_HELP, SEL_RUN, @@ -138,12 +139,14 @@ static struct key bindings[] = { { 't', SEL_MTIME, "", "" }, /* Redraw window */ { CONTROL('L'), SEL_REDRAW, "", "" }, - { KEY_F(5), SEL_REDRAW, "", "" }, + { KEY_F(5), SEL_REDRAW, "", "" }, /* Undocumented */ /* Copy currently selected file path */ { CONTROL('K'), SEL_COPY, "", "" }, + /* Create a new file */ + { 'n', SEL_NEW, "", "" }, /* Show rename prompt */ { CONTROL('R'), SEL_RENAME, "", "" }, - { KEY_F(2), SEL_RENAME, "", "" }, + { KEY_F(2), SEL_RENAME, "", "" }, /* Undocumented */ /* Show help */ { '?', SEL_HELP, "", "" }, /* Run command */