Skip to content

Concepts

Arun edited this page Jul 16, 2022 · 61 revisions

Asciicast

Project dir in preview

Contexts

Open multiple locations with 4 contexts. The status is shown in the top left corner:

  • the current context is in reverse video
  • other active contexts are underlined
  • rest are inactive

Create and cycle contexts using Tab or Shift+Tab. A new context copies the state of the previous context.

Use context-specific colors (see configuration NNN_COLORS) to identify each context easily.

Dual pane

The nnn way is to work with multiple contexts using Tab or Shift+Tab.

Other solutions:

  • terminal multiplexers (tmux, GNU Screen, dvtm, SplitVT)
  • terminal emulators with split support (Terminator, Tilix)

For example, to open 2 instances in dvtm, run:

dvtm n n

You can also have an alias:

alias 2="dvtm n n"

or a Bash function (with ^\ as dvtm modifier) to handle arguments:

2 ()
{
    dvtm -m '^\' "nnn -nr $@" "nnn -nr $@"
}

Sessions

Sessions are a way to save and restore states of work. A session stores the settings and contexts. Sessions can be loaded at runtime or with a program option.

Notes:

  1. When a session is loaded at runtime, the last working state is saved automatically to a dedicated -- "auto session" -- session file. Session option restore would restore the "auto session".
  2. The persistent session option is global. If it is used, the last active session will be updated with the final state at program quit.
  3. The "auto session" is used in persistent session mode if no session is active.
  4. Listing input stream and opening a bookmark by key have higher priority to session options (-s/-S).

All the session files are located by session name in the directory

${XDG_CONFIG_HOME:-$HOME/.config}/nnn/sessions

"@" is the "auto session" file.

Filters

Filters are strings (or regex patterns) to find matching entries in the current directory instantly (search-as-you-type). Matches are case-insensitive by default. The last filter in each context is persisted at runtime or in saved sessions.

When there's a unique match and it's a directory, nnn auto-enters the directory. Program option -A disables this.

Special keys at filter prompt

Key Function
^char Usual keybind functionality
Esc Exit filter prompt but skip dir refresh
Alt+Esc Exit filter prompt and refresh dir (same as Esc^L)

Special keys at empty filter prompt:

Key Function
? Show help and config screen
/ Toggle between string and regex
: Toggle case-sensitivity
^L Clear filter (if prompt is non-empty)
OR apply last filter
Bksp Stay at filter prompt and refresh dir
Del Stay at filter prompt and refresh dir

Common regex use cases

  • to list all matches starting with the filter expression, start with a ^ (caret)
  • type \.mkv to list all MKV files
  • use .* to match any character (sort of fuzzy search)
  • exclude filenames having nnn (with PCRE): ^(?!nnn)

Limitation

Use regex for case-sensitive filtering with wide chars as the function strcasestr (used for string filters) does not work with multibyte locales (ref1, ref2).

Type-to-nav

In this mode directories are opened in filter mode, allowing continuous navigation.

To start in type-to-nav mode, use the program option -n or press ^N.

Additional special keys at empty filter prompt in type-to-nav mode:

Listing 1 Listing 2
Key Function
' Go to first file/match
+ Toggle file selection
, Mark CWD
- Go to last visited dir
. Show hidden files
; Run a plugin by its key
Key Function
= Launch a GUI application
> Export file list
@ Visit start dir
] Show command prompt
` Visit /
~ Go HOME

Selection

nnn allows file selection across directories and contexts!

There are 3 groups of keybinds to add files to selection:

  1. hovered file selection toggle
    • deselects if + is visible before the entry, else adds to selection
  2. add a range of files to selection
    • repeat the range key on the same entry twice to clear selection completely
  3. add all files in the current directory to selection

A selection can be edited, copied, moved, removed, archived or linked. Example workflow to copy or move some files:

  • add files from source dirs (you can select files from multiple dirs in nnn) to selection
  • navigate to a target directory
  • use ^P (cp) or ^V (mv) to copy or move the selected files

Absolute paths of the selected files are copied to .selection file in the config directory. The selection file is shared between multiple program instances. Selection from multiple instances are not merged. The last instance writing to the file overwrites earlier contents. If you have 2 instances of nnn open in 2 panes of a terminal multiplexer, you can select in one pane and use the selection in the other pane. The selection gets cleared in the nnn instance where the selection was made on mv/rm (but not on cp).

nnn clears the selection after a successful operation with the selection. Plugins are allowed to define the behaviour individually.

Editing selection

To edit the selection use the edit selection key. Editing doesn't end the selection mode. You can add more files to the selection and edit the list again. If no file is selected in the current session, this option attempts to list the selection file.

File paths in selection to system clipboard

Use the program option -x to copy selection to the system clipboard. You must have plugins installed.

Grab file paths in selection manually

Many plugins use this method. The file paths are NUL-terminated, so additional processing is required to make them usable.

To run ls -l on the file paths in selection:

xargs -0 ls -l < "${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection"

An special variable may be handy:

export sel=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection

so you can easily handle files together (even at the nnn command prompt!):

xargs -0 ls -l < $sel

Find and list

There are two ways to search and list:

  • feed a list of file paths as input
  • search using a plugin (e.g. finder) and list the results

File paths must be NUL-separated ('\0'). Paths can be relative to the current directory or absolute. Invalid paths in the input are ignored. Input limit is 65,536 paths or 256 MiB of data.

To list the input stream, start nnn by writing to its standard input. E.g., to list files in current directory larger than 1M:

find -maxdepth 1 -size +1M -print0 | nnn
# fd -d 2 -S +1M -0 | nnn

or redirect a list from a file:

nnn < files.txt

Handy bash/zsh shell function to list files by mime-type in current directory:

# to show video files, run: list video

list ()                                                                                                    
{
    find . -maxdepth 1 | file -if- | grep "$1" | awk -F: '{printf "%s\0", $1}' | nnn
    # fd -d 1 | file -if- | grep "$1" | awk -F: '{printf "%s\0", $1}' | nnn
}

A temporary directory will be created containing symlinks to the given paths. Any action performed on these symlinks will be performed only on their targets, after which they might become invalid.

Right or l on a symlink inside the listing dir takes to the target file. Press - to return to the listing dir. Press Enter to open the symlink.

Listing input stream can be scripted. It can be extended to pick (option -p) selected entries from the listed results.

Prompts

The prompts (except the filter prompt) support readline-like command-line shortcuts. Enter or ^D at the empty prompt (except the filter prompt) exits the prompt.

Key ^L clears and Esc exits all prompts.

Native command prompt

The handy REPL command prompt (shows on ]) understands environment variables (like $PWD). Refer to your shell's documentation (e.g. BASH_ENV for bash, ~/.zshenv for zsh) to use aliases and functions. To fuzzy-select commands from your shell history at the command prompt and issue them after editing (like fc), copy the plugin fzhist (as h maybe?) in your $PATH.

The native command prompt remembers only the last executed command in the current session. To access and use the shell's history add a shell function similar to:

h ()
{
    fzf <~/shell-specific_history_file | tr -d '\n' | xsel -bi 
}

Paste the selected command at the prompt using Ctrl-Shift-V, optionally edit and run.

All binary questions are confirmed by y or Y.

Special variables

The following special variables can be accessed from the command prompt or a spawned shell:

Variable Substitution
$nnn Hovered file name in current context
$dN Path open in context N [N=1/2/3/4]
$fN File path hovered in context N [N=1/2/3/4]

E.g. to copy the hovered file in context 1 to the directory open in context 3, run cp "$f1" "$d3".

Selection can be accessed from the native command prompt:

Variable Substitution
%j repeat cmd with all %j substituted by each selected file path
%J run the command only once with %J as the last characters substituted by all selected file paths

E.g.

Look up a string in each file in selection:

printf "Searching for string in %s\n" "%j"; grep "string" "%j"

Archive all files in selection:

tar uvf archive.tar %J

Notes:

  1. You can only use either %j or %J inside a single command. If both are encountered the prompt will close. No command will be executed.
  2. When using %J nnn will automatically escape special characters. Any %J not at the end of the command will be left unsubstituted.

Copy command from spawned shell to native command prompt

The prompt (non-readline nnn-internal one) can remember the last executed command. Sometimes it may be desirable copy a command from shell history to the prompt. Keybinds can be configured to copy a command from bash/zsh prompt to the system clipboard. You can use these at the subshell prompt and paste the command at the prompt with Ctrl-Shift-V.

# bash: add in ~/.bashrc
# copy current line to clipboard with ^]

if [[ -n $DISPLAY ]]; then
    copy_line_to_x_clipboard () {
        printf %s "$READLINE_LINE" | xsel -ib
    }
    bind -x '"\C-]": copy_line_to_x_clipboard'
fi
# zsh: add in ~/.zshrc
# copy current line to clipboard with ^U

if [[ -n $DISPLAY ]]; then                                                                                    
    x-kill-whole-line () {                                                                                    
      zle kill-whole-line                                                                                     
      print -rn -- "$CUTBUFFER" | xsel -ib                                                                    
    }                                                                                                         
    zle -N x-kill-whole-line                                                                                  
    bindkey '\C-u' x-kill-whole-line                                                                          
fi 

Design

nnn (the core C utility) is, generally speaking, feature-restricted. It includes features which you really need so it can remain light enough to finish your workflow accurately before your train of thought is lost.

nnn supports plugins to extend its capabilities.

Here's a list of the design principles driving the core nnn program:

  1. nnn complements X, doesn't substitute it
    • Brings the best of CLI to a GUI user
    • Doesn't expect the user to abandon GUI (the GUI is well-established for a reason)
    • Zero-config comfort-zone for GUI users out of the box
  2. Quick and distraction-free workflows
  3. Clean and clutter-free single-window view focused on content
    • Easily switch context/tabs with (Sh)TAB
  4. Only directories in color, no icons
    • To search/group by extension, use filter or sort by extension option
  5. Support external or plugin-based previewers by writing the the hovered file path to a custom FIFO.
  6. One utility instead of multiple utilities for related tasks e.g.
    • file management, batch rename, disk usage analysis, launching apps etc.
  7. No configuration file and few environment variables
  8. Stay portable - very limited library dependencies
    • support compiling out features
  9. Use a standard desktop opener to handle file associations
  10. Analyze disk usage within the same filesystem, do not follow symbolic links
  11. Case-insensitive alphabetic content listing instead of all uppercase first
  12. Directories first in all modes (even in disk usage analyzer mode)
  13. No navigation restriction with relative paths (let permissions handle it)
  14. Directory updates are disabled in the following modes:
    • disk usage: re-scans are issued on every change in dir
    • filter mode: content refresh is very disruptive in the workflow
  15. Limited (4) number of contexts; for more, please refer to make option O_CTX8
    • file paths copy-paste should work seamlessly between contexts and instances of nnn
  16. Scan each directory on visit (even in disk usage analyzer mode) rather than storing all the information from the first scan. This keeps the information up to date. To compensate, use fast re-scan with highly optimized algorithms.
Clone this wiki locally