jarun/nnn

ToDo list

Closed this issue Β· 56 comments

jarun commented

Rolled from #483.

Ready for next release

  • an official logo
  • previews
    • config NNN_FIFO to write hovered file paths a previewer can read
    • plugin preview-tabbed: tabbed/xembed based file previewer
    • plugin preview-tui: simple TUI file previewer in tmux/xterm
    • plugin preview-kitty: preview using kitty terminal's capabilities
    • live preview configuration example
  • find & list
    • send list of files from (cmd run as) plugin to nnn
    • plugin finder: find/fd/fzf/grep/ripgrep/fzf (in subtree) and list in nnn
    • Right or l on symlink in list dir takes to target file
  • persistent session option -S [for disk usage, run nnn -T d (see help)]
  • hover on the file when a file path is passed as positional argument
  • go to first file or match with ' (followed by ' or char)
  • config NNN_SEL to specify custom selection file
  • config NNN_LOCKER to specify locker program
  • dim file details in detail mode
  • call chdir() on directory change
  • option -l: number of lines to move on mouse scroll
  • graphical keybind map
  • let NNN_COLORS override NO_COLOR
  • plugins
    • option -P: run plugin by key at start
    • run plugins with Alt+key
    • allow NNN_PIPE usage by commands run as plugin
    • input format to NNN_PIPE: <ctxcode><opcode><data> (see plugins doc)
    • set ctxcode to + for smart context usage (next inactive, else current)
    • getplugs to fetch plugins by installed version of nnn
    • plugin mimelist: list files by mime type in subtree
    • plugin bookmarks: named bookmarks using symlinks
    • plugin nbak: backup nnn config
    • nuke adds lowdown as alternative markdown viewer
    • several plugin improvements
  • fix broken screen on resize (see #520)
  • fix broken version sort (see #550)
  • fix list and pipe modes not working together
  • fix multiple issues with listing files
  • fix @ shown in detail mode for symlink to dir
  • fix listing files directly under /
  • move to -std=c11

Proposed features and tasks (up for grabs)

  • a plugin for GPG based encryption
  • make the context-specific code generic, support up to 8 contexts (@0xACE)
  • support pre-defined filters like bookmarks
  • a video exploring nnn plugins
  • move hardware cursor to selected item (see #534)

Anything else which would add value (please discuss in this thread).

Feature Request

Hi, thank you so much for this wonderful command line tool. Is there any plan to enhance fzopen plugin? Something like adding $FZF_DEFAULT_COMMAND so it can be used to exclude some directories that were specified inside $FZF_DEFAULT_COMMAND such as .git, node_modules, etc. Because currently find command tries to indexing all files and directories.

entry=$(find . -type f 2>/dev/null | fzf --delimiter / --nth=-1 --tiebreak=begin --info=hidden)

Let me know what you think. Feel free to send a PR

jarun commented

Yes sure, please raise a PR.

jarun commented

Got a question:

Shouldn't both FZF_DEFAULT_COMMAND and FZF_DEFAULT_OPTS work if they are defined?

Not at this moment. It only reads $FZF_DEFAULT_OPTS

Note: both already defined

jarun commented

Shouldn't that be fixed in fzf instead of the plugin?

It works if I run outside fzopen (zsh, bash, vim, etc) but the problem comes in when I try to search inside fzopen. I think the problem because find command that is using in this plugin

jarun commented

I see. See if it can be fixed.

Is the -c parameter limited to nuke ?
If I have: xdg-mime query default image/jpeg -> chromium.desktop, nnn -c will open images in chromium. Do I need to have NNN_OPENER specified ?

jarun commented

Is the -c parameter limited to nuke ?

No, you can use it with any custom cli opener.

Yes, you'll have to specify the path to the custom opener in NNN_OPENER.

http://0x0.st/iQNI.webm

Hmm maybe I'm doing something wrong. I've attached a short screen recording.

jarun commented
  1. In the image you are running nnn, so the image will open using xdg-open.

  2. To open using nuke or any other opener, you have to

    • set NNN_OPENER
    • use nnn -c
  3. If you want to use xdg-open, use xdg-mime to set the default app for images to something like gpicview.

I set the NNN_OPENER env var using that alias I made for nnn. It's in the upper right terminal.
I'm probably confused about how the -c parameter works. Does nnn actually have a way to control if a file will be opened in something that is not cli ?

jarun commented

In your case:

NNN_OPENER=xdg-open means you want to open files in xdg-open.

Then you have:

xdg-mime query default image/jpeg
chromium.desktop

So images will open in chromium. What is your expectation?

If you do NOT want to open images using chromium see this: https://unix.stackexchange.com/a/59088/164910

I'm probably confused about how the -c parameter works.

If you want to set xdg-open as opener you do NOT have to use -c.

Does nnn actually have a way to control if a file will be opened in something that is not cli ?

There's no issue with nnn here. You have set xdg-open as your opener and the images are set to open in chromium. That's the expected result. Check the link I shared above to set the application to open images from chromium to something else.

What application do you want to open images in?

Forgive me but what is the use case for "-c" if some file will open in a graphical application regardless if the NNN_OPENER is set or not ?

I honestly expected nnn -c to just not open a image in chromium because chromium is a graphical application.

jarun commented

if some file will open in a graphical application regardless if the NNN_OPENER is set or not

Your opener is xdg-open, which is a graphical opener, and that decides which application will open your images (in this case, chromium). Using -c in nnn doesn't change the behaviour of your opener. The option -c cannot change a graphical opener to cli opener.

What open -c does is - it blocks when it spawns the opener. This is useful when you want to edit a file in the cli (nnn has to wait otherwise your editor e.g. will never show). Without the -c option nnn doesn't open for the opener to exit.

Yes, xdg-open does behave like a cli opener in the virtual terminal environment and chooses cli applications. But it detects a virtual terminal using environment variables etc. In your case you are in a desktop environment. So xdg-open will open files using regular GUI desktop apps (like chromium). Any option in nnn cannot change that.

Using -c in nnn doesn't change the behaviour of your opener.

I see. Thank you. What does it actually do ? Because in the man page it says this:

opener opens files in cli utilities only (overrides -e)

EDIT: Saw your edit. Thanks again.

jarun commented

I added more details in my earlier answer.

opener opens files in cli utilities only (overrides -e)

It doesn't mean that the option forces opener to open files in CLI utilities only. It means that when the user sets this flag he is indicating to nnn that the opener opens files in CLI apps only.

Anyway, I see why it's confusing. I will update it.

Firstly, can you elaborate on this feature?

support pre-defined filters like bookmarks

I wrote myself a plugin that seems to work pretty well:
https://github.com/toddyamakawa/bin/blob/master/nnn-bookmarks

If my plugin looks like something that’s usable and what you envisioned, I could write it in such a way that it removes the fzf dependency.

I have a lot of ideas for features that I think could be useful:

  • When a plugin gets run, if it has a non-zero exit code I think that nnn should display the output for the user. This would make writing and debugging plugins a lot easier.
  • Speaking of plugins, instead of putting all the plugins in the ~/.config/nnn/plugins directory, I think it would be great if nnn instead searched $PATH for any nnn- commands. That way I could specify my nnn-bookmarks command by setting the environment variable to b:bookmarks
  • I think nnn should always open a pipe, and every time the directory is changed, it writes the directory to the pipe. This would enable another process to watch the pipe and react to those changes, e.g. another tmux pane that displays things about the directory nnn is currently in. This would enable us to write some really cool plugins.
jarun commented

Firstly, can you elaborate on this feature?

This is for pre-defined filters a user can set like NNN_BMS or NNN_PLUG and apply. The implementation should follow the current ones.

I wrote myself a plugin that seems to work pretty well

Can you please explain what it does? And in which workflow would it replace fzf?

if it has a non-zero exit code I think that nnn should display the output for the user

That would be very useful indeed.

I think it would be great if nnn instead searched

  • we want to have a distinct repo
  • it also makes listing the plugins easy
    • it's not possible to remember shortcuts for all plugins
    • we can't search $PATH for all plugins and list them in a custom view
  • it also doesn't need sudo permissions to install (of course you can extend $PATH but still... we now provide static binary)

I think nnn should always open a pipe, and every time the directory is changed, it writes the directory to the pipe.

That's a lot of disk writes unless your /tmp is tmpfs (maybe we could have a keybind to do that explicitly?).

jarun commented

@toddyamakawa can you also take a look at my request at #520 (comment)?

Firstly, can you elaborate on this feature?

This is for pre-defined filters a user can set like NNN_BMS or NNN_PLUG and apply. The implementation should follow the current ones.

Ah, I misunderstood what the feature does. I do not have a predefined filter.

I wrote myself a plugin that seems to work pretty well

Can you please explain what it does? And in which workflow would it replace fzf?

I have a bunch of symlinks I use in my $HOME/.links directory (although if I turned it into a plugin I would probably change that to $HOME/.config/nnn/bookmarks or something). My plugin will cd into one of the symlinks by using fzf. This effectively gets over the limit on the number of bookmarks a user can have and it allows you to "name" the bookmarks.

I think it would be great if nnn instead searched

  • we want to have a distinct repo

  • it also makes listing the plugins easy

    • it's not possible to remember shortcuts for all plugins
    • we can't search $PATH for all plugins and list them in a custom view
  • it also doesn't need sudo permissions to install (of course you can extend $PATH but still... we now provide static binary)

I personally think that $PATH feels more like the *nix way. e.g. if you add a git-<CMD> command to $PATH, then run git <CMD>, then git will automatically search for the command and run it. nnn is one of those tools that doesn't need a config file because it uses environment variables. This would bring it one step closer to getting rid of the need for a specific config directory. I think a lot of power users probably already have their own bin directories that they extend $PATH with.

Does nnn currently display all plugins somewhere or is it just mapped plugins? There are definitely ways to list all the plugins if it's needed, but it definitely isn't pretty, and will definitely be harder in C.

echo "$PATH" | tr ':' '\n' | xargs -I % bash -c 'ls -l %/nnn-*' 2>/dev/null

I think nnn should always open a pipe, and every time the directory is changed, it writes the directory to the pipe.

That's a lot of disk writes unless your /tmp is tmpfs (maybe we could have a keybind to do that explicitly?).

Good point, I didn't think about that. I guess it would be better to map a key binding or a flag.

jarun commented

I have a bunch of symlinks

Why not create a file with the paths?
Also, on a side note, there are no limits to bookmarks in v3.1.

I would probably change that to $HOME/.config/nnn/bookmarks or something

Plugin gutenbook uses DIR="${XDG_CACHE_HOME:-$HOME/.cache}/nnn/gutenbooks/$EBOOK_ID"

feels more like the *nix way

We can't drop the listing plugins feature. And this also affects run-cmd-as-plugin, now when we have such a command ls can also mean nnn-ls. I do not want to parse the cmd token and do this. I think we are much more organized with what we have today. The last thing I ever want is to parse PATH, touch the filesystem in the core file manager.

Also, we do not run commands with nnn like we do with git. I would like to keep this clean. That's the reason we also don't invoke 5 different utilities in 5 different languages with 5 different params to show images for 5 different mimes in 5 ways for for 5 different terminals, you see. ;)

This would bring it one step closer to getting rid of the need for a specific config directory.

Not having a config file and not having a config dir are different. We still need to store sessions, selection file and so on...

Does nnn currently display all plugins somewhere or is it just mapped plugins?

It does. ; -> Enter.

I have a bunch of symlinks

Why not create a file with the paths?

I guess my plugin on the surface looks like a duplicate of the fzz plugin. There are two good things about symlinks:

  1. It has a name. name -> directory
  2. I use directories with a bunch of symlinks in my $CDPATH.

Also, on a side note, there are no limits to bookmarks in v3.1.

I think the one limitation with the built-in bookmarks is you have to remember which letter is mapped to which bookmark or you have to look it up first with ?. If you have 30+
bookmarks and you haven't used some of them in a while, then using fzf would make it easier.

ls can also mean nnn-ls.

The mappings would be different though. nnn-ls would be l:ls and ls would be l:_ls

Does nnn currently display all plugins somewhere or is it just mapped plugins?

It does. ; -> Enter.

Good to know. Thanks!

Anyways, I understand everything you're saying. nnn has a really cool paradigm in the way that it was developed. It's very easy to use and configure, and (once you figure it out) very easy to extend with plugins.

It does feel like having a config directory sort of conflicts with not having a config file and that setting things with environment variables sort of conflicts with having a config directory, but everything does work really well together.

jarun commented

It has a name. name -> directory

Have entries in the file as: name -> path
And then parse the file output in fzf to show only the first column.
I am insisting on text as it is much easy to configure and edit and only 1 additional file on the disk.

then using fzf would make it easier

Yes, I am OK with adding a plugin that works as the fallback. And we won't have z dep either. I would love it if we could get rid of the fzf dep too.

The mappings would be different though. nnn-ls would be l:ls and ls would be l:_ls

Let's not have this. We are well-provisioned with the current mechanism.

It does feel like having a config directory sort of conflicts with not having a config file and that setting things with environment variables sort of conflicts with having a config directory

The config file isn't there because we don't want to load and read a file from disk every time we start. There's no such issue with dirs.

jarun commented

Also, see my dev-room note on the backup thing. We can do those because we are well organised. Maybe we should have the bookmark file in config dir so that also gets backed up without any additional effort.

jarun commented

But to do that, we need to get the plugin work without fzf or have a way to handle if fzf is not installed.

It has a name. name -> directory

Have entries in the file as: name -> path
And then parse the file output in fzf to show only the first column.
I am insisting on text as it is much easy to configure and edit and only 1 additional file on the disk.

name -> path was an oversimplification since each symlink is a file, which gives additional information like timestamps and group permissions for additional things to filter on. Plus it's impossible to have a syntax error since it's not all in a file.

then using fzf would make it easier

Yes, I am OK with adding a plugin that works as the fallback. And we won't have z dep either. I would love it if we could get rid of the fzf dep too.

I've never looked at z. Does it just use a text file in the home directory? If so, it should be trivial to rewrite fzz to not have an fzf or z dependency if we use the select command.

The config file isn't there because we don't want to load and read a file from disk every time we start. There's no such issue with dirs.

I didn't even think about that. Thanks for the explanation

In the current state, is possible to write a plugin to display file icons using a patched font?

jarun commented

In the current state, is possible to write a plugin to display file icons using a patched font?

And why do we need to do that in nnn?

jarun commented

@RibalGZ we do not want to make nnn a copy of another file manager with tons of fancy features. nnn provides string/regex filters, sort by extension which are dead simple to use and much more effective in finding the file you want. How does showing an icon or a different color help in finding an executable in /bin?

The main goal of nnn still remains to be text-based and simple.

0xACE commented

In the current state, is possible to write a plugin to display file icons using a patched font?

And why do we need to do that in nnn?

Again, it's related to being able to determine information in more ways than just reading file names...

Now i don't find icons necessary, but thumbnails help a lot with pictures... but I guess a image browser fits better for this goal, considering we are in the terminal...

So really: it's not exactly necessary in nnn's case...

@RibalGZ I asked in the private dev-discussion thread:

Could nnn spew out the conents it's listing to the script in this case?

This would allow a seperate script to run along side nnn and let you list information per line...

Didn't receive an answer, but I may add it on my local copy in the future as I find this useful, as it allows you to virtually add extra columns to nnn as you wish.

jarun commented

Could nnn spew out the conents it's listing to the script in this case?

I missed this. That would be too much data written on each hover. Yes, it's probably better to maintain in a fork if you fin it useful. You can refer to the code for handling SEL_EXPORT.

jarun commented

@RibalGZ I checked the feasibility. It would need a regex match per file. Too heavy for nnn standards.

And why do we need to do that in nnn?
we do not want to make nnn a copy of another file manager with tons of fancy features.

We don't need to do that in nnn, and I don't know if other file managers do it either.

I just wondered if something like that could be achieved via plugins in the current state of the project.

@RibalGZ I checked the feasibility. It would need a regex match per file. Too heavy for nnn standards.

I agree, thank you!

What about adding support for specifying custom colors for file entry according to the file name ? Using something like export NNN_FILECOLORS="*mp4:1;*jpg:2;Makefile:4"

0xACE commented

What about adding support for specifying custom colors for file entry according to the file name ? Using something like export NNN_FILECOLORS="*mp4:1;*jpg:2;Makefile:4"

As jarun described, the method of detecting it would increase the complexity of nnn's codebase. And would come at cost of nnn's performance.

Have you tried filtering by search? or sorting by file extension? te?

(as I was writing this)

Wait a minute, we already have te... Maybe it shouldn't be that hard to implement after all. I don't have interest in this problem, but look at cfg.extnorder and change printent() according to your needs.

jarun commented

@0xACE is right. We would like to avoid a regex/string compare per file, which color codes would warrant. You'll have to understand that nnn's priority is performance on low end devices like the Pi and low-end Android devices. Even making it optional means an additional check per file or separate print functions (which would increase binary size).

Sort by extension is a specific case. As @0xACE has suggested, feel free to patch.

Is the folder hover/selection highlight change intentional? Note that the forward slash is no longer included and the highlight no longer has extra padding it's left margin.

Left nnn version 3.0 and right nnn versions 3.1.
20-05-07-010316_1920x1080_scrot

jarun commented

This is intentional. Tells you the exact file name and looks better.

0xACE commented

That is a pleasantly nice setup you have @gyvess (referring to the ricing)

diff --git a/src/nnn.c b/src/nnn.c
index 49127b8..ff50bf3 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -3285,11 +3285,11 @@ static void printent(const struct entry *ent, uint namecols, bool sel)
 #else
 	addstr(unescape(ent->name, MIN(namecols, ent->nlen) + 1));
 #endif
+	if (ind)
+		addch(ind);
 	if (attrs)
 		attroff(attrs);
 
-	if (ind)
-		addch(ind);
 	addch('\n');
 }
 
@@ -3374,10 +3374,10 @@ static void printent_long(const struct entry *ent, uint namecols, bool sel)
 #else
 	addstr(unescape(ent->name, MIN(namecols, ent->nlen) + 1));
 #endif
-	if (attrs)
-		attroff(attrs);
 	if (ind2)
 		addch(ind2);
+	if (attrs)
+		attroff(attrs);
 	addch('\n');
 }

This should fix the / highlight part (I didn't test, I'm shooting from the hips atm)

diff --git a/src/nnn.c b/src/nnn.c
index 49127b8..a83f51d 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -3276,10 +3276,10 @@ static void printent(const struct entry *ent, uint namecols, bool sel)
 	/* Directories are always shown on top */
 	resetdircolor(ent->flags);
 
-	addch((ent->flags & FILE_SELECTED) ? '+' : ' ');
 
 	if (attrs)
 		attron(attrs);
+	addch((ent->flags & FILE_SELECTED) ? '+' : ' ');
 #ifndef NOLOCALE
 	addwstr(unescape(ent->name, namecols));
 #else
@@ -3304,10 +3304,10 @@ static void printent_long(const struct entry *ent, uint namecols, bool sel)
 	/* Directories are always shown on top */
 	resetdircolor(ent->flags);
 
-	addch((ent->flags & FILE_SELECTED) ? '+' : ' ');
 
 	if (attrs)
 		attron(attrs);
+	addch((ent->flags & FILE_SELECTED) ? '+' : ' ');
 
 	/* Timestamp */
 	print_time(&ent->t);

And that should do the same for the + selection marker.

Again I didn't test these, have fun.

jarun commented

@0xACE what is the problem with not highlighting the / and the prefix space?

0xACE commented

@0xACE what is the problem with not highlighting the / and the prefix space?

No problem whatsoever, it was poor wording from me. imho. I was trying to be quick with writing my post... It grinds down to personal taste and behavior.

Imho tough: there is no other user experience where / is excluded...

Tbh, this "issue" is of such minor cause that it is not worth delving into, unless it's considered a problem by others.

So for now let it rest. We both know it is easily reversible. I'll back you up in the public branch, if this becomes a problem

jarun commented

Thanks, I thought I broke something in user experience. Highlighting the file name seemed logical.

I have a feature request / request for help (perhaps this is already possible with plugins, but I haven't been able to achieve it yet).

I use "picker" (-p) mode from my editor to navigate between files. I'd like to be able to control the file that nnn has selected when I start it. For example, I've got files fileA through fileC in my folder, I'm currently editing fileB. I'd like to start nnn with fileB selected (as opposed to the usual case which would start with fileA) so if I want to navigate to fileC it's just 1 file away.

It's sort of like a reverse NNN_FIFO or writable $nnn variable. Is this already possible or a valid feature? Thanks.

Edit: I'm sure it works differently, but the same as how navigating up to the parent directory puts the cursor on the directory that you were just in - I'd like to do that but with files too.

jarun commented

@joshaw your answer is sessions. Have a saved session with that file hovered and use -s session_name to start with that session.

Thank you! I'll try using sessions. I'm guessing it would work to dynamically create the session file in ~/.config/nnn/sessions and load it with -s, simple!

jarun commented

Yes, we try our best to keep the workflows simple for users however complex they are internally.

Is there any documentation on the session file format? I can't find any and am currently just getting either a segfault or "failed" flashing up and the session file has no effect. Thanks for your help

jarun commented

You don't need to know the session file format or create one manually. You need to save a session when you are running nnn.

The documentation is available in the man page as well as in the wiki - https://github.com/jarun/nnn/wiki#sessions

I'd like to start from an artbitrary file though, so can't create a session file beforehand. I can pass the directory so that nnn starts in the right folder, but I'd like to start at the right file as well. My workflow is

  1. $EDITOR some/folder/fileB
  2. I want to move to some/folder/fileC
  3. Press a key to start nnn, which runs nnn -p - some/folder
  4. Select the file and the output is used to change to that file.
    That works very well, I'd just like to be able to start nnn with the cursor on fileB, or whichever other file I happen to be editing at the time.
0xACE commented

https://github.com/jarun/nnn/blob/master/src/nnn.c#L3520-L3528

I guess this is the format you are looking for.

jarun commented

@joshaw At present if you pass a file path to nnn it would just open that file and exit.

I've pushed a sample implementation at commit 5688692 to select the file if the file path is passed.

@0xACE We do not need to modify session handling for this. When a session is saved it will store the path and hovered file correctly which works as it should.

The commit above breaks our current behaviour where we open the file directly using opener if the path points to a file and nnn exits. However, now nnn will stay open with the file hovered.

@0xACE @KlzXS @leovilok do you guys think this new behaviour is acceptable? Consider the scenario where a file is opened from the browser and nnn is set as the default file manager.

0xACE commented

I think it makes sense if nnn highlights the file if it has been given one in the path...

I like this new behaviour better. I think that it's out of the scope of nnn to open the file directly.

jarun commented

OK. Then it stays!

I've pushed a sample implementation at commit 5688692 to select the file if the file path is passed.

This works brilliantly. Thanks very much