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