diff --git a/CHANGELOG b/CHANGELOG
index 9b19944b..76b4c951 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,32 @@
+nnn v5.0 Daiquiri
+2024-08-26
+
+- show relative line numbering when jumping (#1808)
+- option `-N` to use native prompt when compiled with libreadline
+- rm improvements
+ - log removed filename
+ - cancel on 'n' or 'N'
+ - show name of the hovered file to be removed
+ - show number of selected files to be removed
+- new keybind X to force `rm -rf` always (#1811)
+- fix sort order getting changed on context switch (#1757)
+- fix current selection on new file creation, if symlinks exist (#1767)
+- fix filter toggle with mouse click on last 2 rows (#1765)
+- fix file creation (#1864)
+- when handling bookmark, use readlink, not realpath
+- set `$PWD` on directory switch
+- add option `-0` to null-separate file paths in picker mode
+- quitcd.nu (for nushell) now supports modular import (#1806)
+- add _command as plugin_ example to cd to user input directory
+- `cbcopy-mac`, `cbpaste-mac`: plugins for integration with macOS clipboard
+- `fzhist` plugin: add support for zsh history
+- `preview-tui` plugin: support eza as replacement for exa, multiple fixes
+- `preview-tui` plugin: add full svg support (#1865)
+- `preview-tabbed`: show (n)sxiv in thumbnail mode inside "Pictures" directory
+- mpv sixel/kitty support for preview (#1590)
+
+-------------------------------------------------------------------------------
+
nnn v4.9 Elixir
2023-08-27
diff --git a/LICENSE b/LICENSE
index 053ac57a..ffcb266b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -2,7 +2,7 @@ BSD 2-Clause License
Copyright (c) 2014-2016, Lazaros Koromilas
Copyright (c) 2014-2016, Dimitris Papastamos
-Copyright (c) 2016-2023, Arun Prakash Jana
+Copyright (c) 2016-2024, Arun Prakash Jana
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index db3feeb5..de580828 100644
--- a/README.md
+++ b/README.md
@@ -152,7 +152,7 @@ Don't memorize! Arrows, /, q suffice. Tab creat
## Developers
-- [Arun Prakash Jana](https://github.com/jarun) (Copyright © 2016-2023)
+- [Arun Prakash Jana](https://github.com/jarun) (Copyright © 2016-2024)
- [0xACE](https://github.com/0xACE)
- [Anna Arad](https://github.com/annagrram)
- [KlzXS](https://github.com/KlzXS)
diff --git a/misc/auto-completion/bash/nnn-completion.bash b/misc/auto-completion/bash/nnn-completion.bash
index e89e7dd0..b0e1696b 100644
--- a/misc/auto-completion/bash/nnn-completion.bash
+++ b/misc/auto-completion/bash/nnn-completion.bash
@@ -44,6 +44,7 @@ _nnn ()
-U
-V
-x
+ -0
-h
)
if [[ $prev == -b ]]; then
diff --git a/misc/auto-completion/fish/nnn.fish b/misc/auto-completion/fish/nnn.fish
index 07a05418..97eaa664 100644
--- a/misc/auto-completion/fish/nnn.fish
+++ b/misc/auto-completion/fish/nnn.fish
@@ -43,4 +43,5 @@ complete -c nnn -s u -d 'use selection (no prompt)'
complete -c nnn -s U -d 'show user and group'
complete -c nnn -s V -d 'show program version and exit'
complete -c nnn -s x -d 'notis, sel to system clipboard, xterm title'
+complete -c nnn -s 0 -d 'use null separator in picker mode'
complete -c nnn -s h -d 'show program help'
diff --git a/misc/auto-completion/zsh/_nnn b/misc/auto-completion/zsh/_nnn
index 4cc4c3fb..3fd2391d 100644
--- a/misc/auto-completion/zsh/_nnn
+++ b/misc/auto-completion/zsh/_nnn
@@ -42,6 +42,7 @@ args=(
'(-U)-U[show user and group]'
'(-V)-V[show program version and exit]'
'(-x)-x[notis, sel to system clipboard, xterm title]'
+ '(-0)-0[use null separator in picker mode]'
'(-h)-h[show program help]'
'*:filename:_files'
)
diff --git a/misc/haiku/nnn-master.recipe b/misc/haiku/nnn-master.recipe
index 7f09386c..63a03e34 100644
--- a/misc/haiku/nnn-master.recipe
+++ b/misc/haiku/nnn-master.recipe
@@ -12,7 +12,7 @@ Cygwin, WSL, Haiku and works seamlessly with DEs and GUI utilities.
Visit the Wiki for concepts, program usage, how-tos and troubleshooting."
HOMEPAGE="https://github.com/jarun/nnn"
-COPYRIGHT="2016-2023 Arun Prakash Jana"
+COPYRIGHT="2016-2024 Arun Prakash Jana"
LICENSE="BSD (2-clause)"
REVISION="1"
SOURCE_URI="git://github.com/jarun/nnn.git"
diff --git a/misc/haiku/nnn.rdef b/misc/haiku/nnn.rdef
index ada8c529..5ccc7ca1 100644
--- a/misc/haiku/nnn.rdef
+++ b/misc/haiku/nnn.rdef
@@ -8,8 +8,8 @@
resource app_signature "application/x-vnd.Jarun-nnn";
resource app_version {
- major = 4,
- middle = 9,
+ major = 5,
+ middle = 0,
minor = 0,
variety = B_APPV_DEVELOPMENT,
diff --git a/nnn.1 b/nnn.1
index 4a42da0a..ac5463c0 100644
--- a/nnn.1
+++ b/nnn.1
@@ -1,4 +1,4 @@
-.Dd Aug 27, 2023
+.Dd Aug 26, 2024
.Dt NNN 1
.Os
.Sh NAME
@@ -165,6 +165,9 @@ supports the following options:
copy path to system clipboard on selection (requires \fI.cbcp\fR plugin)
show xterm title (if non-picker mode)
.Pp
+.Fl 0
+ use null separator (instead of newline) to separate file paths in picker mode outout
+.Pp
.Fl h
show program help and exit
.Sh CONFIGURATION
diff --git a/patches/gitstatus/mainline.diff b/patches/gitstatus/mainline.diff
index acb0de43..530943b2 100644
--- a/patches/gitstatus/mainline.diff
+++ b/patches/gitstatus/mainline.diff
@@ -6,13 +6,13 @@
# Authors: Luuk van Baal
diff --git a/src/nnn.c b/src/nnn.c
-index 83ecdb90..4397944a 100644
+index 936e9c02..22032dcd 100644
--- a/src/nnn.c
+++ b/src/nnn.c
-@@ -270,6 +270,25 @@
+@@ -286,6 +286,25 @@
#define VFS_USED 1
#define VFS_SIZE 2
-
+
+/* Git icons */
+#ifdef NERD
+#define GIT_ADD ""
@@ -35,26 +35,26 @@ index 83ecdb90..4397944a 100644
/* TYPE DEFINITIONS */
typedef unsigned int uint_t;
typedef unsigned char uchar_t;
-@@ -294,6 +313,7 @@ typedef struct entry {
+@@ -310,6 +329,7 @@ typedef struct entry {
uid_t uid; /* 4 bytes */
gid_t gid; /* 4 bytes */
#endif
+ char git_status[2][5];
} *pEntry;
-
+
/* Selection marker */
-@@ -349,6 +369,7 @@ typedef struct {
+@@ -365,6 +385,7 @@ typedef struct {
uint_t cliopener : 1; /* All-CLI app opener */
uint_t waitedit : 1; /* For ops that can't be detached, used EDITOR */
uint_t rollover : 1; /* Roll over at edges */
+ uint_t normalgit : 1; /* Show git status in normal mode */
} settings;
-
+
/* Non-persistent program-internal states (alphabeical order) */
-@@ -400,7 +421,17 @@ typedef struct {
+@@ -418,7 +439,17 @@ typedef struct {
} session_header_t;
#endif
-
+
+typedef struct {
+ char status[2];
+ char path[PATH_MAX];
@@ -66,13 +66,13 @@ index 83ecdb90..4397944a 100644
+ size_t len;
+ git_status_t *statuses;
+} git_statuses;
-
+
/* Configuration, contexts */
static settings cfg = {
-@@ -3796,6 +3827,47 @@ static int get_kv_key(kv *kvarr, char *val, uchar_t max, uchar_t id)
+@@ -3950,6 +3981,47 @@ static int get_kv_key(kv *kvarr, char *val, uchar_t max, uchar_t id)
return -1;
}
-
+
+static size_t get_git_statuses(const char *path)
+{
+ static char gst[] = "git -c core.quotePath= status -s --no-renames --ignored=matching -unormal . 2>/dev/null";
@@ -117,21 +117,21 @@ index 83ecdb90..4397944a 100644
static void resetdircolor(int flags)
{
/* Directories are always shown on top, clear the color when moving to first file */
-@@ -4123,6 +4195,10 @@ static void printent(const struct entry *ent, uint_t namecols, bool sel)
-
+@@ -4283,6 +4355,10 @@ static void printent(int pdents_index, uint_t namecols, bool sel)
+
uchar_t color_pair = get_color_pair_name_ind(ent, &ind, &attrs);
-
+
+ if (git_statuses.show && (cfg.showdetail || cfg.normalgit))
+ printw("%*s%s%s", (cfg.normalgit && !cfg.showdetail) ? 1 : 0, "",
+ ent->git_status[0], ent->git_status[1]);
+
addch((ent->flags & FILE_SELECTED) ? '+' | A_REVERSE | A_BOLD : ' ');
-
+
if (g_state.oldcolor)
-@@ -5592,6 +5668,11 @@ static int dentfill(char *path, struct entry **ppdents)
+@@ -5788,6 +5864,11 @@ static int dentfill(char *path, struct entry **ppdents)
attron(COLOR_PAIR(cfg.curctx + 1));
}
-
+
+ char linkpath[PATH_MAX];
+ if ((git_statuses.len = get_git_statuses(path)))
+ if (!realpath(path, linkpath))
@@ -140,10 +140,10 @@ index 83ecdb90..4397944a 100644
#if _POSIX_C_SOURCE >= 200112L
posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
#endif
-@@ -5792,6 +5873,29 @@ static int dentfill(char *path, struct entry **ppdents)
+@@ -5988,6 +6069,29 @@ static int dentfill(char *path, struct entry **ppdents)
#endif
}
-
+
+ if (git_statuses.len) {
+ char dentpath[PATH_MAX];
+ size_t pathlen = mkpath(linkpath, dentp->name, dentpath);
@@ -169,8 +169,8 @@ index 83ecdb90..4397944a 100644
+
++ndents;
} while ((dp = readdir(dirp)));
-
-@@ -6361,11 +6465,12 @@ static int adjust_cols(int n)
+
+@@ -6569,11 +6673,12 @@ static int adjust_cols(int n)
#endif
if (cfg.showdetail) {
/* Fallback to light mode if less than 35 columns */
@@ -183,10 +183,10 @@ index 83ecdb90..4397944a 100644
+ n -= (git_statuses.show ? 34 : 32);
+ } else if (cfg.normalgit && git_statuses.show)
+ n -= 3;
-
+
/* 2 columns for preceding space and indicator */
return (n - 2);
-@@ -8143,6 +8248,7 @@ static void usage(void)
+@@ -8401,6 +8506,7 @@ static void usage(void)
" -F val fifo mode [0:preview 1:explore]\n"
#endif
" -g regex filters\n"
@@ -194,7 +194,7 @@ index 83ecdb90..4397944a 100644
" -H show hidden files\n"
" -i show current file info\n"
" -J no auto-advance on selection\n"
-@@ -8282,6 +8388,7 @@ static void cleanup(void)
+@@ -8544,6 +8650,7 @@ static void cleanup(void)
fflush(stdout);
}
#endif
@@ -202,16 +202,16 @@ index 83ecdb90..4397944a 100644
free(selpath);
free(plgpath);
free(cfgpath);
-@@ -8326,7 +8433,7 @@ int main(int argc, char *argv[])
-
+@@ -8589,7 +8696,7 @@ int main(int argc, char *argv[])
+
while ((opt = (env_opts_id > 0
? env_opts[--env_opts_id]
-- : getopt(argc, argv, "aAb:BcCdDeEfF:gHiJKl:nNop:P:QrRs:St:T:uUVxh"))) != -1) {
-+ : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nNop:P:QrRs:St:T:uUVxh"))) != -1) {
+- : getopt(argc, argv, "aAb:BcCdDeEfF:gHiJKl:nNop:P:QrRs:St:T:uUVx0h"))) != -1) {
++ : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nNop:P:QrRs:St:T:uUVx0h"))) != -1) {
switch (opt) {
#ifndef NOFIFO
case 'a':
-@@ -8380,6 +8487,9 @@ int main(int argc, char *argv[])
+@@ -8643,6 +8750,9 @@ int main(int argc, char *argv[])
cfg.regex = 1;
filterfn = &visible_re;
break;
diff --git a/patches/gitstatus/namefirst.diff b/patches/gitstatus/namefirst.diff
index a4cba012..0cb27587 100644
--- a/patches/gitstatus/namefirst.diff
+++ b/patches/gitstatus/namefirst.diff
@@ -209,8 +209,8 @@ index 88538787..d4af7c43 100644
while ((opt = (env_opts_id > 0
? env_opts[--env_opts_id]
-- : getopt(argc, argv, "aAb:BcCdDeEfF:gHiJKl:nNop:P:QrRs:St:T:uUVxh"))) != -1) {
-+ : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nNop:P:QrRs:St:T:uUVxh"))) != -1) {
+- : getopt(argc, argv, "aAb:BcCdDeEfF:gHiJKl:nNop:P:QrRs:St:T:uUVx0h"))) != -1) {
++ : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nNop:P:QrRs:St:T:uUVx0h"))) != -1) {
switch (opt) {
#ifndef NOFIFO
case 'a':
diff --git a/src/dbg.h b/src/dbg.h
index 259f8ec0..f2f7dd9f 100644
--- a/src/dbg.h
+++ b/src/dbg.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014-2016, Lazaros Koromilas
* Copyright (C) 2014-2016, Dimitris Papastamos
- * Copyright (C) 2016-2023, Arun Prakash Jana
+ * Copyright (C) 2016-2024, Arun Prakash Jana
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/icons-hash.c b/src/icons-hash.c
index f0f2b094..699af33b 100644
--- a/src/icons-hash.c
+++ b/src/icons-hash.c
@@ -23,6 +23,7 @@
#include
#include
+#include
#include
#include
#include "icons.h"
diff --git a/src/nnn.c b/src/nnn.c
index 17745729..91475916 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014-2016, Lazaros Koromilas
* Copyright (C) 2014-2016, Dimitris Papastamos
- * Copyright (C) 2016-2023, Arun Prakash Jana
+ * Copyright (C) 2016-2024, Arun Prakash Jana
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -148,7 +148,7 @@
#endif
/* Macro definitions */
-#define VERSION "4.9"
+#define VERSION "5.0"
#define GENERAL_INFO "BSD 2-Clause\nhttps://github.com/jarun/nnn"
#ifndef NOSSN
@@ -192,6 +192,8 @@
#define MSGWAIT '$'
#define SELECT ' '
#define PROMPT ">>> "
+#undef NEWLINE
+#define NEWLINE "\n"
#define REGEX_MAX 48
#define ENTRY_INCR 64 /* Number of dir 'entry' structures to allocate per shot */
#define NAMEBUF_INCR 0x800 /* 64 dir entries at once, avg. 32 chars per file name = 64*32B = 2KB */
@@ -1642,7 +1644,7 @@ static void selbufrealloc(const size_t alloclen)
}
/* Write selected file paths to fd, linefeed separated */
-static size_t seltofile(int fd, uint_t *pcount)
+static size_t seltofile(int fd, uint_t *pcount, const char *separator)
{
uint_t lastpos, count = 0;
char *pbuf = pselbuf;
@@ -1678,7 +1680,7 @@ static size_t seltofile(int fd, uint_t *pcount)
pos += len;
if (pos <= lastpos) {
- if (write(fd, "\n", 1) != 1)
+ if (write(fd, separator, 1) != 1)
return pos;
pbuf += len + 1;
}
@@ -2003,7 +2005,7 @@ static void endselection(bool endselmode)
return;
}
- seltofile(fd, NULL);
+ seltofile(fd, NULL, NEWLINE);
if (close(fd)) {
DPRINTF_S(strerror(errno));
printwarn(NULL);
@@ -2067,7 +2069,7 @@ static int editselection(void)
return -1;
}
- seltofile(fd, NULL);
+ seltofile(fd, NULL, NEWLINE);
if (close(fd)) {
DPRINTF_S(strerror(errno));
return -1;
@@ -2675,7 +2677,7 @@ static bool cpmv_rename(int choice, const char *path)
if (!count)
goto finish;
} else
- seltofile(fd, &count);
+ seltofile(fd, &count, NEWLINE);
close(fd);
@@ -2795,8 +2797,8 @@ static bool batch_rename(void)
for (i = 0; i < ndents; ++i)
appendfpath(pdents[i].name, NAME_MAX);
- seltofile(fd1, &count);
- seltofile(fd2, NULL);
+ seltofile(fd1, &count, NEWLINE);
+ seltofile(fd2, NULL, NEWLINE);
close(fd2);
if (dir) /* Don't retain dir entries in selection */
@@ -6178,7 +6180,7 @@ static void send_to_explorer(int *presel)
{
if (nselected) {
int fd = open(fifopath, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0600);
- if ((fd == -1) || (seltofile(fd, NULL) != (size_t)(selbufpos)))
+ if ((fd == -1) || (seltofile(fd, NULL, NEWLINE) != (size_t)(selbufpos)))
printwarn(presel);
else {
resetselind();
@@ -8532,6 +8534,7 @@ static void usage(void)
#ifndef NOX11
" -x notis, selection sync, xterm title\n"
#endif
+ " -0 null separator in picker mode\n"
" -h show help\n\n"
"v%s\n%s\n", __func__, VERSION, GENERAL_INFO);
}
@@ -8673,6 +8676,7 @@ int main(int argc, char *argv[])
char *arg = NULL;
char *session = NULL;
int fd, opt, sort = 0, pkey = '\0'; /* Plugin key */
+ bool sepnul = FALSE;
#ifndef NOMOUSE
mmask_t mask;
char *middle_click_env = xgetenv(env_cfg[NNN_MCLICK], "\0");
@@ -8690,7 +8694,7 @@ int main(int argc, char *argv[])
while ((opt = (env_opts_id > 0
? env_opts[--env_opts_id]
- : getopt(argc, argv, "aAb:BcCdDeEfF:gGHiJKl:nop:P:QrRs:St:T:uUVxh"))) != -1) {
+ : getopt(argc, argv, "aAb:BcCdDeEfF:gHiJKl:nNop:P:QrRs:St:T:uUVx0h"))) != -1) {
switch (opt) {
#ifndef NOFIFO
case 'a':
@@ -8838,6 +8842,9 @@ int main(int argc, char *argv[])
case 'x':
cfg.x11 = 1;
break;
+ case '0':
+ sepnul = TRUE;
+ break;
case 'h':
usage();
return EXIT_SUCCESS;
@@ -9155,7 +9162,7 @@ int main(int argc, char *argv[])
if (g_state.picker) {
if (selbufpos) {
fd = selpath ? open(selpath, O_WRONLY | O_CREAT | O_TRUNC, 0600) : STDOUT_FILENO;
- if ((fd == -1) || (seltofile(fd, NULL) != (size_t)(selbufpos)))
+ if ((fd == -1) || (seltofile(fd, NULL, sepnul ? "\0" : NEWLINE) != (size_t)(selbufpos)))
xerror();
if (fd > 1)
diff --git a/src/nnn.h b/src/nnn.h
index d1857d59..343841fd 100644
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -3,7 +3,7 @@
*
* Copyright (C) 2014-2016, Lazaros Koromilas
* Copyright (C) 2014-2016, Dimitris Papastamos
- * Copyright (C) 2016-2023, Arun Prakash Jana
+ * Copyright (C) 2016-2024, Arun Prakash Jana
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without